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; }
/* 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; }
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; }
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; }
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; }
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; }