aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--README2
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg_format.823
-rw-r--r--doc/sg_scan.8.linux2
-rw-r--r--doc/sg_unmap.811
-rw-r--r--doc/sg_write_same.832
-rw-r--r--include/sg_lib_data.h14
-rw-r--r--lib/sg_lib.c15
-rw-r--r--lib/sg_lib_data.c12
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/sg_opcodes.c180
-rw-r--r--src/sg_rbuf.c166
-rw-r--r--src/sg_unmap.c20
14 files changed, 293 insertions, 194 deletions
diff --git a/ChangeLog b/ChangeLog
index 5a1921a1..b0c68d09 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,14 +2,18 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.39 [20140422] [svn: r569]
+Changelog for sg3_utils-1.39 [20140426] [svn: r570]
- sg_ses: add --eiioe=auto|force option
- fix AES dpage element indexing problems
- sg_write_buffer: add --bpw=CS option to call
write buffer multiple times for big blobs
- sg_format: add --ip_def option to fully provision
+ - sg_opcodes: add --mask option
- sginfo: strip trailing spaces from INQUIRY text
- sg_sat_set_features: add --readonly option
+ - sg_rbuf: add --echo option (to use echo buffer)
+ - sg_lib: add sanitize command service action names
+ dStrHex(Err): fix output truncation error
- examples/sgq_dd: re-add old utility as example
Changelog for sg3_utils-1.38 [20140401] [svn: r563]
diff --git a/README b/README
index 54a2ea40..b67c090a 100644
--- a/README
+++ b/README
@@ -403,4 +403,4 @@ See http://sg.danny.cz/sg/tools.html
Douglas Gilbert
-4th April 2014
+24th April 2014
diff --git a/debian/changelog b/debian/changelog
index 66da6a2b..cb48e46a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.39-0.1) unstable; urgency=low
* New upstream version
- -- Douglas Gilbert <dgilbert@interlog.com> Fri, 04 Apr 2014 21:00:00 -0400
+ -- Douglas Gilbert <dgilbert@interlog.com> Thu, 24 Apr 2014 15:00:00 -0400
sg3-utils (1.38-0.1) unstable; urgency=low
diff --git a/doc/sg_format.8 b/doc/sg_format.8
index 816424c9..903ab0f6 100644
--- a/doc/sg_format.8
+++ b/doc/sg_format.8
@@ -1,6 +1,6 @@
.TH SG_FORMAT "8" "April 2014" "sg3_utils\-1.39" SG3_UTILS
.SH NAME
-sg_format \- format or resize a SCSI disk (perhaps change its block size)
+sg_format \- format, resize or modify protection information of a SCSI disk
.SH SYNOPSIS
.B sg_format
[\fI\-\-cmplst=\fR{0|1}] [\fI\-\-count=COUNT\fR] [\fI\-\-dcrt\fR]
@@ -45,10 +45,10 @@ time the user is invited twice (5 seconds apart) to abort sg_format. This
occurs just prior the SCSI FORMAT UNIT command being issued. See the NOTES
section for more information.
.PP
-Protection information is optional and is made up of 8 additional bytes
-associated with each logical block. Four protection types are defined
-with protection type 0 being no additional protection bytes. See the
-PROTECTION INFORMATION section below for more information.
+Protection information is optional and is made up of one or more protection
+intervals, each made up of 8 bytes associated with each logical block. Four
+protection types are defined with protection type 0 being no protection
+intervals. See the PROTECTION INFORMATION section below for more information.
.SH OPTIONS
Arguments to long options are mandatory for short options as well.
The options are arranged in alphabetical order based on the long
@@ -169,10 +169,11 @@ below for more information.
\fB\-q\fR, \fB\-\-pie\fR=\fIPIE\fR
sets the "Protection Interval Exponent" field in the parameter block
associated with a FORMAT UNIT command to \fIPIE\fR. The default value is 0.
-The value of 0 is typical for 512 byte blocks, often with 4096 byte blocks
-a value of 3 might be appropriate (i.e. 8 protection intervals interleaved
-with 4096 bytes of user data). This field first appeared in SBC\-3 revision
-18.
+\fIPIE\fR can only be non-zero with protection types 2 and 3.
+The value of 0 is typical for 512 byte blocks; with 4096 byte blocks a value
+of 3 may be appropriate (i.e. 8 protection intervals interleaved with 4096
+bytes of user data). A device may not support any non-zero values. This
+field first appeared in SBC\-3 revision 18.
.TP
\fB\-p\fR, \fB\-\-pinfo\fR
this option is deprecated, use the \fI\-\-fmtpinfo=FPI\fR option instead.
@@ -239,7 +240,9 @@ command's (short) parameter header. If this option (i.e. \fI\-\-wait\fR) is
given then the "IMMED" bit is not set. If \fI\-\-wait\fR is given the
FORMAT UNIT command waits until the format operation completes before
returning its response. This can be many hours on large disks. This
-utility sets a 15 hour timeout on such a FORMAT UNIT command!
+utility sets a 15 hour timeout on such a FORMAT UNIT command! Some recent
+SSDs go to the other extreme of completing a format operation in 1.5
+seconds hence waiting is not an issue.
.SH LISTS
The SBC\-3 draft (revision 36) defines PLIST, CLIST, DLIST and GLIST in
section 4.13 on "Medium defects". Briefly, the PLIST is the "primary"
diff --git a/doc/sg_scan.8.linux b/doc/sg_scan.8.linux
index b42761a0..06980004 100644
--- a/doc/sg_scan.8.linux
+++ b/doc/sg_scan.8.linux
@@ -50,7 +50,7 @@ do numeric scan (i.e. sg0, sg1...) [default]
use a read/write flag when opening sg device (default is read\-only)
.TP
\fB\-x\fR
-extra information output about queuing
+extra information output about queueing
.SH NOTES
This utility was written at a time when hotplugging of SCSI devices
was not supported in Linux. It used a simple algorithm to scan sg
diff --git a/doc/sg_unmap.8 b/doc/sg_unmap.8
index 7eb0588c..5e8e5817 100644
--- a/doc/sg_unmap.8
+++ b/doc/sg_unmap.8
@@ -1,4 +1,4 @@
-.TH SG_UNMAP "8" "January 2014" "sg3_utils\-1.38" SG3_UTILS
+.TH SG_UNMAP "8" "April 2014" "sg3_utils\-1.39" SG3_UTILS
.SH NAME
sg_unmap \- send SCSI UNMAP command (known as 'trim' in ATA specs)
.SH SYNOPSIS
@@ -22,7 +22,8 @@ and the corresponding number(s) to unmap to the '\-\-num=' option. The
other way is by putting start LBA and number to unmap pairs in a file whose
name is given to the '\-\-in=' option. All values are assumed to be decimal
unless prefixed by "0x" (or "0X") or have a trailing "h" (or "H") in which
-case they are interpreted as hexadecimal.
+case they are interpreted as hexadecimal. Suffix multipliers are permitted
+on decimal values (e.g. '\-\-num=1m').
.PP
When the '\-\-lba=' option is given then the '\-\-num=' option must also be
given. If one has a comma separated list as its argument then the other must
@@ -105,6 +106,12 @@ In SBC\-3 revision 25 the LBPU and ANC_SUP bits where added to the
Logical Block Provisioning VPD page. When LBPU is set it indicates that
the device supports the UNMAP command. When the ANC_SUP bit is set it
indicates the device supports anchored LBAs.
+.PP
+The SCSI UNMAP command does the "right thing" with respect to command
+queueing. However its ATA counterpart: the DATA SET MANAGEMENT command with
+the "Trim" bit set does not interact well with SATA queueing known as NCQ.
+To address this problem T13 have introduced a new command called SFQ DATA SET
+MANAGEMENT which also has a Trim bit.
.SH EXAMPLES
In the examples directory of the sg3_utils package there is a
sg_unmap_example.txt file that shows the format that the '\-\-in='
diff --git a/doc/sg_write_same.8 b/doc/sg_write_same.8
index fe4dabc3..2663bda2 100644
--- a/doc/sg_write_same.8
+++ b/doc/sg_write_same.8
@@ -1,4 +1,4 @@
-.TH SG_WRITE_SAME "8" "May 2013" "sg3_utils\-1.36" SG3_UTILS
+.TH SG_WRITE_SAME "8" "April 2014" "sg3_utils\-1.39" SG3_UTILS
.SH NAME
sg_write_same \- send SCSI WRITE SAME command
.SH SYNOPSIS
@@ -157,14 +157,16 @@ greater. If both this option and the \fIIF\fR option are given and
\fILEN\fR exceeds the length of the \fIIF\fR file then \fILEN\fR is the
data out buffer length with zeros used as pad bytes.
.SH UNMAP
-Logical block provisioning is a new term introduced in SBC\-3 revision
-25 for the ability to mark blocks as unused. It is closely related to the
-ATA DATA SET MANAGEMENT command with the "Trim" bit set. For large
-storage arrays, it is a way to provision less physical storage than the
-READ CAPACITY command reports is available, potentially allocating more
-physical storage when WRITE commands require it. For flash memory it is
-a way of potentially saving power (and perhaps access time) when it is
-known large sections (or almost all) of the flash memory is not in use.
+Logical block provisioning is a new term introduced in SBC\-3 revision 25
+for the ability to mark blocks as unused. For large storage arrays, it is a
+way to provision less physical storage than the READ CAPACITY command reports
+is available, potentially allocating more physical storage when WRITE
+commands require it. For flash memory (e.g. SSD drives) it is a way of
+potentially saving power (and perhaps access time) when it is known large
+sections (or almost all) of the flash memory is not in use. SSDs need wear
+levelling algorithms to have acceptable endurance and typically over
+provision to simplify those algorithms; hence they typically contain more
+physical flash storage than their logical size would dictate.
.PP
Support for logical block provisioning is indicated by the LBPME bit being
set in the READ CAPACITY(16) command response (see the sg_readcap utility).
@@ -191,10 +193,18 @@ set then the UNMAP bit is ignored and the data out buffer is written to the
\fIDEVICE\fR as if the UNMAP bit was zero. In the absence of the
\fI\-\-in=IF\fR option, this utility will attempt build a data out buffer
that meets the requirements for the UNMAP bit in the cdb to be acted on by
-the \fIDEVICE\fR.
+the \fIDEVICE\fR.
.PP
Logical blocks may also be unmapped by the SCSI UNMAP and FORMAT UNIT
commands (see the sg_unmap and sg_format utilities).
+.PP
+The unmap capability in SCSI is closely related to the ATA DATA SET
+MANAGEMENT command with the "Trim" bit set. That ATA trim capability does
+not interact well with SATA command queueing known as NCQ. T13 have
+introduced a new command called the SFQ DATA SET MANAGEMENT command also
+with a the "Trim" bit to address that problem. The SCSI WRITE SAME with
+the UNMAP bit set and the UNMAP commands do not have any problems with
+SCSI queueing.
.SH NOTES
Various numeric arguments (e.g. \fILBA\fR) may include multiplicative
suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section
@@ -296,7 +306,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2009\-2013 Douglas Gilbert
+Copyright \(co 2009\-2014 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/include/sg_lib_data.h b/include/sg_lib_data.h
index 68fd1c86..b3dcc55d 100644
--- a/include/sg_lib_data.h
+++ b/include/sg_lib_data.h
@@ -22,20 +22,21 @@ extern "C" {
#endif
/* Commands with service actions that change the command name */
+#define SG_EXTENDED_COPY 0x83 /* since spc4r34 called: Third party copy out */
+#define SG_RECEIVE_COPY 0x84 /* since spc4r34 called: Third party copy in */
#define SG_MAINTENANCE_IN 0xa3
#define SG_MAINTENANCE_OUT 0xa4
#define SG_PERSISTENT_RESERVE_IN 0x5e
#define SG_PERSISTENT_RESERVE_OUT 0x5f
-#define SG_EXTENDED_COPY 0x83 /* since spc4r34 called: Third party copy out */
-#define SG_RECEIVE_COPY 0x84 /* since spc4r34 called: Third party copy in */
-#define SG_SERVICE_ACTION_IN_12 0xab
-#define SG_SERVICE_ACTION_OUT_12 0xa9
+#define SG_READ_BUFFER 0x3c
+#define SG_SANITIZE 0x48
#define SG_SERVICE_ACTION_BIDI 0x9d
+#define SG_SERVICE_ACTION_IN_12 0xab
#define SG_SERVICE_ACTION_IN_16 0x9e
+#define SG_SERVICE_ACTION_OUT_12 0xa9
#define SG_SERVICE_ACTION_OUT_16 0x9f
-#define SG_READ_BUFFER 0x3c
-#define SG_WRITE_BUFFER 0x3b
#define SG_VARIABLE_LENGTH_CMD 0x7f
+#define SG_WRITE_BUFFER 0x3b
@@ -68,6 +69,7 @@ extern struct sg_lib_value_name_t sg_lib_maint_in_arr[];
extern struct sg_lib_value_name_t sg_lib_maint_out_arr[];
extern struct sg_lib_value_name_t sg_lib_pr_in_arr[];
extern struct sg_lib_value_name_t sg_lib_pr_out_arr[];
+extern struct sg_lib_value_name_t sg_lib_sanitize_sa_arr[];
extern struct sg_lib_value_name_t sg_lib_serv_in12_arr[];
extern struct sg_lib_value_name_t sg_lib_serv_out12_arr[];
extern struct sg_lib_value_name_t sg_lib_serv_in16_arr[];
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index f5169222..fba0fd84 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -1280,7 +1280,7 @@ sg_get_opcode_sa_name(unsigned char cmd_byte0, int service_action,
vnp = get_value_name(sg_lib_read_buff_arr, service_action,
peri_type);
if (vnp)
- my_snprintf(buff, buff_len, "Read buffer (%s)\n", vnp->name);
+ my_snprintf(buff, buff_len, "Read buffer, %s", vnp->name);
else
my_snprintf(buff, buff_len, "Read buffer, mode=0x%x",
service_action);
@@ -1290,11 +1290,20 @@ sg_get_opcode_sa_name(unsigned char cmd_byte0, int service_action,
vnp = get_value_name(sg_lib_write_buff_arr, service_action,
peri_type);
if (vnp)
- my_snprintf(buff, buff_len, "Write buffer (%s)\n", vnp->name);
+ my_snprintf(buff, buff_len, "Write buffer, %s", vnp->name);
else
my_snprintf(buff, buff_len, "Write buffer, mode=0x%x",
service_action);
break;
+ case SG_SANITIZE:
+ vnp = get_value_name(sg_lib_sanitize_sa_arr, service_action,
+ peri_type);
+ if (vnp)
+ my_snprintf(buff, buff_len, "%s", vnp->name);
+ else
+ my_snprintf(buff, buff_len, "Sanitize, service action=0x%x",
+ service_action);
+ break;
default:
sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff);
break;
@@ -1430,7 +1439,7 @@ dStrHexFp(const char* str, int len, int no_ascii, FILE * fp)
if (len <= 0)
return;
blen = (int)sizeof(buff);
- formatstr = (0 == no_ascii) ? "%.76s\n" : "%.48s\n";
+ formatstr = (0 == no_ascii) ? "%.76s\n" : "%.58s\n";
memset(buff, ' ', 80);
buff[80] = '\0';
if (no_ascii < 0) {
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index d288b2da..465302db 100644
--- a/lib/sg_lib_data.c
+++ b/lib/sg_lib_data.c
@@ -15,7 +15,7 @@
#endif
-const char * sg_lib_version_str = "1.96 20140401"; /* spc4r36s, sbc4r01 */
+const char * sg_lib_version_str = "1.97 20140424"; /* spc4r36s, sbc4r01 */
#ifdef SG_SCSI_STRINGS
struct sg_lib_value_name_t sg_lib_normal_opcodes[] = {
@@ -230,7 +230,7 @@ struct sg_lib_value_name_t sg_lib_write_buff_arr[] = { /* opcode 0x3b */
{0x7, 0, "download microcode with offsets, save, and activate"},
{0xa, 0, "write data to echo buffer"},
{0xd, 0, "download microcode with offsets, select activation events, "
- " save and defer activate"},
+ "save and defer activate"},
{0xe, 0, "download microcode with offsets, save and defer activate"},
{0xf, 0, "activate deferred microcode"},
{0x1a, 0, "enable expander comms protocol and echo buffer"},
@@ -264,6 +264,14 @@ struct sg_lib_value_name_t sg_lib_maint_out_arr[] = { /* opcode 0xa4 */
{0xffff, 0, NULL},
};
+struct sg_lib_value_name_t sg_lib_sanitize_sa_arr[] = { /* opcode 0x48 */
+ {0x1, 0, "Sanitize, overwrite"},
+ {0x2, 0, "Sanitize, block erase"},
+ {0x3, 0, "Sanitize, cryptographic erase"},
+ {0x1f, 0, "Sanitize, exit failure mode"},
+ {0xffff, 0, NULL},
+};
+
struct sg_lib_value_name_t sg_lib_serv_in12_arr[] = { /* opcode 0xab */
{0x1, 0, "Read media serial number"},
{0xffff, 0, NULL},
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 9936136b..9e9459a3 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -79,7 +79,7 @@ fi
%{_libdir}/*.la
%changelog
-* Fri Apr 04 2014 - dgilbert at interlog dot com
+* Thu Apr 24 2014 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.39
diff --git a/src/sg_opcodes.c b/src/sg_opcodes.c
index 25f58a6d..01903b52 100644
--- a/src/sg_opcodes.c
+++ b/src/sg_opcodes.c
@@ -1,5 +1,5 @@
/* A utility program originally written for the Linux OS SCSI subsystem.
- * Copyright (C) 2004-2013 D. Gilbert
+ * Copyright (C) 2004-2014 D. Gilbert
* 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)
@@ -26,7 +26,7 @@
#include "sg_pt.h"
-static const char * version_str = "0.38 20130507"; /* spc4r26 */
+static const char * version_str = "0.38 20140423"; /* spc4r36s */
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
@@ -39,7 +39,7 @@ static const char * version_str = "0.38 20130507"; /* spc4r26 */
#define RSTMF_CMD_LEN 12
#define MX_ALLOC_LEN 8192
-#define NAME_BUFF_SZ 64
+#define NAME_BUFF_SZ 128
static int peri_type = 0; /* ugly but not easy to pass to alpha compare */
@@ -55,6 +55,7 @@ static struct option long_options[] = {
{"alpha", 0, 0, 'a'},
{"help", 0, 0, 'h'},
{"hex", 0, 0, 'H'},
+ {"mask", 0, 0, 'm'},
{"no-inquiry", 0, 0, 'n'},
{"new", 0, 0, 'N'},
{"opcode", 1, 0, 'o'},
@@ -75,6 +76,7 @@ struct opts_t {
int do_help;
int do_hex;
int no_inquiry;
+ int do_mask;
int do_opcode;
int do_raw;
int do_rctd;
@@ -93,7 +95,7 @@ static void
usage()
{
fprintf(stderr,
- "Usage: sg_opcodes [--alpha] [--help] [--hex] "
+ "Usage: sg_opcodes [--alpha] [--help] [--hex] [--mask] "
"[--no-inquiry]\n"
" [--opcode=OP[,SA]] [--raw] [--rctd] "
"[--repd] [--sa=SA]\n"
@@ -104,6 +106,8 @@ usage()
"alphabetically\n"
" --help|-h print usage message then exit\n"
" --hex|-H output response in hex\n"
+ " --mask|-m and show cdb usage data (a mask) when "
+ "all listed\n"
" --no-inquiry|-n don't output INQUIRY information\n"
" --opcode=OP|-o OP first byte of command to query\n"
" (decimal, prefix with '0x' for hex)\n"
@@ -126,20 +130,21 @@ usage()
" --verbose|-v increase verbosity\n"
" --version|-V print version string then exit\n\n"
"Performs a SCSI REPORT SUPPORTED OPERATION CODES or a REPORT "
- "SUPPORTED\nTASK MANAGEMENT FUNCTIONS command\n");
+ "SUPPORTED\nTASK MANAGEMENT FUNCTIONS command.\n");
}
static void
usage_old()
{
fprintf(stderr,
- "Usage: sg_opcodes [-a] [-H] [-n] [-o=OP] [-q] [-r] [-R] "
+ "Usage: sg_opcodes [-a] [-H] [-m] [-n] [-o=OP] [-q] [-r] [-R] "
"[-s=SA]\n"
" [-t] [-u] [-v] [-V] DEVICE\n"
" where:\n"
" -a output list of operation codes sorted "
"alphabetically\n"
" -H print response in hex\n"
+ " -m and show cdb usage data (a mask) when all listed\n"
" -n don't output INQUIRY information\n"
" -o=OP first byte of command to query (in hex)\n"
" -q set REPD bit for tmf_s\n"
@@ -166,7 +171,7 @@ process_cl_new(struct opts_t * optsp, int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "ahHnNo:OqrRs:tuvV", long_options,
+ c = getopt_long(argc, argv, "ahHmnNo:OqrRs:tuvV", long_options,
&option_index);
if (c == -1)
break;
@@ -182,6 +187,9 @@ process_cl_new(struct opts_t * optsp, int argc, char * argv[])
case 'H':
++optsp->do_hex;
break;
+ case 'm':
+ ++optsp->do_mask;
+ break;
case 'n':
++optsp->no_inquiry;
break;
@@ -296,6 +304,9 @@ process_cl_old(struct opts_t * optsp, int argc, char * argv[])
case 'H':
++optsp->do_hex;
break;
+ case 'm':
+ ++optsp->do_mask;
+ break;
case 'n':
++optsp->no_inquiry;
break;
@@ -463,10 +474,10 @@ opcode_alpha_compare(const void * left, const void * right)
}
static void
-list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
- int alpha, int rctd)
+list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op,
+ int sg_fd)
{
- int k, j, cd_len, serv_act, len;
+ int k, j, m, cd_len, serv_act, len, servactv, opcode, res;
unsigned int to;
unsigned char * ucp;
char name_buff[NAME_BUFF_SZ];
@@ -484,7 +495,7 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
printf("sg_opcodes: no commands to display\n");
return;
}
- if (rctd) {
+ if (op->do_rctd) {
printf("\nOpcode Service CDB Nominal Recommended Name\n");
printf( "(hex) action(h) size timeout timeout(sec) \n");
printf("-----------------------------------------------------------"
@@ -495,7 +506,7 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
printf("-----------------------------------------------\n");
}
/* N.B. SPC-4 does _not_ requiring any ordering of response */
- if (! unsorted) {
+ if (! op->do_unsorted) {
sort_arr = (unsigned char **)malloc(cd_len * sizeof(unsigned char *));
if (NULL == sort_arr) {
printf("sg_opcodes: no memory to sort operation codes, "
@@ -509,24 +520,26 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
len = (ucp[5] & 0x2) ? 20 : 8;
}
qsort(sort_arr, j, sizeof(unsigned char *),
- (alpha ? opcode_alpha_compare : opcode_num_compare));
+ (op->do_alpha ? opcode_alpha_compare : opcode_num_compare));
}
for (k = 0, j = 0; k < cd_len; ++j, k += len) {
- ucp = unsorted ? (rsoc_buff + 4 + k) : sort_arr[j];
+ ucp = op->do_unsorted ? (rsoc_buff + 4 + k) : sort_arr[j];
len = (ucp[5] & 0x2) ? 20 : 8;
- if (ucp[5] & 1) {
+ opcode = ucp[0];
+ servactv = ucp[5] & 1;
+ serv_act = 0;
+ if (servactv) {
serv_act = ((ucp[2] << 8) | ucp[3]);
- sg_get_opcode_sa_name(ucp[0], serv_act, peri_type,
- NAME_BUFF_SZ, name_buff);
+ sg_get_opcode_sa_name(opcode, serv_act, peri_type, NAME_BUFF_SZ,
+ name_buff);
snprintf(sa_buff, sizeof(sa_buff), "%4x", serv_act);
} else {
- sg_get_opcode_name(ucp[0], peri_type,
- NAME_BUFF_SZ, name_buff);
+ sg_get_opcode_name(opcode, peri_type, NAME_BUFF_SZ, name_buff);
memset(sa_buff, ' ', sizeof(sa_buff));
}
- if (rctd) {
+ if (op->do_rctd) {
if (ucp[5] & 0x2) {
- printf(" %.2x %.4s %3d", ucp[0], sa_buff,
+ printf(" %.2x %.4s %3d", opcode, sa_buff,
((ucp[6] << 8) | ucp[7]));
to = ((unsigned int)ucp[12] << 24) + (ucp[13] << 16) +
(ucp[14] << 8) + ucp[15];
@@ -543,11 +556,28 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
printf(" %s\n", name_buff);
} else
printf(" %.2x %.4s %3d "
- "%s\n", ucp[0], sa_buff, ((ucp[6] << 8) | ucp[7]),
+ "%s\n", opcode, sa_buff, ((ucp[6] << 8) | ucp[7]),
name_buff);
} else
printf(" %.2x %.4s %3d %s\n",
ucp[0], sa_buff, ((ucp[6] << 8) | ucp[7]), name_buff);
+ if (op->do_mask) {
+ int cdb_sz;
+ unsigned char b[64];
+
+ memset(b, 0, sizeof(b));
+ res = do_rsoc(sg_fd, 0, (servactv ? 2 : 1), opcode, serv_act,
+ b, sizeof(b), 1, op->do_verbose);
+ if (0 == res) {
+ cdb_sz = (b[2] << 8) + b[3];
+ if ((cdb_sz > 0) && (cdb_sz <= 80)) {
+ printf(" cdb usage: ");
+ for (m = 0; m < cdb_sz; ++m)
+ printf("%.2x ", b[4 + m]);
+ printf("\n");
+ }
+ }
+ }
}
}
@@ -584,8 +614,8 @@ decode_cmd_to_descriptor(unsigned char * dp, int max_b_len, char * b)
}
static void
-list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts, int do_opcode,
- int do_servact)
+list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts,
+ struct opts_t * op)
{
int k;
char name_buff[NAME_BUFF_SZ];
@@ -594,12 +624,12 @@ list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts, int do_opcode,
int v = 0;
- printf("\n Opcode=0x%.2x", do_opcode);
+ printf("\n Opcode=0x%.2x", op->do_opcode);
if (rep_opts > 1)
- printf(" Service_action=0x%.4x", do_servact);
+ printf(" Service_action=0x%.4x", op->do_servact);
printf("\n");
- sg_get_opcode_sa_name(((do_opcode > 0) ? do_opcode : 0),
- ((do_servact > 0) ? do_servact : 0),
+ sg_get_opcode_sa_name(((op->do_opcode > 0) ? op->do_opcode : 0),
+ ((op->do_servact > 0) ? op->do_servact : 0),
peri_type, NAME_BUFF_SZ, name_buff);
printf(" Command_name: %s\n", name_buff);
switch((int)(rsoc_buff[1] & 7)) {
@@ -650,63 +680,65 @@ main(int argc, char * argv[])
struct sg_simple_inquiry_resp inq_resp;
const char * op_name;
struct opts_t opts;
+ struct opts_t * op;
- memset(&opts, 0, sizeof(opts));
- opts.do_opcode = -1;
- opts.do_servact = -1;
- res = process_cl(&opts, argc, argv);
+ op = &opts;
+ memset(op, 0, sizeof(opts));
+ op->do_opcode = -1;
+ op->do_servact = -1;
+ res = process_cl(op, argc, argv);
if (res)
return SG_LIB_SYNTAX_ERROR;
- if (opts.do_help) {
- if (opts.opt_new)
+ if (op->do_help) {
+ if (op->opt_new)
usage();
else
usage_old();
return 0;
}
- if (opts.do_version) {
+ if (op->do_version) {
fprintf(stderr, "Version string: %s\n", version_str);
return 0;
}
- if (NULL == opts.device_name) {
+ if (NULL == op->device_name) {
fprintf(stderr, "No DEVICE argument given\n");
- if (opts.opt_new)
+ if (op->opt_new)
usage();
else
usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- if ((-1 != opts.do_servact) && (-1 == opts.do_opcode)) {
+ if ((-1 != op->do_servact) && (-1 == op->do_opcode)) {
fprintf(stderr, "When '-s' is chosen, so must '-o' be chosen\n");
- if (opts.opt_new)
+ if (op->opt_new)
usage();
else
usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- if (opts.do_unsorted && opts.do_alpha)
+ if (op->do_unsorted && op->do_alpha)
fprintf(stderr, "warning: unsorted ('-u') and alpha ('-a') options "
"chosen, ignoring alpha\n");
- if (opts.do_taskman && ((-1 != opts.do_opcode) || opts.do_alpha ||
- opts.do_unsorted)) {
+ if (op->do_taskman && ((-1 != op->do_opcode) || op->do_alpha ||
+ op->do_unsorted)) {
fprintf(stderr, "warning: task management functions ('-t') chosen "
"so alpha ('-a'),\n unsorted ('-u') and opcode "
"('-o') options ignored\n");
}
- op_name = opts.do_taskman ? "Report supported task management functions" :
+ op_name = op->do_taskman ? "Report supported task management functions" :
"Report supported operation codes";
- if (opts.do_opcode < 0) {
- if ((sg_fd = scsi_pt_open_device(opts.device_name, 1 /* RO */,
- opts.do_verbose)) < 0) {
+ if (op->do_opcode < 0) {
+ if ((sg_fd = scsi_pt_open_device(op->device_name, 1 /* RO */,
+ op->do_verbose)) < 0) {
fprintf(stderr, "sg_opcodes: error opening file (ro): %s: %s\n",
- opts.device_name, safe_strerror(-sg_fd));
+ op->device_name, safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
- if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, opts.do_verbose)) {
+ if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, op->do_verbose)) {
peri_type = inq_resp.peripheral_type;
- if (! (opts.do_raw || opts.no_inquiry)) {
+ if (! (op->do_raw || op->no_inquiry)) {
printf(" %.8s %.16s %.4s\n", inq_resp.vendor,
inq_resp.product, inq_resp.revision);
cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
@@ -717,7 +749,7 @@ main(int argc, char * argv[])
}
} else {
fprintf(stderr, "sg_opcodes: %s doesn't respond to a SCSI "
- "INQUIRY\n", opts.device_name);
+ "INQUIRY\n", op->device_name);
return SG_LIB_CAT_OTHER;
}
res = scsi_pt_close_device(sg_fd);
@@ -727,22 +759,22 @@ main(int argc, char * argv[])
}
}
- if ((sg_fd = scsi_pt_open_device(opts.device_name, 0 /* RW */,
- opts.do_verbose)) < 0) {
+ if ((sg_fd = scsi_pt_open_device(op->device_name, 0 /* RW */,
+ op->do_verbose)) < 0) {
fprintf(stderr, "sg_opcodes: error opening file (rw): %s: %s\n",
- opts.device_name, safe_strerror(-sg_fd));
+ op->device_name, safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
- if (opts.do_opcode >= 0)
- rep_opts = ((opts.do_servact >= 0) ? 2 : 1);
+ if (op->do_opcode >= 0)
+ rep_opts = ((op->do_servact >= 0) ? 2 : 1);
memset(rsoc_buff, 0, sizeof(rsoc_buff));
- if (opts.do_taskman)
- res = do_rstmf(sg_fd, opts.do_repd, rsoc_buff,
- (opts.do_repd ? 16 : 4), 1, opts.do_verbose);
+ if (op->do_taskman)
+ res = do_rstmf(sg_fd, op->do_repd, rsoc_buff,
+ (op->do_repd ? 16 : 4), 1, op->do_verbose);
else
- res = do_rsoc(sg_fd, opts.do_rctd, rep_opts, opts.do_opcode,
- opts.do_servact, rsoc_buff, sizeof(rsoc_buff), 1,
- opts.do_verbose);
+ res = do_rsoc(sg_fd, op->do_rctd, rep_opts, op->do_opcode,
+ op->do_servact, rsoc_buff, sizeof(rsoc_buff), 1,
+ op->do_verbose);
switch (res) {
case 0:
case SG_LIB_CAT_RECOVERED:
@@ -767,14 +799,14 @@ main(int argc, char * argv[])
fprintf(stderr, "%s failed\n", op_name);
goto err_out;
}
- if (opts.do_taskman) {
- if (opts.do_raw) {
- dStrRaw((const char *)rsoc_buff, (opts.do_repd ? 16 : 4));
+ if (op->do_taskman) {
+ if (op->do_raw) {
+ dStrRaw((const char *)rsoc_buff, (op->do_repd ? 16 : 4));
goto err_out;
}
printf("\nTask Management Functions supported by device:\n");
- if (opts.do_hex) {
- dStrHex((const char *)rsoc_buff, (opts.do_repd ? 16 : 4), 1);
+ if (op->do_hex) {
+ dStrHex((const char *)rsoc_buff, (op->do_repd ? 16 : 4), 1);
goto err_out;
}
if (rsoc_buff[0] & 0x80)
@@ -799,7 +831,7 @@ main(int argc, char * argv[])
printf(" Query task set\n");
if (rsoc_buff[1] & 0x1)
printf(" I_T nexus reset\n");
- if (opts.do_repd) {
+ if (op->do_repd) {
if (rsoc_buff[3] < 0xc) {
fprintf(stderr, "when REPD given, byte 3 of response "
"should be >= 12\n");
@@ -829,31 +861,29 @@ main(int argc, char * argv[])
(rsoc_buff[2] << 8) | rsoc_buff[3]) + 4;
if (len > (int)sizeof(rsoc_buff))
len = sizeof(rsoc_buff);
- if (opts.do_raw) {
+ if (op->do_raw) {
dStrRaw((const char *)rsoc_buff, len);
goto err_out;
}
- if (opts.do_hex) {
+ if (op->do_hex) {
dStrHex((const char *)rsoc_buff, len, 1);
goto err_out;
}
- list_all_codes(rsoc_buff, sizeof(rsoc_buff), opts.do_unsorted,
- opts.do_alpha, opts.do_rctd);
+ list_all_codes(rsoc_buff, sizeof(rsoc_buff), op, sg_fd);
} else { /* asked about specific command */
cd_len = ((rsoc_buff[2] << 8) | rsoc_buff[3]);
len = cd_len + 4;
if (len > (int)sizeof(rsoc_buff))
len = sizeof(rsoc_buff);
- if (opts.do_raw) {
+ if (op->do_raw) {
dStrRaw((const char *)rsoc_buff, len);
goto err_out;
}
- if (opts.do_hex) {
+ if (op->do_hex) {
dStrHex((const char *)rsoc_buff, len, 1);
goto err_out;
}
- list_one(rsoc_buff, cd_len, rep_opts, opts.do_opcode,
- opts.do_servact);
+ list_one(rsoc_buff, cd_len, rep_opts, op);
}
res = 0;
diff --git a/src/sg_rbuf.c b/src/sg_rbuf.c
index d9bdb200..3ab94c4b 100644
--- a/src/sg_rbuf.c
+++ b/src/sg_rbuf.c
@@ -1,5 +1,5 @@
/* A utility program originally written for the Linux OS SCSI subsystem.
- * Copyright (C) 1999-2013 D. Gilbert
+ * Copyright (C) 1999-2014 D. Gilbert
* 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)
@@ -39,6 +39,8 @@
#define RB_MODE_DESC 3
#define RB_MODE_DATA 2
+#define RB_MODE_ECHO_DESC 0xb
+#define RB_MODE_ECHO_DATA 0xa
#define RB_DESC_LEN 4
#define RB_DEF_SIZE (200*1024*1024)
#define RB_OPCODE 0x3C
@@ -51,26 +53,28 @@
#endif
-static const char * version_str = "4.90 20131014";
+static const char * version_str = "4.91 20140425";
static struct option long_options[] = {
- {"buffer", 1, 0, 'b'},
- {"dio", 0, 0, 'd'},
- {"help", 0, 0, 'h'},
- {"mmap", 0, 0, 'm'},
- {"new", 0, 0, 'N'},
- {"old", 0, 0, 'O'},
- {"quick", 0, 0, 'q'},
- {"size", 1, 0, 's'},
- {"time", 0, 0, 't'},
- {"verbose", 0, 0, 'v'},
- {"version", 0, 0, 'V'},
+ {"buffer", required_argument, 0, 'b'},
+ {"dio", no_argument, 0, 'd'},
+ {"echo", no_argument, 0, 'e'},
+ {"help", no_argument, 0, 'h'},
+ {"mmap", no_argument, 0, 'm'},
+ {"new", no_argument, 0, 'N'},
+ {"old", no_argument, 0, 'O'},
+ {"quick", no_argument, 0, 'q'},
+ {"size", required_argument, 0, 's'},
+ {"time", no_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
{0, 0, 0, 0},
};
struct opts_t {
int do_buffer;
int do_dio;
+ int do_echo;
int do_help;
int do_mmap;
int do_quick;
@@ -86,13 +90,15 @@ struct opts_t {
static void
usage()
{
- fprintf(stderr, "Usage: sg_rbuf [--buffer=EACH] [--dio] [--help] "
- "[--mmap] [--quick]\n"
- " [--size=OVERALL] [--time] [--verbose] "
- "[--version] DEVICE\n");
+ fprintf(stderr, "Usage: sg_rbuf [--buffer=EACH] [--dio] [--echo] "
+ "[--help] [--mmap]\n"
+ " [--quick] [--size=OVERALL] [--time] [--verbose] "
+ "[--version]\n"
+ " DEVICE\n");
fprintf(stderr, " where:\n"
" --buffer=EACH|-b EACH buffer size to use (in bytes)\n"
" --dio|-d requests dio ('-q' overrides it)\n"
+ " --echo|-e use echo buffer (def: use data mode)\n"
" --help|-h print usage message then exit\n"
" --mmap|-m requests mmap-ed IO (overrides -q, -d)\n"
" --quick|-q quick, don't xfer to user space\n");
@@ -102,8 +108,8 @@ usage()
" --time|-t time the data transfer\n"
" --verbose|-v increase verbosity (more debug)\n"
" --version|-V print version string then exit\n\n"
- "Use SCSI READ BUFFER command (data mode, buffer id 0) "
- "repeatedly\n");
+ "Use SCSI READ BUFFER command (data or echo buffer mode, buffer "
+ "id 0)\nrepeatedly\n");
}
static void
@@ -114,6 +120,7 @@ usage_old()
printf(" where:\n");
printf(" -b=EACH_KIB num is buffer size to use (in KiB)\n");
printf(" -d requests dio ('-q' overrides it)\n");
+ printf(" -e use echo buffer (def: use data mode)\n");
printf(" -m requests mmap-ed IO (overrides -q, -d)\n");
printf(" -q quick, don't xfer to user space\n");
printf(" -s=OVERALL_MIB num is total size to read (in MiB) "
@@ -122,8 +129,8 @@ usage_old()
printf(" -t time the data transfer\n");
printf(" -v increase verbosity (more debug)\n");
printf(" -V print version string then exit\n\n");
- printf("Use SCSI READ BUFFER command (data mode, buffer id 0) "
- "repeatedly\n");
+ printf("Use SCSI READ BUFFER command (data or echo buffer mode, buffer "
+ "id 0)\nrepeatedly\n");
}
static void
@@ -144,7 +151,7 @@ process_cl_new(struct opts_t * optsp, int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "b:dhmNOqs:tvV", long_options,
+ c = getopt_long(argc, argv, "b:dehmNOqs:tvV", long_options,
&option_index);
if (c == -1)
break;
@@ -162,6 +169,9 @@ process_cl_new(struct opts_t * optsp, int argc, char * argv[])
case 'd':
++optsp->do_dio;
break;
+ case 'e':
+ ++optsp->do_echo;
+ break;
case 'h':
case '?':
++optsp->do_help;
@@ -237,6 +247,9 @@ process_cl_old(struct opts_t * optsp, int argc, char * argv[])
case 'd':
++optsp->do_dio;
break;
+ case 'e':
+ ++optsp->do_echo;
+ break;
case 'h':
case '?':
++optsp->do_help;
@@ -349,45 +362,46 @@ main(int argc, char * argv[])
int clear = 1;
#endif
struct opts_t opts;
+ struct opts_t * op;
#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */
#else
psz = 4096; /* give up, pick likely figure */
#endif
- memset(&opts, 0, sizeof(opts));
- res = process_cl(&opts, argc, argv);
+ op = &opts;
+ memset(op, 0, sizeof(opts));
+ res = process_cl(op, argc, argv);
if (res)
return SG_LIB_SYNTAX_ERROR;
- if (opts.do_help) {
- usage_for(&opts);
+ if (op->do_help) {
+ usage_for(op);
return 0;
}
- if (opts.do_version) {
+ if (op->do_version) {
fprintf(stderr, "Version string: %s\n", version_str);
return 0;
}
- if (NULL == opts.device_name) {
+ if (NULL == op->device_name) {
fprintf(stderr, "No DEVICE argument given\n");
- usage_for(&opts);
+ usage_for(op);
return SG_LIB_SYNTAX_ERROR;
}
- if (opts.do_buffer > 0)
- buf_size = opts.do_buffer;
- if (opts.do_size > 0)
- total_size = opts.do_size;
+ if (op->do_buffer > 0)
+ buf_size = op->do_buffer;
+ if (op->do_size > 0)
+ total_size = op->do_size;
- sg_fd = open(opts.device_name, O_RDONLY | O_NONBLOCK);
+ sg_fd = open(op->device_name, O_RDONLY | O_NONBLOCK);
if (sg_fd < 0) {
perror("device open error");
return SG_LIB_FILE_ERROR;
}
- /* Don't worry, being very careful not to write to a none-sg file ... */
- if (opts.do_mmap) {
- opts.do_dio = 0;
- opts.do_quick = 0;
+ if (op->do_mmap) {
+ op->do_dio = 0;
+ op->do_quick = 0;
}
if (NULL == (rawp = malloc(512))) {
printf("out of memory (query)\n");
@@ -397,7 +411,7 @@ main(int argc, char * argv[])
memset(rbCmdBlk, 0, RB_CMD_LEN);
rbCmdBlk[0] = RB_OPCODE;
- rbCmdBlk[1] = RB_MODE_DESC; /* data mode, buffer id 0 */
+ rbCmdBlk[1] = op->do_echo ? RB_MODE_ECHO_DESC : RB_MODE_DESC;
rbCmdBlk[8] = RB_DESC_LEN;
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
io_hdr.interface_id = 'S';
@@ -409,8 +423,9 @@ main(int argc, char * argv[])
io_hdr.cmdp = rbCmdBlk;
io_hdr.sbp = sense_buffer;
io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */
- if (opts.do_verbose) {
- fprintf(stderr, " Read buffer cdb: ");
+ if (op->do_verbose) {
+ fprintf(stderr, " Read buffer (%sdescriptor) cdb: ",
+ (op->do_echo ? "echo " : ""));
for (k = 0; k < RB_CMD_LEN; ++k)
fprintf(stderr, "%02x ", rbCmdBlk[k]);
fprintf(stderr, "\n");
@@ -423,27 +438,33 @@ main(int argc, char * argv[])
return SG_LIB_CAT_OTHER;
}
- if (opts.do_verbose > 2)
+ if (op->do_verbose > 2)
fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
/* now for the error processing */
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
sg_chk_n_print3("READ BUFFER descriptor, continuing", &io_hdr,
- opts.do_verbose > 1);
+ op->do_verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
break;
default: /* won't bother decoding other categories */
sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr,
- opts.do_verbose > 1);
+ op->do_verbose > 1);
if (rawp) free(rawp);
return (res >= 0) ? res : SG_LIB_CAT_OTHER;
}
- buf_capacity = ((rbBuff[1] << 16) | (rbBuff[2] << 8) | rbBuff[3]);
- printf("READ BUFFER reports: buffer capacity=%d, offset boundary=%d\n",
- buf_capacity, (int)rbBuff[0]);
+ if (op->do_echo) {
+ buf_capacity = (((0x1f & rbBuff[2]) << 8) | rbBuff[3]);
+ printf("READ BUFFER reports: echo buffer capacity=%d\n",
+ buf_capacity);
+ } else {
+ buf_capacity = ((rbBuff[1] << 16) | (rbBuff[2] << 8) | rbBuff[3]);
+ printf("READ BUFFER reports: buffer capacity=%d, offset "
+ "boundary=%d\n", buf_capacity, (int)rbBuff[0]);
+ }
if (0 == buf_size)
buf_size = buf_capacity;
@@ -458,23 +479,23 @@ main(int argc, char * argv[])
rawp = NULL;
}
- if (! opts.do_dio) {
+ if (! op->do_dio) {
k = buf_size;
- if (opts.do_mmap && (0 != (k % psz)))
+ if (op->do_mmap && (0 != (k % psz)))
k = ((k / psz) + 1) * psz; /* round up to page size */
res = ioctl(sg_fd, SG_SET_RESERVED_SIZE, &k);
if (res < 0)
perror("SG_SET_RESERVED_SIZE error");
}
- if (opts.do_mmap) {
+ if (op->do_mmap) {
rbBuff = (unsigned char *)mmap(NULL, buf_size, PROT_READ, MAP_SHARED,
sg_fd, 0);
if (MAP_FAILED == rbBuff) {
if (ENOMEM == errno) {
fprintf(stderr, "mmap() out of memory, try a smaller "
"buffer size than %d bytes\n", buf_size);
- if (opts.opt_new)
+ if (op->opt_new)
fprintf(stderr, " [with '--buffer=EACH' where EACH "
"is in bytes]\n");
else
@@ -486,13 +507,13 @@ main(int argc, char * argv[])
}
}
else { /* non mmap-ed IO */
- rawp = (unsigned char *)malloc(buf_size + (opts.do_dio ? psz : 0));
+ rawp = (unsigned char *)malloc(buf_size + (op->do_dio ? psz : 0));
if (NULL == rawp) {
printf("out of memory (data)\n");
return SG_LIB_CAT_OTHER;
}
/* perhaps use posix_memalign() instead */
- if (opts.do_dio) /* align to page boundary */
+ if (op->do_dio) /* align to page boundary */
rbBuff= (unsigned char *)(((unsigned long)rawp + psz - 1) &
(~(psz - 1)));
else
@@ -500,7 +521,7 @@ main(int argc, char * argv[])
}
num = total_size / buf_size;
- if (opts.do_time) {
+ if (op->do_time) {
start_tm.tv_sec = 0;
start_tm.tv_usec = 0;
gettimeofday(&start_tm, NULL);
@@ -509,7 +530,7 @@ main(int argc, char * argv[])
for (k = 0; k < num; ++k) {
memset(rbCmdBlk, 0, RB_CMD_LEN);
rbCmdBlk[0] = RB_OPCODE;
- rbCmdBlk[1] = RB_MODE_DATA;
+ rbCmdBlk[1] = op->do_echo ? RB_MODE_ECHO_DATA : RB_MODE_DATA;
rbCmdBlk[6] = 0xff & (buf_size >> 16);
rbCmdBlk[7] = 0xff & (buf_size >> 8);
rbCmdBlk[8] = 0xff & buf_size;
@@ -523,20 +544,21 @@ main(int argc, char * argv[])
io_hdr.mx_sb_len = sizeof(sense_buffer);
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
io_hdr.dxfer_len = buf_size;
- if (! opts.do_mmap)
+ if (! op->do_mmap)
io_hdr.dxferp = rbBuff;
io_hdr.cmdp = rbCmdBlk;
io_hdr.sbp = sense_buffer;
io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
io_hdr.pack_id = k;
- if (opts.do_mmap)
+ if (op->do_mmap)
io_hdr.flags |= SG_FLAG_MMAP_IO;
- else if (opts.do_dio)
+ else if (op->do_dio)
io_hdr.flags |= SG_FLAG_DIRECT_IO;
- else if (opts.do_quick)
+ else if (op->do_quick)
io_hdr.flags |= SG_FLAG_NO_DXFER;
- if (opts.do_verbose > 1) {
- fprintf(stderr, " Read buffer cdb: ");
+ if (op->do_verbose > 1) {
+ fprintf(stderr, " Read buffer (%sdata) cdb: ",
+ (op->do_echo ? "echo " : ""));
for (j = 0; j < RB_CMD_LEN; ++j)
fprintf(stderr, "%02x ", rbCmdBlk[j]);
fprintf(stderr, "\n");
@@ -546,7 +568,7 @@ main(int argc, char * argv[])
if (ENOMEM == errno) {
fprintf(stderr, "SG_IO data: out of memory, try a smaller "
"buffer size than %d bytes\n", buf_size);
- if (opts.opt_new)
+ if (op->opt_new)
fprintf(stderr, " [with '--buffer=EACH' where EACH "
"is in bytes]\n");
else
@@ -558,7 +580,7 @@ main(int argc, char * argv[])
return SG_LIB_CAT_OTHER;
}
- if (opts.do_verbose > 2)
+ if (op->do_verbose > 2)
fprintf(stderr, " duration=%u ms\n",
io_hdr.duration);
/* now for the error processing */
@@ -568,15 +590,15 @@ main(int argc, char * argv[])
break;
case SG_LIB_CAT_RECOVERED:
sg_chk_n_print3("READ BUFFER data, continuing", &io_hdr,
- opts.do_verbose > 1);
+ op->do_verbose > 1);
break;
default: /* won't bother decoding other categories */
sg_chk_n_print3("READ BUFFER data error", &io_hdr,
- opts.do_verbose > 1);
+ op->do_verbose > 1);
if (rawp) free(rawp);
return (res >= 0) ? res : SG_LIB_CAT_OTHER;
}
- if (opts.do_dio &&
+ if (op->do_dio &&
((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
dio_incomplete = 1; /* flag that dio not done (completely) */
@@ -591,7 +613,7 @@ main(int argc, char * argv[])
}
#endif
}
- if ((opts.do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
+ if ((op->do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
struct timeval res_tm;
double a, b;
@@ -607,10 +629,12 @@ main(int argc, char * argv[])
b = (double)buf_size * num;
printf("time to read data from buffer was %d.%06d secs",
(int)res_tm.tv_sec, (int)res_tm.tv_usec);
- if ((a > 0.00001) && (b > 511))
- printf(", %.2f MB/sec\n", b / (a * 1000000.0));
- else
- printf("\n");
+ if (a > 0.00001) {
+ if (b > 511)
+ printf(", %.2f MB/sec", b / (a * 1000000.0));
+ printf(", %.2f IOPS", num / a);
+ }
+ printf("\n");
}
if (dio_incomplete)
printf(">> direct IO requested but not done\n");
diff --git a/src/sg_unmap.c b/src/sg_unmap.c
index 3da7ddc4..0a010a3a 100644
--- a/src/sg_unmap.c
+++ b/src/sg_unmap.c
@@ -30,7 +30,7 @@
* logical blocks.
*/
-static const char * version_str = "1.06 20140318";
+static const char * version_str = "1.07 20140423";
#define DEF_TIMEOUT_SECS 60
@@ -108,6 +108,7 @@ usage()
);
}
+#if 0
/* Trying to decode multipliers as sg_get_llnum() [in sg_libs] does would
* only confuse things here, so use this local trimmed version */
static int64_t
@@ -135,14 +136,15 @@ get_llnum(const char * buf)
else
return -1LL;
}
+#endif
/* Read numbers (up to 64 bits in size) from command line (comma (or
* (single) space) separated list). Assumed decimal unless prefixed
* by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex).
* Returns 0 if ok, or 1 if error. */
static int
-build_lba_arr(const char * inp, uint64_t * lba_arr,
- int * lba_arr_len, int max_arr_len)
+build_lba_arr(const char * inp, uint64_t * lba_arr, int * lba_arr_len,
+ int max_arr_len)
{
int in_len, k;
const char * lcp;
@@ -161,13 +163,13 @@ build_lba_arr(const char * inp, uint64_t * lba_arr,
pr2serr("'--lba' cannot be read from stdin\n");
return 1;
} else { /* list of numbers (default decimal) on command line */
- k = strspn(inp, "0123456789aAbBcCdDeEfFhHxX, ");
+ k = strspn(inp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, ");
if (in_len != k) {
pr2serr("build_lba_arr: error at pos %d\n", k + 1);
return 1;
}
for (k = 0; k < max_arr_len; ++k) {
- ll = get_llnum(lcp);
+ ll = sg_get_llnum(lcp);
if (-1 != ll) {
lba_arr[k] = (uint64_t)ll;
cp = (char *)strchr(lcp, ',');
@@ -219,13 +221,13 @@ build_num_arr(const char * inp, uint32_t * num_arr,
pr2serr("'--len' cannot be read from stdin\n");
return 1;
} else { /* list of numbers (default decimal) on command line */
- k = strspn(inp, "0123456789aAbBcCdDeEfFhHxX, ");
+ k = strspn(inp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, ");
if (in_len != k) {
pr2serr("build_num_arr: error at pos %d\n", k + 1);
return 1;
}
for (k = 0; k < max_arr_len; ++k) {
- ll = get_llnum(lcp);
+ ll = sg_get_llnum(lcp);
if (-1 != ll) {
if (ll > UINT32_MAX) {
pr2serr("build_num_arr: number exceeds 32 bits at pos "
@@ -305,14 +307,14 @@ build_joint_arr(const char * file_name, uint64_t * lba_arr, uint32_t * num_arr,
in_len -= m;
if ('#' == *lcp)
continue;
- k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxX ,\t");
+ k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP ,\t");
if ((k < in_len) && ('#' != lcp[k])) {
pr2serr("build_joint_arr: syntax error at line %d, pos %d\n",
j + 1, m + k + 1);
return 1;
}
for (k = 0; k < 1024; ++k) {
- ll = get_llnum(lcp);
+ ll = sg_get_llnum(lcp);
if (-1 != ll) {
ind = ((off + k) >> 1);
bit0 = 0x1 & (off + k);