Ejemplo n.º 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;
}
Ejemplo n.º 2
0
static int
do_cmd_read_capacity(int sg_fd, int verbose)
{
    int res, k, do16;
    unsigned int last_blk_addr, block_size;
    unsigned char resp_buff[RCAP16_REPLY_LEN];
    unsigned long long llast_blk_addr;
    double sz_mib;

    do16 = 0;
    res = sg_ll_readcap_10(sg_fd, 0 /* pmi */, 0 /* lba */, resp_buff,
                           RCAP_REPLY_LEN, 1, verbose);
    if (0 == res) {
        last_blk_addr = ((resp_buff[0] << 24) | (resp_buff[1] << 16) |
                         (resp_buff[2] << 8) | resp_buff[3]);
        if (0xffffffff != last_blk_addr) {
            block_size = ((resp_buff[4] << 24) | (resp_buff[5] << 16) |
                         (resp_buff[6] << 8) | resp_buff[7]);
            printf("blocks: %u\n", last_blk_addr + 1);
            printf("block_length: %u\n", block_size);
            sz_mib = ((double)(last_blk_addr + 1) * block_size) / 
                      (double)(1048576);
#ifdef SG3_UTILS_MINGW
            printf("capacity_mib: %g\n", sz_mib);
#else
            printf("capacity_mib: %.1f\n", sz_mib);
#endif
        } else
            do16 = 1;
    } else
        return res;
    if (do16) {
        /* within SERVICE ACTION IN. May need RW or root permissions. */
        res = sg_ll_readcap_16(sg_fd, 0 /* pmi */, 0 /* llba */, resp_buff,
                               RCAP16_REPLY_LEN, 1, verbose);
        if (0 == res) {
            for (k = 0, llast_blk_addr = 0; k < 8; ++k) {
                llast_blk_addr <<= 8;
                llast_blk_addr |= resp_buff[k];
            }
            block_size = ((resp_buff[8] << 24) | (resp_buff[9] << 16) |
                          (resp_buff[10] << 8) | resp_buff[11]);
            printf("blocks: %" PRIu64 "\n", llast_blk_addr + 1);
            printf("block_length: %u\n", block_size);
            sz_mib = ((double)(llast_blk_addr + 1) * block_size) / 
                      (double)(1048576);
#ifdef SG3_UTILS_MINGW
            printf("capacity_mib: %g\n", sz_mib);
#else
            printf("capacity_mib: %.1f\n", sz_mib);
#endif
        } else
            return res;
    }
    return 0;
}
Ejemplo n.º 3
0
int
main(int argc, char * argv[])
{
    bool got_stdin = false;
    bool if_given = false;
    bool lba_given = false;
    bool num_given = false;
    bool prot_en;
    int res, c, infd, act_cdb_len, vb, err;
    int sg_fd = -1;
    int ret = -1;
    uint32_t block_size;
    int64_t ll;
    const char * device_name = NULL;
    struct opts_t * op;
    uint8_t * wBuff = NULL;
    uint8_t * free_wBuff = NULL;
    char ebuff[EBUFF_SZ];
    char b[80];
    uint8_t resp_buff[RCAP16_RESP_LEN];
    struct opts_t opts;
    struct stat a_stat;

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

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

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

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

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

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

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

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

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

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

err_out:
    if (free_wBuff)
        free(free_wBuff);
    if (sg_fd >= 0) {
        res = sg_cmds_close_device(sg_fd);
        if (res < 0) {
            pr2serr("close error: %s\n", safe_strerror(-res));
            if (0 == ret)
                ret = sg_convert_errno(-res);
        }
    }
    if (0 == op->verbose) {
        if (! sg_if_can2stderr("sg_write_same failed: ", ret))
            pr2serr("Some error occurred, try again with '-v' "
                    "or '-vv' for more information\n");
    }
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Ejemplo n.º 4
0
                               (resp_buff[10] << 8) |
                               resp_buff[11]);
                 printf("Read Capacity (16) results:\n");
                 printf("   Protection: prot_en=%d, p_type=%d\n",
                        !!(resp_buff[12] & 0x1),
                        ((resp_buff[12] >> 1) & 0x7));
                 printf("   Thin provisioning: tpe=%d, tprz=%d\n",
                        !!(resp_buff[14] & 0x80),
                        !!(resp_buff[14] & 0x40));
                 printf("   Number of blocks=%" PRIu64 "\n",
                        llast_blk_addr + 1);
                 printf("   Block size=%u bytes\n", block_size);
                 return (int)block_size;
         }
 } else {
         res = sg_ll_readcap_10(fd, 0 /* pmi */, 0 /* lba */,
                                resp_buff, 8, 0, verbose);
         if (0 == res) {
                 last_blk_addr = ((resp_buff[0] << 24) |
                                  (resp_buff[1] << 16) |
                                  (resp_buff[2] << 8) |
                                  resp_buff[3]);
                 block_size = ((resp_buff[4] << 24) |
                               (resp_buff[5] << 16) |
                               (resp_buff[6] << 8) |
                               resp_buff[7]);
                 printf("Read Capacity (10) results:\n");
                 printf("   Number of blocks=%u\n",
                        last_blk_addr + 1);
                 printf("   Block size=%u bytes\n", block_size);
                 return (int)block_size;
         }