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

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

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

    destruct_scsi_pt_obj(ptvp);
    return ret;
}
/* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
int
sg_ll_readcap_16(int sg_fd, int pmi, uint64_t llba, void * resp,
                 int mx_resp_len, int noisy, int verbose)
{
    static const char * const cdb_name_s = "read capacity(16)";
    int k, ret, res, sense_cat;
    unsigned char rc_cdb[SERVICE_ACTION_IN_16_CMDLEN] =
                        {SERVICE_ACTION_IN_16_CMD, READ_CAPACITY_16_SA,
                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

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

    destruct_scsi_pt_obj(ptvp);
    return ret;
}
Exemple #3
0
/* Note that CAM (circa FreeBSD 9) cannot directly communicate with a SAS
 * expander because it isn't a SCSI device. FreeBSD assumes each SAS
 * expander is paired with a SES (enclosure) device. This seems to be true
 * for SAS-2 expanders but not the older SAS-1 expanders. Hence device_name
 * will be something like /dev/ses0 . */
int
smp_initiator_open(const char * device_name, int subvalue,
                   const char * i_params, uint64_t sa,
                   struct smp_target_obj * tobj, int verbose)
{
    struct cam_device* cam_dev;
    struct tobj_cam_t * tcp;

    if (i_params) { ; }     /* unused, suppress warning */
    if ((NULL == tobj) || (NULL == device_name))
        return -1;
    memset(tobj, 0, sizeof(struct smp_target_obj));
    strncpy(tobj->device_name, device_name, SMP_MAX_DEVICE_NAME);
    if (sa)
        sg_put_unaligned_be64(sa, tobj->sas_addr + 0);
    tobj->interface_selector = I_CAM;
    tcp = (struct tobj_cam_t *)
                calloc(1, sizeof(struct tobj_cam_t));
    if (tcp == NULL) {
        // errno already set by call to calloc()
        return -1;
    }
    if (cam_get_device(device_name, tcp->devname, DEV_IDLEN,
                       &(tcp->unitnum)) == -1) {
        if (verbose)
            fprintf(stderr, "bad device name structure\n");
        free(tcp);
        return -1;
    }
    if (! (cam_dev = cam_open_spec_device(tcp->devname, tcp->unitnum,
                                          O_RDWR, NULL))) {
        fprintf(stderr, "cam_open_spec_device: %s\n", cam_errbuf);
        free(tcp);
        return -1;
    }
    tcp->cam_dev = cam_dev;
    tobj->vp = tcp;
    tobj->opened = 1;
    tobj->subvalue = subvalue;  /* unused */
    return 0;
}
/* Invokes a SCSI WRITE AND VERIFY (16) command (SBC). Returns 0 -> success,
* various SG_LIB_CAT_* positive values or -1 -> other errors */
static int
sg_ll_write_verify16(int sg_fd, int wrprotect, bool dpo, int bytchk,
                     uint64_t llba, int num_lb, int group, uint8_t *dop,
                     int do_len, int timeout, bool noisy, int verbose)
{
    int ret;
    uint8_t wv_cdb[WRITE_VERIFY16_CMDLEN];


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

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

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

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

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

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

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

    destruct_scsi_pt_obj(ptvp);
    return ret;
}
/* Invokes a SCSI READ BUFFER(16) command (spc5r02).  Return of 0 -> success,
 * various SG_LIB_CAT_* positive values or -1 -> other errors */
static int
sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
                     uint64_t rb_offset, void * resp, int mx_resp_len,
                     int * residp, bool noisy, int verbose)
{
    int k, ret, res, sense_cat;
    uint8_t rb16_cb[SG_READ_BUFFER_16_CMDLEN] =
          {SG_READ_BUFFER_16_CMD, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
           0, 0, 0, 0};
    uint8_t sense_b[SENSE_BUFF_LEN];
    struct sg_pt_base * ptvp;

    rb16_cb[1] = (uint8_t)(rb_mode & 0x1f);
    if (rb_mode_sp)
        rb16_cb[1] |= (uint8_t)((rb_mode_sp & 0x7) << 5);
    sg_put_unaligned_be64(rb_offset, rb16_cb + 2);
    sg_put_unaligned_be24(mx_resp_len, rb16_cb + 11);
    rb16_cb[14] = (uint8_t)rb_id;
    if (verbose) {
        pr2serr("    Read buffer(16) cdb: ");
        for (k = 0; k < SG_READ_BUFFER_16_CMDLEN; ++k)
            pr2serr("%02x ", rb16_cb[k]);
        pr2serr("\n");
    }

    ptvp = construct_scsi_pt_obj();
    if (NULL == ptvp) {
        pr2serr("Read buffer(16): out of memory\n");
        return -1;
    }
    set_scsi_pt_cdb(ptvp, rb16_cb, sizeof(rb16_cb));
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    ret = sg_cmds_process_resp(ptvp, "Read buffer(16)", res, mx_resp_len,
                               sense_b, noisy, verbose, &sense_cat);
    if (-1 == ret)
        ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
    else if (-2 == ret) {
        switch (sense_cat) {
        case SG_LIB_CAT_RECOVERED:
        case SG_LIB_CAT_NO_SENSE:
            ret = 0;
            break;
        default:
            ret = sense_cat;
            break;
        }
    } else {
        if ((verbose > 2) && (ret > 0)) {
            pr2serr("    Read buffer(16): response%s\n",
                    (ret > 256 ? ", first 256 bytes" : ""));
            hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1);
        }
        ret = 0;
    }
    if (residp)
        *residp = get_scsi_pt_resid(ptvp);
    destruct_scsi_pt_obj(ptvp);
    return ret;
}
Exemple #8
0
int
main(int argc, char * argv[])
{
    int res, c, k, len, act_resplen;
    int expected_cc = 0;
    int do_hex = 0;
    int do_min = 0;
    int do_max = 0;
    int op_val = 0;
    int sas_pa = 0;
    int sas_sl = 0;
    int sata_pa = 0;
    int sata_sl = 0;
    int pptv = -1;
    int phy_id = 0;
    int pwrdis = 0;
    int do_raw = 0;
    int verbose = 0;
    int64_t sa_ll;
    uint64_t sa = 0;
    uint64_t adn = 0;
    char i_params[256];
    char device_name[512];
    char b[256];
    unsigned char smp_req[] = {SMP_FRAME_TYPE_REQ, SMP_FN_PHY_CONTROL, 0, 9,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, };
    unsigned char smp_resp[8];
    struct smp_req_resp smp_rr;
    struct smp_target_obj tobj;
    struct smp_val_name * vnp;
    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, "a:D:E:hHI:l:L:m:M:o:p:P:q:Q;rs:vV",
                        long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'a':
           sa_ll = smp_get_llnum(optarg);
           if (-1LL == sa_ll) {
                pr2serr("bad argument to '--attached'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            adn = (uint64_t)sa_ll;
            break;
        case 'D':
           pwrdis = smp_get_num(optarg);
           if ((pwrdis < 0) || (pwrdis > 3)) {
                pr2serr("bad argument to '--pwrdis'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            break;
        case 'E':
            expected_cc = smp_get_num(optarg);
            if ((expected_cc < 0) || (expected_cc > 65535)) {
                pr2serr("bad argument to '--expected'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            break;
        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 'm':
            do_min = smp_get_num(optarg);
            switch (do_min) {
            case 0:
            case 8:
            case 9:
            case 10:
            case 11:
            case 12:
                break;
            default:
                pr2serr("bad argument to '--min', want 0, 8, 9, 10, 11 or "
                        "12\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            break;
        case 'M':
            do_max = smp_get_num(optarg);
            switch (do_max) {
            case 0:
            case 8:
            case 9:
            case 10:
            case 11:
            case 12:
                break;
            default:
                pr2serr("bad argument to '--max', want 0, 8, 9, 10, 11 or "
                        "12\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            break;
        case 'l':
           sas_sl = smp_get_num(optarg);
           if ((sas_sl < 0) || (sas_sl > 3)) {
                pr2serr("bad argument to '--sas_sl'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            break;
        case 'L':
           sata_sl = smp_get_num(optarg);
           if ((sata_sl < 0) || (sata_sl > 3)) {
                pr2serr("bad argument to '--sata_sl'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            break;
        case 'o':
            if (isalpha(optarg[0])) {
                for (vnp = op_abbrev; vnp->name; ++vnp) {
                    if (0 == strncmp(optarg, vnp->name, 2))
                        break;
                }
                if (vnp->name)
                    op_val = vnp->value;
                else {
                    pr2serr("bad argument to '--op'\n");
                    list_op_abbrevs();
                    return SMP_LIB_SYNTAX_ERROR;
                }
            } else {
                op_val = smp_get_num(optarg);
                if ((op_val < 0) || (op_val > 255)) {
                    pr2serr("bad numeric argument to '--op'\n");
                    return SMP_LIB_SYNTAX_ERROR;
                }
            }
            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;
            }
            break;
        case 'P':
           pptv = smp_get_num(optarg);
           if ((pptv < 0) || (pptv > 15)) {
                pr2serr("bad argument to '--pptv', want value from 0 to 15 "
                        "inclusive\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            break;
        case 'q':
           sas_pa = smp_get_num(optarg);
           if ((sas_pa < 0) || (sas_pa > 3)) {
                pr2serr("bad argument to '--sas_pa'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            break;
        case 'Q':
           sata_pa = smp_get_num(optarg);
           if ((sata_pa < 0) || (sata_pa > 3)) {
                pr2serr("bad argument to '--sata_pa'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            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;
        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;

    sg_put_unaligned_be16(expected_cc, smp_req + 4);
    smp_req[9] = phy_id;
    smp_req[10] = op_val;
    if (pptv >= 0) {
        smp_req[11] |= 1;
        smp_req[36] |= (pptv & 0xf);
    }
    if (adn)
        sg_put_unaligned_be64(adn, smp_req + 24);
    smp_req[32] |= (do_min << 4);
    smp_req[33] |= (do_max << 4);
    smp_req[34] = (sas_sl << 6) | (sas_pa << 4) | (sata_sl << 2) | sata_pa;
    smp_req[35] = (pwrdis << 6);        /* added spl3r3 */
    if (verbose) {
        pr2serr("    Phy control request: ");
        for (k = 0; k < (int)sizeof(smp_req); ++k) {
            if (0 == (k % 16))
                pr2serr("\n      ");
            else if (0 == (k % 8))
                pr2serr(" ");
            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("Phy control 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("Phy control result: %s\n", cp);
        ret = smp_resp[2];
        goto err_out;
    }

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;
}
Exemple #9
0
int
main(int argc, char * argv[])
{
    int res, c, k, len, act_resplen;
    int do_disable = 0;
    int expected_cc = 0;
    int do_hex = 0;
    int er_ind = 0;
    int phy_id = 0;
    int do_raw = 0;
    int verbose = 0;
    int64_t sa_ll;
    uint64_t sa = 0;
    uint64_t routed = 0;
    char i_params[256];
    char device_name[512];
    char b[256];
    unsigned char smp_req[] = {SMP_FRAME_TYPE_REQ, SMP_FN_CONFIG_ROUTE_INFO,
                               0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
    unsigned char smp_resp[8];
    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, "dE:hHi:I:p:rR:s:vV", long_options,
                        &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'd':
            do_disable = 1;
            break;
        case 'E':
            expected_cc = smp_get_num(optarg);
            if ((expected_cc < 0) || (expected_cc > 65535)) {
                pr2serr("bad argument to '--expected'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            break;
        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 'i':
            er_ind = smp_get_num(optarg);
            if ((er_ind < 0) || (er_ind > 65535)) {
                pr2serr("bad argument to '--index'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            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;
            }
            break;
        case 'r':
            ++do_raw;
            break;
        case 'R':
            sa_ll = smp_get_llnum(optarg);
            if (-1LL == sa_ll) {
                pr2serr("bad argument to '--routed'\n");
                return SMP_LIB_SYNTAX_ERROR;
            }
            routed = (uint64_t)sa_ll;
            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;
        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;
            }
        }
    }
    if (routed) {
        if (! smp_is_naa5(routed)) {
            pr2serr("routed SAS address not in naa-5 format\n");
            if ('\0' == i_params[0]) {
                pr2serr("    use any '--interface=' to continue\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;

    sg_put_unaligned_be16(expected_cc, smp_req + 4);
    sg_put_unaligned_be16(er_ind, smp_req + 6);
    smp_req[9] = phy_id;
    if (do_disable)
        smp_req[12] |= 0x80;
    if (routed) {
        sg_put_unaligned_be64(routed, smp_req + 16);
    }
    if (verbose) {
        pr2serr("    Configure route information request: ");
        for (k = 0; k < (int)sizeof(smp_req); ++k) {
            if (0 == (k % 16))
                pr2serr("\n      ");
            else if (0 == (k % 8))
                pr2serr(" ");
            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("Configure route information 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("Configure route information result: %s\n", cp);
        ret = smp_resp[2];
        goto err_out;
    }
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;
}