static int fail_all_paths(int fd) { unsigned char fail_paths_pg[118]; struct rdac_legacy_page *rdac_page; int res; char b[80]; memset(fail_paths_pg, 0, 118); memcpy(fail_paths_pg, mode6_hdr, 4); memcpy(fail_paths_pg + 4, block_descriptor, 8); rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); rdac_page->page_code = RDAC_CONTROLLER_PAGE | 0x40; rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; rdac_page->quiescence = RDAC_QUIESCENCE_TIME; rdac_page->options = RDAC_FORCE_QUIESCENCE; rdac_page->current_mode_lsb = RDAC_FAIL_ALL_PATHS; res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 118, 1, (do_verbose ? 2 : 0)); switch (res) { case 0: if (do_verbose) fprintf(stderr, "fail paths successful\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, do_verbose); fprintf(stderr, "fail paths failed: %s\n", b); break; } return res; }
/* Returns 0 if successful */ static int process_read_long(int sg_fd, bool do_16, bool pblock, bool correct, uint64_t llba, void * data_out, int xfer_len, int verbose) { int offset, res; const char * ten_or; char b[80]; if (do_16) res = sg_ll_read_long16(sg_fd, pblock, correct, llba, data_out, xfer_len, &offset, true, verbose); else res = sg_ll_read_long10(sg_fd, pblock, correct, (unsigned int)llba, data_out, xfer_len, &offset, true, verbose); ten_or = do_16 ? "16" : "10"; switch (res) { case 0: break; case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: pr2serr("<<< device indicates 'xfer_len' should be %d >>>\n", xfer_len - offset); break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr(" SCSI READ LONG (%s): %s\n", ten_or, b); break; } return res; }
static int fail_all_paths(int fd, int use_6_byte) { unsigned char fail_paths_pg[308]; struct rdac_legacy_page *rdac_page; struct rdac_expanded_page *rdac_page_exp; struct rdac_page_common *rdac_common = NULL; int res; char b[80]; memset(fail_paths_pg, 0, 308); if (use_6_byte) { memcpy(fail_paths_pg, mode6_hdr, 4); memcpy(fail_paths_pg + 4, block_descriptor, 8); rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); rdac_page->page_code = RDAC_CONTROLLER_PAGE; rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; rdac_common = &rdac_page->attr; } else { memcpy(fail_paths_pg, mode10_hdr, 8); rdac_page_exp = (struct rdac_expanded_page *) (fail_paths_pg + 8); rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40; rdac_page_exp->subpage_code = 0x1; rdac_page_exp->page_length[0] = EXPANDED_LUN_SPACE_PAGE_LEN >> 8; rdac_page_exp->page_length[1] = EXPANDED_LUN_SPACE_PAGE_LEN & 0xFF; rdac_common = &rdac_page_exp->attr; } rdac_common->current_mode_lsb = RDAC_FAIL_ALL_PATHS; rdac_common->quiescence = RDAC_QUIESCENCE_TIME; rdac_common->options = RDAC_FORCE_QUIESCENCE; if (use_6_byte) { res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 118, 1, (do_verbose ? 2 : 0)); } else { res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 308, 1, (do_verbose ? 2: 0)); } switch (res) { case 0: if (do_verbose) fprintf(stderr, "fail paths successful\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, do_verbose); fprintf(stderr, "fail paths failed: %s\n", b); break; } return res; }
/* Get expected extended self-test time from mode page 0xa (for '-e') */ static int do_modes_0a(int sg_fd, void * resp, int mx_resp_len, int noisy, int mode6, int verbose) { int res; if (mode6) res = sg_ll_mode_sense6(sg_fd, 1 /* dbd */, 0 /* pc */, 0xa /* page */, 0, resp, mx_resp_len, noisy, verbose); else res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, 1 /* dbd */, 0, 0xa, 0, resp, mx_resp_len, noisy, verbose); if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Mode sense (%s): %s\n", (mode6 ? "6" : "10"), b); } return res; }
int main(int argc, char * argv[]) { int res, c, len, k; int sg_fd = -1; int do_help = 0; int do_hex = 0; int do_long = 0; int o_readonly = 0; int rb_id = 0; int rb_len = 4; int rb_mode = 0; int rb_mode_sp = 0; int64_t ll; uint64_t rb_offset = 0; int do_raw = 0; int resid = 0; int verbose = 0; int ret = 0; const char * device_name = NULL; unsigned char * resp; const struct mode_s * mp; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHi:l:Lm:o:rRS:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': ++do_help; break; case 'H': ++do_hex; break; case 'i': rb_id = sg_get_num(optarg); if ((rb_id < 0) || (rb_id > 255)) { fprintf(stderr, "argument to '--id' should be in the range " "0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'l': rb_len = sg_get_num(optarg); if (rb_len < 0) { fprintf(stderr, "bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } if (rb_len > 0xffffff) { fprintf(stderr, "argument to '--length' must be <= " "0xffffff\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'L': ++do_long; break; case 'm': if (isdigit(*optarg)) { rb_mode = sg_get_num(optarg); if ((rb_mode < 0) || (rb_mode > 31)) { fprintf(stderr, "argument to '--mode' should be in the " "range 0 to 31\n"); return SG_LIB_SYNTAX_ERROR; } } else { len = strlen(optarg); for (mp = modes; mp->mode_string; ++mp) { if (0 == strncmp(mp->mode_string, optarg, len)) { rb_mode = mp->mode; break; } } if (NULL == mp) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'o': ll = sg_get_llnum(optarg); if (ll < 0) { fprintf(stderr, "bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } rb_offset = ll; break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 'S': rb_mode_sp = sg_get_num(optarg); if ((rb_mode_sp < 0) || (rb_mode_sp > 7)) { fprintf(stderr, "expected argument to '--specific' to be 0 " "to 7\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (do_help) { if (do_help > 1) { usage(); fprintf(stderr, "\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) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (rb_len > 0) { resp = (unsigned char *)malloc(rb_len); if (NULL == resp) { fprintf(stderr, "unable to allocate %d bytes on the heap\n", rb_len); return SG_LIB_CAT_OTHER; } memset(resp, 0, rb_len); } else resp = NULL; if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto fini; } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (verbose > 4) fprintf(stderr, "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, o_readonly, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto fini; } if (do_long) res = ll_read_buffer_16(sg_fd, rb_mode, rb_mode_sp, rb_id, rb_offset, resp, rb_len, &resid, 1, verbose); else if (rb_offset > 0xffffff) { fprintf(stderr, "--offset value is too large for READ BUFFER(10), " "try --16\n"); ret = SG_LIB_SYNTAX_ERROR; goto fini; } else res = ll_read_buffer_10(sg_fd, rb_mode, rb_mode_sp, rb_id, (uint32_t)rb_offset, resp, rb_len, &resid, 1, verbose); if (0 != res) { char b[80]; ret = res; if (res > 0) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Read buffer(%d) failed: %s\n", (do_long ? 16 : 10), b); } goto fini; } if (resid > 0) rb_len -= resid; /* got back less than requested */ if (rb_len > 0) { if (do_raw) dStrRaw((const char *)resp, rb_len); else if (do_hex || (rb_len < 4)) dStrHex((const char *)resp, rb_len, ((do_hex > 1) ? 0 : 1)); else { switch (rb_mode) { case MODE_DESCRIPTOR: k = (resp[1] << 16) | (resp[2] << 8) | resp[3]; printf("OFFSET BOUNDARY: %d, Buffer offset alignment: " "%d-byte\n", resp[0], (1 << resp[0])); printf("BUFFER CAPACITY: %d (0x%x)\n", k, k); break; case MODE_ECHO_BDESC: k = ((resp[2] & 0x1F) << 8) | resp[3]; printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0); printf("Echo buffer capacity: %d (0x%x)\n", k, k); break; default: dStrHex((const char *)resp, rb_len, (verbose > 1 ? 0 : 1)); break; } } } fini: if (resp) free(resp); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { int64_t skip = 0; int64_t seek = 0; int ibs = 0; int obs = 0; int bpt = DEF_BLOCKS_PER_TRANSFER; int bpt_given = 0; char str[STR_SZ]; char * key; char * buf; char inf[INOUTF_SZ]; int in_type = FT_OTHER; char outf[INOUTF_SZ]; int out_type = FT_OTHER; int res, k, t; int infd, outfd, blocks; unsigned char * wrkPos; unsigned char * wrkBuff = NULL; unsigned char * wrkMmap = NULL; int64_t in_num_sect = -1; int in_res_sz = 0; int64_t out_num_sect = -1; int out_res_sz = 0; int scsi_cdbsz_in = DEF_SCSI_CDBSZ; int scsi_cdbsz_out = DEF_SCSI_CDBSZ; int cdbsz_given = 0; int do_coe = 0; /* dummy, just accept + ignore */ int do_sync = 0; int num_dio_not_done = 0; int in_sect_sz, out_sect_sz; int n, flags; char ebuff[EBUFF_SZ]; char b[80]; int blocks_per; size_t psz; struct flags_t in_flags; struct flags_t out_flags; int ret = 0; #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ #else psz = 4096; /* give up, pick likely figure */ #endif inf[0] = '\0'; outf[0] = '\0'; memset(&in_flags, 0, sizeof(in_flags)); memset(&out_flags, 0, sizeof(out_flags)); for (k = 1; k < argc; k++) { if (argv[k]) strncpy(str, argv[k], STR_SZ); else continue; for (key = str, buf = key; *buf && *buf != '=';) buf++; if (*buf) *buf++ = '\0'; if (0 == strcmp(key,"bpt")) { bpt = sg_get_num(buf); if (-1 == bpt) { pr2serr(ME "bad argument to 'bpt'\n"); return SG_LIB_SYNTAX_ERROR; } bpt_given = 1; } else if (0 == strcmp(key,"bs")) { blk_sz = sg_get_num(buf); if (-1 == blk_sz) { pr2serr(ME "bad argument to 'bs'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"cdbsz")) { scsi_cdbsz_in = sg_get_num(buf); scsi_cdbsz_out = scsi_cdbsz_in; cdbsz_given = 1; } else if (0 == strcmp(key,"coe")) { do_coe = sg_get_num(buf); /* dummy, just accept + ignore */ if (do_coe) { ; /* unused, dummy to suppress warning */ } } else if (0 == strcmp(key,"count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); if (-1LL == dd_count) { pr2serr(ME "bad argument to 'count'\n"); return SG_LIB_SYNTAX_ERROR; } } /* treat 'count=-1' as calculate count (same as not given) */ } else if (0 == strcmp(key,"dio")) out_flags.dio = sg_get_num(buf); else if (0 == strcmp(key,"fua")) { n = sg_get_num(buf); if (n & 1) out_flags.fua = 1; if (n & 2) in_flags.fua = 1; } else if (0 == strcmp(key,"ibs")) { ibs = sg_get_num(buf); if (-1 == ibs) { pr2serr(ME "bad argument to 'ibs'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"if") == 0) { if ('\0' != inf[0]) { pr2serr("Second 'if=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(inf, buf, INOUTF_SZ); } else if (0 == strcmp(key, "iflag")) { if (process_flags(buf, &in_flags)) { pr2serr(ME "bad argument to 'iflag'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"of") == 0) { if ('\0' != outf[0]) { pr2serr("Second 'of=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(outf, buf, INOUTF_SZ); } else if (0 == strcmp(key, "oflag")) { if (process_flags(buf, &out_flags)) { pr2serr(ME "bad argument to 'oflag'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"obs")) { obs = sg_get_num(buf); if (-1 == obs) { pr2serr(ME "bad argument to 'obs'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"seek")) { seek = sg_get_llnum(buf); if (-1LL == seek) { pr2serr(ME "bad argument to 'seek'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"skip")) { skip = sg_get_llnum(buf); if (-1LL == skip) { pr2serr(ME "bad argument to 'skip'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"sync")) do_sync = sg_get_num(buf); else if (0 == strcmp(key,"time")) do_time = sg_get_num(buf); else if (0 == strncmp(key, "verb", 4)) verbose = sg_get_num(buf); else if ((0 == strncmp(key, "--help", 7)) || (0 == strcmp(key, "-h")) || (0 == strcmp(key, "-?"))) { usage(); return 0; } else if ((0 == strncmp(key, "--vers", 6)) || (0 == strcmp(key, "-V"))) { pr2serr(ME ": %s\n", version_str); return 0; } else { pr2serr("Unrecognized option '%s'\n", key); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } } if (blk_sz <= 0) { blk_sz = DEF_BLOCK_SIZE; pr2serr("Assume default 'bs' (block size) of %d bytes\n", blk_sz); } if ((ibs && (ibs != blk_sz)) || (obs && (obs != blk_sz))) { pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((skip < 0) || (seek < 0)) { pr2serr("skip and seek cannot be negative\n"); return SG_LIB_SYNTAX_ERROR; } if ((out_flags.append > 0) && (seek > 0)) { pr2serr("Can't use both append and seek switches\n"); return SG_LIB_SYNTAX_ERROR; } if (bpt < 1) { pr2serr("bpt must be greater than 0\n"); return SG_LIB_SYNTAX_ERROR; } /* defaulting transfer size to 128*2048 for CD/DVDs is too large for the block layer in lk 2.6 and results in an EIO on the SG_IO ioctl. So reduce it in that case. */ if ((blk_sz >= 2048) && (0 == bpt_given)) bpt = DEF_BLOCKS_PER_2048TRANSFER; #ifdef SG_DEBUG pr2serr(ME "if=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64 "\n", inf, skip, outf, seek, dd_count); #endif install_handler (SIGINT, interrupt_handler); install_handler (SIGQUIT, interrupt_handler); install_handler (SIGPIPE, interrupt_handler); install_handler (SIGUSR1, siginfo_handler); infd = STDIN_FILENO; outfd = STDOUT_FILENO; if (inf[0] && ('-' != inf[0])) { in_type = dd_filetype(inf); if (verbose) pr2serr(" >> Input file type: %s\n", dd_filetype_str(in_type, ebuff)); if (FT_ERROR == in_type) { pr2serr(ME "unable to access %s\n", inf); return SG_LIB_FILE_ERROR; } else if (FT_ST == in_type) { pr2serr(ME "unable to use scsi tape device %s\n", inf); return SG_LIB_FILE_ERROR; } else if (FT_SG == in_type) { flags = O_RDWR | O_NONBLOCK; if (in_flags.direct) flags |= O_DIRECT; if (in_flags.excl) flags |= O_EXCL; if (in_flags.dsync) flags |= O_SYNC; if ((infd = open(inf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg reading", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } res = ioctl(infd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30122)) { pr2serr(ME "sg driver prior to 3.1.22\n"); return SG_LIB_FILE_ERROR; } in_res_sz = blk_sz * bpt; if (0 != (in_res_sz % psz)) /* round up to next page */ in_res_sz = ((in_res_sz / psz) + 1) * psz; if (ioctl(infd, SG_GET_RESERVED_SIZE, &t) < 0) { perror(ME "SG_GET_RESERVED_SIZE error"); return SG_LIB_FILE_ERROR; } if (t < MIN_RESERVED_SIZE) t = MIN_RESERVED_SIZE; if (in_res_sz > t) { if (ioctl(infd, SG_SET_RESERVED_SIZE, &in_res_sz) < 0) { perror(ME "SG_SET_RESERVED_SIZE error"); return SG_LIB_FILE_ERROR; } } wrkMmap = (unsigned char *)mmap(NULL, in_res_sz, PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0); if (MAP_FAILED == wrkMmap) { snprintf(ebuff, EBUFF_SZ, ME "error using mmap() on file: %s", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } } else { flags = O_RDONLY; if (in_flags.direct) flags |= O_DIRECT; if (in_flags.excl) flags |= O_EXCL; if (in_flags.dsync) flags |= O_SYNC; if ((infd = open(inf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } else if (skip > 0) { off64_t offset = skip; offset *= blk_sz; /* could exceed 32 bits here! */ if (lseek64(infd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " "required position on %s", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } if (verbose) pr2serr(" >> skip: lseek64 SEEK_SET, byte offset=0x%" PRIx64 "\n", (uint64_t)offset); } } } if (outf[0] && ('-' != outf[0])) { out_type = dd_filetype(outf); if (verbose) pr2serr(" >> Output file type: %s\n", dd_filetype_str(out_type, ebuff)); if (FT_ST == out_type) { pr2serr(ME "unable to use scsi tape device %s\n", outf); return SG_LIB_FILE_ERROR; } else if (FT_SG == out_type) { flags = O_RDWR | O_NONBLOCK; if (out_flags.direct) flags |= O_DIRECT; if (out_flags.excl) flags |= O_EXCL; if (out_flags.dsync) flags |= O_SYNC; if ((outfd = open(outf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for " "sg writing", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } res = ioctl(outfd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30122)) { pr2serr(ME "sg driver prior to 3.1.22\n"); return SG_LIB_FILE_ERROR; } if (ioctl(outfd, SG_GET_RESERVED_SIZE, &t) < 0) { perror(ME "SG_GET_RESERVED_SIZE error"); return SG_LIB_FILE_ERROR; } if (t < MIN_RESERVED_SIZE) t = MIN_RESERVED_SIZE; out_res_sz = blk_sz * bpt; if (out_res_sz > t) { if (ioctl(outfd, SG_SET_RESERVED_SIZE, &out_res_sz) < 0) { perror(ME "SG_SET_RESERVED_SIZE error"); return SG_LIB_FILE_ERROR; } } if (NULL == wrkMmap) { wrkMmap = (unsigned char *)mmap(NULL, out_res_sz, PROT_READ | PROT_WRITE, MAP_SHARED, outfd, 0); if (MAP_FAILED == wrkMmap) { snprintf(ebuff, EBUFF_SZ, ME "error using mmap() on file: %s", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } } } else if (FT_DEV_NULL == out_type) outfd = -1; /* don't bother opening */ else { if (FT_RAW != out_type) { flags = O_WRONLY | O_CREAT; if (out_flags.direct) flags |= O_DIRECT; if (out_flags.excl) flags |= O_EXCL; if (out_flags.dsync) flags |= O_SYNC; if (out_flags.append) flags |= O_APPEND; if ((outfd = open(outf, flags, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for writing", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } } else { if ((outfd = open(outf, O_WRONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s " "for raw writing", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } } if (seek > 0) { off64_t offset = seek; offset *= blk_sz; /* could exceed 32 bits here! */ if (lseek64(outfd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't seek to " "required position on %s", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } if (verbose) pr2serr(" >> seek: lseek64 SEEK_SET, byte offset=0x%" PRIx64 "\n", (uint64_t)offset); } } } if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) { pr2serr("Won't default both IFILE to stdin _and_ OFILE to as " "stdout\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } if (dd_count < 0) { in_num_sect = -1; if (FT_SG == in_type) { res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention(in), continuing\n"); res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { pr2serr("Aborted command(in), continuing\n"); res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); } if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Read capacity (if=%s): %s\n", inf, b); in_num_sect = -1; } } else if (FT_BLOCK == in_type) { if (0 != read_blkdev_capacity(infd, &in_num_sect, &in_sect_sz)) { pr2serr("Unable to read block capacity on %s\n", inf); in_num_sect = -1; } if (blk_sz != in_sect_sz) { pr2serr("block size on %s confusion; bs=%d, from device=%d\n", inf, blk_sz, in_sect_sz); in_num_sect = -1; } } if (in_num_sect > skip) in_num_sect -= skip; out_num_sect = -1; if (FT_SG == out_type) { res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention(out), continuing\n"); res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { pr2serr("Aborted command(out), continuing\n"); res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); } if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Read capacity (of=%s): %s\n", inf, b); out_num_sect = -1; } } else if (FT_BLOCK == out_type) { if (0 != read_blkdev_capacity(outfd, &out_num_sect, &out_sect_sz)) { pr2serr("Unable to read block capacity on %s\n", outf); out_num_sect = -1; } if (blk_sz != out_sect_sz) { pr2serr("block size on %s confusion: bs=%d, from device=%d\n", outf, blk_sz, out_sect_sz); out_num_sect = -1; } } if (out_num_sect > seek) out_num_sect -= seek; #ifdef SG_DEBUG pr2serr("Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64 ", " "out_num_sect=%" PRId64 "\n", dd_count, in_num_sect, out_num_sect); #endif if (in_num_sect > 0) { if (out_num_sect > 0) dd_count = (in_num_sect > out_num_sect) ? out_num_sect : in_num_sect; else dd_count = in_num_sect; } else dd_count = out_num_sect; } if (dd_count < 0) { pr2serr("Couldn't calculate count, please give one\n"); return SG_LIB_SYNTAX_ERROR; } if (! cdbsz_given) { if ((FT_SG == in_type) && (MAX_SCSI_CDBSZ != scsi_cdbsz_in) && (((dd_count + skip) > UINT_MAX) || (bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'if')\n"); scsi_cdbsz_in = MAX_SCSI_CDBSZ; } if ((FT_SG == out_type) && (MAX_SCSI_CDBSZ != scsi_cdbsz_out) && (((dd_count + seek) > UINT_MAX) || (bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'of')\n"); scsi_cdbsz_out = MAX_SCSI_CDBSZ; } } if (out_flags.dio && (FT_SG != in_type)) { out_flags.dio = 0; pr2serr(">>> dio only performed on 'of' side when 'if' is an sg " "device\n"); } if (out_flags.dio) { int fd; char c; if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) pr2serr(">>> %s set to '0' but should be set to '1' for " "direct IO\n", proc_allow_dio); } close(fd); } } if (wrkMmap) { wrkPos = wrkMmap; } else { if ((FT_RAW == in_type) || (FT_RAW == out_type)) { wrkBuff = (unsigned char *)malloc(blk_sz * bpt + psz); if (0 == wrkBuff) { pr2serr("Not enough user memory for raw\n"); return SG_LIB_FILE_ERROR; } /* perhaps use posix_memalign() instead */ wrkPos = (unsigned char *)(((uintptr_t)wrkBuff + psz - 1) & (~(psz - 1))); } else { wrkBuff = (unsigned char *)malloc(blk_sz * bpt); if (0 == wrkBuff) { pr2serr("Not enough user memory\n"); return SG_LIB_FILE_ERROR; } wrkPos = wrkBuff; } } blocks_per = bpt; #ifdef SG_DEBUG pr2serr("Start of loop, count=%" PRId64 ", blocks_per=%d\n", dd_count, blocks_per); #endif if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); start_tm_valid = 1; } req_count = dd_count; if (verbose && (dd_count > 0) && (0 == out_flags.dio) && (FT_SG == in_type) && (FT_SG == out_type)) pr2serr("Since both 'if' and 'of' are sg devices, only do mmap-ed " "transfers on 'if'\n"); while (dd_count > 0) { blocks = (dd_count > blocks_per) ? blocks_per : dd_count; if (FT_SG == in_type) { ret = sg_read(infd, wrkPos, blocks, skip, blk_sz, scsi_cdbsz_in, in_flags.fua, in_flags.dpo, 1); if ((SG_LIB_CAT_UNIT_ATTENTION == ret) || (SG_LIB_CAT_ABORTED_COMMAND == ret)) { pr2serr("Unit attention or aborted command, continuing " "(r)\n"); ret = sg_read(infd, wrkPos, blocks, skip, blk_sz, scsi_cdbsz_in, in_flags.fua, in_flags.dpo, 1); } if (0 != ret) { pr2serr("sg_read failed, skip=%" PRId64 "\n", skip); break; } else in_full += blocks; } else { while (((res = read(infd, wrkPos, blocks * blk_sz)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) ; if (verbose > 2) pr2serr("read(unix): count=%d, res=%d\n", blocks * blk_sz, res); if (ret < 0) { snprintf(ebuff, EBUFF_SZ, ME "reading, skip=%" PRId64 " ", skip); perror(ebuff); ret = -1; break; } else if (res < blocks * blk_sz) { dd_count = 0; blocks = res / blk_sz; if ((res % blk_sz) > 0) { blocks++; in_partial++; } } in_full += blocks; } if (0 == blocks) break; /* read nothing so leave loop */ if (FT_SG == out_type) { int do_mmap = (FT_SG == in_type) ? 0 : 1; int dio_res = out_flags.dio; ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz, scsi_cdbsz_out, out_flags.fua, out_flags.dpo, do_mmap, &dio_res); if ((SG_LIB_CAT_UNIT_ATTENTION == ret) || (SG_LIB_CAT_ABORTED_COMMAND == ret)) { pr2serr("Unit attention or aborted command, continuing (w)\n"); dio_res = out_flags.dio; ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz, scsi_cdbsz_out, out_flags.fua, out_flags.dpo, do_mmap, &dio_res); } if (0 != ret) { pr2serr("sg_write failed, seek=%" PRId64 "\n", seek); break; } else { out_full += blocks; if (out_flags.dio && (0 == dio_res)) num_dio_not_done++; } } else if (FT_DEV_NULL == out_type) out_full += blocks; /* act as if written out without error */ else { while (((res = write(outfd, wrkPos, blocks * blk_sz)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) ; if (verbose > 2) pr2serr("write(unix): count=%d, res=%d\n", blocks * blk_sz, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "writing, seek=%" PRId64 " ", seek); perror(ebuff); break; } else if (res < blocks * blk_sz) { pr2serr("output file probably full, seek=%" PRId64 " ", seek); blocks = res / blk_sz; out_full += blocks; if ((res % blk_sz) > 0) out_partial++; break; } else out_full += blocks; } if (dd_count > 0) dd_count -= blocks; skip += blocks; seek += blocks; } if (do_time) calc_duration_throughput(0); if (do_sync) { if (FT_SG == out_type) { pr2serr(">> Synchronizing cache on %s\n", outf); res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 0, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention(out), continuing\n"); res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 0, 0); } if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Synchronize cache(out): %s\n", b); } } } if (wrkBuff) free(wrkBuff); if (STDIN_FILENO != infd) close(infd); if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type)) close(outfd); if (0 != dd_count) { pr2serr("Some error occurred,"); if (0 == ret) ret = SG_LIB_CAT_OTHER; } print_stats(); if (sum_of_resids) pr2serr(">> Non-zero sum of residual counts=%d\n", sum_of_resids); if (num_dio_not_done) pr2serr(">> dio requested but _not_ done %d times\n", num_dio_not_done); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { int sg_fd, k, j, res, c, rlen, num_descs; int do_brief = 0; int do_hex = 0; int64_t ll; uint64_t lba = 0; uint64_t d_lba = 0; uint32_t d_blocks = 0; int maxlen = DEF_GLBAS_BUFF_LEN; int do_raw = 0; int o_readonly = 0; int verbose = 0; const char * device_name = NULL; const unsigned char * ucp; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "bhHl:m:rRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': ++do_brief; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "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_GLBAS_BUFF_LEN)) { fprintf(stderr, "argument to '--maxlen' should be %d or " "less\n", MAX_GLBAS_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "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) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (maxlen > DEF_GLBAS_BUFF_LEN) { glbasBuffp = (unsigned char *)calloc(maxlen, 1); if (NULL == glbasBuffp) { fprintf(stderr, "unable to allocate %d bytes on heap\n", maxlen); return SG_LIB_SYNTAX_ERROR; } } 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) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto free_buff; } res = sg_ll_get_lba_status(sg_fd, lba, glbasBuffp, maxlen, 1, verbose); ret = res; if (0 == res) { /* in sbc3r25 offset for calculating the 'parameter data length' * (rlen variable below) was reduced from 8 to 4. */ if (maxlen >= 4) rlen = (glbasBuffp[0] << 24) + (glbasBuffp[1] << 16) + (glbasBuffp[2] << 8) + glbasBuffp[3] + 4; else rlen = maxlen; k = (rlen > maxlen) ? maxlen : rlen; if (do_raw) { dStrRaw((const char *)glbasBuffp, k); goto the_end; } if (do_hex) { dStrHex((const char *)glbasBuffp, k, 1); goto the_end; } if (maxlen < 4) { if (verbose) fprintf(stderr, "Exiting because allocation length (maxlen) " " less than 4\n"); goto the_end; } if ((verbose > 1) || (verbose && (rlen > maxlen))) { fprintf(stderr, "response length %d bytes\n", rlen); if (rlen > maxlen) fprintf(stderr, " ... which is greater than maxlen " "(allocation length %d), truncation\n", maxlen); } if (rlen > maxlen) rlen = maxlen; if (do_brief > 1) { if (rlen < 24) { fprintf(stderr, "Need maxlen and response length to " " be at least 24, have %d bytes\n", rlen); ret = SG_LIB_CAT_OTHER; goto the_end; } res = decode_lba_status_desc(glbasBuffp + 8, &d_lba, &d_blocks); if ((res < 0) || (res > 15)) { fprintf(stderr, "first LBA status descriptor returned %d " "??\n", res); ret = SG_LIB_CAT_OTHER; goto the_end; } if ((lba < d_lba) || (lba >= (d_lba + d_blocks))) { fprintf(stderr, "given LBA not in range of first " "descriptor:\n" " descriptor LBA: 0x"); for (j = 0; j < 8; ++j) fprintf(stderr, "%02x", glbasBuffp[8 + j]); fprintf(stderr, " blocks: 0x%x p_status: %d\n", (unsigned int)d_blocks, res); ret = SG_LIB_CAT_OTHER; goto the_end; } printf("%d\n", res); goto the_end; } if (rlen < 24) { printf("No complete LBA status descriptors available\n"); goto the_end; } num_descs = (rlen - 8) / 16; if (verbose) fprintf(stderr, "%d complete LBA status descriptors found\n", num_descs); for (ucp = glbasBuffp + 8, k = 0; k < num_descs; ucp += 16, ++k) { res = decode_lba_status_desc(ucp, &d_lba, &d_blocks); if ((res < 0) || (res > 15)) fprintf(stderr, "descriptor %d: bad LBA status descriptor " "returned %d\n", k + 1, res); if (do_brief) { printf("0x"); for (j = 0; j < 8; ++j) printf("%02x", ucp[j]); printf(" 0x%x %d\n", (unsigned int)d_blocks, res); } else { printf("descriptor LBA: 0x"); for (j = 0; j < 8; ++j) printf("%02x", ucp[j]); printf(" blocks: %u", (unsigned int)d_blocks); switch (res) { case 0: printf(" mapped\n"); break; case 1: printf(" deallocated\n"); break; case 2: printf(" anchored\n"); break; default: printf(" Provisioning status: %d\n", res); break; } } } if ((num_descs * 16) + 8 < rlen) fprintf(stderr, "incomplete trailing LBA status descriptors " "found\n"); } else if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "Get LBA Status command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "Get LBA Status command: bad field in cdb\n"); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Get LBA Status command: %s\n", b); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = SG_LIB_FILE_ERROR; } free_buff: if (glbasBuffp && (glbasBuffp != glbasBuff)) free(glbasBuffp); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { bool do_long = false; bool o_readonly = false; bool do_raw = false; bool verbose_given = false; bool version_given = false; int res, c, len, k; int sg_fd = -1; int do_help = 0; int do_hex = 0; int rb_id = 0; int rb_len = 4; int rb_mode = 0; int rb_mode_sp = 0; int resid = 0; int verbose = 0; int ret = 0; int64_t ll; uint64_t rb_offset = 0; const char * device_name = NULL; uint8_t * resp; const struct mode_s * mp; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHi:l:Lm:o:rRS:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': ++do_help; break; case 'H': ++do_hex; break; case 'i': rb_id = sg_get_num(optarg); if ((rb_id < 0) || (rb_id > 255)) { pr2serr("argument to '--id' should be in the range 0 to " "255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'l': rb_len = sg_get_num(optarg); if (rb_len < 0) { pr2serr("bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } if (rb_len > 0xffffff) { pr2serr("argument to '--length' must be <= 0xffffff\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'L': do_long = true; break; case 'm': if (isdigit(*optarg)) { rb_mode = sg_get_num(optarg); if ((rb_mode < 0) || (rb_mode > 31)) { pr2serr("argument to '--mode' should be in the range 0 " "to 31\n"); return SG_LIB_SYNTAX_ERROR; } } else { len = strlen(optarg); for (mp = modes; mp->mode_string; ++mp) { if (0 == strncmp(mp->mode_string, optarg, len)) { rb_mode = mp->mode; break; } } if (NULL == mp->mode_string) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'o': ll = sg_get_llnum(optarg); if (ll < 0) { pr2serr("bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } rb_offset = ll; break; case 'r': do_raw = true; break; case 'R': o_readonly = true; break; case 'S': rb_mode_sp = sg_get_num(optarg); if ((rb_mode_sp < 0) || (rb_mode_sp > 7)) { pr2serr("expected argument to '--specific' to be 0 to 7\n"); return SG_LIB_SYNTAX_ERROR; } 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 (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; 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\n"); usage(); return SG_LIB_SYNTAX_ERROR; } len = rb_len ? rb_len : 8; resp = (uint8_t *)malloc(len); if (NULL == resp) { pr2serr("unable to allocate %d bytes on the heap\n", len); return SG_LIB_CAT_OTHER; } memset(resp, 0, len); if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto fini; } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (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, 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 fini; } if (do_long) res = sg_ll_read_buffer_16(sg_fd, rb_mode, rb_mode_sp, rb_id, rb_offset, resp, rb_len, &resid, true, verbose); else if (rb_offset > 0xffffff) { pr2serr("--offset value is too large for READ BUFFER(10), try " "--16\n"); ret = SG_LIB_SYNTAX_ERROR; goto fini; } else res = sg_ll_read_buffer_10(sg_fd, rb_mode, rb_mode_sp, rb_id, (uint32_t)rb_offset, resp, rb_len, &resid, true, verbose); if (0 != res) { char b[80]; ret = res; if (res > 0) { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Read buffer(%d) failed: %s\n", (do_long ? 16 : 10), b); } goto fini; } if (resid > 0) rb_len -= resid; /* got back less than requested */ if (rb_len > 0) { if (do_raw) dStrRaw(resp, rb_len); else if (do_hex || (rb_len < 4)) hex2stdout((const uint8_t *)resp, rb_len, ((do_hex > 1) ? 0 : 1)); else { switch (rb_mode) { case MODE_DESCRIPTOR: k = sg_get_unaligned_be24(resp + 1); printf("OFFSET BOUNDARY: %d, Buffer offset alignment: " "%d-byte\n", resp[0], (1 << resp[0])); printf("BUFFER CAPACITY: %d (0x%x)\n", k, k); break; case MODE_ECHO_BDESC: k = sg_get_unaligned_be16(resp + 2) & 0x1fff; printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0); printf("Echo buffer capacity: %d (0x%x)\n", k, k); break; default: hex2stdout((const uint8_t *)resp, rb_len, (verbose > 1 ? 0 : 1)); break; } } } fini: if (resp) free(resp); 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 == verbose) { if (! sg_if_can2stderr("sg_read_buffer failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
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; }
int main(int argc, char * argv[]) { int sg_fd, res, c, num, nread, infd; int64_t ll; int dpo = 0; int bytchk = 0; int ndo = 0; char *ref_data = NULL; int vrprotect = 0; int64_t count = 1; int64_t orig_count; int bpc = 128; int bpc_given = 0; int got_stdin = 0; int group = 0; uint64_t lba = 0; uint64_t orig_lba; int quiet = 0; int readonly = 0; int verbose = 0; int verify16 = 0; const char * device_name = NULL; const char * file_name = NULL; const char * vc; int ret = 0; unsigned int info = 0; uint64_t info64 = 0; char ebuff[EBUFF_SZ]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:B:c:dE:g:hi:l:n:P:qrSvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': bpc = sg_get_num(optarg); if (bpc < 1) { fprintf(stderr, "bad argument to '--bpc'\n"); return SG_LIB_SYNTAX_ERROR; } ++bpc_given; break; case 'c': count = sg_get_llnum(optarg); if (count < 0) { fprintf(stderr, "bad argument to '--count'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'd': dpo = 1; break; case 'E': bytchk = sg_get_num(optarg); if ((bytchk < 1) || (bytchk > 3)) { fprintf(stderr, "bad argument to '--ebytchk'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'g': group = sg_get_num(optarg); if ((group < 0) || (group > 31)) { fprintf(stderr, "bad argument to '--group'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': file_name = optarg; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } lba = (uint64_t)ll; break; case 'n': case 'B': /* undocumented, old --bytchk=NDO option */ ndo = sg_get_num(optarg); if (ndo < 1) { fprintf(stderr, "bad argument to '--ndo'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'P': vrprotect = sg_get_num(optarg); if (-1 == vrprotect) { fprintf(stderr, "bad argument to '--vrprotect'\n"); return SG_LIB_SYNTAX_ERROR; } if ((vrprotect < 0) || (vrprotect > 7)) { fprintf(stderr, "'--vrprotect' requires a value from 0 to " "7 (inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'q': ++quiet; break; case 'r': ++readonly; break; case 'S': ++verify16; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; default: fprintf(stderr, "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) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (ndo > 0) { if (0 == bytchk) bytchk = 1; if (bpc_given && (bpc != count)) fprintf(stderr, "'bpc' argument ignored, using --bpc=%" PRIu64 "\n", count); if (count > 0x7fffffffLL) { fprintf(stderr, "count exceed 31 bits, way too large\n"); return SG_LIB_SYNTAX_ERROR; } if ((3 == bytchk) && (1 != count)) { fprintf(stderr, "count must be 1 when bytchk=3\n"); return SG_LIB_SYNTAX_ERROR; } bpc = (int)count; } else if (bytchk > 0) { fprintf(stderr, "when the 'ebytchk=BCH' option is given, " "then '--bytchk=NDO' must also be given\n"); return SG_LIB_SYNTAX_ERROR; } if ((bpc > 0xffff) && (0 == verify16)) { fprintf(stderr, "'%s' exceeds 65535, so use VERIFY(16)\n", (ndo > 0) ? "count" : "bpc"); ++verify16; } if (((lba + count - 1) > 0xffffffffLLU) && (0 == verify16)) { fprintf(stderr, "'lba' exceed 32 bits, so use VERIFY(16)\n"); ++verify16; } if ((group > 0) && (0 == verify16)) fprintf(stderr, "group number ignored with VERIFY(10) command, " "use the --16 option\n"); orig_count = count; orig_lba = lba; if (ndo > 0) { ref_data = (char *)malloc(ndo); if (NULL == ref_data) { fprintf(stderr, "failed to allocate %d byte buffer\n", ndo); return SG_LIB_FILE_ERROR; } if ((NULL == file_name) || (0 == strcmp(file_name, "-"))) { ++got_stdin; infd = STDIN_FILENO; if (sg_set_binary_mode(STDIN_FILENO) < 0) perror("sg_set_binary_mode"); } 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 err_out; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); } if (verbose && got_stdin) fprintf(stderr, "about to wait on STDIN\n"); for (nread = 0; nread < ndo; nread += res) { res = read(infd, ref_data + nread, ndo - nread); if (res <= 0) { fprintf(stderr, "reading from %s failed at file offset=%d\n", (got_stdin ? "stdin" : file_name), nread); ret = SG_LIB_FILE_ERROR; goto err_out; } } if (! got_stdin) close(infd); } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto err_out; } vc = verify16 ? "VERIFY(16)" : "VERIFY(10)"; for (; count > 0; count -= bpc, lba += bpc) { num = (count > bpc) ? bpc : count; if (verify16) res = sg_ll_verify16(sg_fd, vrprotect, dpo, bytchk, lba, num, group, ref_data, ndo, &info64, !quiet , verbose); else res = sg_ll_verify10(sg_fd, vrprotect, dpo, bytchk, (unsigned int)lba, num, ref_data, ndo, &info, !quiet, verbose); if (0 != res) { char b[80]; ret = res; switch (res) { case SG_LIB_CAT_ILLEGAL_REQ: fprintf(stderr, "bad field in %s cdb, near lba=0x%" PRIx64 "\n", vc, lba); break; case SG_LIB_CAT_MEDIUM_HARD: fprintf(stderr, "%s medium or hardware error near " "lba=0x%" PRIx64 "\n", vc, lba); break; case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO: if (verify16) fprintf(stderr, "%s medium or hardware error, reported " "lba=0x%" PRIx64 "\n", vc, info64); else fprintf(stderr, "%s medium or hardware error, reported " "lba=0x%x\n", vc, info); break; case SG_LIB_CAT_MISCOMPARE: if ((0 == quiet) || verbose) fprintf(stderr, "%s reported MISCOMPARE\n", vc); break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "%s: %s\n", vc, b); fprintf(stderr, " failed near lba=%" PRIu64 " [0x%" PRIx64 "]\n", lba, lba); break; } break; } } if (verbose && (0 == ret) && (orig_count > 1)) fprintf(stderr, "Verified %" PRId64 " [0x%" PRIx64 "] blocks from " "lba %" PRIu64 " [0x%" PRIx64 "]\n without error\n", orig_count, (uint64_t)orig_count, orig_lba, orig_lba); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = SG_LIB_FILE_ERROR; } err_out: if (ref_data) free(ref_data); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char *argv[]) { int ret = 0; int res_cat, status, slen, k, ret2; int sg_fd = -1; struct sg_pt_base *ptvp = NULL; unsigned char sense_buffer[32]; unsigned char * dxfer_buffer_in = NULL; unsigned char * dxfer_buffer_out = NULL; unsigned char *wrkBuf = NULL; struct opts_t opts; struct opts_t * op; char b[128]; op = &opts; memset(op, 0, sizeof(opts)); op->timeout = DEFAULT_TIMEOUT; ret = process_cl(op, argc, argv); if (ret != 0) { usage(); goto done; } else if (op->do_help) { usage(); goto done; } else if (op->do_version) { version(); goto done; } sg_fd = scsi_pt_open_device(op->device_name, op->readonly, op->do_verbose); if (sg_fd < 0) { fprintf(stderr, "%s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto done; } ptvp = construct_scsi_pt_obj(); if (ptvp == NULL) { fprintf(stderr, "out of memory\n"); ret = SG_LIB_CAT_OTHER; goto done; } if (op->do_verbose) { fprintf(stderr, " cdb to send: "); for (k = 0; k < op->cdb_length; ++k) fprintf(stderr, "%02x ", op->cdb[k]); fprintf(stderr, "\n"); if (op->do_verbose > 2) { sg_get_command_name(op->cdb, 0, sizeof(b) - 1, b); b[sizeof(b) - 1] = '\0'; fprintf(stderr, " Command name: %s\n", b); } } set_scsi_pt_cdb(ptvp, op->cdb, op->cdb_length); set_scsi_pt_sense(ptvp, sense_buffer, sizeof(sense_buffer)); if (op->do_dataout) { dxfer_buffer_out = fetch_dataout(op); if (dxfer_buffer_out == NULL) { ret = SG_LIB_CAT_OTHER; goto done; } set_scsi_pt_data_out(ptvp, dxfer_buffer_out, op->dataout_len); } if (op->do_datain) { dxfer_buffer_in = my_memalign(op->datain_len, &wrkBuf); if (dxfer_buffer_in == NULL) { perror("malloc"); ret = SG_LIB_CAT_OTHER; goto done; } set_scsi_pt_data_in(ptvp, dxfer_buffer_in, op->datain_len); } ret = do_scsi_pt(ptvp, sg_fd, op->timeout, op->do_verbose); if (ret > 0) { if (SCSI_PT_DO_BAD_PARAMS == ret) { fprintf(stderr, "do_scsi_pt: bad pass through setup\n"); ret = SG_LIB_CAT_OTHER; } else if (SCSI_PT_DO_TIMEOUT == ret) { fprintf(stderr, "do_scsi_pt: timeout\n"); ret = SG_LIB_CAT_TIMEOUT; } else ret = SG_LIB_CAT_OTHER; goto done; } else if (ret < 0) { fprintf(stderr, "do_scsi_pt: %s\n", safe_strerror(-ret)); ret = SG_LIB_CAT_OTHER; goto done; } slen = 0; res_cat = get_scsi_pt_result_category(ptvp); switch (res_cat) { case SCSI_PT_RESULT_GOOD: ret = 0; break; case SCSI_PT_RESULT_SENSE: slen = get_scsi_pt_sense_len(ptvp); ret = sg_err_category_sense(sense_buffer, slen); break; case SCSI_PT_RESULT_TRANSPORT_ERR: get_scsi_pt_transport_err_str(ptvp, sizeof(b), b); fprintf(stderr, ">>> transport error: %s\n", b); ret = SG_LIB_CAT_OTHER; break; case SCSI_PT_RESULT_OS_ERR: get_scsi_pt_os_err_str(ptvp, sizeof(b), b); fprintf(stderr, ">>> os error: %s\n", b); ret = SG_LIB_CAT_OTHER; break; default: fprintf(stderr, ">>> unknown pass through result category (%d)\n", res_cat); ret = SG_LIB_CAT_OTHER; break; } status = get_scsi_pt_status_response(ptvp); fprintf(stderr, "SCSI Status: "); sg_print_scsi_status(status); fprintf(stderr, "\n\n"); if ((SAM_STAT_CHECK_CONDITION == status) && (! op->no_sense)) { if (SCSI_PT_RESULT_SENSE != res_cat) slen = get_scsi_pt_sense_len(ptvp); if (0 == slen) fprintf(stderr, ">>> Strange: status is CHECK CONDITION but no " "Sense Information\n"); else { fprintf(stderr, "Sense Information:\n"); sg_print_sense(NULL, sense_buffer, slen, (op->do_verbose > 0)); fprintf(stderr, "\n"); } } if (SAM_STAT_RESERVATION_CONFLICT == status) ret = SG_LIB_CAT_RES_CONFLICT; if (op->do_datain) { int data_len = op->datain_len - get_scsi_pt_resid(ptvp); if (ret && !(SG_LIB_CAT_RECOVERED == ret || SG_LIB_CAT_NO_SENSE == ret)) fprintf(stderr, "Error %d occurred, no data received\n", ret); else if (data_len == 0) { fprintf(stderr, "No data received\n"); } else { if (op->datain_file == NULL && !op->datain_binary) { fprintf(stderr, "Received %d bytes of data:\n", data_len); dStrHexErr((const char *)dxfer_buffer_in, data_len, 0); } else { const char * cp = "stdout"; if (op->datain_file && ! ((1 == strlen(op->datain_file)) && ('-' == op->datain_file[0]))) cp = op->datain_file; fprintf(stderr, "Writing %d bytes of data to %s\n", data_len, cp); ret2 = write_dataout(op->datain_file, dxfer_buffer_in, data_len); if (0 != ret2) { if (0 == ret) ret = ret2; goto done; } } } } done: if (op->do_verbose) { sg_get_category_sense_str(ret, sizeof(b), b, op->do_verbose - 1); fprintf(stderr, "%s\n", b); } if (wrkBuf) free(wrkBuf); if (ptvp) destruct_scsi_pt_obj(ptvp); if (sg_fd >= 0) scsi_pt_close_device(sg_fd); return ret; }
int main(int argc, char * argv[]) { bool bpw_then_activate = false; bool dry_run = false; bool got_stdin = false; bool wb_len_given = false; int sg_fd, infd, res, c, len, k, n; int bpw = 0; int do_help = 0; int ret = 0; int verbose = 0; int wb_id = 0; int wb_len = 0; int wb_mode = 0; int wb_offset = 0; int wb_skip = 0; int wb_timeout = DEF_PT_TIMEOUT; int wb_mspec = 0; const char * device_name = NULL; const char * file_name = NULL; unsigned char * dop = NULL; char * cp; const struct mode_s * mp; char ebuff[EBUFF_SZ]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:dhi:I:l:m:o:rs:S:t:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': bpw = sg_get_num(optarg); if (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)) bpw_then_activate = true; } break; case 'd': dry_run = true; break; case 'h': case '?': ++do_help; break; case 'i': wb_id = sg_get_num(optarg); if ((wb_id < 0) || (wb_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': wb_len = sg_get_num(optarg); if (wb_len < 0) { pr2serr("bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } wb_len_given = true; break; case 'm': if (isdigit(*optarg)) { wb_mode = sg_get_num(optarg); if ((wb_mode < 0) || (wb_mode > 31)) { pr2serr("argument to '--mode' should be in the range 0 " "to 31\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)) { wb_mode = mp->mode; break; } } if (! mp->mode_string) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'o': wb_offset = sg_get_num(optarg); if (wb_offset < 0) { pr2serr("bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': /* --read-stdin and --raw (previous name) */ file_name = "-"; break; case 's': wb_skip = sg_get_num(optarg); if (wb_skip < 0) { pr2serr("bad argument to '--skip'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'S': wb_mspec = sg_get_num(optarg); if ((wb_mspec < 0) || (wb_mspec > 7)) { pr2serr("expected argument to '--specific' to be 0 to 7\n"); return SG_LIB_SYNTAX_ERROR; } break; case 't': wb_timeout = sg_get_num(optarg); if (wb_timeout < 0) { pr2serr("Invalid argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++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 ((wb_len > 0) && (bpw > wb_len)) { pr2serr("trim chunk size (CS) to be the same as LEN\n"); bpw = wb_len; } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (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 */, 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 || (wb_len > 0)) { if (0 == wb_len) wb_len = DEF_XFER_LEN; if (NULL == (dop = (unsigned char *)malloc(wb_len))) { pr2serr(ME "out of memory\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } memset(dop, 0xff, wb_len); if (file_name) { got_stdin = (0 == strcmp(file_name, "-")); if (got_stdin) { if (wb_skip > 0) { pr2serr("Can't skip on stdin\n"); ret = SG_LIB_FILE_ERROR; goto err_out; } 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 err_out; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); if (wb_skip > 0) { if (lseek(infd, wb_skip, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " "required position on %s", file_name); perror(ebuff); close(infd); ret = SG_LIB_FILE_ERROR; goto err_out; } } } res = read(infd, dop, wb_len); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", file_name); perror(ebuff); if (! got_stdin) close(infd); ret = SG_LIB_FILE_ERROR; goto err_out; } if (res < wb_len) { if (wb_len_given) { pr2serr("tried to read %d bytes from %s, got %d bytes\n", wb_len, file_name, res); pr2serr("pad with 0xff bytes and continue\n"); } else { if (verbose) { pr2serr("tried to read %d bytes from %s, got %d " "bytes\n", wb_len, file_name, res); pr2serr("will write %d bytes", res); if ((bpw > 0) && (bpw < wb_len)) pr2serr(", %d bytes per WRITE BUFFER command\n", bpw); else pr2serr("\n"); } wb_len = res; } } if (! got_stdin) close(infd); } } res = 0; if (bpw > 0) { for (k = 0; k < wb_len; k += n) { n = wb_len - k; if (n > bpw) n = bpw; if (verbose) pr2serr("sending write buffer, mode=0x%x, mspec=%d, id=%d, " " offset=%d, len=%d\n", wb_mode, wb_mspec, wb_id, wb_offset + k, n); if (dry_run) { if (verbose) pr2serr("skipping WRITE BUFFER command due to " "--dry-run\n"); res = 0; } else res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id, wb_offset + k, dop + k, n, wb_timeout, true, verbose); if (res) break; } if (bpw_then_activate) { if (verbose) pr2serr("sending Activate deferred microcode [0xf]\n"); if (dry_run) { if (verbose) pr2serr("skipping WRITE BUFFER(ACTIVATE) command due to " "--dry-run\n"); res = 0; } else res = sg_ll_write_buffer_v2(sg_fd, MODE_ACTIVATE_MC, 0 /* buffer_id */, 0 /* buffer_offset */, 0, NULL, 0, wb_timeout, true, verbose); } } else { if (verbose) pr2serr("sending single write buffer, mode=0x%x, mpsec=%d, " "id=%d, offset=%d, len=%d\n", wb_mode, wb_mspec, wb_id, wb_offset, wb_len); if (dry_run) { if (verbose) pr2serr("skipping WRITE BUFFER(all in one) command due to " "--dry-run\n"); res = 0; } else res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id, wb_offset, dop, wb_len, wb_timeout, true, verbose); } if (0 != res) { char b[80]; ret = res; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Write buffer failed: %s\n", b); } err_out: if (dop) free(dop); 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; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { unsigned char rsp_buff[MX_ALLOC_LEN]; char **argptr; char * file_name = 0; int res, fd, k, lun = -1; int fail_all = 0; int fail_path = 0; int ret = 0; if (argc < 2) { usage (); return SG_LIB_SYNTAX_ERROR; } for (k = 1; k < argc; ++k) { argptr = argv + k; if (!strcmp (*argptr, "-v")) ++do_verbose; else if (!strncmp(*argptr, "-f=",3)) { ++fail_path; lun = strtoul(*argptr + 3, NULL, 0); } else if (!strcmp(*argptr, "-a")) { ++fail_all; } else if (!strcmp(*argptr, "-V")) { fprintf(stderr, "sg_rdac version: %s\n", version_str); return 0; } else if (*argv[k] == '-') { fprintf(stderr, "Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { fprintf(stderr, "too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { usage(); return SG_LIB_SYNTAX_ERROR; } fd = sg_cmds_open_device(file_name, 0 /* rw */, do_verbose); if (fd < 0) { fprintf(stderr, "open error: %s: %s\n", file_name, safe_strerror(-fd)); usage(); return SG_LIB_FILE_ERROR; } if (fail_all) { res = fail_all_paths(fd); } else if (fail_path) { res = fail_this_path(fd, lun); } else { res = sg_ll_mode_sense6(fd, /*DBD*/ 0, /* page control */0, 0x2c, 0, rsp_buff, 252, 1, do_verbose); if (!res) { if (do_verbose) dump_mode_page(rsp_buff, rsp_buff[0]); print_rdac_mode(rsp_buff); } else { if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, ">>>>>> try again without " "the '-6' switch for a 10 byte MODE " "SENSE command\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "mode sense: invalid field " "in cdb (perhaps subpages or page " "control (PC) not supported)\n"); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, do_verbose); fprintf(stderr, "mode sense failed: %s\n", b); } } } ret = res; res = sg_cmds_close_device(fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { bool allow = false; bool verbose_given = false; bool version_given = false; int sg_fd, res, c; int prevent = -1; int verbose = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "ahp:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': allow = true; break; case 'h': case '?': usage(); return 0; case 'p': prevent = sg_get_num(optarg); if ((prevent < 0) || (prevent > 3)) { pr2serr("bad argument to '--prevent'\n"); return SG_LIB_SYNTAX_ERROR; } 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(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (allow && (prevent >= 0)) { pr2serr("can't give both '--allow' and '--prevent='\n"); usage(); return SG_LIB_CONTRADICT; } if (allow) prevent = 0; else if (prevent < 0) prevent = 1; /* default is to prevent, as utility name suggests */ sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { if (verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } res = sg_ll_prevent_allow(sg_fd, prevent, true, verbose); ret = res; if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Prevent allow medium removal: %s\n", b); } 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); } fini: if (0 == verbose) { if (! sg_if_can2stderr("sg_prevent failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
int main(int argc, char * argv[]) { int sg_fd, res, c; int64_t count = 0; unsigned int num_lb = 0; int do_16 = 0; int group = 0; int64_t lba = 0; int immed = 0; int sync_nv = 0; int to_secs = DEF_PT_TIMEOUT; int verbose = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:g:hil:sSt:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': count = sg_get_llnum(optarg); if ((count < 0) || (count > UINT_MAX)) { pr2serr("bad argument to '--count'\n"); return SG_LIB_SYNTAX_ERROR; } num_lb = (unsigned int)count; break; case 'g': group = sg_get_num(optarg); if ((group < 0) || (group > 31)) { pr2serr("bad argument to '--group'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': immed = 1; break; case 'l': lba = sg_get_llnum(optarg); if (lba < 0) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': sync_nv = 1; break; case 'S': do_16 = 1; break; case 't': to_secs = sg_get_num(optarg); if (to_secs < 0) { pr2serr("bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++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 (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (do_16) res = ll_sync_cache_16(sg_fd, sync_nv, immed, group, lba, num_lb, to_secs, 1, verbose); else res = sg_ll_sync_cache_10(sg_fd, sync_nv, immed, group, (unsigned int)lba, num_lb, 1, verbose); ret = res; if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Synchronize cache failed: %s\n", b); } 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; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
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; }
int main(int argc, char * argv[]) { int sg_fd, res, c; int do_origin = 0; int do_set = 0; int do_srep = 0; int do_raw = 0; int readonly = 0; bool secs_given = false; int verbose = 0; uint64_t secs = 0; uint64_t msecs = 0; int64_t ll; const char * device_name = NULL; const char * cmd_name; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hm:orRs:SvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'm': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--milliseconds=MS'\n"); return SG_LIB_SYNTAX_ERROR; } msecs = (uint64_t)ll; ++do_set; break; case 'o': ++do_origin; break; case 'r': ++do_raw; break; case 'R': ++readonly; break; case 's': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--seconds=SEC'\n"); return SG_LIB_SYNTAX_ERROR; } secs = (uint64_t)ll; ++do_set; secs_given = true; break; case 'S': ++do_srep; break; case 'v': ++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 (do_set > 1) { pr2serr("either --milliseconds=MS or --seconds=SEC may be given, " "not both\n"); usage(); return SG_LIB_SYNTAX_ERROR; } 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) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } memset(d_buff, 0, 12); if (do_set) { cmd_name = "Set timestamp"; sg_put_unaligned_be48(secs_given ? (secs * 1000) : msecs, d_buff + 4); res = sg_ll_set_timestamp(sg_fd, d_buff, 12, 1, verbose); } else { cmd_name = "Report timestamp"; res = sg_ll_rep_timestamp(sg_fd, d_buff, 12, NULL, 1, verbose); if (0 == res) { if (do_raw) dStrRaw((const char *)d_buff, 12); else { int len = sg_get_unaligned_be16(d_buff + 0); if (len < 8) pr2serr("timestamp parameter data length too short, " "expect >= 10, got %d\n", len + 2); else { if (do_origin) printf("Device clock %s\n", ts_origin_arr[0x7 & d_buff[2]]); msecs = sg_get_unaligned_be48(d_buff + 4); printf("%" PRIu64 "\n", do_srep ? (msecs / 1000) : msecs); } } } } ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", cmd_name); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", cmd_name, b); } } 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; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
/* Returns number of TURs performed */ static int loop_turs(struct sg_pt_base * ptvp, struct loop_res_t * resp, struct opts_t * op) { int k, res; int vb = op->verbose; char b[80]; if (op->do_low) { int rs, n, sense_cat; uint8_t cdb[6]; uint8_t sense_b[32]; for (k = 0; k < op->do_number; ++k) { /* Might get Unit Attention on first invocation */ memset(cdb, 0, sizeof(cdb)); /* TUR's cdb is 6 zeros */ set_scsi_pt_cdb(ptvp, cdb, sizeof(cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); rs = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, vb); n = sg_cmds_process_resp(ptvp, "Test unit ready", rs, (0 == k), vb, &sense_cat); if (-1 == n) { resp->ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); return k; } else if (-2 == n) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: break; case SG_LIB_CAT_NOT_READY: ++resp->num_errs; if (1 == op->do_number) { resp->ret = sense_cat; printf("device not ready\n"); resp->reported = true; } break; case SG_LIB_CAT_UNIT_ATTENTION: ++resp->num_errs; if (vb) { pr2serr("Ignoring Unit attention (sense key)\n"); resp->reported = true; } break; default: ++resp->num_errs; if (1 == op->do_number) { resp->ret = sense_cat; sg_get_category_sense_str(sense_cat, sizeof(b), b, vb); printf("%s\n", b); resp->reported = true; return k; } break; } } clear_scsi_pt_obj(ptvp); } return k; } else { for (k = 0; k < op->do_number; ++k) { /* Might get Unit Attention on first invocation */ res = sg_ll_test_unit_ready_pt(ptvp, k, (0 == k), vb); if (res) { ++resp->num_errs; resp->ret = res; if (1 == op->do_number) { if (SG_LIB_CAT_NOT_READY == res) printf("device not ready\n"); else { sg_get_category_sense_str(res, sizeof(b), b, vb); printf("%s\n", b); } resp->reported = true; break; } } } return k; } }
static int prin_work(int sg_fd, const struct opts_t * op) { int k, j, num, add_len, add_desc_len; int res = 0; unsigned int pr_gen; uint8_t * bp; uint8_t * pr_buff = NULL; uint8_t * free_pr_buff = NULL; pr_buff = sg_memalign(op->alloc_len, 0 /* page aligned */, &free_pr_buff, false); if (NULL == pr_buff) { pr2serr("%s: unable to allocate %d bytes on heap\n", __func__, op->alloc_len); return sg_convert_errno(ENOMEM); } res = sg_ll_persistent_reserve_in(sg_fd, op->prin_sa, pr_buff, op->alloc_len, true, op->verbose); if (res) { char b[64]; char bb[80]; if (op->prin_sa < num_prin_sa_strs) snprintf(b, sizeof(b), "%s", prin_sa_strs[op->prin_sa]); else snprintf(b, sizeof(b), "service action=0x%x", op->prin_sa); if (SG_LIB_CAT_INVALID_OP == res) pr2serr("PR in (%s): command not supported\n", b); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("PR in (%s): bad field in cdb or parameter list (perhaps " "unsupported service action)\n", b); else { sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose); pr2serr("PR in (%s): %s\n", b, bb); } goto fini; } if (PRIN_RCAP_SA == op->prin_sa) { if (8 != pr_buff[1]) { pr2serr("Unexpected response for PRIN Report Capabilities\n"); if (op->hex) hex2stdout(pr_buff, pr_buff[1], 1); res = SG_LIB_CAT_MALFORMED; goto fini; } if (op->hex) hex2stdout(pr_buff, 8, 1); else { printf("Report capabilities response:\n"); printf(" Replace Lost Reservation Capable(RLR_C): %d\n", !!(pr_buff[2] & 0x80)); /* added spc4r26 */ printf(" Compatible Reservation Handling(CRH): %d\n", !!(pr_buff[2] & 0x10)); printf(" Specify Initiator Ports Capable(SIP_C): %d\n", !!(pr_buff[2] & 0x8)); printf(" All Target Ports Capable(ATP_C): %d\n", !!(pr_buff[2] & 0x4)); printf(" Persist Through Power Loss Capable(PTPL_C): %d\n", !!(pr_buff[2] & 0x1)); printf(" Type Mask Valid(TMV): %d\n", !!(pr_buff[3] & 0x80)); printf(" Allow Commands: %d\n", (pr_buff[3] >> 4) & 0x7); printf(" Persist Through Power Loss Active(PTPL_A): %d\n", !!(pr_buff[3] & 0x1)); if (pr_buff[3] & 0x80) { printf(" Support indicated in Type mask:\n"); 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 {
int main(int argc, char * argv[]) { bool verbose_given = false; bool version_given = false; int sg_fd = -1; int res, c; unsigned int ctl = 0; unsigned int time_tnth = 0; int verbose = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:ht:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': if ((1 != sscanf(optarg, "%4u", &ctl)) || (ctl > 3)) { pr2serr("--ctl= expects a number from 0 to 3\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 't': if ((1 != sscanf(optarg, "%4u", &time_tnth)) || (time_tnth > 255)) { pr2serr("--time= expects a number from 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } 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("missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, false, 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 fini; } res = sg_ll_background_control(sg_fd, ctl, time_tnth, true, verbose); ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", cmd_name); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", cmd_name, b); } } fini: if (0 == verbose) { if (! sg_if_can2stderr("sg_bg_ctl failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } 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); } } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
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; }
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; }
int main(int argc, char * argv[]) { int sg_fd, c, ret, peri_type, no_hex_raw; int res = SG_LIB_CAT_OTHER; const char * device_name = NULL; char ebuff[EBUFF_SZ]; unsigned char *rb_buff; int do_config = 0; int do_status = 0; int do_slots = 0; int do_flags = 0; int do_usage = 0; int do_hex = 0; int do_raw = 0; int verbose = 0; int do_insertions = 0; const char * cp; char buff[48]; char b[80]; struct sg_simple_inquiry_resp inq_resp; const char op_name[] = "READ BUFFER"; while (1) { int option_index = 0; c = getopt_long(argc, argv, "cdfhHirsuvV?", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': do_config = 1; break; case 'd': do_slots = 1; break; case 'f': do_flags = 1; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'i': do_insertions = 1; break; case 'r': ++do_raw; break; case 's': do_status = 1; break; case 'u': do_usage = 1; break; case 'v': ++verbose; break; case 'V': pr2serr("Version string: %s\n", version_str); exit(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 (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if ((sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_safte: error opening file: %s (rw)", device_name); perror(ebuff); return SG_LIB_FILE_ERROR; } no_hex_raw = ((0 == do_hex) && (0 == do_raw)); if (no_hex_raw) { if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, verbose)) { printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product, inq_resp.revision); peri_type = inq_resp.peripheral_type; cp = sg_get_pdt_str(peri_type, sizeof(buff), buff); if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); else printf(" Peripheral device type: 0x%x\n", peri_type); } else { pr2serr("sg_safte: %s doesn't respond to a SCSI INQUIRY\n", device_name); return SG_LIB_CAT_OTHER; } } rb_buff = (unsigned char *)malloc(buf_capacity); if (!rb_buff) goto err_out; memset(rb_buff, 0, buf_capacity); res = read_safte_configuration(sg_fd, rb_buff, buf_capacity, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } if (1 == do_raw) { dStrRaw((const char *)rb_buff, buf_capacity); goto finish; } if (1 == do_hex) { dStrHex((const char *)rb_buff, buf_capacity, 1); goto finish; } if (do_config && no_hex_raw) print_safte_configuration(); if (do_status) { res = do_safte_encl_status(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_usage) { res = do_safte_usage_statistics(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_insertions) { res = do_safte_slot_insertions(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_slots) { res = do_safte_slot_status(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_flags) { res = do_safte_global_flags(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } finish: res = 0; err_out: switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s failed: %s\n", op_name, b); break; } ret = res; 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; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; }
static int fail_this_path(int fd, int lun, int use_6_byte) { unsigned char fail_paths_pg[308]; struct rdac_legacy_page *rdac_page; struct rdac_expanded_page *rdac_page_exp; struct rdac_page_common *rdac_common = NULL; int res; char b[80]; if (use_6_byte && lun > 32) { pr2serr("must use 10 byte cdb to fail luns over 32\n"); return -1; } memset(fail_paths_pg, 0, 308); if (use_6_byte) { memcpy(fail_paths_pg, mode6_hdr, 4); memcpy(fail_paths_pg + 4, block_descriptor, 8); rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); rdac_page->page_code = RDAC_CONTROLLER_PAGE; rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; rdac_common = &rdac_page->attr; memset(rdac_page->lun_table, 0x0, 32); rdac_page->lun_table[lun] = 0x81; } else { memcpy(fail_paths_pg, mode10_hdr, 8); rdac_page_exp = (struct rdac_expanded_page *) (fail_paths_pg + 8); rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40; rdac_page_exp->subpage_code = 0x1; sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN, rdac_page_exp->page_length + 0); rdac_common = &rdac_page_exp->attr; memset(rdac_page_exp->lun_table, 0x0, 256); rdac_page_exp->lun_table[lun] = 0x81; } rdac_common->current_mode_lsb = RDAC_FAIL_SELECTED_PATHS; rdac_common->quiescence = RDAC_QUIESCENCE_TIME; rdac_common->options = RDAC_FORCE_QUIESCENCE; if (use_6_byte) { res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 118, 1, (do_verbose ? 2 : 0)); } else { res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 308, 1, (do_verbose ? 2: 0)); } switch (res) { case 0: if (do_verbose) pr2serr("fail paths successful\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, do_verbose); pr2serr("fail paths page (lun=%d) failed: %s\n", lun, b); break; } return res; }