aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2018-02-28 03:48:11 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2018-02-28 03:48:11 +0000
commit090d6026610616895444792b75d90861b3c968f9 (patch)
tree45519da51f3e6e59487148dda9a40b0c8099c563
parentd421ee73f7d1eee168b1e87cf14a725f10edf6b9 (diff)
downloadsg3_utils-090d6026610616895444792b75d90861b3c968f9.tar.gz
sg_write_x: add --quiet option; fix sg_if_can2stdxxx problem when es=0; other cleanups
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@757 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog5
-rw-r--r--debian/compat2
-rw-r--r--doc/sg_write_x.817
-rw-r--r--include/freebsd_nvme_ioctl.h215
-rw-r--r--include/sg_lib.h1
-rw-r--r--include/sg_pt.h2
-rw-r--r--include/sg_pt_win32.h2
-rw-r--r--lib/sg_lib.c12
-rw-r--r--src/sg_inq.c117
-rw-r--r--src/sg_persist.c3
-rw-r--r--src/sg_raw.c2
-rw-r--r--src/sg_write_x.c58
12 files changed, 255 insertions, 181 deletions
diff --git a/ChangeLog b/ChangeLog
index f2f1c237..dee7229c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,10 +2,10 @@ 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.43 [20180224] [svn: r756]
+Changelog for sg3_utils-1.43 [20180227] [svn: r757]
- sg_write_x: where x can be normal, atomic, or(write),
same, scattered, or stream writes with 16 or 32 byte
- cdbs (sbc4r04 for atomic, sbc4r11 for scattered)
+ cdbs (sbc4r04 for atomic, sbc4r11 for scattered)
- sg_bg_ctl: new Background control command (sbc4r08)
- sg_seek: new SEEK(10) or PRE-FETCH(10 or 16)
- sg_stream_ctl: new, STREAM CONTROL or GET STREAM STATUS
@@ -176,6 +176,7 @@ Changelog for sg3_utils-1.43 [20180224] [svn: r756]
- Info section now printed at end of ./configure
- update BSD license from 3 to 2 clause aka FreeBSD
license (without reference to FreeBSD project)
+ - debian: bump compat file contents from 7 to 10
Changelog for sg3_utils-1.42 [20160217] [svn: r663]
- sg_timestamp: new, to report or set timestamp
diff --git a/debian/compat b/debian/compat
index 7f8f011e..f599e28b 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-7
+10
diff --git a/doc/sg_write_x.8 b/doc/sg_write_x.8
index 25bde0d9..866344ca 100644
--- a/doc/sg_write_x.8
+++ b/doc/sg_write_x.8
@@ -1,4 +1,4 @@
-.TH SG_WRITE_X "8" "December 2017" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_WRITE_X "8" "February 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg_write_x \- SCSI WRITE normal/ATOMIC/SAME/SCATTERED/STREAM, ORWRITE commands
.SH SYNOPSIS
@@ -9,11 +9,11 @@ sg_write_x \- SCSI WRITE normal/ATOMIC/SAME/SCATTERED/STREAM, ORWRITE commands
[\fI\-\-generation=EOG,NOG\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-help\fR]
\fI\-\-in=IF\fR [\fI\-\-lba=LBA[,LBA...]\fR] [\fI\-\-normal\fR]
[\fI\-\-num=NUM[,NUM...]\fR] [\fI\-\-offset=OFF[,DLEN]\fR] [\fI\-\-or\fR]
-[\fI\-\-ref\-tag=RT\fR] [\fI\-\-same=NDOB\fR] [\fI\-\-scat\-file=SF\fR]
-[\fI\-\-scat\-raw\fR] [\fI\-\-scattered=RD\fR] [\fI\-\-stream=ID\fR]
-[\fI\-\-strict\fR] [\fI\-\-tag\-mask=TM\fR] [\fI\-\-timeout=TO\fR]
-[\fI\-\-unmap=U_A\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
-[\fI\-\-wrprotect=WPR\fR] \fIDEVICE\fR
+[\fI\-\-quiet\fR] [\fI\-\-ref\-tag=RT\fR] [\fI\-\-same=NDOB\fR]
+[\fI\-\-scat\-file=SF\fR] [\fI\-\-scat\-raw\fR] [\fI\-\-scattered=RD\fR]
+[\fI\-\-stream=ID\fR] [\fI\-\-strict\fR] [\fI\-\-tag\-mask=TM\fR]
+[\fI\-\-timeout=TO\fR] [\fI\-\-unmap=U_A\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] [\fI\-\-wrprotect=WPR\fR] \fIDEVICE\fR
.PP
Synopsis per supported command:
.PP
@@ -344,6 +344,11 @@ extra fields that are set with the \fI\-\-bmop=OP,PGP\fR and
command in this utility that does not require a \fIDEVICE\fR formatted with
type 1, 2 or 3 PI (although it will still work if it is formatted with PI).
.TP
+\fB\-Q\fR, \fB\-\-quiet\fR
+suppress some informational messages such as the ones associated with
+detected errors when this utility is about to exit. The exit status value
+is still returned to the operating system when this utility exits.
+.TP
\fB\-r\fR, \fB\-\-ref\-tag\fR=\fIRT\fR
where \fIRT\fR is the "expected initial logical block reference tag" field
found in the 32 byte cdb variants of WRITE, WRITE ATOMIC, WRITE SAME and
diff --git a/include/freebsd_nvme_ioctl.h b/include/freebsd_nvme_ioctl.h
index f5761430..a7c970b9 100644
--- a/include/freebsd_nvme_ioctl.h
+++ b/include/freebsd_nvme_ioctl.h
@@ -1,3 +1,6 @@
+#ifndef FREEBSD_NVME_IOCTL_H
+#define FREEBSD_NVME_IOCTL_H
+
/*-
* Copyright (C) 2012-2013 Intel Corporation
* All rights reserved.
@@ -25,131 +28,141 @@
*
* $FreeBSD$
*/
-
-
+
+
#include <sys/param.h>
-#define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct nvme_pt_command)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct nvme_pt_command)
#if __FreeBSD_version < 1100110
struct nvme_command
{
- /* dword 0 */
- uint16_t opc : 8; /* opcode */
- uint16_t fuse : 2; /* fused operation */
- uint16_t rsvd1 : 6;
- uint16_t cid; /* command identifier */
-
- /* dword 1 */
- uint32_t nsid; /* namespace identifier */
-
- /* dword 2-3 */
- uint32_t rsvd2;
- uint32_t rsvd3;
-
- /* dword 4-5 */
- uint64_t mptr; /* metadata pointer */
-
- /* dword 6-7 */
- uint64_t prp1; /* prp entry 1 */
-
- /* dword 8-9 */
- uint64_t prp2; /* prp entry 2 */
-
- /* dword 10-15 */
- uint32_t cdw10; /* command-specific */
- uint32_t cdw11; /* command-specific */
- uint32_t cdw12; /* command-specific */
- uint32_t cdw13; /* command-specific */
- uint32_t cdw14; /* command-specific */
- uint32_t cdw15; /* command-specific */
+ /* dword 0 */
+ uint16_t opc : 8; /* opcode */
+ uint16_t fuse : 2; /* fused operation */
+ uint16_t rsvd1 : 6;
+ uint16_t cid; /* command identifier */
+
+ /* dword 1 */
+ uint32_t nsid; /* namespace identifier */
+
+ /* dword 2-3 */
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+
+ /* dword 4-5 */
+ uint64_t mptr; /* metadata pointer */
+
+ /* dword 6-7 */
+ uint64_t prp1; /* prp entry 1 */
+
+ /* dword 8-9 */
+ uint64_t prp2; /* prp entry 2 */
+
+ /* dword 10-15 */
+ uint32_t cdw10; /* command-specific */
+ uint32_t cdw11; /* command-specific */
+ uint32_t cdw12; /* command-specific */
+ uint32_t cdw13; /* command-specific */
+ uint32_t cdw14; /* command-specific */
+ uint32_t cdw15; /* command-specific */
} __packed;
struct nvme_status {
- uint16_t p : 1; /* phase tag */
- uint16_t sc : 8; /* status code */
- uint16_t sct : 3; /* status code type */
- uint16_t rsvd2 : 2;
- uint16_t m : 1; /* more */
- uint16_t dnr : 1; /* do not retry */
+ uint16_t p : 1; /* phase tag */
+ uint16_t sc : 8; /* status code */
+ uint16_t sct : 3; /* status code type */
+ uint16_t rsvd2 : 2;
+ uint16_t m : 1; /* more */
+ uint16_t dnr : 1; /* do not retry */
} __packed;
struct nvme_completion {
- /* dword 0 */
- uint32_t cdw0; /* command-specific */
+ /* dword 0 */
+ uint32_t cdw0; /* command-specific */
- /* dword 1 */
- uint32_t rsvd1;
+ /* dword 1 */
+ uint32_t rsvd1;
- /* dword 2 */
- uint16_t sqhd; /* submission queue head pointer */
- uint16_t sqid; /* submission queue identifier */
+ /* dword 2 */
+ uint16_t sqhd; /* submission queue head pointer */
+ uint16_t sqid; /* submission queue identifier */
- /* dword 3 */
- uint16_t cid; /* command identifier */
- struct nvme_status status;
+ /* dword 3 */
+ uint16_t cid; /* command identifier */
+ struct nvme_status status;
} __packed;
struct nvme_pt_command {
- /*
- * cmd is used to specify a passthrough command to a controller or
- * namespace.
- *
- * The following fields from cmd may be specified by the caller:
- * * opc (opcode)
- * * nsid (namespace id) - for admin commands only
- * * cdw10-cdw15
- *
- * Remaining fields must be set to 0 by the caller.
- */
- struct nvme_command cmd;
-
- /*
- * cpl returns completion status for the passthrough command
- * specified by cmd.
- *
- * The following fields will be filled out by the driver, for
- * consumption by the caller:
- * * cdw0
- * * status (except for phase)
- *
- * Remaining fields will be set to 0 by the driver.
- */
- struct nvme_completion cpl;
-
- /* buf is the data buffer associated with this passthrough command. */
- void * buf;
-
- /*
- * len is the length of the data buffer associated with this
- * passthrough command.
- */
- uint32_t len;
-
- /*
- * is_read = 1 if the passthrough command will read data into the
- * supplied buffer from the controller.
- *
- * is_read = 0 if the passthrough command will write data from the
- * supplied buffer to the controller.
- */
- uint32_t is_read;
-
- /*
- * driver_lock is used by the driver only. It must be set to 0
- * by the caller.
- */
- struct mtx * driver_lock;
+ /*
+ * cmd is used to specify a passthrough command to a controller or
+ * namespace.
+ *
+ * The following fields from cmd may be specified by the caller:
+ * * opc (opcode)
+ * * nsid (namespace id) - for admin commands only
+ * * cdw10-cdw15
+ *
+ * Remaining fields must be set to 0 by the caller.
+ */
+ struct nvme_command cmd;
+
+ /*
+ * cpl returns completion status for the passthrough command
+ * specified by cmd.
+ *
+ * The following fields will be filled out by the driver, for
+ * consumption by the caller:
+ * * cdw0
+ * * status (except for phase)
+ *
+ * Remaining fields will be set to 0 by the driver.
+ */
+ struct nvme_completion cpl;
+
+ /* buf is the data buffer associated with this passthrough command. */
+ void * buf;
+
+ /*
+ * len is the length of the data buffer associated with this
+ * passthrough command.
+ */
+ uint32_t len;
+
+ /*
+ * is_read = 1 if the passthrough command will read data into the
+ * supplied buffer from the controller.
+ *
+ * is_read = 0 if the passthrough command will write data from the
+ * supplied buffer to the controller.
+ */
+ uint32_t is_read;
+
+ /*
+ * driver_lock is used by the driver only. It must be set to 0
+ * by the caller.
+ */
+ struct mtx * driver_lock;
};
#else
#include <dev/nvme/nvme.h>
#endif
-#define nvme_completion_is_error(cpl) \
- ((cpl)->status.sc != 0 || (cpl)->status.sct != 0)
+#define nvme_completion_is_error(cpl) \
+ ((cpl)->status.sc != 0 || (cpl)->status.sct != 0)
+
+#define NVME_CTRLR_PREFIX "/dev/nvme"
+#define NVME_NS_PREFIX "ns"
+
+#ifdef __cplusplus
+}
+#endif
-#define NVME_CTRLR_PREFIX "/dev/nvme"
-#define NVME_NS_PREFIX "ns"
+#endif /* for FREEBSD_NVME_IOCTL_H */
diff --git a/include/sg_lib.h b/include/sg_lib.h
index c479bc29..ca91f7dd 100644
--- a/include/sg_lib.h
+++ b/include/sg_lib.h
@@ -443,6 +443,7 @@ bool sg_exit2str(int exit_status, bool longer, int b_len, char * b);
#define SG_LIB_CAT_SENSE 98 /* Something else is in the sense buffer */
#define SG_LIB_CAT_OTHER 99 /* Some other error/warning has occurred */
/* (e.g. a transport or driver error) */
+#define SG_LIB_UNUSED_ABOVE 99 /* Put extra errors in holes below this */
/* Returns a SG_LIB_CAT_* value. If cannot decode sense_buffer or a less
* common sense key then return SG_LIB_CAT_SENSE .*/
diff --git a/include/sg_pt.h b/include/sg_pt.h
index 712e9075..c2e1aad5 100644
--- a/include/sg_pt.h
+++ b/include/sg_pt.h
@@ -220,4 +220,4 @@ int scsi_pt_win32_spt_state(void);
}
#endif
-#endif
+#endif /* SG_PT_H */
diff --git a/include/sg_pt_win32.h b/include/sg_pt_win32.h
index b49437f9..a19485d4 100644
--- a/include/sg_pt_win32.h
+++ b/include/sg_pt_win32.h
@@ -470,4 +470,4 @@ typedef struct _NVME_PASS_THROUGH_IOCTL
}
#endif
-#endif
+#endif /* SG_PT_WIN32_H */
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index a27d27b6..bfb95380 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -1949,19 +1949,29 @@ sg_if_can2fp(const char * leadin, int exit_status, FILE * fp)
char b[256];
const char * s = leadin ? leadin : "";
- if (sg_exit2str(exit_status, false, sizeof(b), b)) {
+ if (0 == exit_status)
+ return true; /* don't print anything */
+ else if (sg_exit2str(exit_status, false, sizeof(b), b)) {
fprintf(fp, "%s%s\n", s, b);
return true;
} else
return false;
}
+/* This examines exit_status and if an error message is known it is output
+ * to stdout/stderr and true is returned. If no error message is
+ * available nothing is output and false is returned. If exit_status is
+ * zero (no error) nothing is output and true is returned. If exit_status
+ * is negative then nothing is output and false is returned. If leadin is
+ * non-NULL then it is printed before the error message. All messages are
+ * a single line with a trailing LF. */
bool
sg_if_can2stdout(const char * leadin, int exit_status)
{
return sg_if_can2fp(leadin, exit_status, stdout);
}
+/* See sg_if_can2stdout() comments */
bool
sg_if_can2stderr(const char * leadin, int exit_status)
{
diff --git a/src/sg_inq.c b/src/sg_inq.c
index de3251ed..8397a708 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -27,9 +27,6 @@
#include <inttypes.h>
#include <errno.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
#ifdef SG_LIB_LINUX
#include <sys/ioctl.h>
#include <sys/types.h>
@@ -37,6 +34,10 @@
#include <linux/hdreg.h>
#endif
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include "sg_lib.h"
#include "sg_lib_data.h"
#include "sg_cmds_basic.h"
@@ -47,7 +48,7 @@
#include "sg_pt_nvme.h"
#endif
-static const char * version_str = "1.88 20180218"; /* SPC-5 rev 19 */
+static const char * version_str = "1.89 20180227"; /* SPC-5 rev 19 */
/* INQUIRY notes:
* It is recommended that the initial allocation length given to a
@@ -119,7 +120,7 @@ static const char * version_str = "1.88 20180218"; /* SPC-5 rev 19 */
#define VPD_DI_SEL_TARGET 4
#define VPD_DI_SEL_AS_IS 32
-#define DEF_ALLOC_LEN 252
+#define DEF_ALLOC_LEN 252 /* highest 1 byte value that is modulo 4 */
#define SAFE_STD_INQ_RESP_LEN 36
#define MX_ALLOC_LEN (0xc000 + 0x80)
#define VPD_ATA_INFO_LEN 572
@@ -141,7 +142,8 @@ static const char * find_version_descriptor_str(int value);
static void decode_dev_ids(const char * leadin, uint8_t * buff,
int len, int do_hex, int verbose);
-#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
+#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
+ defined(HDIO_GET_IDENTITY)
static int try_ata_identify(int ata_fd, int do_hex, int do_raw,
int verbose);
struct opts_t;
@@ -212,7 +214,8 @@ static struct svpd_values_name_t vpd_pg[] = {
};
static struct option long_options[] = {
-#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
+#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
+ defined(HDIO_GET_IDENTITY)
{"ata", no_argument, 0, 'a'},
#endif
{"block", required_argument, 0, 'B'},
@@ -277,7 +280,9 @@ struct opts_t {
static void
usage()
{
-#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
+#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
+ defined(HDIO_GET_IDENTITY)
+
pr2serr("Usage: sg_inq [--ata] [--block=0|1] [--cmddt] [--descriptors] "
"[--export]\n"
" [--extended] [--help] [--hex] [--id] [--inhex=FN] "
@@ -465,7 +470,8 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
break;
switch (c) {
-#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
+#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
+ defined(HDIO_GET_IDENTITY)
case 'a':
op->do_ata = true;
break;
@@ -3105,7 +3111,7 @@ std_inq_decode(const struct opts_t * op, int act_len)
/* When sg_fd >= 0 fetch VPD page from device; mxlen is command line
* --maxlen=LEN option (def: 0) or -1 for a VPD page with a short length
- * (1 byte). When sg_fd < 0 then mxlen bytes have been read from
+ * field (1 byte). When sg_fd < 0 then mxlen bytes have been read from
* --inhex=FN file. Returns 0 for success. */
static int
vpd_fetch_page_from_dev(int sg_fd, uint8_t * rp, int page,
@@ -3185,17 +3191,26 @@ static int
fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len, int verbose)
{
int len, k, res, c;
- uint8_t b[DEF_ALLOC_LEN];
+ uint8_t * b;
+ uint8_t * free_b;
+ b = sg_memalign(DEF_ALLOC_LEN, 0, &free_b, false);
+ if (NULL == b) {
+ pr2serr("%s: unable to allocate on heap\n", __func__);
+ return sg_convert_errno(ENOMEM);
+ }
res = vpd_fetch_page_from_dev(sg_fd, b, VPD_SUPPORTED_VPDS,
- -1,verbose, &len);
+ -1 /* 1 byte alloc_len */, verbose, &len);
if (res) {
if (verbose > 2)
- pr2serr("fetch_unit_serial_num: no supported VPDs page\n");
- return SG_LIB_CAT_MALFORMED;
+ pr2serr("%s: no supported VPDs page\n", __func__);
+ res = SG_LIB_CAT_MALFORMED;
+ goto fini;
+ }
+ if (vpd_page_not_supported(b, len, VPD_UNIT_SERIAL_NUM)) {
+ res = SG_LIB_CAT_ILLEGAL_REQ;
+ goto fini;
}
- if (vpd_page_not_supported(b, len, VPD_UNIT_SERIAL_NUM))
- return SG_LIB_CAT_ILLEGAL_REQ;
memset(b, 0xff, 4); /* guard against empty response */
res = vpd_fetch_page_from_dev(sg_fd, b, VPD_UNIT_SERIAL_NUM, -1, verbose,
@@ -3213,17 +3228,21 @@ fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len, int verbose)
break;
}
obuff[k] = '\0';
- return 0;
+ res = 0;
+ goto fini;
} else {
if (verbose > 2)
- pr2serr("fetch_unit_serial_num: bad sn VPD page\n");
- return SG_LIB_CAT_MALFORMED;
+ pr2serr("%s: bad sn VPD page\n", __func__);
+ res = SG_LIB_CAT_MALFORMED;
}
} else {
if (verbose > 2)
- pr2serr("fetch_unit_serial_num: no supported VPDs page\n");
- return SG_LIB_CAT_MALFORMED;
+ pr2serr("%s: no supported VPDs page\n", __func__);
+ res = SG_LIB_CAT_MALFORMED;
}
+fini:
+ if (free_b)
+ free(free_b);
return res;
}
@@ -3281,13 +3300,14 @@ std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len)
std_inq_decode(op, act_len);
return 0;
} else if (res < 0) { /* could be an ATA device */
-#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
+#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
+ defined(HDIO_GET_IDENTITY)
/* Try an ATA Identify Device command */
res = try_ata_identify(sg_fd, op->do_hex, op->do_raw, vb);
if (0 != res) {
pr2serr("SCSI INQUIRY, NVMe Identify and fetching ATA "
"information failed on %s\n", op->device_name);
- return SG_LIB_CAT_OTHER;
+ return (res < 0) ? SG_LIB_CAT_OTHER : res;
}
#else
pr2serr("SCSI INQUIRY failed on %s, res=%d\n",
@@ -4117,14 +4137,18 @@ do_nvme_identify(int pt_fd, const struct opts_t * op)
ptvp = construct_scsi_pt_obj_with_fd(pt_fd, vb);
if (NULL == ptvp) {
pr2serr("%s: memory problem\n", __func__);
- return SG_LIB_CAT_OTHER;
+ return sg_convert_errno(ENOMEM);
}
memset(id_cmdp, 0, sizeof(*id_cmdp));
id_cmdp->opcode = 0x6;
nsid = get_pt_nvme_nsid(ptvp);
/* leave id_cmdp->nsid at 0 */
id_cmdp->cdw10 = 0x1; /* CNS=0x1 Identify controller */
- id_dinp = sg_memalign(pg_sz, pg_sz, &free_id_dinp, vb > 3);
+ id_dinp = sg_memalign(pg_sz, pg_sz, &free_id_dinp, false);
+ if (NULL == id_dinp) {
+ pr2serr("%s: sg_memalign problem\n", __func__);
+ return sg_convert_errno(ENOMEM);
+ }
set_scsi_pt_data_in(ptvp, id_dinp, pg_sz);
set_scsi_pt_cdb(ptvp, (const uint8_t *)id_cmdp, sizeof(*id_cmdp));
set_scsi_pt_sense(ptvp, resp, sizeof(resp));
@@ -4437,7 +4461,8 @@ main(int argc, char * argv[])
ret = vpd_mainly_hex(-1, op, inhex_len);
goto err_out;
}
-#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
+#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
+ defined(HDIO_GET_IDENTITY)
else if (op->do_ata) {
prepare_ata_identify(op, inhex_len);
ret = 0;
@@ -4501,7 +4526,8 @@ main(int argc, char * argv[])
}
#endif
-#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
+#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
+ defined(HDIO_GET_IDENTITY)
if (op->do_ata) {
res = try_ata_identify(sg_fd, op->do_hex, op->do_raw,
op->verbose);
@@ -4541,7 +4567,8 @@ main(int argc, char * argv[])
#if (HAVE_NVME && (! IGNORE_NVME))
fini2:
#endif
-#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
+#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
+ defined(HDIO_GET_IDENTITY)
fini3:
#endif
@@ -4563,7 +4590,8 @@ err_out:
}
-#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
+#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
+ defined(HDIO_GET_IDENTITY)
/* Following code permits ATA IDENTIFY commands to be performed on
ATA non "Packet Interface" devices (e.g. ATA disks).
GPL-ed code borrowed from smartmontools (smartmontools.sf.net).
@@ -4605,6 +4633,7 @@ struct ata_identify_device {
static int
ata_command_interface(int device, char *data, bool * atapi_flag, int verbose)
{
+ int err;
uint8_t buff[ATA_IDENTIFY_BUFF_SZ + HDIO_DRIVE_CMD_OFFSET];
unsigned short get_ident[256];
@@ -4612,7 +4641,8 @@ ata_command_interface(int device, char *data, bool * atapi_flag, int verbose)
*atapi_flag = false;
memset(buff, 0, sizeof(buff));
if (ioctl(device, HDIO_GET_IDENTITY, &get_ident) < 0) {
- if (ENOTTY == errno) {
+ err = errno;
+ if (ENOTTY == err) {
if (verbose > 1)
pr2serr("HDIO_GET_IDENTITY failed with ENOTTY, "
"try HDIO_DRIVE_CMD ioctl ...\n");
@@ -4622,16 +4652,16 @@ ata_command_interface(int device, char *data, bool * atapi_flag, int verbose)
if (verbose)
pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) "
"ioctl failed:\n\t%s [%d]\n",
- safe_strerror(errno), errno);
- return errno;
+ safe_strerror(err), err);
+ return sg_convert_errno(err);
}
memcpy(data, buff + HDIO_DRIVE_CMD_OFFSET, ATA_IDENTIFY_BUFF_SZ);
return 0;
} else {
if (verbose)
pr2serr("HDIO_GET_IDENTITY ioctl failed:\n"
- "\t%s [%d]\n", safe_strerror(errno), errno);
- return errno;
+ "\t%s [%d]\n", safe_strerror(err), err);
+ return sg_convert_errno(err);
}
} else if (verbose > 1)
pr2serr("HDIO_GET_IDENTITY succeeded\n");
@@ -4642,18 +4672,18 @@ ata_command_interface(int device, char *data, bool * atapi_flag, int verbose)
buff[0] = ATA_IDENTIFY_PACKET_DEVICE;
buff[3] = 1;
if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
+ err = errno;
if (verbose)
- pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_PACKET_DEVICE) "
- "ioctl failed:\n\t%s [%d]\n", safe_strerror(errno),
- errno);
+ pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_PACKET_DEVICE) ioctl "
+ "failed:\n\t%s [%d]\n", safe_strerror(err), err);
buff[0] = ATA_IDENTIFY_DEVICE;
buff[3] = 1;
if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
+ err = errno;
if (verbose)
- pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) "
- "ioctl failed:\n\t%s [%d]\n", safe_strerror(errno),
- errno);
- return errno;
+ pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) ioctl "
+ "failed:\n\t%s [%d]\n", safe_strerror(err), err);
+ return sg_convert_errno(err);
}
} else if (atapi_flag) {
*atapi_flag = true;
@@ -4664,10 +4694,11 @@ ata_command_interface(int device, char *data, bool * atapi_flag, int verbose)
buff[0] = ATA_IDENTIFY_DEVICE;
buff[3] = 1;
if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
+ err = errno;
if (verbose)
pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) ioctl failed:"
- "\n\t%s [%d]\n", safe_strerror(errno), errno);
- return errno;
+ "\n\t%s [%d]\n", safe_strerror(err), err);
+ return sg_convert_errno(err);
} else if (verbose > 1)
pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) succeeded\n");
}
diff --git a/src/sg_persist.c b/src/sg_persist.c
index 0e811789..339e91a3 100644
--- a/src/sg_persist.c
+++ b/src/sg_persist.c
@@ -33,7 +33,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "0.61 20180221";
+static const char * version_str = "0.62 20180226";
#define PRIN_RKEY_SA 0x0
@@ -1257,7 +1257,6 @@ main(int argc, char * argv[])
goto fini;
}
sg_cmds_close_device(sg_fd);
- sg_fd = -1;
}
if (! op->readwrite_force) {
diff --git a/src/sg_raw.c b/src/sg_raw.c
index bea6ee69..73f61e02 100644
--- a/src/sg_raw.c
+++ b/src/sg_raw.c
@@ -804,8 +804,6 @@ main(int argc, char *argv[])
}
goto done;
} else if (ret < 0) {
- int err;
-
k = -ret;
pr2serr("do_scsi_pt: %s\n", safe_strerror(k));
err = get_scsi_pt_os_err(ptvp);
diff --git a/src/sg_write_x.c b/src/sg_write_x.c
index f5dd128a..20418d3e 100644
--- a/src/sg_write_x.c
+++ b/src/sg_write_x.c
@@ -36,7 +36,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.13 20180217";
+static const char * version_str = "1.14 20180227";
/* Protection Information refers to 8 bytes of extra information usually
* associated with each logical block and is often abbreviated to PI while
@@ -107,6 +107,7 @@ static struct option long_options[] = {
{"num", required_argument, 0, 'n'},
{"offset", required_argument, 0, 'o'},
{"or", no_argument, 0, 'O'},
+ {"quiet", no_argument, 0, 'Q'},
{"ref-tag", required_argument, 0, 'r'},
{"ref_tag", required_argument, 0, 'r'},
{"same", required_argument, 0, 'M'},
@@ -135,6 +136,7 @@ struct opts_t {
/* --atomic=AB AB --> .atomic_boundary */
bool do_combined; /* -c DOF --> .scat_lbdof */
bool do_or; /* -O ORWRITE(16 or 32) */
+ bool do_quiet; /* -Q suppress some messages */
bool do_scat_raw;
bool do_same; /* -M WRITE SAME(16 or 32) */
/* --same=NDOB NDOB --> .ndob */
@@ -210,20 +212,22 @@ usage(int do_help)
" [--fua] [--generation=EOG,NOG] [--grpnum=GN] "
"[--help] --in=IF\n"
" [--lba=LBA,LBA...] [--normal] [--num=NUM,NUM...]\n"
- " [--offset=OFF[,DLEN]] [--or] [--ref-tag=RT] "
- "[--same=NDOB]\n"
- " [--scat-file=SF] [--scat-raw] [--scattered=RD] "
- "[--stream=ID]\n"
- " [--strict] [--tag-mask=TM] [--timeout=TO] "
- "[--unmap=U_A]\n"
- " [--verbose] [--version] [--wrprotect=WRP] DEVICE\n");
+ " [--offset=OFF[,DLEN]] [--or] [--quiet] "
+ "[--ref-tag=RT]\n"
+ " [--same=NDOB] [--scat-file=SF] [--scat-raw] "
+ "[--scattered=RD]\n"
+ " [--stream=ID] [--strict] [--tag-mask=TM] "
+ "[--timeout=TO]\n"
+ " [--unmap=U_A] [--verbose] [--version] "
+ "[--wrprotect=WRP]\n"
+ " DEVICE\n");
if (1 != do_help) {
pr2serr("\nOr the corresponding short option usage:\n"
"sg_write_x [-6] [-3] [-a AT] [-A AB] [-B OP,PGP] [-b BS] "
"[-c DOF] [-D DLD]\n"
" [-d] [-x] [-f] [-G EOG,NOG] [-g GN] [-h] -i IF "
"[-l LBA,LBA...]\n"
- " [-N] [-n NUM,NUM...] [-o OFF[,DLEN]] [-O] "
+ " [-N] [-n NUM,NUM...] [-o OFF[,DLEN]] [-O] [-Q] "
"[-r RT] [-M NDOB]\n"
" [-q SF] [-R] [-S RD] [-T ID] [-s] [-t TM] [-I TO] "
"[-u U_A] [-v]\n"
@@ -295,6 +299,7 @@ usage(int do_help)
" |-o OFF[,DLEN] (def: 0), then read DLEN bytes(def: "
"rest of IF)\n"
" --or|-O send ORWRITE command\n"
+ " --quiet|-Q suppress some informational messages\n"
" --ref-tag=RT|-r RT expected reference tag field (def: "
"0xffffffff)\n"
" --same=NDOB|-M NDOB send WRITE SAME command. NDOB (no "
@@ -1476,7 +1481,7 @@ do_read_capacity(int sg_fd, struct opts_t *op)
#define WANT_ZERO_EXIT 9999
static const char * const opt_long_ctl_str =
- "36a:A:b:B:c:dD:Efg:G:hi:I:l:M:n:No:Oq:r:RsS:t:T:u:vVw:x";
+ "36a:A:b:B:c:dD:Efg:G:hi:I:l:M:n:No:Oq:Qr:RsS:t:T:u:vVw:x";
/* command line processing, options and arguments. Returns 0 if ok,
* returns WANT_ZERO_EXIT so upper level yields an exist status of zero.
@@ -1703,6 +1708,9 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[],
case 'q':
op->scat_filename = optarg;
break;
+ case 'Q':
+ op->do_quiet = true;
+ break;
case 'R':
op->do_scat_raw = true;
break;
@@ -1827,7 +1835,7 @@ process_scattered(int sg_fd, int infd, uint32_t if_len, uint32_t if_rlen,
"unknown length\nthen give up\n");
return SG_LIB_SYNTAX_ERROR;
}
- up = sg_memalign(d, 0, &free_up, vb > 4);
+ up = sg_memalign(d, 0, &free_up, false);
if (NULL == up) {
pr2serr("unable to allocate aligned memory for "
"scatterlist+data\n");
@@ -1894,7 +1902,7 @@ process_scattered(int sg_fd, int infd, uint32_t if_len, uint32_t if_rlen,
goto file_err_outt;
}
}
- u2p = sg_memalign(dd, 0, &free_u2p, vb > 4);
+ u2p = sg_memalign(dd, 0, &free_u2p, false);
if (NULL == u2p) {
pr2serr("unable to allocate memory for final "
"scatterlist+data\n");
@@ -1929,7 +1937,7 @@ process_scattered(int sg_fd, int infd, uint32_t if_len, uint32_t if_rlen,
d = sum_num * op->bs_pi_do;
do_len = dd + d;
/* zeroed data-out buffer for SL+DATA */
- up = sg_memalign(do_len, 0, &free_up, vb > 4);
+ up = sg_memalign(do_len, 0, &free_up, false);
if (NULL == up) {
pr2serr("unable to allocate aligned memory for "
"scatterlist+data\n");
@@ -2018,7 +2026,7 @@ process_scattered(int sg_fd, int infd, uint32_t if_len, uint32_t if_rlen,
d = op->bs_pi_do; /* guess one LB */
/* zero data-out buffer for SL+DATA */
nn = dd + d;
- up = sg_memalign(nn, 0, &free_up, vb > 4);
+ up = sg_memalign(nn, 0, &free_up, false);
if (NULL == up) {
pr2serr("unable to allocate aligned memory for "
"scatterlist+data\n");
@@ -2040,7 +2048,7 @@ process_scattered(int sg_fd, int infd, uint32_t if_len, uint32_t if_rlen,
d = sum_num * op->bs_pi_do;
nn = dd + d;
- u2p = sg_memalign(nn, 0, &free_u2p, vb > 4);
+ u2p = sg_memalign(nn, 0, &free_u2p, false);
if (NULL == u2p) {
pr2serr("unable to allocate memory for final "
"scatterlist+data\n");
@@ -2082,7 +2090,7 @@ process_scattered(int sg_fd, int infd, uint32_t if_len, uint32_t if_rlen,
for (sum_num = 0, k = 0; k < (int)addr_arr_len; ++k)
sum_num += num_arr[k];
do_len = ((op->scat_lbdof + sum_num) * op->bs_pi_do);
- up = sg_memalign(do_len, 0, &free_up, vb > 4);
+ up = sg_memalign(do_len, 0, &free_up, false);
if (NULL == up) {
pr2serr("unable to allocate aligned memory for "
"scatterlist+data\n");
@@ -2549,7 +2557,7 @@ main(int argc, char * argv[])
if (do_len > 0) {
/* fill allocated buffer with zeros */
- up = sg_memalign(do_len, 0, &free_up, vb > 4);
+ up = sg_memalign(do_len, 0, &free_up, false);
if (NULL == up) {
pr2serr("unable to allocate %u bytes of memory\n", do_len);
ret = SG_LIB_OS_BASE_ERR + ENOMEM;
@@ -2563,7 +2571,7 @@ main(int argc, char * argv[])
up = NULL;
ret = do_write_x(sg_fd, up, do_len, op);
- if (ret) {
+ if (ret && (! op->do_quiet)) {
strcpy(b,"OS error");
if (ret > 0)
sg_get_category_sense_str(ret, sizeof(b), b, vb);
@@ -2583,24 +2591,32 @@ fini:
if (sg_fd >= 0) {
res = sg_cmds_close_device(sg_fd);
if (res < 0) {
- pr2serr("sg_fd close error: %s\n", safe_strerror(-res));
+ if (! op->do_quiet)
+ pr2serr("sg_fd close error: %s\n", safe_strerror(-res));
if (0 == ret)
ret = SG_LIB_FILE_ERROR;
}
}
if (sfr_fd >= 0) {
if (close(sfr_fd) < 0) {
- perror("sfr_fd close error");
+ if (! op->do_quiet)
+ perror("sfr_fd close error");
if (0 == ret)
ret = SG_LIB_FILE_ERROR;
}
}
if ((! got_stdin) && (infd >= 0)) {
if (close(infd) < 0) {
- perror("infd close error");
+ if (! op->do_quiet)
+ perror("infd close error");
if (0 == ret)
ret = SG_LIB_FILE_ERROR;
}
}
+ if ((0 == op->verbose) && (! op->do_quiet)) {
+ if (! sg_if_can2stderr("sg_write_x failed: ", ret))
+ pr2serr("Some error occurred, try again with '-v' or '-vv' for "
+ "more information\n");
+ }
return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}