| /* |
| ** sg_format : format a SCSI disk (potentially with a different block size) |
| ** |
| ** formerly called blk512-linux.c (v0.4) |
| ** |
| ** Copyright (C) 2003 Grant Grundler grundler at parisc-linux dot org |
| ** Copyright (C) 2003 James Bottomley jejb at parisc-linux dot org |
| ** Copyright (C) 2005 Douglas Gilbert dgilbert at interlog dot com |
| ** |
| ** This program is free software; you can redistribute it and/or modify |
| ** it under the terms of the GNU General Public License as published by |
| ** the Free Software Foundation; either version 2, or (at your option) |
| ** any later version. |
| ** |
| ** http://www.t10.org/scsi-3.htm |
| ** http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO |
| ** |
| ** |
| ** List of some (older) disk manufacturers' block counts. |
| ** These are not needed in newer disks which will automatically use |
| ** the manufacturers' recommended block count if a count of -1 is given. |
| ** Inquiry Block Count (@512 byte blocks) |
| ** ST150150N 8388315 |
| ** IBM_DCHS04F 8888543 |
| ** IBM_DGHS09Y 17916240 |
| ** ST336704FC 71132960 |
| ** ST318304FC 35145034 (Factory spec is 35885167 sectors) |
| ** ST336605FC ??? |
| ** ST336753FC 71132960 (Factory spec is 71687372 sectors) |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <getopt.h> |
| #include <unistd.h> |
| #include <sys/fcntl.h> |
| #include <sys/ioctl.h> |
| #include <scsi/scsi.h> |
| #include <scsi/scsi_ioctl.h> |
| #include <scsi/sg.h> |
| #include <sys/errno.h> |
| |
| #include "sg_lib.h" |
| #include "sg_cmds.h" |
| |
| #define RW_ERROR_RECOVERY_PAGE 1 /* every disk should have one */ |
| #define FORMAT_DEV_PAGE 3 /* Format Device Mode Page [now obsolete] */ |
| #define CONTROL_MODE_PAGE 0xa /* alternative page all devices have?? */ |
| |
| #define CDB_SIZE 6 /* SCSI Command Block */ |
| #define MODE_HDR_SIZE 4 /* Mode Sense Header */ |
| #define BLOCK_DESCR_SIZE 8 /* Block Descriptor Header */ |
| |
| #define LOGICAL_UNIT_NOT_READY 4 /* ASC */ |
| #define FORMAT_IN_PROGRESS 4 /* ASCQ */ |
| |
| #define SHORT_TIMEOUT 20000 /* 20 seconds unless immed=0 ... */ |
| #define FORMAT_TIMEOUT (4 * 3600 * 1000) /* 4 hours ! */ |
| |
| #define POLL_DURATION_SECS 30 |
| |
| |
| #define MAX_SENSE_SZ 32 |
| static unsigned char sbuff[MAX_SENSE_SZ]; |
| |
| #define MAX_BUFF_SZ 252 |
| static unsigned char dbuff[MAX_BUFF_SZ]; |
| |
| static char * version_str = "1.03 20050405"; |
| |
| static struct option long_options[] = { |
| {"count", 1, 0, 'c'}, |
| {"early", 0, 0, 'e'}, |
| {"format", 0, 0, 'F'}, |
| {"help", 0, 0, 'h'}, |
| {"long", 0, 0, 'l'}, |
| {"pinfo", 0, 0, 'p'}, |
| {"resize", 0, 0, 'r'}, |
| {"rto_req", 0, 0, 'R'}, |
| {"size", 1, 0, 's'}, |
| {"verbose", 0, 0, 'v'}, |
| {"version", 0, 0, 'V'}, |
| {"wait", 0, 0, 'w'}, |
| {0, 0, 0, 0}, |
| }; |
| |
| static const char * scsi_ptype_strs[] = { |
| "disk", /* 0x0 */ |
| "tape", |
| "printer", |
| "processor", |
| "write once optical disk", |
| "cd/dvd", |
| "scanner", |
| "optical memory device", |
| "medium changer", /* 0x8 */ |
| "communications", |
| "graphics [0xa]", |
| "graphics [0xb]", |
| "storage array controller", |
| "enclosure services device", |
| "simplified direct access device", |
| "optical card reader/writer device", |
| "bridge controller commands", /* 0x10 */ |
| "object storage device", |
| "automation/drive interface", |
| "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", |
| "0x19", "0x1a", "0x1b", "0x1c", "0x1d", |
| "well known logical unit", |
| "no physical device on this lu", |
| }; |
| |
| static const char * get_ptype_str(int scsi_ptype) |
| { |
| int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]); |
| |
| return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : ""; |
| } |
| |
| |
| /* Return 0 on success, else -1 */ |
| static int |
| scsi_format(int fd, int pinfo, int rto_req, int immed, int early, int verbose) |
| { |
| int k, res; |
| const char FORMAT_HEADER_SIZE = 4; |
| unsigned char cdb[CDB_SIZE], fmt_hdr[FORMAT_HEADER_SIZE]; |
| sg_io_hdr_t io_hdr; |
| |
| cdb[0] = FORMAT_UNIT; |
| cdb[1] = (pinfo ? 0x80 : 0) | (rto_req ? 0x40 : 0) | |
| (immed ? 0x10 : 0); |
| cdb[2] = 0; /* vendor specific */ |
| cdb[3] = 0; /* interleave MSB */ |
| cdb[4] = 0; /* interleave LSB */ |
| cdb[5] = 0; /* control */ |
| |
| /* fmt_hdr is a short format header, only used when 'immed' is set */ |
| fmt_hdr[0] = 0; /* reserved */ |
| fmt_hdr[1] = 0x02; /* use device defaults, IMMED return */ |
| fmt_hdr[2] = 0; /* defect list length MSB */ |
| fmt_hdr[3] = 0; /* defect list length LSB */ |
| |
| memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); |
| memset(sbuff, 0, MAX_SENSE_SZ); |
| io_hdr.interface_id = 'S'; |
| io_hdr.dxfer_direction = immed ? SG_DXFER_TO_DEV : SG_DXFER_NONE; |
| io_hdr.cmd_len = CDB_SIZE; |
| io_hdr.mx_sb_len = MAX_SENSE_SZ; |
| io_hdr.iovec_count = 0; /* no scatter gather */ |
| if (immed) { |
| io_hdr.dxfer_len = FORMAT_HEADER_SIZE; |
| io_hdr.dxferp = fmt_hdr; |
| } |
| io_hdr.cmdp = cdb; |
| io_hdr.sbp = sbuff; |
| io_hdr.timeout = immed ? SHORT_TIMEOUT : FORMAT_TIMEOUT; |
| |
| if (verbose) { |
| fprintf(stderr, " format cdb: "); |
| for (k = 0; k < 6; ++k) |
| fprintf(stderr, "%02x ", cdb[k]); |
| fprintf(stderr, "\n"); |
| } |
| if ((verbose > 1) && immed) { |
| fprintf(stderr, " format parameter block\n"); |
| dStrHex((const char *)fmt_hdr, FORMAT_HEADER_SIZE, -1); |
| } |
| |
| if (ioctl(fd, SG_IO, &io_hdr) < 0) { |
| perror("FORMAT UNIT ioctl error"); |
| return -1; |
| } |
| if (verbose > 2) |
| fprintf(stderr, " duration=%u ms\n", io_hdr.duration); |
| res = sg_err_category3(&io_hdr); |
| switch (res) { |
| case SG_LIB_CAT_RECOVERED: |
| sg_chk_n_print3("Format, continuing", &io_hdr); |
| /* fall through */ |
| case SG_LIB_CAT_CLEAN: |
| break; |
| case SG_LIB_CAT_INVALID_OP: |
| fprintf(stderr, "Format command not supported\n"); |
| if (verbose > 1) |
| sg_chk_n_print3("Format", &io_hdr); |
| return -1; |
| case SG_LIB_CAT_ILLEGAL_REQ: |
| fprintf(stderr, "Format command illegal parameter\n"); |
| if (verbose > 1) |
| sg_chk_n_print3("Format", &io_hdr); |
| return -1; |
| default: |
| if (verbose > 1) |
| sg_chk_n_print3("Format", &io_hdr); |
| return -1; |
| } |
| if (! immed) |
| return 0; |
| |
| printf("\nFormat has started\n"); |
| if (early) { |
| if (immed) |
| printf("Format continuing, use request sense or " |
| "test unit ready to monitor progress\n"); |
| return 0; |
| } |
| |
| for(;;) { |
| int progress; |
| struct sg_scsi_sense_hdr sshdr; |
| |
| sleep(POLL_DURATION_SECS); |
| cdb[0] = TEST_UNIT_READY; /* draft say REQUEST SENSE */ |
| cdb[1] = 0; |
| cdb[2] = 0; |
| cdb[3] = 0; |
| cdb[4] = 0; |
| cdb[5] = 0; |
| |
| memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); |
| memset(sbuff, 0, MAX_SENSE_SZ); |
| |
| io_hdr.interface_id = 'S'; |
| io_hdr.dxfer_direction = SG_DXFER_NONE; |
| io_hdr.cmd_len = CDB_SIZE; |
| io_hdr.mx_sb_len = MAX_SENSE_SZ; |
| io_hdr.iovec_count = 0; /* no scatter gather */ |
| io_hdr.dxfer_len = 0; |
| io_hdr.dxferp = NULL; |
| io_hdr.cmdp = cdb; |
| io_hdr.sbp = sbuff; |
| io_hdr.timeout = SHORT_TIMEOUT; |
| |
| if (verbose) { |
| fprintf(stderr, " test unit ready cdb: "); |
| for (k = 0; k < 6; ++k) |
| fprintf(stderr, "%02x ", cdb[k]); |
| fprintf(stderr, "\n"); |
| } |
| |
| if (ioctl(fd, SG_IO, &io_hdr) < 0) { |
| perror("Test Unit Ready SG_IO ioctl error"); |
| return -1; |
| } |
| if (sg_normalize_sense(&io_hdr, &sshdr)) { |
| if (sg_get_sense_progress_fld(sbuff, |
| io_hdr.sb_len_wr, &progress)) { |
| printf("Format in progress, %d%% done\n", |
| progress * 100 / 65536); |
| if (verbose > 1) |
| sg_print_sense("tur", sbuff, |
| io_hdr.sb_len_wr); |
| continue; |
| } else { |
| sg_print_sense("tur: unexpected sense", sbuff, |
| io_hdr.sb_len_wr); |
| continue; |
| } |
| } else |
| break; |
| } |
| printf("FORMAT Complete\n"); |
| return 0; |
| } |
| |
| #define RCAP_REPLY_LEN 32 |
| |
| static int |
| print_read_cap(int fd, int do_16, int verbose) |
| { |
| int res, k; |
| unsigned char resp_buff[RCAP_REPLY_LEN]; |
| unsigned int last_blk_addr, block_size; |
| unsigned long long llast_blk_addr; |
| |
| if (do_16) { |
| res = sg_ll_readcap_16(fd, 0 /* pmi */, 0 /* llba */, |
| resp_buff, 32, verbose); |
| if (0 == res) { |
| for (k = 0, llast_blk_addr = 0; k < 8; ++k) { |
| llast_blk_addr <<= 8; |
| llast_blk_addr |= resp_buff[k]; |
| } |
| block_size = ((resp_buff[8] << 24) | |
| (resp_buff[9] << 16) | |
| (resp_buff[10] << 8) | |
| resp_buff[11]); |
| printf("Read Capacity (16) results:\n"); |
| printf(" Protection: prot_en=%d, rto_en=%d\n", |
| !!(resp_buff[12] & 0x1), |
| !!(resp_buff[12] & 0x2)); |
| printf(" Number of blocks=%llu\n", |
| llast_blk_addr + 1); |
| printf(" Block size=%u bytes\n", block_size); |
| return (int)block_size; |
| } |
| } else { |
| res = sg_ll_readcap_10(fd, 0 /* pmi */, 0 /* lba */, |
| resp_buff, 8, verbose); |
| if (0 == res) { |
| last_blk_addr = ((resp_buff[0] << 24) | |
| (resp_buff[1] << 16) | |
| (resp_buff[2] << 8) | |
| resp_buff[3]); |
| block_size = ((resp_buff[4] << 24) | |
| (resp_buff[5] << 16) | |
| (resp_buff[6] << 8) | |
| resp_buff[7]); |
| printf("Read Capacity (10) results:\n"); |
| printf(" Number of blocks=%u\n", |
| last_blk_addr + 1); |
| printf(" Block size=%u bytes\n", block_size); |
| return (int)block_size; |
| } |
| } |
| if (SG_LIB_CAT_INVALID_OP == res) |
| fprintf(stderr, "READ CAPACITY (%d) not supported\n", |
| (do_16 ? 16 : 10)); |
| if (SG_LIB_CAT_ILLEGAL_REQ == res) |
| fprintf(stderr, "bad field in READ CAPACITY (%d) " |
| "cdb\n", (do_16 ? 16 : 10)); |
| if (verbose) |
| fprintf(stderr, "READ CAPACITY (%d) failed " |
| "[res=%d]\n", (do_16 ? 16 : 10), res); |
| return -1; |
| } |
| |
| static void usage() |
| { |
| printf("usage: sg_format [--count=<block count>] [--early] [--format]" |
| " [--help]\n" |
| " [--long] [--pinfo] [--resize] [--rto_req]\n" |
| " [--size=<block size>] [--verbose]" |
| " [--version] [--wait]\n" |
| " <scsi_disk>\n" |
| " where:\n" |
| " --count=<block count> | -c <block count>\n" |
| " best left alone during format (defaults " |
| "to max allowable)\n" |
| " --early | -e exit once format started (user can " |
| "monitor progress)\n" |
| " --format | -F format unit (default report current count" |
| " and size)\n" |
| " --help | -h prints out this usage message\n" |
| " --long | -l allow for 64 bit lbas (default: assume " |
| "32 bit lbas)\n" |
| " --pinfo | -p set the FMTPINFO bit to format with " |
| "protection\n"); |
| printf( " information (defaults to no protection " |
| "information)\n" |
| " --resize | -r resize (rather than format) to '--count' " |
| "value\n" |
| " --rto_req | -R set the RTO_REQ bit in format (only valid " |
| "with '--pinfo')\n" |
| " --size=<block size> | -s <block size>\n" |
| " only needed to change block size" |
| " (default to\n" |
| " current device's block size)\n" |
| " --verbose | -v verbosity (show commands + parameters " |
| "sent)\n" |
| " use multiple time for more verbosity\n" |
| " --version | -V print version details and exit\n" |
| " --wait | -w format command waits till complete (def: " |
| "poll)\n\n" |
| "\tExample: sg_format --format /dev/sdc\n"); |
| printf("\nWARNING: This program will destroy all the data on the " |
| "target device when\n\t '--format' is given. Check that you " |
| "have the correct device.\n"); |
| } |
| |
| |
| int main(int argc, char **argv) |
| { |
| const int mode_page = RW_ERROR_RECOVERY_PAGE; |
| int fd, res, calc_len, bd_len, dev_specific_param; |
| int offset, j, bd_blk_len, prob, len; |
| unsigned long long ull; |
| long long blk_count = 0; /* -c value */ |
| int blk_size = 0; /* -s value */ |
| int format = 0; /* -F */ |
| int resize = 0; /* -r */ |
| int verbose = 0; /* -v */ |
| int fwait = 0; /* -w */ |
| int mode6 = 0; |
| int pinfo = 0; |
| int rto_req = 0; |
| int do_rcap16 = 0; |
| int long_lba = 0; |
| int early = 0; |
| char device_name[256]; |
| struct sg_simple_inquiry_resp inq_out; |
| int ret = 1; |
| |
| device_name[0] = '\0'; |
| while (1) { |
| int option_index = 0; |
| char c; |
| |
| c = getopt_long(argc, argv, "c:eFhlprRs:vVw", |
| long_options, &option_index); |
| if (c == -1) |
| break; |
| |
| switch (c) { |
| case 'c': |
| if (0 == strcmp("-1", optarg)) |
| blk_count = -1; |
| else { |
| blk_count = sg_get_llnum(optarg); |
| if (-1 == blk_count) { |
| fprintf(stderr, "bad argument to " |
| "'--count'\n"); |
| return 1; |
| } |
| } |
| break; |
| case 'e': |
| early = 1; |
| break; |
| case 'F': |
| format = 1; |
| break; |
| case 'h': |
| usage(); |
| return 0; |
| case 'l': |
| long_lba = 1; |
| do_rcap16 = 1; |
| break; |
| case 'p': |
| pinfo = 1; |
| break; |
| case 'r': |
| resize = 1; |
| break; |
| case 'R': |
| rto_req = 1; |
| break; |
| case 's': |
| blk_size = sg_get_num(optarg); |
| if (blk_size <= 0) { |
| fprintf(stderr, "bad argument to '--size', " |
| "want arg > 0)\n"); |
| return 1; |
| } |
| break; |
| case 'v': |
| verbose++; |
| break; |
| case 'V': |
| fprintf(stderr, "sg_format version: %s\n", |
| version_str); |
| return 0; |
| case 'w': |
| fwait = 1; |
| break; |
| default: |
| usage(); |
| return 1; |
| } |
| } |
| if (optind < argc) { |
| if ('\0' == device_name[0]) { |
| strncpy(device_name, argv[optind], |
| sizeof(device_name) - 1); |
| device_name[sizeof(device_name) - 1] = '\0'; |
| ++optind; |
| } |
| } |
| if (optind < argc) { |
| for (; optind < argc; ++optind) |
| fprintf(stderr, "Unexpected extra argument: %s\n", |
| argv[optind]); |
| usage(); |
| return 1; |
| } |
| if ('\0' == device_name[0]) { |
| fprintf(stderr, "no device name given\n"); |
| usage(); |
| return 1; |
| } |
| if (resize) { |
| if (format) { |
| fprintf(stderr, "both '--format' and '--resize'" |
| "not permitted\n"); |
| usage(); |
| return 1; |
| } else if (0 == blk_count) { |
| fprintf(stderr, "'--resize' needs a '--count' (other" |
| " than 0)\n"); |
| usage(); |
| return 1; |
| } else if (0 != blk_size) { |
| fprintf(stderr, "'--resize' not compatible with " |
| "'--size')\n"); |
| usage(); |
| return 1; |
| } |
| } |
| |
| /* FIXME: add more sanity checks: |
| ** o block size/count might already be set...don't repeat |
| ** o verify SCSI device is a disk (get inquiry data first) |
| */ |
| |
| if ((fd = open(device_name, O_RDWR)) < 0) { |
| char ebuff[128]; |
| sprintf(ebuff, "error opening device file: %s", device_name); |
| perror(ebuff); |
| return 1; |
| } |
| |
| if (sg_simple_inquiry(fd, &inq_out, 1, verbose)) { |
| fprintf(stderr, "%s doesn't respond to a SCSI INQUIRY\n", |
| device_name); |
| goto out; |
| } |
| printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n", |
| inq_out.vendor, inq_out.product, inq_out.revision, |
| get_ptype_str(inq_out.peripheral_type), |
| inq_out.peripheral_type); |
| if (verbose) |
| printf(" PROTECT=%d\n", !!(inq_out.byte_5 & 1)); |
| if (inq_out.byte_5 & 1) |
| printf(" << supports 'protection information'>>\n"); |
| |
| if ((0 != inq_out.peripheral_type) && |
| (0xe != inq_out.peripheral_type)) { |
| fprintf(stderr, "This format is only defined for disks " |
| "(using SBC-2 or RBC)\n"); |
| goto out; |
| } |
| |
| memset(dbuff, 0, MAX_BUFF_SZ); |
| if (mode6) |
| res = sg_ll_mode_sense6(fd, 0 /* DBD */, 0 /* current */, |
| mode_page, 0 /* subpage */, dbuff, |
| MAX_BUFF_SZ, 1, verbose); |
| else |
| res = sg_ll_mode_sense10(fd, long_lba, 0 /* DBD */, |
| 0 /* current */, mode_page, |
| 0 /* subpage */, dbuff, |
| MAX_BUFF_SZ, 1, verbose); |
| if (res) { |
| if (SG_LIB_CAT_INVALID_OP == res) |
| fprintf(stderr, "MODE SENSE (%d) command is not " |
| "supported\n", (mode6 ? 6 : 10)); |
| else if (SG_LIB_CAT_ILLEGAL_REQ == res) { |
| if (long_lba && (! mode6)) |
| fprintf(stderr, "bad field in MODE SENSE " |
| "(%d) [longlba flag not supported?]" |
| "\n", (mode6 ? 6 : 10)); |
| else |
| fprintf(stderr, "bad field in MODE SENSE " |
| "(%d) [mode_page %d not supported?]" |
| "\n", (mode6 ? 6 : 10), mode_page); |
| } else |
| fprintf(stderr, "MODE SENSE (%d) command failed\n", |
| (mode6 ? 6 : 10)); |
| goto out; |
| } |
| if (mode6) { |
| calc_len = dbuff[0] + 1; |
| dev_specific_param = dbuff[2]; |
| bd_len = dbuff[3]; |
| long_lba = 0; |
| offset = 4; |
| /* prepare for mode select */ |
| dbuff[0] = 0; |
| dbuff[1] = 0; |
| dbuff[2] = 0; |
| } else { |
| calc_len = (dbuff[0] << 8) + dbuff[1] + 2; |
| dev_specific_param = dbuff[3]; |
| bd_len = (dbuff[6] << 8) + dbuff[7]; |
| long_lba = (dbuff[4] & 1); |
| offset = 8; |
| /* prepare for mode select */ |
| dbuff[0] = 0; |
| dbuff[1] = 0; |
| dbuff[2] = 0; |
| dbuff[3] = 0; |
| } |
| if ((offset + bd_len) < calc_len) |
| dbuff[offset + bd_len] &= 0x7f; /* clear PS bit in mpage */ |
| prob = 0; |
| bd_blk_len = 0; |
| printf("Mode sense (block descriptor) data, prior to changes:\n"); |
| if (dev_specific_param & 0x40) |
| printf(" <<< Write Protect (WP) bit set >>>\n"); |
| if (bd_len > 0) { |
| ull = 0; |
| for (j = 0; j < (long_lba ? 8 : 4); ++j) { |
| if (j > 0) |
| ull <<= 8; |
| ull |= dbuff[offset + j]; |
| } |
| if (long_lba) |
| bd_blk_len = (dbuff[offset + 12] << 24) + |
| (dbuff[offset + 13] << 16) + |
| (dbuff[offset + 14] << 8) + |
| dbuff[offset + 15]; |
| else |
| bd_blk_len = (dbuff[offset + 5] << 16) + |
| (dbuff[offset + 6] << 8) + |
| dbuff[offset + 7]; |
| if (long_lba) { |
| printf(" <<< longlba flag set (64 bit lba) >>>\n"); |
| if (bd_len != 16) |
| prob = 1; |
| } else if (bd_len != 8) |
| prob = 1; |
| printf(" Number of blocks=%llu [0x%llx]\n", ull, ull); |
| printf(" Block size=%d [0x%x]\n", bd_blk_len, bd_blk_len); |
| } else { |
| printf(" No block descriptors present\n"); |
| prob = 1; |
| } |
| if (resize || |
| (format && ((blk_count != 0) || |
| ((blk_size > 0) && (blk_size != bd_blk_len))))) { |
| /* want to run MODE SELECT */ |
| |
| /* Working Draft SCSI Primary Commands - 3 (SPC-3) pg 255 |
| ** |
| ** If the SCSI device doesn't support changing its capacity by changing |
| ** the NUMBER OF BLOCKS field using the MODE SELECT command, the value |
| ** in the NUMBER OF BLOCKS field is ignored. If the device supports changing |
| ** its capacity by changing the NUMBER OF BLOCKS field, then the |
| ** NUMBER OF BLOCKS field is interpreted as follows: |
| ** a) If the number of blocks is set to zero, the device shall retain |
| ** its current capacity if the block size has not changed. If the |
| ** number of blocks is set to zero and the block size has changed, |
| ** the device shall be set to its maximum capacity when the new |
| ** block size takes effect; |
| ** |
| ** b) If the number of blocks is greater than zero and less than or |
| ** equal to its maximum capacity, the device shall be set to that |
| ** number of blocks. If the block size has not changed, the device |
| ** shall not become format corrupted. This capacity setting shall be |
| ** retained through power cycles, hard resets, logical unit resets, |
| ** and I_T nexus losses; |
| ** |
| ** c) If the number of blocks field is set to a value greater than the |
| ** maximum capacity of the device and less than FFFF FFFFh, then the |
| ** command is terminated with a CHECK CONDITION status. The sense key |
| ** is set to ILLEGAL REQUEST. The device shall retain its previous |
| ** block descriptor settings; or |
| ** |
| ** d) If the number of blocks is set to FFFF FFFFh, the device shall be |
| ** set to its maximum capacity. If the block size has not changed, |
| ** the device shall not become format corrupted. This capacity setting |
| ** shall be retained through power cycles, hard resets, logical unit |
| ** resets, and I_T nexus losses. |
| */ |
| |
| if (prob) { |
| fprintf(stderr, "Need to perform MODE SELECT (to " |
| "change number or blocks or block length)\n"); |
| fprintf(stderr, "but (single) block descriptor not " |
| "found in earlier MODE SENSE\n"); |
| goto out; |
| } |
| if (blk_count != 0) { |
| len = (long_lba ? 8 : 4); |
| for (j = 0; j < len; ++j) |
| dbuff[offset + j] = |
| (blk_count >> ((len - j - 1) * 8)) & 0xff; |
| } else if ((blk_size > 0) && (blk_size != bd_blk_len)) { |
| len = (long_lba ? 8 : 4); |
| for (j = 0; j < len; ++j) |
| dbuff[offset + j] = 0; |
| } |
| if ((blk_size > 0) && (blk_size != bd_blk_len)) { |
| if (long_lba) { |
| dbuff[offset + 12] = (blk_size >> 24) & 0xff; |
| dbuff[offset + 13] = (blk_size >> 16) & 0xff; |
| dbuff[offset + 14] = (blk_size >> 8) & 0xff; |
| dbuff[offset + 15] = blk_size & 0xff; |
| } else { |
| dbuff[offset + 5] = (blk_size >> 16) & 0xff; |
| dbuff[offset + 6] = (blk_size >> 8) & 0xff; |
| dbuff[offset + 7] = blk_size & 0xff; |
| } |
| } |
| if (mode6) |
| res = sg_ll_mode_select6(fd, 1 /* PF */, 1 /* SP */, |
| dbuff, calc_len, 1, verbose); |
| else |
| res = sg_ll_mode_select10(fd, 1 /* PF */, 1 /* SP */, |
| dbuff, calc_len, 1, verbose); |
| if (res) { |
| if (SG_LIB_CAT_INVALID_OP == res) |
| fprintf(stderr, "MODE SELECT (%d) command is " |
| "not supported\n", (mode6 ? 6 : 10)); |
| else if (SG_LIB_CAT_ILLEGAL_REQ == res) |
| fprintf(stderr, "bad field in MODE SELECT " |
| "(%d)\n", (mode6 ? 6 : 10)); |
| else |
| fprintf(stderr, "MODE SELECT (%d) command " |
| "failed\n", (mode6 ? 6 : 10)); |
| goto out; |
| } |
| } |
| if (resize) { |
| ret = 0; |
| printf("Resize operation seems to have been successful\n"); |
| goto out; |
| } |
| else if (! format) { |
| res = print_read_cap(fd, do_rcap16, verbose); |
| if ((res > 0) && (bd_blk_len > 0) && |
| (res != (int)bd_blk_len)) { |
| printf(" Warning: mode sense and read capacity " |
| "report different block sizes [%d,%d]\n", |
| bd_blk_len, res); |
| printf(" Probably needs format\n"); |
| } |
| printf("No changes made. To format use '--format'. To " |
| "resize use '--resize'\n"); |
| ret = 0; |
| goto out; |
| } |
| |
| if(format) |
| #if 1 |
| printf("\nA FORMAT will commence in 10 seconds\n"); |
| printf(" ALL data on %s will be DESTROYED\n", device_name); |
| printf(" Press control-C to abort\n"); |
| sleep(5); |
| printf("A FORMAT will commence in 5 seconds\n"); |
| printf(" ALL data on %s will be DESTROYED\n", device_name); |
| printf(" Press control-C to abort\n"); |
| sleep(5); |
| scsi_format(fd, pinfo, rto_req, ! fwait, early, verbose); |
| #else |
| fprintf(stderr, "FORMAT ignored, testing\n"); |
| #endif |
| ret = 0; |
| |
| out: |
| close(fd); |
| return ret; |
| } |