예제 #1
0
/* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */
static int
scsi_read_capacity(int sg_fd, int64_t * num_sect, int * sect_sz)
{
    int res;
    unsigned int ui;
    unsigned char rcBuff[RCAP16_REPLY_LEN];
    int verb;

    verb = (verbose ? verbose - 1: 0);
    res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, 0,
                           verb);
    if (0 != res)
        return res;

    if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) &&
            (0xff == rcBuff[3])) {

        res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, 0,
                               verb);
        if (0 != res)
            return res;
        *num_sect = sg_get_unaligned_be64(rcBuff + 0) + 1;
        *sect_sz = sg_get_unaligned_be32(rcBuff + 8);
    } else {
        ui = sg_get_unaligned_be32(rcBuff + 0);
        /* take care not to sign extend values > 0x7fffffff */
        *num_sect = (int64_t)ui + 1;
        *sect_sz = sg_get_unaligned_be32(rcBuff + 4);
    }
    if (verbose)
        pr2serr("      number of blocks=%" PRId64 " [0x%" PRIx64 "], block "
                "size=%d\n", *num_sect, *num_sect, *sect_sz);
    return 0;
}
예제 #2
0
파일: sg_safte.c 프로젝트: junroh/sg3_utils
/* Buffer ID 0x02: Read Usage Statistics (optional) */
static int
do_safte_usage_statistics(int sg_fd, int do_hex, int do_raw, int verbose)
{
    int res;
    unsigned int rb_len;
    unsigned char *rb_buff;
    unsigned int minutes;

    rb_len = 16 + safte_cfg.vendor_specific;
    rb_buff = (unsigned char *)malloc(rb_len);

    if (verbose > 1)
        pr2serr("Use READ BUFFER,mode=vendor_specific,buff_id=2 to read "
                "usage statistics\n");
    res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 2, 0,
                            rb_buff, rb_len, 0, verbose);
    if (res) {
        if (res == SG_LIB_CAT_ILLEGAL_REQ) {
            printf("Usage Statistics:\n\tNot implemented\n");
            return 0;
        }
        if (res != SG_LIB_CAT_RECOVERED) {
            free(rb_buff);
            return res;
        }
    }

    if (do_raw > 1) {
        dStrRaw((const char *)rb_buff, buf_capacity);
        return 0;
    }
    if (do_hex > 1) {
        dStrHex((const char *)rb_buff, buf_capacity, 1);
        return 0;
    }
    printf("Usage Statistics:\n");
    minutes = sg_get_unaligned_be32(rb_buff + 0);
    printf("\tPower on Minutes: %u\n", minutes);
    minutes = sg_get_unaligned_be32(rb_buff + 4);
    printf("\tPower on Cycles: %u\n", minutes);

    free(rb_buff);
    return 0;
}
예제 #3
0
/* display DPC_DOWNLOAD_MICROCODE status dpage [0xe] */
static void
show_download_mc_sdg(const uint8_t * resp, int resp_len,
                     uint32_t gen_code)
{
    int k, num_subs, num;
    const uint8_t * bp;
    const char * cp;

    printf("Download microcode status diagnostic page:\n");
    if (resp_len < 8)
        goto truncated;
    num_subs = resp[1];  /* primary is additional one) */
    num = (resp_len - 8) / 16;
    if ((resp_len - 8) % 16)
        pr2serr("Found %d Download microcode status descriptors, but there "
                "is residual\n", num);
    printf("  number of secondary subenclosures: %d\n", num_subs);
    printf("  generation code: 0x%" PRIx32 "\n", gen_code);
    bp = resp + 8;
    for (k = 0; k < num; ++k, bp += 16) {
        cp = (0 == bp[1]) ? " [primary]" : "";
        printf("   subenclosure identifier: %d%s\n", bp[1], cp);
        cp = get_mc_status_str(bp[2]);
        if (strlen(cp) > 0) {
            printf("     download microcode status: %s [0x%x]\n", cp, bp[2]);
            printf("     download microcode additional status: 0x%x\n",
                   bp[3]);
        } else
            printf("     download microcode status: 0x%x [additional "
                   "status: 0x%x]\n", bp[2], bp[3]);
        printf("     download microcode maximum size: %" PRIu32 " bytes\n",
               sg_get_unaligned_be32(bp + 4));
        printf("     download microcode expected buffer id: 0x%x\n", bp[11]);
        printf("     download microcode expected buffer id offset: %" PRIu32
               "\n", sg_get_unaligned_be32(bp + 12));
    }
    return;
truncated:
    pr2serr("    <<<download status: response too short>>>\n");
    return;
}
예제 #4
0
/* Return of 0 -> success, -1 -> failure, 2 -> try again */
static int
read_capacity(int sg_fd, int * num_sect, int * sect_sz)
{
    int res;
    uint8_t rc_cdb [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    uint8_t rcBuff[64];
    uint8_t sense_b[64];
    sg_io_hdr_t io_hdr;

    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(rc_cdb);
    io_hdr.mx_sb_len = sizeof(sense_b);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = sizeof(rcBuff);
    io_hdr.dxferp = rcBuff;
    io_hdr.cmdp = rc_cdb;
    io_hdr.sbp = sense_b;
    io_hdr.timeout = DEF_TIMEOUT;

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("read_capacity (SG_IO) error");
        return -1;
    }
    res = sg_err_category3(&io_hdr);
    if (SG_LIB_CAT_UNIT_ATTENTION == res)
        return 2; /* probably have another go ... */
    else if (SG_LIB_CAT_CLEAN != res) {
        sg_chk_n_print3("read capacity", &io_hdr, 1);
        return -1;
    }
    *num_sect = 1 + sg_get_unaligned_be32(rcBuff + 0);
    *sect_sz = sg_get_unaligned_be32(rcBuff + 4);
#ifdef DEBUG
    fprintf(stderr, "number of sectors=%d, sector size=%d\n",
            *num_sect, *sect_sz);
#endif
    return 0;
}
예제 #5
0
int
main(int argc, char * argv[])
{
    bool got_stdin = false;
    bool if_given = false;
    bool lba_given = false;
    bool num_given = false;
    bool prot_en;
    int res, c, infd, act_cdb_len, vb, err;
    int sg_fd = -1;
    int ret = -1;
    uint32_t block_size;
    int64_t ll;
    const char * device_name = NULL;
    struct opts_t * op;
    uint8_t * wBuff = NULL;
    uint8_t * free_wBuff = NULL;
    char ebuff[EBUFF_SZ];
    char b[80];
    uint8_t resp_buff[RCAP16_RESP_LEN];
    struct opts_t opts;
    struct stat a_stat;

    op = &opts;
    memset(op, 0, sizeof(opts));
    op->numblocks = DEF_WS_NUMBLOCKS;
    op->pref_cdb_size = DEF_WS_CDB_SIZE;
    op->timeout = DEF_TIMEOUT_SECS;
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "ag:hi:l:Ln:NPRSt:TUvVw:x:",
                        long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'a':
            op->anchor = true;
            break;
        case 'g':
            op->grpnum = sg_get_num(optarg);
            if ((op->grpnum < 0) || (op->grpnum > 63))  {
                pr2serr("bad argument to '--grpnum'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'i':
            strncpy(op->ifilename, optarg, sizeof(op->ifilename) - 1);
            op->ifilename[sizeof(op->ifilename) - 1] = '\0';
            if_given = true;
            break;
        case 'l':
            ll = sg_get_llnum(optarg);
            if (-1 == ll) {
                pr2serr("bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            op->lba = (uint64_t)ll;
            lba_given = true;
            break;
        case 'L':
            op->lbdata = true;
            break;
        case 'n':
            op->numblocks = sg_get_num(optarg);
            if (op->numblocks < 0)  {
                pr2serr("bad argument to '--num'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            num_given = true;
            break;
        case 'N':
            op->ndob = true;
            break;
        case 'P':
            op->pbdata = true;
            break;
        case 'R':
            op->want_ws10 = true;
            break;
        case 'S':
            if (DEF_WS_CDB_SIZE != op->pref_cdb_size) {
                pr2serr("only one '--10', '--16' or '--32' please\n");
                return SG_LIB_CONTRADICT;
            }
            op->pref_cdb_size = 16;
            break;
        case 't':
            op->timeout = sg_get_num(optarg);
            if (op->timeout < 0)  {
                pr2serr("bad argument to '--timeout'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'T':
            if (DEF_WS_CDB_SIZE != op->pref_cdb_size) {
                pr2serr("only one '--10', '--16' or '--32' please\n");
                return SG_LIB_CONTRADICT;
            }
            op->pref_cdb_size = 32;
            break;
        case 'U':
            op->unmap = true;
            break;
        case 'v':
            op->verbose_given = true;
            ++op->verbose;
            break;
        case 'V':
            op->version_given = true;
            break;
        case 'w':
            op->wrprotect = sg_get_num(optarg);
            if ((op->wrprotect < 0) || (op->wrprotect > 7))  {
                pr2serr("bad argument to '--wrprotect'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'x':
            op->xfer_len = sg_get_num(optarg);
            if (op->xfer_len < 0) {
                pr2serr("bad argument to '--xferlen'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (op->want_ws10 && (DEF_WS_CDB_SIZE != op->pref_cdb_size)) {
        pr2serr("only one '--10', '--16' or '--32' please\n");
        return SG_LIB_CONTRADICT;
    }

#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (op->verbose_given && op->version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        op->verbose_given = false;
        op->version_given = false;
        op->verbose = 0;
    } else if (! op->verbose_given) {
        pr2serr("set '-vv'\n");
        op->verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", op->verbose);
#else
    if (op->verbose_given && op->version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (op->version_given) {
        pr2serr(ME "version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("Missing device name!\n\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    vb = op->verbose;

    if ((! if_given) && (! lba_given) && (! num_given)) {
        pr2serr("As a precaution, one of '--in=', '--lba=' or '--num=' is "
                "required\n");
        return SG_LIB_CONTRADICT;
    }

    if (op->ndob) {
        if (if_given) {
            pr2serr("Can't have both --ndob and '--in='\n");
            return SG_LIB_CONTRADICT;
        }
        if (0 != op->xfer_len) {
            pr2serr("With --ndob only '--xferlen=0' (or not given) is "
                    "acceptable\n");
            return SG_LIB_CONTRADICT;
        }
    } else if (op->ifilename[0]) {
        got_stdin = (0 == strcmp(op->ifilename, "-"));
        if (! got_stdin) {
            memset(&a_stat, 0, sizeof(a_stat));
            if (stat(op->ifilename, &a_stat) < 0) {
                err = errno;
                if (vb)
                    pr2serr("unable to stat(%s): %s\n", op->ifilename,
                            safe_strerror(err));
                return sg_convert_errno(err);
            }
            if (op->xfer_len <= 0)
                op->xfer_len = (int)a_stat.st_size;
        }
    }

    sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb);
    if (sg_fd < 0) {
        if (op->verbose)
            pr2serr(ME "open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto err_out;
    }

    if (! op->ndob) {
        prot_en = false;
        if (0 == op->xfer_len) {
            res = sg_ll_readcap_16(sg_fd, false /* pmi */, 0 /* llba */,
                                   resp_buff, RCAP16_RESP_LEN, true,
                                   (vb ? (vb - 1): 0));
            if (SG_LIB_CAT_UNIT_ATTENTION == res) {
                pr2serr("Read capacity(16) unit attention, try again\n");
                res = sg_ll_readcap_16(sg_fd, false, 0, resp_buff,
                                       RCAP16_RESP_LEN, true,
                                       (vb ? (vb - 1): 0));
            }
            if (0 == res) {
                if (vb > 3)
                    hex2stderr(resp_buff, RCAP16_RESP_LEN, 1);
                block_size = sg_get_unaligned_be32(resp_buff + 8);
                prot_en = !!(resp_buff[12] & 0x1);
                op->xfer_len = block_size;
                if (prot_en && (op->wrprotect > 0))
                    op->xfer_len += 8;
            } else if ((SG_LIB_CAT_INVALID_OP == res) ||
                       (SG_LIB_CAT_ILLEGAL_REQ == res)) {
                if (vb)
                    pr2serr("Read capacity(16) not supported, try Read "
                            "capacity(10)\n");
                res = sg_ll_readcap_10(sg_fd, false /* pmi */, 0 /* lba */,
                                       resp_buff, RCAP10_RESP_LEN, true,
                                       (vb ? (vb - 1): 0));
                if (0 == res) {
                    if (vb > 3)
                        hex2stderr(resp_buff, RCAP10_RESP_LEN, 1);
                    block_size = sg_get_unaligned_be32(resp_buff + 4);
                    op->xfer_len = block_size;
                } else {
                    sg_get_category_sense_str(res, sizeof(b), b, vb);
                    pr2serr("Read capacity(10): %s\n", b);
                    pr2serr("Unable to calculate block size\n");
                }
            } else if (vb) {
                sg_get_category_sense_str(res, sizeof(b), b, vb);
                pr2serr("Read capacity(16): %s\n", b);
                pr2serr("Unable to calculate block size\n");
            }
        }
        if (op->xfer_len < 1) {
            pr2serr("unable to deduce block size, please give '--xferlen=' "
                    "argument\n");
            ret = SG_LIB_SYNTAX_ERROR;
            goto err_out;
        }
        if (op->xfer_len > MAX_XFER_LEN) {
            pr2serr("'--xferlen=%d is out of range ( want <= %d)\n",
                    op->xfer_len, MAX_XFER_LEN);
            ret = SG_LIB_SYNTAX_ERROR;
            goto err_out;
        }
        wBuff = (uint8_t *)sg_memalign(op->xfer_len, 0, &free_wBuff, vb > 3);
        if (NULL == wBuff) {
            pr2serr("unable to allocate %d bytes of memory with "
                    "sg_memalign()\n", op->xfer_len);
            ret = sg_convert_errno(ENOMEM);
            goto err_out;
        }
        if (op->ifilename[0]) {
            if (got_stdin) {
                infd = STDIN_FILENO;
                if (sg_set_binary_mode(STDIN_FILENO) < 0)
                    perror("sg_set_binary_mode");
            } else {
                if ((infd = open(op->ifilename, O_RDONLY)) < 0) {
                    ret = sg_convert_errno(errno);
                    snprintf(ebuff, EBUFF_SZ, ME "could not open %.400s for "
                             "reading", op->ifilename);
                    perror(ebuff);
                    goto err_out;
                } else if (sg_set_binary_mode(infd) < 0)
                    perror("sg_set_binary_mode");
            }
            res = read(infd, wBuff, op->xfer_len);
            if (res < 0) {
                ret = sg_convert_errno(errno);
                snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %.400s",
                         op->ifilename);
                perror(ebuff);
                if (! got_stdin)
                    close(infd);
                goto err_out;
            }
            if (res < op->xfer_len) {
                pr2serr("tried to read %d bytes from %s, got %d bytes\n",
                        op->xfer_len, op->ifilename, res);
                pr2serr("  so pad with 0x0 bytes and continue\n");
            }
            if (! got_stdin)
                close(infd);
        } else {
            if (vb)
                pr2serr("Default data-out buffer set to %d zeros\n",
                        op->xfer_len);
            if (prot_en && (op->wrprotect > 0)) {
               /* default for protection is 0xff, rest get 0x0 */
                memset(wBuff + op->xfer_len - 8, 0xff, 8);
                if (vb)
                    pr2serr(" ... apart from last 8 bytes which are set to "
                            "0xff\n");
            }
        }
    }

    ret = do_write_same(sg_fd, op, wBuff, &act_cdb_len);
    if (ret) {
        sg_get_category_sense_str(ret, sizeof(b), b, vb);
        pr2serr("Write same(%d): %s\n", act_cdb_len, b);
    }

err_out:
    if (free_wBuff)
        free(free_wBuff);
    if (sg_fd >= 0) {
        res = sg_cmds_close_device(sg_fd);
        if (res < 0) {
            pr2serr("close error: %s\n", safe_strerror(-res));
            if (0 == ret)
                ret = sg_convert_errno(-res);
        }
    }
    if (0 == op->verbose) {
        if (! sg_if_can2stderr("sg_write_same failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
예제 #6
0
             printf("      %s: %d\n", pr_type_strs[7],
                    !!(pr_buff[4] & 0x80));  /* WR_EX_AR */
             printf("      %s: %d\n", pr_type_strs[6],
                    !!(pr_buff[4] & 0x40));  /* EX_AC_RO */
             printf("      %s: %d\n", pr_type_strs[5],
                    !!(pr_buff[4] & 0x20));  /* WR_EX_RO */
             printf("      %s: %d\n", pr_type_strs[3],
                    !!(pr_buff[4] & 0x8));   /* EX_AC */
             printf("      %s: %d\n", pr_type_strs[1],
                    !!(pr_buff[4] & 0x2));   /* WR_EX */
             printf("      %s: %d\n", pr_type_strs[8],
                    !!(pr_buff[5] & 0x1));   /* EX_AC_AR */
         }
     }
 } else {
     pr_gen =  sg_get_unaligned_be32(pr_buff + 0);
     add_len = sg_get_unaligned_be32(pr_buff + 4);
     if (op->hex) {
         if (op->hex > 1)
             hex2stdout(pr_buff, add_len + 8, ((2 == op->hex) ? 1 : -1));
         else {
             printf("  PR generation=0x%x, ", pr_gen);
             if (add_len <= 0)
                 printf("Additional length=%d\n", add_len);
             if ((uint32_t)add_len > (op->alloc_len - 8)) {
                 printf("Additional length too large=%d, truncate\n",
                        add_len);
                 hex2stdout((pr_buff + 8), op->alloc_len - 8, 1);
             } else {
                 printf("Additional length=%d\n", add_len);
                 hex2stdout((pr_buff + 8), add_len, 1);
예제 #7
0
int
main(int argc, char * argv[])
{
    bool last, got_stdin, is_reg;
    bool want_file = false;
    bool verbose_given = false;
    bool version_given = false;
    int res, c, len, k, n, rsp_len, resid, act_len, din_len, verb;
    int sg_fd = -1;
    int infd = -1;
    int do_help = 0;
    int ret = 0;
    uint32_t gen_code = 0;
    const char * device_name = NULL;
    const char * file_name = NULL;
    uint8_t * dmp = NULL;
    uint8_t * dip = NULL;
    uint8_t * free_dip = NULL;
    char * cp;
    char ebuff[EBUFF_SZ];
    struct stat a_stat;
    struct dout_buff_t dout;
    struct opts_t opts;
    struct opts_t * op;
    const struct mode_s * mp;

    op = &opts;
    memset(op, 0, sizeof(opts));
    memset(&dout, 0, sizeof(dout));
    din_len = DEF_DIN_LEN;
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "b:dehi:I:l:m:No:s:S:t:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'b':
            op->bpw = sg_get_num(optarg);
            if (op->bpw < 0) {
                pr2serr("argument to '--bpw' should be in a positive "
                        "number\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if ((cp = strchr(optarg, ','))) {
                if (0 == strncmp("act", cp + 1, 3))
                    op->bpw_then_activate = true;
            }
            break;
        case 'd':
            op->dry_run = true;
            break;
        case 'e':
            op->ealsd = true;
            break;
        case 'h':
        case '?':
            ++do_help;
            break;
        case 'i':
            op->mc_id = sg_get_num_nomult(optarg);
            if ((op->mc_id < 0) || (op->mc_id > 255)) {
                pr2serr("argument to '--id' should be in the range 0 to "
                        "255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'I':
            file_name = optarg;
            break;
        case 'l':
            op->mc_len = sg_get_num(optarg);
            if (op->mc_len < 0) {
                pr2serr("bad argument to '--length'\n");
                return SG_LIB_SYNTAX_ERROR;
             }
             op->mc_len_given = true;
             break;
        case 'm':
            if (isdigit(*optarg)) {
                op->mc_mode = sg_get_num_nomult(optarg);
                if ((op->mc_mode < 0) || (op->mc_mode > 255)) {
                    pr2serr("argument to '--mode' should be in the range 0 "
                            "to 255\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else {
                len = strlen(optarg);
                for (mp = mode_arr; mp->mode_string; ++mp) {
                    if (0 == strncmp(mp->mode_string, optarg, len)) {
                        op->mc_mode = mp->mode;
                        break;
                    }
                }
                if (! mp->mode_string) {
                    print_modes();
                    return SG_LIB_SYNTAX_ERROR;
                }
            }
            break;
        case 'N':
            op->mc_non = true;
            break;
        case 'o':
           op->mc_offset = sg_get_num(optarg);
           if (op->mc_offset < 0) {
                pr2serr("bad argument to '--offset'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if (0 != (op->mc_offset % 4)) {
                pr2serr("'--offset' value needs to be a multiple of 4\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 's':
           op->mc_skip = sg_get_num(optarg);
           if (op->mc_skip < 0) {
                pr2serr("bad argument to '--skip'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'S':
           op->mc_subenc = sg_get_num_nomult(optarg);
           if ((op->mc_subenc < 0) || (op->mc_subenc > 255)) {
                pr2serr("expected argument to '--subenc' to be 0 to 255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 't':
           op->mc_tlen = sg_get_num(optarg);
           if (op->mc_tlen < 0) {
                pr2serr("bad argument to '--tlength'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            verbose_given = true;
            ++op->verbose;
            break;
        case 'V':
            version_given = true;
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (do_help) {
        if (do_help > 1) {
            usage();
            pr2serr("\n");
            print_modes();
        } else
            usage();
        return 0;
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        op->verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        op->verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", op->verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr(ME "version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("missing device name!\n\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    switch (op->mc_mode) {
    case MODE_DNLD_MC_OFFS:
    case MODE_DNLD_MC_OFFS_SAVE:
    case MODE_DNLD_MC_OFFS_DEFER:
        want_file = true;
        break;
    case MODE_DNLD_STATUS:
    case MODE_ACTIVATE_MC:
    case MODE_ABORT_MC:
        want_file = false;
        break;
    default:
        pr2serr("%s: mc_mode=0x%x, continue for now\n", __func__,
                op->mc_mode);
        break;
    }

    if ((op->mc_len > 0) && (op->bpw > op->mc_len)) {
        pr2serr("trim chunk size (CS) to be the same as LEN\n");
        op->bpw = op->mc_len;
    }
    if ((op->mc_offset > 0) && (op->bpw > 0)) {
        op->mc_offset = 0;
        pr2serr("WARNING: --offset= ignored (set back to 0) when --bpw= "
                "argument given (and > 0)\n");
    }

#ifdef SG_LIB_WIN32
#ifdef SG_LIB_WIN32_DIRECT
    if (op->verbose > 4)
        pr2serr("Initial win32 SPT interface state: %s\n",
                scsi_pt_win32_spt_state() ? "direct" : "indirect");
    scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
#endif
#endif

    sg_fd = sg_cmds_open_device(device_name, false /* rw */, op->verbose);
    if (sg_fd < 0) {
        if (op->verbose)
            pr2serr(ME "open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto fini;
    }

    if (file_name && (! want_file))
        pr2serr("ignoring --in=FILE option\n");
    else if (file_name) {
        got_stdin = (0 == strcmp(file_name, "-"));
        if (got_stdin)
            infd = STDIN_FILENO;
        else {
            if ((infd = open(file_name, O_RDONLY)) < 0) {
                ret = sg_convert_errno(errno);
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for reading", file_name);
                perror(ebuff);
                goto fini;
            } else if (sg_set_binary_mode(infd) < 0)
                perror("sg_set_binary_mode");
        }
        if ((0 == fstat(infd, &a_stat)) && S_ISREG(a_stat.st_mode)) {
            is_reg = true;
            if (0 == op->mc_len) {
                if (op->mc_skip >= a_stat.st_size) {
                    pr2serr("skip exceeds file size of %d bytes\n",
                            (int)a_stat.st_size);
                    ret = SG_LIB_FILE_ERROR;
                    goto fini;
                }
                op->mc_len = (int)(a_stat.st_size) - op->mc_skip;
            }
        } else {
            is_reg = false;
            if (0 == op->mc_len)
                op->mc_len = DEF_XFER_LEN;
        }
        if (op->mc_len > MAX_XFER_LEN) {
            pr2serr("file size or requested length (%d) exceeds "
                    "MAX_XFER_LEN of %d bytes\n", op->mc_len,
                    MAX_XFER_LEN);
            ret = SG_LIB_FILE_ERROR;
            goto fini;
        }
        if (NULL == (dmp = (uint8_t *)malloc(op->mc_len))) {
            pr2serr(ME "out of memory to hold microcode read from FILE\n");
            ret = SG_LIB_CAT_OTHER;
            goto fini;
        }
        /* Don't remember why this is preset to 0xff, from write_buffer */
        memset(dmp, 0xff, op->mc_len);
        if (op->mc_skip > 0) {
            if (! is_reg) {
                if (got_stdin)
                    pr2serr("Can't skip on stdin\n");
                else
                    pr2serr(ME "not a 'regular' file so can't apply skip\n");
                ret = SG_LIB_FILE_ERROR;
                goto fini;
            }
            if (lseek(infd, op->mc_skip, SEEK_SET) < 0) {
                ret = sg_convert_errno(errno);
                snprintf(ebuff,  EBUFF_SZ, ME "couldn't skip to "
                         "required position on %s", file_name);
                perror(ebuff);
                goto fini;
            }
        }
        res = read(infd, dmp, op->mc_len);
        if (res < 0) {
            ret = sg_convert_errno(errno);
            snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
                     file_name);
            perror(ebuff);
            goto fini;
        }
        if (res < op->mc_len) {
            if (op->mc_len_given) {
                pr2serr("tried to read %d bytes from %s, got %d bytes\n",
                        op->mc_len, file_name, res);
                pr2serr("pad with 0xff bytes and continue\n");
            } else {
                if (op->verbose) {
                    pr2serr("tried to read %d bytes from %s, got %d "
                            "bytes\n", op->mc_len, file_name, res);
                    pr2serr("will send %d bytes", res);
                    if ((op->bpw > 0) && (op->bpw < op->mc_len))
                        pr2serr(", %d bytes per WRITE BUFFER command\n",
                                op->bpw);
                    else
                        pr2serr("\n");
                }
                op->mc_len = res;
            }
        }
        if (! got_stdin)
            close(infd);
        infd = -1;
    } else if (want_file) {
        pr2serr("need --in=FILE option with given mode\n");
        ret = SG_LIB_CONTRADICT;
        goto fini;
    }
    if (op->mc_tlen < op->mc_len)
        op->mc_tlen = op->mc_len;
    if (op->mc_non && (MODE_DNLD_STATUS == op->mc_mode)) {
        pr2serr("Do nothing because '--non' given so fetching the Download "
                "microcode status\ndpage might be dangerous\n");
        goto fini;
    }

    dip = sg_memalign(din_len, 0, &free_dip, op->verbose > 3);
    if (NULL == dip) {
        pr2serr(ME "out of memory (data-in buffer)\n");
        ret = SG_LIB_CAT_OTHER;
        goto fini;
    }
    verb = (op->verbose > 1) ? op->verbose - 1 : 0;
    /* Fetch Download microcode status dpage for generation code ++ */
    if (op->dry_run) {
        n = sizeof(dummy_rd_resp);
        n = (n < din_len) ? n : din_len;
        memcpy(dip, dummy_rd_resp, n);
        resid = din_len - n;
        res = 0;
    } else
        res = sg_ll_receive_diag_v2(sg_fd, true /* pcv */,
                                    DPC_DOWNLOAD_MICROCODE, dip, din_len,
                                    0 /*default timeout */, &resid, true,
                                    verb);
    if (0 == res) {
        rsp_len = sg_get_unaligned_be16(dip + 2) + 4;
        act_len = din_len - resid;
        if (rsp_len > din_len) {
            pr2serr("<<< warning response buffer too small [%d but need "
                    "%d]>>>\n", din_len, rsp_len);
            rsp_len = din_len;
        }
        if (rsp_len > act_len) {
            pr2serr("<<< warning response too short [actually got %d but "
                    "need %d]>>>\n", act_len, rsp_len);
            rsp_len = act_len;
        }
        if (rsp_len < 8) {
            pr2serr("Download microcode status dpage too short\n");
            ret = SG_LIB_CAT_OTHER;
            goto fini;
        }
        if ((op->verbose > 2) || (op->dry_run && op->verbose))
            pr2serr("rec diag(ini): rsp_len=%d, num_sub-enc=%u "
                    "rec_gen_code=%u\n", rsp_len, dip[1],
                    sg_get_unaligned_be32(dip + 4));
    } else {
        ret = res;
        goto fini;
    }
    gen_code = sg_get_unaligned_be32(dip + 4);

    if (MODE_DNLD_STATUS == op->mc_mode) {
        show_download_mc_sdg(dip, rsp_len, gen_code);
        goto fini;
    } else if (! want_file) {   /* ACTIVATE and ABORT */
        res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip,
                                din_len, true, op);
        ret = res;
        goto fini;
    }

    res = 0;
    if (op->bpw > 0) {
        for (k = 0, last = false; k < op->mc_len; k += n) {
            n = op->mc_len - k;
            if (n > op->bpw)
                n = op->bpw;
            else
                last = true;
            if (op->verbose)
                pr2serr("bpw loop: mode=0x%x, id=%d, off_off=%d, len=%d, "
                        "last=%d\n", op->mc_mode, op->mc_id, k, n, last);
            res = send_then_receive(sg_fd, gen_code, k, dmp + k, n, &dout,
                                    dip, din_len, last, op);
            if (res)
                break;
        }
        if (op->bpw_then_activate && (0 == res)) {
            op->mc_mode = MODE_ACTIVATE_MC;
            if (op->verbose)
                pr2serr("sending Activate deferred microcode [0xf]\n");
            res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout,
                                    dip, din_len, true, op);
        }
    } else {
        if (op->verbose)
            pr2serr("single: mode=0x%x, id=%d, offset=%d, len=%d\n",
                    op->mc_mode, op->mc_id, op->mc_offset, op->mc_len);
        res = send_then_receive(sg_fd, gen_code, 0, dmp, op->mc_len, &dout,
                                dip, din_len, true, op);
    }
    if (res)
        ret = res;

fini:
    if ((infd >= 0) && (! got_stdin))
        close(infd);
    if (dmp)
        free(dmp);
    if (dout.free_doutp)
        free(dout.free_doutp);
    if (free_dip)
        free(free_dip);
    if (sg_fd >= 0) {
        res = sg_cmds_close_device(sg_fd);
        if (res < 0) {
            pr2serr("close error: %s\n", safe_strerror(-res));
            if (0 == ret)
                ret = sg_convert_errno(-res);
        }
    }
    if (0 == op->verbose) {
        if (! sg_if_can2stderr("sg_ses_mocrocode failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
예제 #8
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;
}
예제 #9
0
int
main(int argc, char * argv[])
{
    int sg_fd, res, c, len, k, n, got_stdin, is_reg, rsp_len, verb, last;
    int infd = -1;
    int do_help = 0;
    const char * device_name = NULL;
    const char * file_name = NULL;
    unsigned char * dmp = NULL;
    unsigned char * dip = NULL;
    char * cp;
    char ebuff[EBUFF_SZ];
    struct stat a_stat;
    struct dout_buff_t dout;
    struct opts_t opts;
    struct opts_t * op;
    const struct mode_s * mp;
    uint32_t gen_code = 0;
    int ret = 0;

    op = &opts;
    memset(op, 0, sizeof(opts));
    memset(&dout, 0, sizeof(dout));
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "b:hi:I:l:m:No:s:S:t:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'b':
            op->bpw = sg_get_num(optarg);
            if (op->bpw < 0) {
                pr2serr("argument to '--bpw' should be in a positive "
                        "number\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if ((cp = strchr(optarg, ','))) {
                if (0 == strncmp("act", cp + 1, 3))
                    ++op->bpw_then_activate;
            }
            break;
        case 'h':
        case '?':
            ++do_help;
            break;
        case 'i':
            op->mc_id = sg_get_num(optarg);
            if ((op->mc_id < 0) || (op->mc_id > 255)) {
                pr2serr("argument to '--id' should be in the range 0 to "
                        "255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'I':
            file_name = optarg;
            break;
        case 'l':
            op->mc_len = sg_get_num(optarg);
            if (op->mc_len < 0) {
                pr2serr("bad argument to '--length'\n");
                return SG_LIB_SYNTAX_ERROR;
             }
             op->mc_len_given = 1;
             break;
        case 'm':
            if (isdigit(*optarg)) {
                op->mc_mode = sg_get_num(optarg);
                if ((op->mc_mode < 0) || (op->mc_mode > 255)) {
                    pr2serr("argument to '--mode' should be in the range 0 "
                            "to 255\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else {
                len = strlen(optarg);
                for (mp = mode_arr; mp->mode_string; ++mp) {
                    if (0 == strncmp(mp->mode_string, optarg, len)) {
                        op->mc_mode = mp->mode;
                        break;
                    }
                }
                if (! mp->mode_string) {
                    print_modes();
                    return SG_LIB_SYNTAX_ERROR;
                }
            }
            break;
        case 'N':
            ++op->mc_non;
            break;
        case 'o':
           op->mc_offset = sg_get_num(optarg);
           if (op->mc_offset < 0) {
                pr2serr("bad argument to '--offset'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            if (0 != (op->mc_offset % 4)) {
                pr2serr("'--offset' value needs to be a multiple of 4\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 's':
           op->mc_skip = sg_get_num(optarg);
           if (op->mc_skip < 0) {
                pr2serr("bad argument to '--skip'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'S':
           op->mc_subenc = sg_get_num(optarg);
           if ((op->mc_subenc < 0) || (op->mc_subenc > 255)) {
                pr2serr("expected argument to '--subenc' to be 0 to 255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 't':
           op->mc_tlen = sg_get_num(optarg);
           if (op->mc_tlen < 0) {
                pr2serr("bad argument to '--tlength'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'v':
            ++op->verbose;
            break;
        case 'V':
            pr2serr(ME "version: %s\n", version_str);
            return 0;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (do_help) {
        if (do_help > 1) {
            usage();
            pr2serr("\n");
            print_modes();
        } else
            usage();
        return 0;
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (NULL == device_name) {
        pr2serr("missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }

    if ((op->mc_len > 0) && (op->bpw > op->mc_len)) {
        pr2serr("trim chunk size (CS) to be the same as LEN\n");
        op->bpw = op->mc_len;
    }

#ifdef SG_LIB_WIN32
#ifdef SG_LIB_WIN32_DIRECT
    if (op->verbose > 4)
        pr2serr("Initial win32 SPT interface state: %s\n",
                scsi_pt_win32_spt_state() ? "direct" : "indirect");
    scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
#endif
#endif

    sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, op->verbose);
    if (sg_fd < 0) {
        pr2serr(ME "open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        return SG_LIB_FILE_ERROR;
    }

    if (file_name && ((MODE_DNLD_STATUS == op->mc_mode) ||
                      (MODE_ACTIVATE_MC == op->mc_mode)))
        pr2serr("ignoring --in=FILE option\n");
    else if (file_name) {
        got_stdin = (0 == strcmp(file_name, "-")) ? 1 : 0;
        if (got_stdin)
            infd = STDIN_FILENO;
        else {
            if ((infd = open(file_name, O_RDONLY)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for reading", file_name);
                perror(ebuff);
                ret = SG_LIB_FILE_ERROR;
                goto fini;
            } else if (sg_set_binary_mode(infd) < 0)
                perror("sg_set_binary_mode");
        }
        if ((0 == fstat(infd, &a_stat)) && S_ISREG(a_stat.st_mode)) {
            is_reg = 1;
            if (0 == op->mc_len) {
                if (op->mc_skip >= a_stat.st_size) {
                    pr2serr("skip exceeds file size of %d bytes\n",
                            (int)a_stat.st_size);
                    ret = SG_LIB_FILE_ERROR;
                    goto fini;
                }
                op->mc_len = (int)(a_stat.st_size) - op->mc_skip;
            }
        } else {
            is_reg = 0;
            if (0 == op->mc_len)
                op->mc_len = DEF_XFER_LEN;
        }
        if (op->mc_len > MAX_XFER_LEN) {
            pr2serr("file size or requested length (%d) exceeds "
                    "MAX_XFER_LEN of %d bytes\n", op->mc_len,
                    MAX_XFER_LEN);
            ret = SG_LIB_FILE_ERROR;
            goto fini;
        }
        if (NULL == (dmp = (unsigned char *)malloc(op->mc_len))) {
            pr2serr(ME "out of memory (to hold microcode)\n");
            ret = SG_LIB_CAT_OTHER;
            goto fini;
        }
        /* Don't remember why this is preset to 0xff, from write_buffer */
        memset(dmp, 0xff, op->mc_len);
        if (op->mc_skip > 0) {
            if (! is_reg) {
                if (got_stdin)
                    pr2serr("Can't skip on stdin\n");
                else
                    pr2serr(ME "not a 'regular' file so can't apply skip\n");
                ret = SG_LIB_FILE_ERROR;
                goto fini;
            }
            if (lseek(infd, op->mc_skip, SEEK_SET) < 0) {
                snprintf(ebuff,  EBUFF_SZ, ME "couldn't skip to "
                         "required position on %s", file_name);
                perror(ebuff);
                ret = SG_LIB_FILE_ERROR;
                goto fini;
            }
        }
        res = read(infd, dmp, op->mc_len);
        if (res < 0) {
            snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
                     file_name);
            perror(ebuff);
            ret = SG_LIB_FILE_ERROR;
            goto fini;
        }
        if (res < op->mc_len) {
            if (op->mc_len_given) {
                pr2serr("tried to read %d bytes from %s, got %d bytes\n",
                        op->mc_len, file_name, res);
                pr2serr("pad with 0xff bytes and continue\n");
            } else {
                if (op->verbose) {
                    pr2serr("tried to read %d bytes from %s, got %d "
                            "bytes\n", op->mc_len, file_name, res);
                    pr2serr("will send %d bytes", res);
                    if ((op->bpw > 0) && (op->bpw < op->mc_len))
                        pr2serr(", %d bytes per WRITE BUFFER command\n",
                                op->bpw);
                    else
                        pr2serr("\n");
                }
                op->mc_len = res;
            }
        }
        if (! got_stdin)
            close(infd);
        infd = -1;
    } else if (! ((MODE_DNLD_STATUS == op->mc_mode) ||
                  (MODE_ACTIVATE_MC == op->mc_mode))) {
        pr2serr("need --in=FILE option with given mode\n");
        ret = SG_LIB_SYNTAX_ERROR;
        goto fini;
    }
    if (op->mc_tlen < op->mc_len)
        op->mc_tlen = op->mc_len;
    if (op->mc_non && (MODE_DNLD_STATUS == op->mc_mode)) {
        pr2serr("Do nothing because '--non' given so fetching the Download "
                "microcode status\ndpage might be dangerous\n");
        goto fini;
    }

    if (NULL == (dip = (unsigned char *)malloc(DEF_DI_LEN))) {
        pr2serr(ME "out of memory (data-in buffer)\n");
        ret = SG_LIB_CAT_OTHER;
        goto fini;
    }
    memset(dip, 0, DEF_DI_LEN);
    verb = (op->verbose > 1) ? op->verbose - 1 : 0;
    /* Fetch Download microcode status dpage for generation code ++ */
    res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip,
                             DEF_DI_LEN, 1, verb);
    if (0 == 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");
            ret = SG_LIB_CAT_OTHER;
            goto fini;
        }
    } else {
        ret = res;
        goto fini;
    }
    gen_code = sg_get_unaligned_be32(dip + 4);

    if (MODE_DNLD_STATUS == op->mc_mode) {
        ses_download_code_sdg(dip, rsp_len, gen_code);
        goto fini;
    } else if (MODE_ACTIVATE_MC == op->mc_mode) {
        res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, 1,
                                op);
        ret = res;
        goto fini;
    }

    res = 0;
    if (op->bpw > 0) {
        for (k = 0, last = 0; k < op->mc_len; k += n) {
            n = op->mc_len - k;
            if (n > op->bpw)
                n = op->bpw;
            else
                last = 1;
            if (op->verbose)
                pr2serr("bpw loop: mode=0x%x, id=%d, off_off=%d, len=%d, "
                        "last=%d\n", op->mc_mode, op->mc_id, k, n, last);
            res = send_then_receive(sg_fd, gen_code, k, dmp + k, n, &dout,
                                    dip, last, op);
            if (res)
                break;
        }
        if (op->bpw_then_activate && (0 == res)) {
            op->mc_mode = MODE_ACTIVATE_MC;
            if (op->verbose)
                pr2serr("sending Activate deferred microcode [0xf]\n");
            res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout,
                                    dip, 1, op);
        }
    } else {
        if (op->verbose)
            pr2serr("single: mode=0x%x, id=%d, offset=%d, len=%d\n",
                    op->mc_mode, op->mc_id, op->mc_offset, op->mc_len);
        res = send_then_receive(sg_fd, gen_code, 0, dmp, op->mc_len, &dout,
                                dip, 1, op);
    }
    if (res)
        ret = res;

fini:
    if ((infd >= 0) && (! got_stdin))
        close(infd);
    if (dmp)
        free(dmp);
    if (dout.doutp)
        free(dout.doutp);
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            return SG_LIB_FILE_ERROR;
    }
    if (ret && (0 == op->verbose)) {
        if (SG_LIB_CAT_INVALID_OP == ret)
            pr2serr("%sRECEIVE DIAGNOSTIC RESULTS command not supported\n",
                    ((MODE_DNLD_STATUS == op->mc_mode) ?
                     "" : "SEND DIAGNOSTIC or "));
        else if (ret > 0)
            pr2serr("Failed, exit status %d\n", ret);
        else if (ret < 0)
            pr2serr("Some error occurred\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
예제 #10
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;
}
예제 #11
0
int
main(int argc, char * argv[])
{
    int sg_fd, res, c, len, resid, rlen, in_len;
    unsigned int ra_len;
    int ret = 0;
    const char * device_name = NULL;
    const char * fname = NULL;
    unsigned char * rabp = NULL;
    struct opts_t opts;
    struct opts_t * op;
    char b[80];

    op = &opts;
    memset(op, 0, sizeof(opts));
    op->filter = -1;
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "ceE:f:F:hHi:l:m:p:qrRs:vV",
                        long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'c':
            ++op->cache;
            break;
        case 'e':
            ++op->enumerate;
            break;
        case 'E':
           op->ea = sg_get_num(optarg);
           if ((op->ea < 0) || (op->ea > 65535)) {
                pr2serr("bad argument to '--ea=EA', expect 0 to 65535\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'f':
           op->filter = sg_get_num(optarg);
           if ((op->filter < -3) || (op->filter > 65535)) {
                pr2serr("bad argument to '--filter=FL', expect -3 to "
                        "65535\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'F':
           op->fai = sg_get_num(optarg);
           if ((op->fai < 0) || (op->fai > 65535)) {
                pr2serr("bad argument to '--first=FAI', expect 0 to 65535\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++op->do_hex;
            break;
        case 'i':
            fname = optarg;
            break;
        case 'l':
           op->lvn = sg_get_num(optarg);
           if ((op->lvn < 0) || (op->lvn > 255)) {
                pr2serr("bad argument to '--lvn=LVN', expect 0 to 255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'm':
            op->maxlen = sg_get_num(optarg);
            if ((op->maxlen < 0) || (op->maxlen > MAX_RATTR_BUFF_LEN)) {
                pr2serr("argument to '--maxlen' should be %d or "
                        "less\n", MAX_RATTR_BUFF_LEN);
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'p':
           op->pn = sg_get_num(optarg);
           if ((op->pn < 0) || (op->pn > 255)) {
                pr2serr("bad argument to '--pn=PN', expect 0 to 255\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 'q':
            ++op->quiet;
            break;
        case 'r':
            ++op->do_raw;
            break;
        case 'R':
            ++op->o_readonly;
            break;
        case 's':
           if (isdigit(*optarg)) {
               op->sa = sg_get_num(optarg);
               if ((op->sa < 0) || (op->sa > 63)) {
                    pr2serr("bad argument to '--sa=SA', expect 0 to 63\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            } else {
                res = find_sa_acron(optarg);
                if (res < 0) {
                    enum_sa_acrons();
                    return SG_LIB_SYNTAX_ERROR;
                }
                op->sa = res;
            }
            break;
        case 'v':
            ++op->verbose;
            break;
        case 'V':
            pr2serr("version: %s\n", version_str);
            return 0;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }

    if (op->enumerate) {
        enum_attributes();
        printf("\n");
        enum_sa_acrons();
        return 0;
    }

    if (fname && device_name) {
        pr2serr("since '--in=FN' given, ignoring DEVICE\n");
        device_name = NULL;
    }

    if (0 == op->maxlen)
        op->maxlen = DEF_RATTR_BUFF_LEN;
    rabp = (unsigned char *)calloc(1, op->maxlen);
    if (NULL == rabp) {
        pr2serr("unable to calloc %d bytes\n", op->maxlen);
        return SG_LIB_CAT_OTHER;
    }

    if (NULL == device_name) {
        if (fname) {
            if (f2hex_arr(fname, op->do_raw, 0, rabp, &in_len, op->maxlen)) {
                ret = SG_LIB_FILE_ERROR;
                goto clean_up;
            }
            if (op->do_raw)
                op->do_raw = 0;    /* can interfere on decode */
            if (in_len < 4) {
                pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n",
                        fname, in_len);
                ret = SG_LIB_SYNTAX_ERROR;
                goto clean_up;
            }
            decode_all_sa_s(rabp, in_len, op);
            goto clean_up;
        }
        pr2serr("missing device name!\n");
        usage();
        ret = SG_LIB_SYNTAX_ERROR;
        goto clean_up;
    }

    if (op->do_raw) {
        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
            perror("sg_set_binary_mode");
            ret = SG_LIB_FILE_ERROR;
                goto clean_up;
        }
    }

    sg_fd = sg_cmds_open_device(device_name, op->o_readonly, op->verbose);
    if (sg_fd < 0) {
        pr2serr("open error: %s: %s\n", device_name,
                safe_strerror(-sg_fd));
        ret = SG_LIB_FILE_ERROR;
        goto clean_up;
    }

    res = sg_ll_read_attr(sg_fd, rabp, &resid, op);
    ret = res;
    if (0 == res) {
        rlen = op->maxlen - resid;
        if (rlen < 4) {
            pr2serr("Response length (%d) too short\n", rlen);
            ret = SG_LIB_CAT_MALFORMED;
            goto close_then_end;
        }
        if ((op->sa <= RA_HIGHEST_SA) && (op->sa != RA_SMC2_SA)) {
            ra_len = ((RA_LV_LIST_SA == op->sa) ||
                      (RA_PART_LIST_SA == op->sa)) ?
                        (unsigned int)sg_get_unaligned_be16(rabp + 0) :
                        sg_get_unaligned_be32(rabp + 0) + 2;
            ra_len += 2;
        } else
            ra_len = rlen;
        if ((int)ra_len > rlen) {
            if (op->verbose)
                pr2serr("ra_len available is %d, response length is %d\n",
                        ra_len, rlen);
            len = rlen;
        } else
            len = (int)ra_len;
        if (op->do_raw) {
            dStrRaw((const char *)rabp, len);
            goto close_then_end;
        }
        decode_all_sa_s(rabp, len, op);
    } else if (SG_LIB_CAT_INVALID_OP == res)
        pr2serr("Read attribute command not supported\n");
    else {
        sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
        pr2serr("Read attribute command: %s\n", b);
    }

close_then_end:
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = SG_LIB_FILE_ERROR;
    }
clean_up:
    if (rabp)
        free(rabp);
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
예제 #12
0
static void
helper_full_attr(const unsigned char * alp, int len, int id,
                 const struct attr_name_info_t * anip,
                 const struct opts_t * op)
{
    int k;
    const unsigned char * bp;

    if (op->verbose)
        printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w');
    if (op->verbose > 3)
        pr2serr("%s: id=0x%x, len=%d, anip->format=%d, anip->len=%d\n",
                __func__, id, len, anip->format, anip->len);
    switch (id) {
    case 0x224:         /* logical position of first encrypted block */
        k = all_ffs_or_last_fe(alp + 5, len - 5);
        if (1 == k)
            printf("<unknown> [ff]\n");
        else if (2 == k)
            printf("<unknown [fe]>\n");
        else {
            if ((len - 5) <= 8)
                printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5));
            else {
                printf("\n");
                dStrHex((const char *)(alp + 5), len - 5, 0);
            }
        }
        break;
    case 0x225:         /* logical position of first unencrypted block
                         * after first encrypted block */
        k = all_ffs_or_last_fe(alp + 5, len - 5);
        if (1 == k)
            printf("<unknown> [ff]\n");
        else if (2 == k)
            printf("<unknown [fe]>\n");
        else {
            if ((len - 5) <= 8)
                printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5));
            else {
                printf("\n");
                dStrHex((const char *)(alp + 5), len - 5, 0);
            }
        }
        break;
    case 0x340:         /* Medium Usage history */
        bp = alp + 5;
        printf("\n");
        if ((len - 5) < 90) {
            pr2serr("%s: expected 90 bytes, got %d\n", __func__, len - 5);
            break;
        }
        printf("    Current amount of data written [MiB]: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 0));
        printf("    Current write retry count: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 6));
        printf("    Current amount of data read [MiB]: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 12));
        printf("    Current read retry count: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 18));
        printf("    Previous amount of data written [MiB]: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 24));
        printf("    Previous write retry count: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 30));
        printf("    Previous amount of data read [MiB]: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 36));
        printf("    Previous read retry count: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 42));
        printf("    Total amount of data written [MiB]: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 48));
        printf("    Total write retry count: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 54));
        printf("    Total amount of data read [MiB]: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 60));
        printf("    Total read retry count: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 66));
        printf("    Load count: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 72));
        printf("    Total change partition count: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 78));
        printf("    Total partition initialization count: %" PRIu64 "\n",
               sg_get_unaligned_be48(bp + 84));
        break;
    case 0x341:         /* Partition Usage history */
        bp = alp + 5;
        printf("\n");
        if ((len - 5) < 60) {
            pr2serr("%s: expected 60 bytes, got %d\n", __func__, len - 5);
            break;
        }
        printf("    Current amount of data written [MiB]: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 0));
        printf("    Current write retry count: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 4));
        printf("    Current amount of data read [MiB]: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 8));
        printf("    Current read retry count: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 12));
        printf("    Previous amount of data written [MiB]: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 16));
        printf("    Previous write retry count: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 20));
        printf("    Previous amount of data read [MiB]: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 24));
        printf("    Previous read retry count: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 28));
        printf("    Total amount of data written [MiB]: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 32));
        printf("    Total write retry count: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 36));
        printf("    Total amount of data read [MiB]: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 40));
        printf("    Total read retry count: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 44));
        printf("    Load count: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 48));
        printf("    change partition count: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 52));
        printf("    partition initialization count: %" PRIu32 "\n",
               sg_get_unaligned_be32(bp + 56));
        break;
    default:
        pr2serr("%s: unknown attribute id: 0x%x\n", __func__, id);
        printf("  In hex:\n");
        dStrHex((const char *)alp, len, 0);
        break;
    }
}
예제 #13
0
int
main(int argc, char * argv[])
{
    bool do_one_segment = false;
    bool o_readonly = false;
    bool do_raw = false;
    bool verbose_given = false;
    bool version_given = false;
    int k, res, c, rlen;
    int sg_fd = -1;
    int do_hex = 0;
    int maxlen = DEF_REFER_BUFF_LEN;
    int verbose = 0;
    int desc = 0;
    int ret = 0;
    int64_t ll;
    uint64_t lba = 0;
    const char * device_name = NULL;
    const uint8_t * bp;
    uint8_t * referralBuffp = referralBuff;
    uint8_t * free_referralBuffp = NULL;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "hHl:m:rRsvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++do_hex;
            break;
        case 'l':
            ll = sg_get_llnum(optarg);
            if (-1 == ll) {
                pr2serr("bad argument to '--lba'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            lba = (uint64_t)ll;
            break;
        case 'm':
            maxlen = sg_get_num(optarg);
            if ((maxlen < 0) || (maxlen > MAX_REFER_BUFF_LEN)) {
                pr2serr("argument to '--maxlen' should be %d or less\n",
                        MAX_REFER_BUFF_LEN);
                return SG_LIB_SYNTAX_ERROR;
            }
            break;
        case 's':
            do_one_segment = true;
            break;
        case 'r':
            do_raw = true;
            break;
        case 'R':
            o_readonly = true;
            break;
        case 'v':
            verbose_given = true;
            ++verbose;
            break;
        case 'V':
            version_given = true;
            break;
        default:
            pr2serr("unrecognised option code 0x%x ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr("version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("No DEVICE argument given\n\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if (maxlen > DEF_REFER_BUFF_LEN) {
        referralBuffp = (uint8_t *)sg_memalign(maxlen, 0,
                                               &free_referralBuffp,
                                               verbose > 3);
        if (NULL == referralBuffp) {
            pr2serr("unable to allocate %d bytes on heap\n", maxlen);
            return sg_convert_errno(ENOMEM);
        }
    }
    if (do_raw) {
        if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
            perror("sg_set_binary_mode");
            ret = SG_LIB_FILE_ERROR;
            goto free_buff;
        }
    }

    sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose);
    if (sg_fd < 0) {
        if (verbose)
            pr2serr("open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto free_buff;
    }

    res = sg_ll_report_referrals(sg_fd, lba, do_one_segment, referralBuffp,
                                 maxlen, true, verbose);
    ret = res;
    if (0 == res) {
        if (maxlen >= 4)
            /*
             * This is strictly speaking incorrect. However, the
             * spec reserved bytes 0 and 1, so some implementations
             * might want to use them to increase the number of
             * possible user segments.
             * And maybe someone takes a pity and updates the spec ...
             */
            rlen = sg_get_unaligned_be32(referralBuffp + 0) + 4;
        else
            rlen = maxlen;
        k = (rlen > maxlen) ? maxlen : rlen;
        if (do_raw) {
            dStrRaw(referralBuffp, k);
            goto the_end;
        }
        if (do_hex) {
            hex2stdout(referralBuffp, k, 1);
            goto the_end;
        }
        if (maxlen < 4) {
            if (verbose)
                pr2serr("Exiting because allocation length (maxlen)  less "
                        "than 4\n");
            goto the_end;
        }
        if ((verbose > 1) || (verbose && (rlen > maxlen))) {
            pr2serr("response length %d bytes\n", rlen);
            if (rlen > maxlen)
                pr2serr("  ... which is greater than maxlen (allocation "
                        "length %d), truncation\n", maxlen);
        }
        if (rlen > maxlen)
            rlen = maxlen;

        bp = referralBuffp + 4;
        k = 0;
        printf("Report referrals:\n");
        while (k < rlen - 4) {
            printf("  descriptor %d:\n", desc);
            res = decode_referral_desc(bp + k, rlen - 4 - k);
            if (res < 0) {
                pr2serr("bad user data segment referral descriptor\n");
                break;
            }
            k += res;
            desc++;
        }
    } else {
        char b[80];

        sg_get_category_sense_str(res, sizeof(b), b, verbose);
        pr2serr("Report Referrals command failed: %s\n", b);
    }

the_end:
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = sg_convert_errno(-res);
    }
free_buff:
    if (free_referralBuffp)
        free(free_referralBuffp);
    if (0 == verbose) {
        if (! sg_if_can2stderr("sg_referrals failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
예제 #14
0
int
main(int argc, char * argv[])
{
    bool do_raw = false;
    bool readonly = false;
    bool verbose_given = false;
    bool version_given = false;
    int sg_fd, k, m, res, c;
    int do_hex = 0;
    int verbose = 0;
    int ret = 0;
    uint32_t max_block_size;
    uint16_t min_block_size;
    const char * device_name = NULL;

    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "hHrRvV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++do_hex;
            break;
        case 'r':
            do_raw = true;
            break;
        case 'R':
            readonly = true;
            break;
        case 'v':
            verbose_given = true;
            ++verbose;
            break;
        case 'V':
            version_given = true;
            break;
        default:
            pr2serr("invalid option -%c ??\n", c);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if (NULL == device_name) {
            device_name = argv[optind];
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SG_LIB_SYNTAX_ERROR;
        }
    }
#ifdef DEBUG
    pr2serr("In DEBUG mode, ");
    if (verbose_given && version_given) {
        pr2serr("but override: '-vV' given, zero verbose and continue\n");
        verbose_given = false;
        version_given = false;
        verbose = 0;
    } else if (! verbose_given) {
        pr2serr("set '-vv'\n");
        verbose = 2;
    } else
        pr2serr("keep verbose=%d\n", verbose);
#else
    if (verbose_given && version_given)
        pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
    if (version_given) {
        pr2serr("version: %s\n", version_str);
        return 0;
    }

    if (NULL == device_name) {
        pr2serr("missing device name!\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }

    sg_fd = sg_cmds_open_device(device_name, readonly, verbose);
    if (sg_fd < 0) {
        if (verbose)
            pr2serr("open error: %s: %s\n", device_name,
                    safe_strerror(-sg_fd));
        ret = sg_convert_errno(-sg_fd);
        goto the_end2;
    }

    memset(readBlkLmtBuff, 0x0, 6);
    res = sg_ll_read_block_limits(sg_fd, readBlkLmtBuff, 6, true, verbose);
    ret = res;
    if (0 == res) {
      if (do_hex) {
        hex2stdout(readBlkLmtBuff, sizeof(readBlkLmtBuff), 1);
        goto the_end;
      } else if (do_raw) {
        dStrRaw((const char *)readBlkLmtBuff, sizeof(readBlkLmtBuff));
        goto the_end;
      }

      max_block_size = sg_get_unaligned_be32(readBlkLmtBuff + 0);
      min_block_size = sg_get_unaligned_be16(readBlkLmtBuff + 4);
      k = min_block_size / 1024;
      pr2serr("Read Block Limits results:\n");
      pr2serr("\tMinimum block size: %u byte(s)",
              (unsigned int)min_block_size);
      if (k != 0)
        pr2serr(", %d KB", k);
      pr2serr("\n");
      k = max_block_size / 1024;
      m = max_block_size / 1048576;
      pr2serr("\tMaximum block size: %u byte(s)",
              (unsigned int)max_block_size);
      if (k != 0)
        pr2serr(", %d KB", k);
      if (m != 0)
        pr2serr(", %d MB", m);
      pr2serr("\n");
    } else {
        char b[80];

        sg_get_category_sense_str(res, sizeof(b), b, verbose);
        pr2serr("Read block limits: %s\n", b);
        if (0 == verbose)
            pr2serr("    try '-v' option for more information\n");
    }

the_end:
    res = sg_cmds_close_device(sg_fd);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(-res));
        if (0 == ret)
            ret = sg_convert_errno(-res);
    }
the_end2:
    if (0 == verbose) {
        if (! sg_if_can2stderr("sg_read_block_limits failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' or '-vv' for "
                    "more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
예제 #15
0
int
main(int argc, char * argv[])
{
    int res, c, k, len, act_resplen;
    int do_hex = 0;
    int phy_id = 0;
    int phy_id_given = 0;
    int do_raw = 0;
    int verbose = 0;
    int do_zero = 0;
    int64_t sa_ll;
    uint64_t sa = 0;
    char i_params[256];
    char device_name[512];
    char b[256];
    unsigned char smp_req[] = {SMP_FRAME_TYPE_REQ, SMP_FN_REPORT_PHY_ERR_LOG,
                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char smp_resp[SMP_FN_REPORT_PHY_ERR_LOG_RESP_LEN];
    struct smp_req_resp smp_rr;
    struct smp_target_obj tobj;
    int subvalue = 0;
    char * cp;
    int ret = 0;

    memset(device_name, 0, sizeof device_name);
    while (1) {
        int option_index = 0;

        c = getopt_long(argc, argv, "hHI:p:rs:vVz", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'h':
        case '?':
            usage();
            return 0;
        case 'H':
            ++do_hex;
            break;
        case 'I':
            strncpy(i_params, optarg, sizeof(i_params));
            i_params[sizeof(i_params) - 1] = '\0';
            break;
        case 'p':
           phy_id = smp_get_num(optarg);
           if ((phy_id < 0) || (phy_id > 254)) {
                pr2serr("bad argument to '--phy', expect value from 0 to "
                        "254\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            ++phy_id_given;
            break;
        case 'r':
            ++do_raw;
            break;
        case 's':
           sa_ll = smp_get_llnum(optarg);
           if (-1LL == sa_ll) {
                pr2serr("bad argument to '--sa'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            sa = (uint64_t)sa_ll;
            break;
        case 'v':
            ++verbose;
            break;
        case 'V':
            pr2serr("version: %s\n", version_str);
            return 0;
        case 'z':
            ++do_zero;
            break;
        default:
            pr2serr("unrecognised switch code 0x%x ??\n", c);
            usage();
            return SMP_LIB_SYNTAX_ERROR;
        }
    }
    if (optind < argc) {
        if ('\0' == device_name[0]) {
            strncpy(device_name, argv[optind], sizeof(device_name) - 1);
            device_name[sizeof(device_name) - 1] = '\0';
            ++optind;
        }
        if (optind < argc) {
            for (; optind < argc; ++optind)
                pr2serr("Unexpected extra argument: %s\n", argv[optind]);
            usage();
            return SMP_LIB_SYNTAX_ERROR;
        }
    }
    if (0 == device_name[0]) {
        cp = getenv("SMP_UTILS_DEVICE");
        if (cp)
            strncpy(device_name, cp, sizeof(device_name) - 1);
        else {
            pr2serr("missing device name on command line\n    [Could use "
                    "environment variable SMP_UTILS_DEVICE instead]\n");
            usage();
            return SMP_LIB_SYNTAX_ERROR;
        }
    }
    if ((cp = strchr(device_name, SMP_SUBVALUE_SEPARATOR))) {
        *cp = '\0';
        if (1 != sscanf(cp + 1, "%d", &subvalue)) {
            pr2serr("expected number after separator in SMP_DEVICE name\n");
            return SMP_LIB_SYNTAX_ERROR;
        }
    }
    if (0 == sa) {
        cp = getenv("SMP_UTILS_SAS_ADDR");
        if (cp) {
           sa_ll = smp_get_llnum(cp);
           if (-1LL == sa_ll) {
                pr2serr("bad value in environment variable "
                        "SMP_UTILS_SAS_ADDR\n    use 0\n");
                sa_ll = 0;
            }
            sa = (uint64_t)sa_ll;
        }
    }
    if (sa > 0) {
        if (! smp_is_naa5(sa)) {
            pr2serr("SAS (target) address not in naa-5 format (may need "
                    "leading '0x')\n");
            if ('\0' == i_params[0]) {
                pr2serr("    use '--interface=' to override\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
        }
    }

    res = smp_initiator_open(device_name, subvalue, i_params, sa,
                             &tobj, verbose);
    if (res < 0)
        return SMP_LIB_FILE_ERROR;

    if (! do_zero) {     /* SAS-2 or later */
        len = (sizeof(smp_resp) - 8) / 4;
        smp_req[2] = (len < 0x100) ? len : 0xff; /* Allocated Response Len */
        smp_req[3] = 2; /* Request Length: in dwords */
    }
    smp_req[9] = phy_id;
    if (verbose) {
        pr2serr("    Report phy error log request: ");
        for (k = 0; k < (int)sizeof(smp_req); ++k)
            pr2serr("%02x ", smp_req[k]);
        pr2serr("\n");
    }
    memset(&smp_rr, 0, sizeof(smp_rr));
    smp_rr.request_len = sizeof(smp_req);
    smp_rr.request = smp_req;
    smp_rr.max_response_len = sizeof(smp_resp);
    smp_rr.response = smp_resp;
    res = smp_send_req(&tobj, &smp_rr, verbose);

    if (res) {
        pr2serr("smp_send_req failed, res=%d\n", res);
        if (0 == verbose)
            pr2serr("    try adding '-v' option for more debug\n");
        ret = -1;
        goto err_out;
    }
    if (smp_rr.transport_err) {
        pr2serr("smp_send_req transport_error=%d\n", smp_rr.transport_err);
        ret = -1;
        goto err_out;
    }
    act_resplen = smp_rr.act_response_len;
    if ((act_resplen >= 0) && (act_resplen < 4)) {
        pr2serr("response too short, len=%d\n", act_resplen);
        ret = SMP_LIB_CAT_MALFORMED;
        goto err_out;
    }
    len = smp_resp[3];
    if ((0 == len) && (0 == smp_resp[2])) {
        len = smp_get_func_def_resp_len(smp_resp[1]);
        if (len < 0) {
            len = 0;
            if (verbose > 0)
                pr2serr("unable to determine response length\n");
        }
    }
    len = 4 + (len * 4);        /* length in bytes, excluding 4 byte CRC */
    if ((act_resplen >= 0) && (len > act_resplen)) {
        if (verbose)
            pr2serr("actual response length [%d] less than deduced length "
                    "[%d]\n", act_resplen, len);
        len = act_resplen;
    }
    if (do_hex || do_raw) {
        if (do_hex)
            dStrHex((const char *)smp_resp, len, 1);
        else
            dStrRaw((const char *)smp_resp, len);
        if (SMP_FRAME_TYPE_RESP != smp_resp[0])
            ret = SMP_LIB_CAT_MALFORMED;
        else if (smp_resp[1] != smp_req[1])
            ret = SMP_LIB_CAT_MALFORMED;
        else if (smp_resp[2]) {
            if (verbose)
                pr2serr("Report phy error log result: %s\n",
                        smp_get_func_res_str(smp_resp[2], sizeof(b), b));
            ret = smp_resp[2];
        }
        goto err_out;
    }
    if (SMP_FRAME_TYPE_RESP != smp_resp[0]) {
        pr2serr("expected SMP frame response type, got=0x%x\n", smp_resp[0]);
        ret = SMP_LIB_CAT_MALFORMED;
        goto err_out;
    }
    if (smp_resp[1] != smp_req[1]) {
        pr2serr("Expected function code=0x%x, got=0x%x\n", smp_req[1],
                 smp_resp[1]);
        ret = SMP_LIB_CAT_MALFORMED;
        goto err_out;
    }
    if (smp_resp[2]) {
        cp = smp_get_func_res_str(smp_resp[2], sizeof(b), b);
        pr2serr("Report phy error log result%s: %s\n",
                (phy_id_given ? "" : " (for phy_id=0)"), cp);
        ret = smp_resp[2];
        goto err_out;
    }
    printf("Report phy error log response:\n");
    res = sg_get_unaligned_be16(smp_resp + 4);
    if (verbose || res)
        printf("  Expander change count: %d\n", res);
    printf("  phy identifier: %d\n", smp_resp[9]);
    printf("  invalid dword count: %u\n",
           sg_get_unaligned_be32(smp_resp + 12));
    printf("  running disparity error count: %u\n",
           sg_get_unaligned_be32(smp_resp + 16));
    printf("  loss of dword synchronization count: %u\n",
           sg_get_unaligned_be32(smp_resp + 20));
    printf("  phy reset problem count: %u\n",
           sg_get_unaligned_be32(smp_resp + 24));

err_out:
    res = smp_initiator_close(&tobj);
    if (res < 0) {
        pr2serr("close error: %s\n", safe_strerror(errno));
        if (0 == ret)
            return SMP_LIB_FILE_ERROR;
    }
    if (ret < 0)
        ret = SMP_LIB_CAT_OTHER;
    if (verbose && ret)
        pr2serr("Exit status %d indicates error detected\n", ret);
    return ret;
}