aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBart Van Assche <bvanassche@google.com>2022-11-23 16:34:49 -0800
committerJaegeuk Kim <jaegeuk@kernel.org>2022-11-23 16:47:21 -0800
commitfb6575e583c9aeca1e719ee373cb448f629dfd47 (patch)
tree063440f2025b7a7dd2dea3b44830647e6dd7e622
parent1bb669e872ac2026e5e58f977ab65e8caf58e918 (diff)
downloadf2fs-tools-fb6575e583c9aeca1e719ee373cb448f629dfd47.tar.gz
Remove sg_write_buffer
Remove the sg_write_buffer source code and build rules now that the sg3_utils project has been imported. Signed-off-by: Bart Van Assche <bvanassche@google.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--.gitignore1
-rw-r--r--configure.ac1
-rw-r--r--tools/Makefile.am2
-rw-r--r--tools/sg_write_buffer/Android.bp27
-rw-r--r--tools/sg_write_buffer/Makefile.am18
-rw-r--r--tools/sg_write_buffer/include/freebsd_nvme_ioctl.h156
-rw-r--r--tools/sg_write_buffer/include/sg_cmds.h21
-rw-r--r--tools/sg_write_buffer/include/sg_cmds_basic.h310
-rw-r--r--tools/sg_write_buffer/include/sg_cmds_extra.h369
-rw-r--r--tools/sg_write_buffer/include/sg_cmds_mmc.h52
-rw-r--r--tools/sg_write_buffer/include/sg_io_linux.h185
-rw-r--r--tools/sg_write_buffer/include/sg_lib.h602
-rw-r--r--tools/sg_write_buffer/include/sg_lib_data.h121
-rw-r--r--tools/sg_write_buffer/include/sg_linux_inc.h56
-rw-r--r--tools/sg_write_buffer/include/sg_pr2serr.h30
-rw-r--r--tools/sg_write_buffer/include/sg_pt.h215
-rw-r--r--tools/sg_write_buffer/include/sg_pt_linux.h171
-rw-r--r--tools/sg_write_buffer/include/sg_pt_nvme.h172
-rw-r--r--tools/sg_write_buffer/include/sg_pt_win32.h473
-rw-r--r--tools/sg_write_buffer/include/sg_unaligned.h325
-rw-r--r--tools/sg_write_buffer/sg_cmds_basic.c663
-rw-r--r--tools/sg_write_buffer/sg_cmds_basic2.c1069
-rw-r--r--tools/sg_write_buffer/sg_cmds_extra.c2524
-rw-r--r--tools/sg_write_buffer/sg_cmds_mmc.c382
-rw-r--r--tools/sg_write_buffer/sg_io_linux.c256
-rw-r--r--tools/sg_write_buffer/sg_lib.c3494
-rw-r--r--tools/sg_write_buffer/sg_lib_data.c1688
-rw-r--r--tools/sg_write_buffer/sg_pt_common.c141
-rw-r--r--tools/sg_write_buffer/sg_pt_linux.c964
-rw-r--r--tools/sg_write_buffer/sg_pt_linux_nvme.c1185
-rw-r--r--tools/sg_write_buffer/sg_write_buffer.c516
31 files changed, 1 insertions, 16188 deletions
diff --git a/.gitignore b/.gitignore
index c1341da..9acac42 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,7 +51,6 @@ stamp-h1
/tools/parse.f2fs
/tools/f2fscrypt
/tools/f2fs_io/f2fs_io
-/tools/sg_write_buffer/sg_write_buffer
# cscope files
cscope.*
diff --git a/configure.ac b/configure.ac
index d3f9fb1..818ff37 100644
--- a/configure.ac
+++ b/configure.ac
@@ -260,7 +260,6 @@ AC_CONFIG_FILES([
mkfs/Makefile
fsck/Makefile
tools/Makefile
- tools/sg_write_buffer/Makefile
tools/f2fs_io/Makefile
])
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 8756a29..8dd963a 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -17,4 +17,4 @@ f2fscrypt_LDFLAGS = ${libuuid_LIBS}
dist_man_MANS = f2fscrypt.8
endif
-SUBDIRS = sg_write_buffer f2fs_io
+SUBDIRS = f2fs_io
diff --git a/tools/sg_write_buffer/Android.bp b/tools/sg_write_buffer/Android.bp
deleted file mode 100644
index 5222a59..0000000
--- a/tools/sg_write_buffer/Android.bp
+++ /dev/null
@@ -1,27 +0,0 @@
-cc_defaults {
- name: "sg3-utils-defaults",
- cflags: [
- "-Wno-unused-function"
- ],
- local_include_dirs: [
- "include",
- ],
-}
-
-cc_binary {
- name: "sg_write_buffer",
- defaults: [ "sg3-utils-defaults" ],
- srcs: [
- "sg_write_buffer.c",
- "sg_cmds_basic.c",
- "sg_cmds_basic2.c",
- "sg_cmds_extra.c",
- "sg_cmds_mmc.c",
- "sg_io_linux.c",
- "sg_lib.c",
- "sg_lib_data.c",
- "sg_pt_common.c",
- "sg_pt_linux.c",
- "sg_pt_linux_nvme.c",
- ],
-}
diff --git a/tools/sg_write_buffer/Makefile.am b/tools/sg_write_buffer/Makefile.am
deleted file mode 100644
index 19c438d..0000000
--- a/tools/sg_write_buffer/Makefile.am
+++ /dev/null
@@ -1,18 +0,0 @@
-## Makefile.am
-
-if LINUX
-AM_CPPFLAGS = -I$(srcdir)/include
-AM_CFLAGS = -Wall
-sbin_PROGRAMS = sg_write_buffer
-sg_write_buffer_SOURCES = sg_write_buffer.c \
- sg_cmds_basic.c \
- sg_cmds_basic2.c \
- sg_cmds_extra.c \
- sg_cmds_mmc.c \
- sg_io_linux.c \
- sg_lib.c \
- sg_lib_data.c \
- sg_pt_common.c \
- sg_pt_linux.c \
- sg_pt_linux_nvme.c
-endif
diff --git a/tools/sg_write_buffer/include/freebsd_nvme_ioctl.h b/tools/sg_write_buffer/include/freebsd_nvme_ioctl.h
deleted file mode 100644
index f5d2443..0000000
--- a/tools/sg_write_buffer/include/freebsd_nvme_ioctl.h
+++ /dev/null
@@ -1,156 +0,0 @@
-PROPS-END
-/*-
- * Copyright (C) 2012-2013 Intel Corporation
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-
-#include <sys/param.h>
-
-#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 */
-} __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 */
-} __packed;
-
-struct nvme_completion {
-
- /* dword 0 */
- uint32_t cdw0; /* command-specific */
-
- /* dword 1 */
- uint32_t rsvd1;
-
- /* 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;
-} __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;
-};
-#else
-#include <dev/nvme/nvme.h>
-#endif
-
-#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"
diff --git a/tools/sg_write_buffer/include/sg_cmds.h b/tools/sg_write_buffer/include/sg_cmds.h
deleted file mode 100644
index 690f53a..0000000
--- a/tools/sg_write_buffer/include/sg_cmds.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef SG_CMDS_H
-#define SG_CMDS_H
-
-/********************************************************************
- * This header did contain wrapper declarations for many SCSI commands
- * up until sg3_utils version 1.22 . In that version, the command
- * wrappers were broken into two groups, the 'basic' ones found in the
- * "sg_cmds_basic.h" header and the 'extra' ones found in the
- * "sg_cmds_extra.h" header. This header now simply includes those two
- * headers.
- * In sg3_utils version 1.26 the sg_cmds_mmc.h header was added and
- * contains some MMC specific commands.
- * The corresponding function definitions are found in the sg_cmds_basic.c,
- * sg_cmds_extra.c and sg_cmds_mmc.c files.
- ********************************************************************/
-
-#include "sg_cmds_basic.h"
-#include "sg_cmds_extra.h"
-#include "sg_cmds_mmc.h"
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_cmds_basic.h b/tools/sg_write_buffer/include/sg_cmds_basic.h
deleted file mode 100644
index 507effa..0000000
--- a/tools/sg_write_buffer/include/sg_cmds_basic.h
+++ /dev/null
@@ -1,310 +0,0 @@
-#ifndef SG_CMDS_BASIC_H
-#define SG_CMDS_BASIC_H
-
-/*
- * Copyright (c) 2004-2017 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-/*
- * Error, warning and verbose output is sent to the file pointed to by
- * sg_warnings_strm which is declared in sg_lib.h and can be set with
- * the sg_set_warnings_strm() function. If not given sg_warnings_strm
- * defaults to stderr.
- * If 'noisy' is false and 'verbose' is zero then following functions should
- * not output anything to sg_warnings_strm. If 'noisy' is true and
- * 'verbose' is zero then Unit Attention, Recovered, Medium and Hardware
- * errors (sense keys) send output to sg_warnings_strm. Increasing values
- * of 'verbose' send increasing amounts of (debug) output to
- * sg_warnings_strm.
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Invokes a SCSI INQUIRY command and yields the response
- * Returns 0 when successful, SG_LIB_CAT_INVALID_OP -> not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
- * SG_LIB_CAT_ABORTED_COMMAND, -1 -> other errors */
-int sg_ll_inquiry(int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when
- * successful, various SG_LIB_CAT_* positive values or -1 -> other errors.
- * The CMDDT field is obsolete in the INQUIRY cdb (since spc3r16 in 2003) so
- * an argument to set it has been removed (use the REPORT SUPPORTED OPERATION
- * CODES command instead). Adds the ability to set the command abort timeout
- * and the ability to report the residual count. If timeout_secs is zero
- * or less the default command abort timeout (60 seconds) is used.
- * If residp is non-NULL then the residual value is written where residp
- * points. A residual value of 0 implies mx_resp_len bytes have be written
- * where resp points. If the residual value equals mx_resp_len then no
- * bytes have been written. */
-int
-sg_ll_inquiry_v2(int sg_fd, bool evpd, int pg_op, void * resp,
- int mx_resp_len, int timeout_secs, int * residp,
- bool noisy, int verbose);
-
-/* Invokes a SCSI LOG SELECT command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Log Select not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_NOT_READY -> device not ready,
- * -1 -> other failure */
-int sg_ll_log_select(int sg_fd, bool pcr, bool sp, int pc, int pg_code,
- int subpg_code, unsigned char * paramp, int param_len,
- bool noisy, int verbose);
-
-/* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Log Sense not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_log_sense(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
- int subpg_code, int paramp, unsigned char * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Same as sg_ll_log_sense() apart from timeout_secs and residp. See
- * sg_ll_inquiry_v2() for their description */
-int sg_ll_log_sense_v2(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
- int subpg_code, int paramp, unsigned char * resp,
- int mx_resp_len, int timeout_secs, int * residp,
- bool noisy, int verbose);
-
-/* Invokes a SCSI MODE SELECT (6) command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
- * bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_mode_select6(int sg_fd, bool pf, bool sp, void * paramp,
- int param_len, bool noisy, int verbose);
-
-/* Invokes a SCSI MODE SELECT (10) command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
- * bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_mode_select10(int sg_fd, bool pf, bool sp, void * paramp,
- int param_len, bool noisy, int verbose);
-
-/* Invokes a SCSI MODE SENSE (6) command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
- * bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_mode_sense6(int sg_fd, bool dbd, int pc, int pg_code,
- int sub_pg_code, void * resp, int mx_resp_len,
- bool noisy, int verbose);
-
-/* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
- * bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_mode_sense10(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
- int sub_pg_code, void * resp, int mx_resp_len,
- bool noisy, int verbose);
-
-/* Same as sg_ll_mode_sense10() apart from timeout_secs and residp. See
- * sg_ll_inquiry_v2() for their description */
-int sg_ll_mode_sense10_v2(int sg_fd, bool llbaa, bool dbd, int pc,
- int pg_code, int sub_pg_code, void * resp,
- int mx_resp_len, int timeout_secs, int * residp,
- bool noisy, int verbose);
-
-/* Invokes a SCSI PREVENT ALLOW MEDIUM REMOVAL command (SPC-3)
- * prevent==0 allows removal, prevent==1 prevents removal ...
- * Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> command not supported
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_prevent_allow(int sg_fd, int prevent, bool noisy, int verbose);
-
-/* Invokes a SCSI READ CAPACITY (10) command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_UNIT_ATTENTION
- * -> perhaps media changed, SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_readcap_10(int sg_fd, bool pmi, unsigned int lba, void * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success,
- * SG_LIB_CAT_UNIT_ATTENTION -> media changed??, SG_LIB_CAT_INVALID_OP
- * -> cdb not supported, SG_LIB_CAT_IlLEGAL_REQ -> bad field in cdb
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_readcap_16(int sg_fd, bool pmi, uint64_t llba, void * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Report Luns not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_NOT_READY (shouldn't happen), -1 -> other failure */
-int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Invokes a SCSI REQUEST SENSE command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Request Sense not supported??,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_request_sense(int sg_fd, bool desc, void * resp, int mx_resp_len,
- bool noisy, int verbose);
-
-/* Invokes a SCSI START STOP UNIT command (SBC + MMC).
- * Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Start stop unit not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure
- * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and
- * format_layer_number(mmc) fields. They also overlap on the noflush(sbc)
- * and fl(mmc) one bit field. This is the cause of the awkardly named
- * pc_mod__fl_num and noflush__fl arguments to this function. */
-int sg_ll_start_stop_unit(int sg_fd, bool immed, int pc_mod__fl_num,
- int power_cond, bool noflush__fl, bool loej,
- bool start, bool noisy, int verbose);
-
-/* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_INVALID_OP -> cdb not supported,
- * SG_LIB_CAT_IlLEGAL_REQ -> bad field in cdb
- * SG_LIB_CAT_NOT_READY -> device not ready, -1 -> other failure */
-int sg_ll_sync_cache_10(int sg_fd, bool sync_nv, bool immed, int group,
- unsigned int lba, unsigned int count, bool noisy,
- int verbose);
-
-/* Invokes a SCSI TEST UNIT READY command.
- * 'pack_id' is just for diagnostics, safe to set to 0.
- * Return of 0 -> success, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready,
- * SG_LIB_CAT_ABORTED_COMMAND, -1 -> other failure */
-int sg_ll_test_unit_ready(int sg_fd, int pack_id, bool noisy, int verbose);
-
-/* Invokes a SCSI TEST UNIT READY command.
- * 'pack_id' is just for diagnostics, safe to set to 0.
- * Looks for progress indicator if 'progress' non-NULL;
- * if found writes value [0..65535] else write -1.
- * Return of 0 -> success, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_ABORTED_COMMAND, SG_LIB_CAT_NOT_READY ->
- * device not ready, -1 -> other failure */
-int sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress,
- bool noisy, int verbose);
-
-
-struct sg_simple_inquiry_resp {
- unsigned char peripheral_qualifier;
- unsigned char peripheral_type;
- unsigned char byte_1; /* was 'rmb' prior to version 1.39 */
- /* now rmb == !!(0x80 & byte_1) */
- unsigned char version; /* as per recent drafts: whole of byte 2 */
- unsigned char byte_3;
- unsigned char byte_5;
- unsigned char byte_6;
- unsigned char byte_7;
- char vendor[9]; /* T10 field is 8 bytes, NUL char appended */
- char product[17];
- char revision[5];
-};
-
-/* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response.
- * Returns 0 when successful, SG_LIB_CAT_INVALID_OP -> not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other errors */
-int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
- bool noisy, int verbose);
-
-/* MODE SENSE commands yield a response that has header then zero or more
- * block descriptors followed by mode pages. In most cases users are
- * interested in the first mode page. This function returns the (byte)
- * offset of the start of the first mode page. Set mode_sense_6 to true for
- * MODE SENSE (6) and false for MODE SENSE (10). Returns >= 0 is successful
- * or -1 if failure. If there is a failure a message is written to err_buff
- * if it is non-NULL and err_buff_len > 0. */
-int sg_mode_page_offset(const unsigned char * resp, int resp_len,
- bool mode_sense_6, char * err_buff, int err_buff_len);
-
-/* MODE SENSE commands yield a response that has header then zero or more
- * block descriptors followed by mode pages. This functions returns the
- * length (in bytes) of those three components. Note that the return value
- * can exceed resp_len in which case the MODE SENSE command should be
- * re-issued with a larger response buffer. If bd_lenp is non-NULL and if
- * successful the block descriptor length (in bytes) is written to *bd_lenp.
- * Set mode_sense_6 to true for MODE SENSE (6) and false for MODE SENSE (10)
- * responses. Returns -1 if there is an error (e.g. response too short). */
-int sg_msense_calc_length(const unsigned char * resp, int resp_len,
- bool mode_sense_6, int * bd_lenp);
-
-/* Fetches current, changeable, default and/or saveable modes pages as
- * indicated by pcontrol_arr for given pg_code and sub_pg_code. If
- * mode6==0 then use MODE SENSE (10) else use MODE SENSE (6). If
- * flexible set and mode data length seems wrong then try and
- * fix (compensating hack for bad device or driver). pcontrol_arr
- * should have 4 elements for output of current, changeable, default
- * and saved values respectively. Each element should be NULL or
- * at least mx_mpage_len bytes long.
- * Return of 0 -> overall success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready,
- * SG_LIB_CAT_MALFORMED -> bad response, -1 -> other failure.
- * If success_mask pointer is not NULL then first zeros it. Then set bits
- * 0, 1, 2 and/or 3 if the current, changeable, default and saved values
- * respectively have been fetched. If error on current page
- * then stops and returns that error; otherwise continues if an error is
- * detected but returns the first error encountered. */
-int sg_get_mode_page_controls(int sg_fd, bool mode6, int pg_code,
- int sub_pg_code, bool dbd, bool flexible,
- int mx_mpage_len, int * success_mask,
- void * pcontrol_arr[], int * reported_lenp,
- int verbose);
-
-/* Returns file descriptor >= 0 if successful. If error in Unix returns
- negated errno. Implementation calls scsi_pt_open_device(). */
-int sg_cmds_open_device(const char * device_name, bool read_only, int verbose);
-
-/* Returns file descriptor >= 0 if successful. If error in Unix returns
- negated errno. Implementation calls scsi_pt_open_flags(). */
-int sg_cmds_open_flags(const char * device_name, int flags, int verbose);
-
-/* Returns 0 if successful. If error in Unix returns negated errno.
- Implementation calls scsi_pt_close_device(). */
-int sg_cmds_close_device(int device_fd);
-
-const char * sg_cmds_version();
-
-#define SG_NO_DATA_IN 0
-
-struct sg_pt_base;
-
-/* This is a helper function used by sg_cmds_* implementations after the
- * call to the pass-through. pt_res is returned from do_scsi_pt(). If valid
- * sense data is found it is decoded and output to sg_warnings_strm (def:
- * stderr); depending on the 'noisy' and 'verbose' settings. Returns -2 for
- * sense data (may not be fatal), -1 for failed, 0, or a positive number. If
- * 'mx_di_len > 0' then asks pass-through for resid and returns
- * (mx_di_len - resid); otherwise returns 0. So for data-in it should return
- * the actual number of bytes received. For data-out (to device) or no data
- * call with 'mx_di_len' set to 0 or less. If -2 returned then sense category
- * output via 'o_sense_cat' pointer (if not NULL). Note that several sense
- * categories also have data in bytes received; -2 is still returned. */
-int sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin,
- int pt_res, int mx_di_len,
- const unsigned char * sense_b, bool noisy,
- int verbose, int * o_sense_cat);
-
-/* NVMe devices use a different command set. This function will return true
- * if the device associated with 'pvtp' is a NVME device, else it will
- * return false (e.g. for SCSI devices). */
-bool sg_cmds_is_nvme(const struct sg_pt_base * ptvp);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_cmds_extra.h b/tools/sg_write_buffer/include/sg_cmds_extra.h
deleted file mode 100644
index fbc2377..0000000
--- a/tools/sg_write_buffer/include/sg_cmds_extra.h
+++ /dev/null
@@ -1,369 +0,0 @@
-#ifndef SG_CMDS_EXTRA_H
-#define SG_CMDS_EXTRA_H
-
-/*
- * Copyright (c) 2004-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Note: all functions that have an 'int timeout_secs' argument will use
- * that value if it is > 0. Otherwise they will set an internal default
- * which is currently 60 seconds. This timeout is typically applied in the
- * SCSI stack above the initiator. If it goes off then the SCSI command is
- * aborted and there can be other unwelcome side effects. Note that some
- * commands (e.g. FORMAT UNIT and the Third Party copy commands) can take
- * a lot longer than the default timeout. */
-
-
-/* Invokes a ATA PASS-THROUGH (12, 16 or 32) SCSI command (SAT). This is
- * selected by the cdb_len argument that can take values of 12, 16 or 32
- * only (else -1 is returned). The byte at offset 0 (and bytes 0 to 9
- * inclusive for ATA PT(32)) pointed to be cdbp are ignored and apart from
- * the control byte, the rest is copied into an internal cdb which is then
- * sent to the device. The control byte is byte 11 for ATA PT(12), byte 15
- * for ATA PT(16) and byte 1 for ATA PT(32). If timeout_secs <= 0 then the
- * timeout is set to 60 seconds. For data in or out transfers set dinp or
- * doutp, and dlen to the number of bytes to transfer. If dlen is zero then
- * no data transfer is assumed. If sense buffer obtained then it is written
- * to sensep, else sensep[0] is set to 0x0. If ATA return descriptor is
- * obtained then written to ata_return_dp, else ata_return_dp[0] is set to
- * 0x0. Either sensep or ata_return_dp (or both) may be NULL pointers.
- * Returns SCSI status value (>= 0) or -1 if other error. Users are
- * expected to check the sense buffer themselves. If available the data in
- * resid is written to residp. Note in SAT-2 and later, fixed format sense
- * data may be placed in *sensep in which case sensep[0]==0x70, prior to
- * SAT-2 descriptor sense format was required (i.e. sensep[0]==0x72).
- */
-int sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
- int timeout_secs, void * dinp, void * doutp, int dlen,
- unsigned char * sensep, int max_sense_len,
- unsigned char * ata_return_dp, int max_ata_return_len,
- int * residp, int verbose);
-
-/* Invokes a FORMAT UNIT (SBC-3) command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Format unit not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure. Note that sg_ll_format_unit2() and
- * sg_ll_format_unit_v2() are the same, both add the ffmt argument. */
-int sg_ll_format_unit(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata,
- bool cmplist, int dlist_format, int timeout_secs,
- void * paramp, int param_len, bool noisy, int verbose);
-int sg_ll_format_unit2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata,
- bool cmplist, int dlist_format, int ffmt,
- int timeout_secs, void * paramp, int param_len,
- bool noisy, int verbose);
-int sg_ll_format_unit_v2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata,
- bool cmplist, int dlist_format, int ffmt,
- int timeout_secs, void * paramp, int param_len,
- bool noisy, int verbose);
-
-/* Invokes a SCSI GET LBA STATUS(16) or GET LBA STATUS(32) command (SBC).
- * Returns 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> GET LBA STATUS(16 or 32) not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_NOT_READY -> device not ready, -1 -> other failure.
- * sg_ll_get_lba_status() calls the 16 byte variant with rt=0 . */
-int sg_ll_get_lba_status(int sg_fd, uint64_t start_llba, void * resp,
- int alloc_len, bool noisy, int verbose);
-int sg_ll_get_lba_status16(int sg_fd, uint64_t start_llba, uint8_t rt,
- void * resp, int alloc_len, bool noisy,
- int verbose);
-int sg_ll_get_lba_status32(int sg_fd, uint64_t start_llba, uint32_t scan_len,
- uint32_t element_id, uint8_t rt,
- void * resp, int alloc_len, bool noisy,
- int verbose);
-
-/* Invokes a SCSI PERSISTENT RESERVE IN command (SPC). Returns 0
- * when successful, SG_LIB_CAT_INVALID_OP if command not supported,
- * SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */
-int sg_ll_persistent_reserve_in(int sg_fd, int rq_servact, void * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Invokes a SCSI PERSISTENT RESERVE OUT command (SPC). Returns 0
- * when successful, SG_LIB_CAT_INVALID_OP if command not supported,
- * SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */
-int sg_ll_persistent_reserve_out(int sg_fd, int rq_servact, int rq_scope,
- unsigned int rq_type, void * paramp,
- int param_len, bool noisy, int verbose);
-
-/* Invokes a SCSI READ BLOCK LIMITS command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> READ BLOCK LIMITS not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_NOT_READY (shouldn't happen), -1 -> other failure */
-int sg_ll_read_block_limits(int sg_fd, void * resp, int mx_resp_len,
- bool noisy, int verbose);
-
-/* Invokes a SCSI READ BUFFER command (SPC). Return of 0 ->
- * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_read_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset,
- void * resp, int mx_resp_len, bool noisy, int verbose);
-
-/* Invokes a SCSI READ DEFECT DATA (10) command (SBC). Return of 0 ->
- * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_read_defect10(int sg_fd, bool req_plist, bool req_glist,
- int dl_format, void * resp, int mx_resp_len,
- bool noisy, int verbose);
-
-/* Invokes a SCSI READ LONG (10) command (SBC). Note that 'xfer_len'
- * is in bytes. Returns 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> READ LONG(10) not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
- * SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO -> bad field in cdb, with info
- * field written to 'offsetp', SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_read_long10(int sg_fd, bool pblock, bool correct, unsigned int lba,
- void * resp, int xfer_len, int * offsetp, bool noisy,
- int verbose);
-
-/* Invokes a SCSI READ LONG (16) command (SBC). Note that 'xfer_len'
- * is in bytes. Returns 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> READ LONG(16) not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
- * SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO -> bad field in cdb, with info
- * field written to 'offsetp', SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_read_long16(int sg_fd, bool pblock, bool correct, uint64_t llba,
- void * resp, int xfer_len, int * offsetp, bool noisy,
- int verbose);
-
-/* Invokes a SCSI READ MEDIA SERIAL NUMBER command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Read media serial number not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_read_media_serial_num(int sg_fd, void * resp, int mx_resp_len,
- bool noisy, int verbose);
-
-/* Invokes a SCSI REASSIGN BLOCKS command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_NOT_READY -> device not ready, -1 -> other failure */
-int sg_ll_reassign_blocks(int sg_fd, bool longlba, bool longlist,
- void * paramp, int param_len, bool noisy,
- int verbose);
-
-/* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Receive diagnostic results not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_receive_diag(int sg_fd, bool pcv, int pg_code, void * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Same as sg_ll_receive_diag() but with added timeout_secs and residp
- * arguments. Adds the ability to set the command abort timeout
- * and the ability to report the residual count. If timeout_secs is zero
- * or less the default command abort timeout (60 seconds) is used.
- * If residp is non-NULL then the residual value is written where residp
- * points. A residual value of 0 implies mx_resp_len bytes have be written
- * where resp points. If the residual value equals mx_resp_len then no
- * bytes have been written. */
-int sg_ll_receive_diag_v2(int sg_fd, bool pcv, int pg_code, void * resp,
- int mx_resp_len, int timeout_secs, int * residp,
- bool noisy, int verbose);
-
-/* Invokes a SCSI REPORT IDENTIFYING INFORMATION command. This command was
- * called REPORT DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Report identifying information not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_report_id_info(int sg_fd, int itype, void * resp, int max_resp_len,
- bool noisy, int verbose);
-
-/* Invokes a SCSI REPORT TARGET PORT GROUPS command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Report Target Port Groups not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_UNIT_ATTENTION, -1 -> other failure */
-int sg_ll_report_tgt_prt_grp(int sg_fd, void * resp, int mx_resp_len,
- bool noisy, int verbose);
-int sg_ll_report_tgt_prt_grp2(int sg_fd, void * resp, int mx_resp_len,
- bool extended, bool noisy, int verbose);
-
-/* Invokes a SCSI SET TARGET PORT GROUPS command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Report Target Port Groups not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_UNIT_ATTENTION, -1 -> other failure */
-int sg_ll_set_tgt_prt_grp(int sg_fd, void * paramp, int param_len, bool noisy,
- int verbose);
-
-/* Invokes a SCSI REPORT REFERRALS command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Report Referrals not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_UNIT_ATTENTION, -1 -> other failure */
-int sg_ll_report_referrals(int sg_fd, uint64_t start_llba, bool one_seg,
- void * resp, int mx_resp_len, bool noisy,
- int verbose);
-
-/* Invokes a SCSI SEND DIAGNOSTIC command. Foreground, extended self tests can
- * take a long time, if so set long_duration flag in which case the timeout
- * is set to 7200 seconds; if the value of long_duration is > 7200 then that
- * value is taken as the timeout value in seconds. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Send diagnostic not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_send_diag(int sg_fd, int st_code, bool pf_bit, bool st_bit,
- bool devofl_bit, bool unitofl_bit, int long_duration,
- void * paramp, int param_len, bool noisy, int verbose);
-
-/* Invokes a SCSI SET IDENTIFYING INFORMATION command. This command was
- * called SET DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Set identifying information not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_set_id_info(int sg_fd, int itype, void * paramp, int param_len,
- bool noisy, int verbose);
-
-/* Invokes a SCSI UNMAP (SBC-3) command. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> command not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_UNIT_ATTENTION, -1 -> other failure */
-int sg_ll_unmap(int sg_fd, int group_num, int timeout_secs, void * paramp,
- int param_len, bool noisy, int verbose);
-/* Invokes a SCSI UNMAP (SBC-3) command. Version 2 adds anchor field
- * (sbc3r22). Otherwise same as sg_ll_unmap() . */
-int sg_ll_unmap_v2(int sg_fd, bool anchor, int group_num, int timeout_secs,
- void * paramp, int param_len, bool noisy, int verbose);
-
-/* Invokes a SCSI VERIFY (10) command (SBC and MMC).
- * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes.
- * Returns of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Verify(10) not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_MEDIUM_HARD -> medium or hardware error, no valid info,
- * SG_LIB_CAT_MEDIUM_HARD_WITH_INFO -> as previous, with valid info,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_MISCOMPARE, -1 -> other failure */
-int sg_ll_verify10(int sg_fd, int vrprotect, bool dpo, int bytechk,
- unsigned int lba, int veri_len, void * data_out,
- int data_out_len, unsigned int * infop, bool noisy,
- int verbose);
-
-/* Invokes a SCSI VERIFY (16) command (SBC).
- * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes.
- * Returns of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Verify(16) not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_MEDIUM_HARD -> medium or hardware error, no valid info,
- * SG_LIB_CAT_MEDIUM_HARD_WITH_INFO -> as previous, with valid info,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_MISCOMPARE, -1 -> other failure */
-int sg_ll_verify16(int sg_fd, int vrprotect, bool dpo, int bytechk,
- uint64_t llba, int veri_len, int group_num,
- void * data_out, int data_out_len, uint64_t * infop,
- bool noisy, int verbose);
-
-/* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 ->
- * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_write_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset,
- void * paramp, int param_len, bool noisy, int verbose);
-
-/* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 ->
- * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure. Adds mode specific field (spc4r32) and timeout
- * to command abort to override default of 60 seconds. If timeout_secs is
- * 0 or less then the default timeout is used instead. */
-int
-sg_ll_write_buffer_v2(int sg_fd, int mode, int m_specific, int buffer_id,
- uint32_t buffer_offset, void * paramp,
- uint32_t param_len, int timeout_secs, bool noisy,
- int verbose);
-
-/* Invokes a SCSI WRITE LONG (10) command (SBC). Note that 'xfer_len'
- * is in bytes. Returns 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> WRITE LONG(10) not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
- * SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO -> bad field in cdb, with info
- * field written to 'offsetp', SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_write_long10(int sg_fd, bool cor_dis, bool wr_uncor, bool pblock,
- unsigned int lba, void * data_out, int xfer_len,
- int * offsetp, bool noisy, int verbose);
-
-/* Invokes a SCSI WRITE LONG (16) command (SBC). Note that 'xfer_len'
- * is in bytes. Returns 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> WRITE LONG(16) not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
- * SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO -> bad field in cdb, with info
- * field written to 'offsetp', SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_write_long16(int sg_fd, bool cor_dis, bool wr_uncor, bool pblock,
- uint64_t llba, void * data_out, int xfer_len,
- int * offsetp, bool noisy, int verbose);
-
-/* Invokes a SPC-3 SCSI RECEIVE COPY RESULTS command. In SPC-4 this function
- * supports all service action variants of the THIRD-PARTY COPY IN opcode.
- * SG_LIB_CAT_INVALID_OP -> Receive copy results not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_receive_copy_results(int sg_fd, int sa, int list_id, void * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Invokes a SCSI EXTENDED COPY(LID1) command. For EXTENDED COPY(LID4)
- * including POPULATE TOKEN and WRITE USING TOKEN use
- * sg_ll_3party_copy_out(). Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Extended copy not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_extended_copy(int sg_fd, void * paramp, int param_len, bool noisy,
- int verbose);
-
-/* Handles various service actions associated with opcode 0x83 which is
- * called THIRD PARTY COPY OUT. These include the EXTENDED COPY(LID4),
- * POPULATE TOKEN and WRITE USING TOKEN commands. Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> opcode 0x83 not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_3party_copy_out(int sg_fd, int sa, unsigned int list_id,
- int group_num, int timeout_secs, void * paramp,
- int param_len, bool noisy, int verbose);
-
-/* Invokes a SCSI PRE-FETCH(10), PRE-FETCH(16) or SEEK(10) command (SBC).
- * Returns 0 -> success, 25 (SG_LIB_CAT_CONDITION_MET), various SG_LIB_CAT_*
- * positive values or -1 -> other errors. Note that CONDITION MET status
- * is returned when immed=true and num_blocks can fit in device's cache,
- * somewaht strangely, GOOD status (return 0) is returned if num_blocks
- * cannot fit in device's cache. If do_seek10==true then does a SEEK(10)
- * command with given lba, if that LBA is < 2**32 . Unclear what SEEK(10)
- * does, assume it is like PRE-FETCH. If timeout_secs is 0 (or less) then
- * use DEF_PT_TIMEOUT (60 seconds) as command timeout. */
-int sg_ll_pre_fetch_x(int sg_fd, bool do_seek10, bool cdb16, bool immed,
- uint64_t lba, uint32_t num_blocks, int group_num,
- int timeout_secs, bool noisy, int verbose);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_cmds_mmc.h b/tools/sg_write_buffer/include/sg_cmds_mmc.h
deleted file mode 100644
index 3988b1d..0000000
--- a/tools/sg_write_buffer/include/sg_cmds_mmc.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef SG_CMDS_MMC_H
-#define SG_CMDS_MMC_H
-
-/*
- * Copyright (c) 2008-2017 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Invokes a SCSI GET CONFIGURATION command (MMC-3...6).
- * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not
- * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */
-int sg_ll_get_config(int sg_fd, int rt, int starting, void * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Invokes a SCSI GET PERFORMANCE command (MMC-3...6).
- * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not
- * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */
-int sg_ll_get_performance(int sg_fd, int data_type, unsigned int starting_lba,
- int max_num_desc, int type, void * resp,
- int mx_resp_len, bool noisy, int verbose);
-
-/* Invokes a SCSI SET CD SPEED command (MMC).
- * Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> command not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int sg_ll_set_cd_speed(int sg_fd, int rot_control, int drv_read_speed,
- int drv_write_speed, bool noisy, int verbose);
-
-/* Invokes a SCSI SET STREAMING command (MMC). Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Set Streaming not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_NOT_READY -> device not ready,
- * -1 -> other failure */
-int sg_ll_set_streaming(int sg_fd, int type, void * paramp, int param_len,
- bool noisy, int verbose);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_io_linux.h b/tools/sg_write_buffer/include/sg_io_linux.h
deleted file mode 100644
index bd44bd6..0000000
--- a/tools/sg_write_buffer/include/sg_io_linux.h
+++ /dev/null
@@ -1,185 +0,0 @@
-#ifndef SG_IO_LINUX_H
-#define SG_IO_LINUX_H
-
-/*
- * Copyright (c) 2004-2017 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-/*
- * Version 1.05 [20171009]
- */
-
-/*
- * This header file contains linux specific information related to the SCSI
- * command pass through in the SCSI generic (sg) driver and the linux
- * block layer.
- */
-
-#include "sg_lib.h"
-#include "sg_linux_inc.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The following are 'host_status' codes */
-#ifndef DID_OK
-#define DID_OK 0x00
-#endif
-#ifndef DID_NO_CONNECT
-#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */
-#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */
-#define DID_TIME_OUT 0x03 /* Timed out for some other reason */
-#define DID_BAD_TARGET 0x04 /* Bad target (id?) */
-#define DID_ABORT 0x05 /* Told to abort for some other reason */
-#define DID_PARITY 0x06 /* Parity error (on SCSI bus) */
-#define DID_ERROR 0x07 /* Internal error */
-#define DID_RESET 0x08 /* Reset by somebody */
-#define DID_BAD_INTR 0x09 /* Received an unexpected interrupt */
-#define DID_PASSTHROUGH 0x0a /* Force command past mid-level */
-#define DID_SOFT_ERROR 0x0b /* The low-level driver wants a retry */
-#endif
-#ifndef DID_IMM_RETRY
-#define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */
-#endif
-#ifndef DID_REQUEUE
-#define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also
- * without decrementing the retry count */
-#endif
-#ifndef DID_TRANSPORT_DISRUPTED
-#define DID_TRANSPORT_DISRUPTED 0xe
-#endif
-#ifndef DID_TRANSPORT_FAILFAST
-#define DID_TRANSPORT_FAILFAST 0xf
-#endif
-#ifndef DID_TARGET_FAILURE
-#define DID_TARGET_FAILURE 0x10
-#endif
-#ifndef DID_NEXUS_FAILURE
-#define DID_NEXUS_FAILURE 0x11
-#endif
-
-/* These defines are to isolate applications from kernel define changes */
-#define SG_LIB_DID_OK DID_OK
-#define SG_LIB_DID_NO_CONNECT DID_NO_CONNECT
-#define SG_LIB_DID_BUS_BUSY DID_BUS_BUSY
-#define SG_LIB_DID_TIME_OUT DID_TIME_OUT
-#define SG_LIB_DID_BAD_TARGET DID_BAD_TARGET
-#define SG_LIB_DID_ABORT DID_ABORT
-#define SG_LIB_DID_PARITY DID_PARITY
-#define SG_LIB_DID_ERROR DID_ERROR
-#define SG_LIB_DID_RESET DID_RESET
-#define SG_LIB_DID_BAD_INTR DID_BAD_INTR
-#define SG_LIB_DID_PASSTHROUGH DID_PASSTHROUGH
-#define SG_LIB_DID_SOFT_ERROR DID_SOFT_ERROR
-#define SG_LIB_DID_IMM_RETRY DID_IMM_RETRY
-#define SG_LIB_DID_REQUEUE DID_REQUEUE
-#define SG_LIB_TRANSPORT_DISRUPTED DID_TRANSPORT_DISRUPTED
-#define SG_LIB_DID_TRANSPORT_FAILFAST DID_TRANSPORT_FAILFAST
-#define SG_LIB_DID_TARGET_FAILURE DID_TARGET_FAILURE
-#define SG_LIB_DID_NEXUS_FAILURE DID_NEXUS_FAILURE
-
-/* The following are 'driver_status' codes */
-#ifndef DRIVER_OK
-#define DRIVER_OK 0x00
-#endif
-#ifndef DRIVER_BUSY
-#define DRIVER_BUSY 0x01
-#define DRIVER_SOFT 0x02
-#define DRIVER_MEDIA 0x03
-#define DRIVER_ERROR 0x04
-#define DRIVER_INVALID 0x05
-#define DRIVER_TIMEOUT 0x06
-#define DRIVER_HARD 0x07
-#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */
-
-/* N.B. the SUGGEST_* codes are no longer used in Linux and are only kept
- * to stop compilation breakages.
- * Following "suggests" are "or-ed" with one of previous 8 entries */
-#define SUGGEST_RETRY 0x10
-#define SUGGEST_ABORT 0x20
-#define SUGGEST_REMAP 0x30
-#define SUGGEST_DIE 0x40
-#define SUGGEST_SENSE 0x80
-#define SUGGEST_IS_OK 0xff
-#endif
-
-#ifndef DRIVER_MASK
-#define DRIVER_MASK 0x0f
-#endif
-#ifndef SUGGEST_MASK
-#define SUGGEST_MASK 0xf0
-#endif
-
-/* These defines are to isolate applications from kernel define changes */
-#define SG_LIB_DRIVER_OK DRIVER_OK
-#define SG_LIB_DRIVER_BUSY DRIVER_BUSY
-#define SG_LIB_DRIVER_SOFT DRIVER_SOFT
-#define SG_LIB_DRIVER_MEDIA DRIVER_MEDIA
-#define SG_LIB_DRIVER_ERROR DRIVER_ERROR
-#define SG_LIB_DRIVER_INVALID DRIVER_INVALID
-#define SG_LIB_DRIVER_TIMEOUT DRIVER_TIMEOUT
-#define SG_LIB_DRIVER_HARD DRIVER_HARD
-#define SG_LIB_DRIVER_SENSE DRIVER_SENSE
-
-
-/* N.B. the SUGGEST_* codes are no longer used in Linux and are only kept
- * to stop compilation breakages. */
-#define SG_LIB_SUGGEST_RETRY SUGGEST_RETRY
-#define SG_LIB_SUGGEST_ABORT SUGGEST_ABORT
-#define SG_LIB_SUGGEST_REMAP SUGGEST_REMAP
-#define SG_LIB_SUGGEST_DIE SUGGEST_DIE
-#define SG_LIB_SUGGEST_SENSE SUGGEST_SENSE
-#define SG_LIB_SUGGEST_IS_OK SUGGEST_IS_OK
-#define SG_LIB_DRIVER_MASK DRIVER_MASK
-#define SG_LIB_SUGGEST_MASK SUGGEST_MASK
-
-void sg_print_masked_status(int masked_status);
-void sg_print_host_status(int host_status);
-void sg_print_driver_status(int driver_status);
-
-/* sg_chk_n_print() returns 1 quietly if there are no errors/warnings
- else it prints errors/warnings (prefixed by 'leadin') to
- 'sg_warnings_fd' and returns 0. raw_sinfo indicates whether the
- raw sense buffer (in ASCII hex) should be printed. */
-int sg_chk_n_print(const char * leadin, int masked_status, int host_status,
- int driver_status, const unsigned char * sense_buffer,
- int sb_len, bool raw_sinfo);
-
-/* The following function declaration is for the sg version 3 driver. */
-struct sg_io_hdr;
-/* sg_chk_n_print3() returns 1 quietly if there are no errors/warnings;
- else it prints errors/warnings (prefixed by 'leadin') to
- 'sg_warnings_fd' and returns 0. */
-int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp,
- bool raw_sinfo);
-
-/* Calls sg_scsi_normalize_sense() after obtaining the sense buffer and
- its length from the struct sg_io_hdr pointer. If these cannot be
- obtained, false is returned. */
-bool sg_normalize_sense(const struct sg_io_hdr * hp,
- struct sg_scsi_sense_hdr * sshp);
-
-int sg_err_category(int masked_status, int host_status, int driver_status,
- const unsigned char * sense_buffer, int sb_len);
-
-int sg_err_category_new(int scsi_status, int host_status, int driver_status,
- const unsigned char * sense_buffer, int sb_len);
-
-/* The following function declaration is for the sg version 3 driver. */
-int sg_err_category3(struct sg_io_hdr * hp);
-
-
-/* Note about SCSI status codes found in older versions of Linux.
- Linux has traditionally used a 1 bit right shifted and masked
- version of SCSI standard status codes. Now CHECK_CONDITION
- and friends (in <scsi/scsi.h>) are deprecated. */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_lib.h b/tools/sg_write_buffer/include/sg_lib.h
deleted file mode 100644
index bc93d49..0000000
--- a/tools/sg_write_buffer/include/sg_lib.h
+++ /dev/null
@@ -1,602 +0,0 @@
-#ifndef SG_LIB_H
-#define SG_LIB_H
-
-/*
- * Copyright (c) 2004-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-/*
- *
- * On 5th October 2004 a FreeBSD license was added to this file.
- * The intention is to keep this file and the related sg_lib.c file
- * as open source and encourage their unencumbered use.
- *
- * Current version number is in the sg_lib.c file and can be accessed
- * with the sg_lib_version() function.
- */
-
-
-/*
- * This header file contains defines and function declarations that may
- * be useful to applications that communicate with devices that use a
- * SCSI command set. These command sets have names like SPC-4, SBC-3,
- * SSC-3, SES-2 and draft standards defining them can be found at
- * http://www.t10.org . Virtually all devices in the Linux SCSI subsystem
- * utilize SCSI command sets. Many devices in other Linux device subsystems
- * utilize SCSI command sets either natively or via emulation (e.g. a
- * parallel ATA disk in a USB enclosure).
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* SCSI Peripheral Device Types (PDT) [5 bit field] */
-#define PDT_DISK 0x0 /* direct access block device (disk) */
-#define PDT_TAPE 0x1 /* sequential access device (magnetic tape) */
-#define PDT_PRINTER 0x2 /* printer device (see SSC-1) */
-#define PDT_PROCESSOR 0x3 /* processor device (e.g. SAFTE device) */
-#define PDT_WO 0x4 /* write once device (some optical disks) */
-#define PDT_MMC 0x5 /* CD/DVD/BD (multi-media) */
-#define PDT_SCANNER 0x6 /* obsolete */
-#define PDT_OPTICAL 0x7 /* optical memory device (some optical disks) */
-#define PDT_MCHANGER 0x8 /* media changer device (e.g. tape robot) */
-#define PDT_COMMS 0x9 /* communications device (obsolete) */
-#define PDT_SAC 0xc /* storage array controller device */
-#define PDT_SES 0xd /* SCSI Enclosure Services (SES) device */
-#define PDT_RBC 0xe /* Reduced Block Commands (simplified PDT_DISK) */
-#define PDT_OCRW 0xf /* optical card read/write device */
-#define PDT_BCC 0x10 /* bridge controller commands */
-#define PDT_OSD 0x11 /* Object Storage Device (OSD) */
-#define PDT_ADC 0x12 /* Automation/drive commands (ADC) */
-#define PDT_SMD 0x13 /* Security Manager Device (SMD) */
-#define PDT_ZBC 0x14 /* Zoned Block Commands (ZBC) */
-#define PDT_WLUN 0x1e /* Well known logical unit (WLUN) */
-#define PDT_UNKNOWN 0x1f /* Unknown or no device type */
-
-#ifndef SAM_STAT_GOOD
-/* The SCSI status codes as found in SAM-4 at www.t10.org */
-#define SAM_STAT_GOOD 0x0
-#define SAM_STAT_CHECK_CONDITION 0x2
-#define SAM_STAT_CONDITION_MET 0x4
-#define SAM_STAT_BUSY 0x8
-#define SAM_STAT_INTERMEDIATE 0x10 /* obsolete in SAM-4 */
-#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14 /* obsolete in SAM-4 */
-#define SAM_STAT_RESERVATION_CONFLICT 0x18
-#define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */
-#define SAM_STAT_TASK_SET_FULL 0x28
-#define SAM_STAT_ACA_ACTIVE 0x30
-#define SAM_STAT_TASK_ABORTED 0x40
-#endif
-
-/* The SCSI sense key codes as found in SPC-4 at www.t10.org */
-#define SPC_SK_NO_SENSE 0x0
-#define SPC_SK_RECOVERED_ERROR 0x1
-#define SPC_SK_NOT_READY 0x2
-#define SPC_SK_MEDIUM_ERROR 0x3
-#define SPC_SK_HARDWARE_ERROR 0x4
-#define SPC_SK_ILLEGAL_REQUEST 0x5
-#define SPC_SK_UNIT_ATTENTION 0x6
-#define SPC_SK_DATA_PROTECT 0x7
-#define SPC_SK_BLANK_CHECK 0x8
-#define SPC_SK_VENDOR_SPECIFIC 0x9
-#define SPC_SK_COPY_ABORTED 0xa
-#define SPC_SK_ABORTED_COMMAND 0xb
-#define SPC_SK_RESERVED 0xc
-#define SPC_SK_VOLUME_OVERFLOW 0xd
-#define SPC_SK_MISCOMPARE 0xe
-#define SPC_SK_COMPLETED 0xf
-
-/* Transport protocol identifiers or just Protocol identifiers */
-#define TPROTO_FCP 0
-#define TPROTO_SPI 1
-#define TPROTO_SSA 2
-#define TPROTO_1394 3
-#define TPROTO_SRP 4 /* SCSI over RDMA */
-#define TPROTO_ISCSI 5
-#define TPROTO_SAS 6
-#define TPROTO_ADT 7
-#define TPROTO_ATA 8
-#define TPROTO_UAS 9 /* USB attached SCSI */
-#define TPROTO_SOP 0xa /* SCSI over PCIe */
-#define TPROTO_PCIE 0xb /* includes NVMe */
-#define TPROTO_NONE 0xf
-
-/* SCSI Feature Sets (sfs) */
-#define SCSI_FS_SPC_DISCOVERY_2016 0x1
-#define SCSI_FS_SBC_BASE_2010 0x102
-#define SCSI_FS_SBC_BASE_2016 0x101
-#define SCSI_FS_SBC_BASIC_PROV_2016 0x103
-#define SCSI_FS_SBC_DRIVE_MAINT_2016 0x104
-
-/* Often SCSI responses use the highest integer that can fit in a field
- * to indicate "unbounded" or limit does not apply. Sometimes represented
- * in output as "-1" for brevity */
-#define SG_LIB_UNBOUNDED_16BIT 0xffff
-#define SG_LIB_UNBOUNDED_32BIT 0xffffffffU
-#define SG_LIB_UNBOUNDED_64BIT 0xffffffffffffffffULL
-
-#if (__STDC_VERSION__ >= 199901L) /* C99 or later */
- typedef uintptr_t sg_uintptr_t;
-#else
- typedef unsigned long sg_uintptr_t;
-#endif
-
-
-/* The format of the version string is like this: "2.26 20170906" */
-const char * sg_lib_version();
-
-/* Returns length of SCSI command given the opcode (first byte).
- * Yields the wrong answer for variable length commands (opcode=0x7f)
- * and potentially some vendor specific commands. */
-int sg_get_command_size(unsigned char cdb_byte0);
-
-/* Command name given pointer to the cdb. Certain command names
- * depend on peripheral type (give 0 or -1 if unknown). Places command
- * name into buff and will write no more than buff_len bytes. */
-void sg_get_command_name(const unsigned char * cdbp, int peri_type,
- int buff_len, char * buff);
-
-/* Command name given only the first byte (byte 0) of a cdb and
- * peripheral type (give 0 or -1 if unknown). */
-void sg_get_opcode_name(unsigned char cdb_byte0, int peri_type, int buff_len,
- char * buff);
-
-/* Command name given opcode (byte 0), service action and peripheral type.
- * If no service action give 0, if unknown peripheral type give 0 or -1 . */
-void sg_get_opcode_sa_name(unsigned char cdb_byte0, int service_action,
- int peri_type, int buff_len, char * buff);
-
-/* Fetch scsi status string. */
-void sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff);
-
-/* This is a slightly stretched SCSI sense "descriptor" format header.
- * The addition is to allow the 0x70 and 0x71 response codes. The idea
- * is to place the salient data of both "fixed" and "descriptor" sense
- * format into one structure to ease application processing.
- * The original sense buffer should be kept around for those cases
- * in which more information is required (e.g. the LBA of a MEDIUM ERROR). */
-struct sg_scsi_sense_hdr {
- unsigned char response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
- unsigned char sense_key;
- unsigned char asc;
- unsigned char ascq;
- unsigned char byte4;
- unsigned char byte5;
- unsigned char byte6;
- unsigned char additional_length;
-};
-
-/* Maps the salient data from a sense buffer which is in either fixed or
- * descriptor format into a structure mimicking a descriptor format
- * header (i.e. the first 8 bytes of sense descriptor format).
- * If zero response code returns false. Otherwise returns true and if 'sshp'
- * is non-NULL then zero all fields and then set the appropriate fields in
- * that structure. sshp::additional_length is always 0 for response
- * codes 0x70 and 0x71 (fixed format). */
-bool sg_scsi_normalize_sense(const unsigned char * sensep, int sense_len,
- struct sg_scsi_sense_hdr * sshp);
-
-/* Attempt to find the first SCSI sense data descriptor that matches the
- * given 'desc_type'. If found return pointer to start of sense data
- * descriptor; otherwise (including fixed format sense data) returns NULL. */
-const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep,
- int sense_len, int desc_type);
-
-/* Get sense key from sense buffer. If successful returns a sense key value
- * between 0 and 15. If sense buffer cannot be decode, returns -1 . */
-int sg_get_sense_key(const unsigned char * sensep, int sense_len);
-
-/* Yield string associated with sense_key value. Returns 'buff'. */
-char * sg_get_sense_key_str(int sense_key, int buff_len, char * buff);
-
-/* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
-char * sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff);
-
-/* Returns true if valid bit set, false if valid bit clear. Irrespective the
- * information field is written out via 'info_outp' (except when it is
- * NULL). Handles both fixed and descriptor sense formats. */
-bool sg_get_sense_info_fld(const unsigned char * sensep, int sb_len,
- uint64_t * info_outp);
-
-/* Returns true if fixed format or command specific information descriptor
- * is found in the descriptor sense; else false. If available the command
- * specific information field (4 byte integer in fixed format, 8 byte
- * integer in descriptor format) is written out via 'cmd_spec_outp'.
- * Handles both fixed and descriptor sense formats. */
-bool sg_get_sense_cmd_spec_fld(const unsigned char * sensep, int sb_len,
- uint64_t * cmd_spec_outp);
-
-/* Returns true if any of the 3 bits (i.e. FILEMARK, EOM or ILI) are set.
- * In descriptor format if the stream commands descriptor not found
- * then returns false. Writes true or false corresponding to these bits to
- * the last three arguments if they are non-NULL. */
-bool sg_get_sense_filemark_eom_ili(const unsigned char * sensep, int sb_len,
- bool * filemark_p, bool * eom_p,
- bool * ili_p);
-
-/* Returns true if SKSV is set and sense key is NO_SENSE or NOT_READY. Also
- * returns true if progress indication sense data descriptor found. Places
- * progress field from sense data where progress_outp points. If progress
- * field is not available returns false. Handles both fixed and descriptor
- * sense formats. N.B. App should multiply by 100 and divide by 65536
- * to get percentage completion from given value. */
-bool sg_get_sense_progress_fld(const unsigned char * sensep, int sb_len,
- int * progress_outp);
-
-/* Closely related to sg_print_sense(). Puts decoded sense data in 'buff'.
- * Usually multiline with multiple '\n' including one trailing. If
- * 'raw_sinfo' set appends sense buffer in hex. 'leadin' is string prepended
- * to each line written to 'buff', NULL treated as "". Returns the number of
- * bytes written to 'buff' excluding the trailing '\0'.
- * N.B. prior to sg3_utils v 1.42 'leadin' was only prepended to the first
- * line output. Also this function returned type void. */
-int sg_get_sense_str(const char * leadin, const unsigned char * sense_buffer,
- int sb_len, bool raw_sinfo, int buff_len, char * buff);
-
-/* Decode descriptor format sense descriptors (assumes sense buffer is
- * in descriptor format). 'leadin' is string prepended to each line written
- * to 'b', NULL treated as "". Returns the number of bytes written to 'b'
- * excluding the trailing '\0'. */
-int sg_get_sense_descriptors_str(const char * leadin,
- const unsigned char * sense_buffer,
- int sb_len, int blen, char * b);
-
-/* Decodes a designation descriptor (e.g. as found in the Device
- * Identification VPD page (0x83)) into string 'b' whose maximum length is
- * blen. 'leadin' is string prepended to each line written to 'b', NULL
- * treated as "". Returns the number of bytes written to 'b' excluding the
- * trailing '\0'. */
-int sg_get_designation_descriptor_str(const char * leadin,
- const unsigned char * ddp, int dd_len,
- bool print_assoc, bool do_long,
- int blen, char * b);
-
-/* Yield string associated with peripheral device type (pdt). Returns
- * 'buff'. If 'pdt' out of range yields "bad pdt" string. */
-char * sg_get_pdt_str(int pdt, int buff_len, char * buff);
-
-/* Some lesser used PDTs share a lot in common with a more used PDT.
- * Examples are PDT_ADC decaying to PDT_TAPE and PDT_ZBC to PDT_DISK.
- * If such a lesser used 'pdt' is given to this function, then it will
- * return the more used PDT (i.e. "decays to"); otherwise 'pdt' is returned.
- * Valid for 'pdt' 0 to 31, for other values returns 0. */
-int sg_lib_pdt_decay(int pdt);
-
-/* Yield string associated with transport protocol identifier (tpi). Returns
- * 'buff'. If 'tpi' out of range yields "bad tpi" string. */
-char * sg_get_trans_proto_str(int tpi, int buff_len, char * buff);
-
-/* Decode TransportID pointed to by 'bp' of length 'bplen'. Place decoded
- * string output in 'buff' which is also the return value. Each new line
- * is prefixed by 'leadin'. If leadin NULL treat as "". */
-char * sg_decode_transportid_str(const char * leadin, unsigned char * bp,
- int bplen, bool only_one, int buff_len,
- char * buff);
-
-/* Returns a designator's type string given 'val' (0 to 15 inclusive),
- * otherwise returns NULL. */
-const char * sg_get_desig_type_str(int val);
-
-/* Returns a designator's code_set string given 'val' (0 to 15 inclusive),
- * otherwise returns NULL. */
-const char * sg_get_desig_code_set_str(int val);
-
-/* Returns a designator's association string given 'val' (0 to 3 inclusive),
- * otherwise returns NULL. */
-const char * sg_get_desig_assoc_str(int val);
-
-/* Yield SCSI Feature Set (sfs) string. When 'peri_type' is < -1 (or > 31)
- * returns pointer to string (same as 'buff') associated with 'sfs_code'.
- * When 'peri_type' is between -1 (for SPC) and 31 (inclusive) then a match
- * on both 'sfs_code' and 'peri_type' is required. If 'foundp' is not NULL
- * then where it points is set to true if a match is found else it is set to
- * false. If 'buff' is not NULL then in the case of a match a descriptive
- * string is written to 'buff' while if there is not a not then a string
- * ending in "Reserved" is written (and may be prefixed with SPC, SBC, SSC
- * or ZBC). Returns 'buff' (i.e. a pointer value) even if it is NULL.
- * Example:
- * char b[64];
- * ...
- * printf("%s\n", sg_get_sfs_str(sfs_code, -2, sizeof(b), b, NULL, 0));
- */
-const char * sg_get_sfs_str(uint16_t sfs_code, int peri_type, int buff_len,
- char * buff, bool * foundp, int verbose);
-
-/* This is a heuristic that takes into account the command bytes and length
- * to decide whether the presented unstructured sequence of bytes could be
- * a SCSI command. If so it returns true otherwise false. Vendor specific
- * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
- * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
- * only SCSI commands considered above 16 bytes of length are the Variable
- * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
- * Both have an inbuilt length field which can be cross checked with clen.
- * No NVMe commands (64 bytes long plus some extra added by some OSes) have
- * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
- * structures that are sent across the wire. The 'FIS register' structure is
- * used to move a command from a SATA host to device, but the ATA 'command'
- * is not the first byte. So it is harder to say what will happen if a
- * FIS structure is presented as a SCSI command, hopfully there is a low
- * probability this function will yield true in that case. */
-bool sg_is_scsi_cdb(const uint8_t * cdbp, int clen);
-
-/* Yield string associated with NVMe command status value in sct_sc. It
- * expects to decode DW3 bits 27:17 from the completion queue. Bits 27:25
- * are the Status Code Type (SCT) and bits 24:17 are the Status Code (SC).
- * Bit 17 in DW3 should be bit 0 in sct_sc. If no status string is found
- * a string of the form "Reserved [0x<sct_sc_in_hex>]" is generated.
- * Returns 'buff'. Does nothing if buff_len<=0 or if buff is NULL.*/
-char * sg_get_nvme_cmd_status_str(uint16_t sct_sc, int buff_len, char * buff);
-
-/* Attempts to map NVMe status value ((SCT << 8) | SC) n sct_sc to a SCSI
- * status, sense_key, asc and ascq tuple. If successful returns true and
- * writes to non-NULL pointer arguments; otherwise returns false. */
-bool sg_nvme_status2scsi(uint16_t sct_sc, uint8_t * status_p, uint8_t * sk_p,
- uint8_t * asc_p, uint8_t * ascq_p);
-
-extern FILE * sg_warnings_strm;
-
-void sg_set_warnings_strm(FILE * warnings_strm);
-
-/* The following "print" functions send ACSII to 'sg_warnings_strm' file
- * descriptor (default value is stderr). 'leadin' is string prepended to
- * each line printed out, NULL treated as "". */
-void sg_print_command(const unsigned char * command);
-void sg_print_scsi_status(int scsi_status);
-
-/* 'leadin' is string prepended to each line printed out, NULL treated as
- * "". N.B. prior to sg3_utils v 1.42 'leadin' was only prepended to the
- * first line printed. */
-void sg_print_sense(const char * leadin, const unsigned char * sense_buffer,
- int sb_len, bool raw_info);
-
-/* Following examines exit_status and outputs a clear error message to
- * warnings_strm (usually stderr) if one is known and returns true.
- * Otherwise it doesn't print anything and returns false. Note that if
- * exit_status==0 then returns true but prints nothing and if
- * exit_status<0 ("some error occurred") false is returned. If leadin is
- * non-NULL is will be printed before error message. */
-bool sg_if_can2stderr(const char * leadin, int exit_status);
-
-/* Utilities can use these exit status values for syntax errors and
- * file (device node) problems (e.g. not found or permissions). */
-#define SG_LIB_SYNTAX_ERROR 1 /* command line syntax problem */
-#define SG_LIB_FILE_ERROR 15 /* device or other file problem */
-
-/* The sg_err_category_sense() function returns one of the following.
- * These may be used as exit status values (from a process). Notice that
- * some of the lower values correspond to SCSI sense key values. */
-#define SG_LIB_CAT_CLEAN 0 /* No errors or other information */
-/* Value 1 left unused for utilities to use SG_LIB_SYNTAX_ERROR */
-#define SG_LIB_CAT_NOT_READY 2 /* sense key, unit stopped? */
- /* [sk,asc,ascq: 0x2,*,*] */
-#define SG_LIB_CAT_MEDIUM_HARD 3 /* medium or hardware error, blank check */
- /* [sk,asc,ascq: 0x3/0x4/0x8,*,*] */
-#define SG_LIB_CAT_ILLEGAL_REQ 5 /* Illegal request (other than invalid */
- /* opcode): [sk,asc,ascq: 0x5,*,*] */
-#define SG_LIB_CAT_UNIT_ATTENTION 6 /* sense key, device state changed */
- /* [sk,asc,ascq: 0x6,*,*] */
- /* was SG_LIB_CAT_MEDIA_CHANGED earlier [sk,asc,ascq: 0x6,0x28,*] */
-#define SG_LIB_CAT_DATA_PROTECT 7 /* sense key, media write protected? */
- /* [sk,asc,ascq: 0x7,*,*] */
-#define SG_LIB_CAT_INVALID_OP 9 /* (Illegal request,) Invalid opcode: */
- /* [sk,asc,ascq: 0x5,0x20,0x0] */
-#define SG_LIB_CAT_COPY_ABORTED 10 /* sense key, some data transferred */
- /* [sk,asc,ascq: 0xa,*,*] */
-#define SG_LIB_CAT_ABORTED_COMMAND 11 /* interpreted from sense buffer */
- /* [sk,asc,ascq: 0xb,! 0x10,*] */
-#define SG_LIB_CAT_MISCOMPARE 14 /* sense key, probably verify */
- /* [sk,asc,ascq: 0xe,*,*] */
-#define SG_LIB_CAT_NO_SENSE 20 /* sense data with key of "no sense" */
- /* [sk,asc,ascq: 0x0,*,*] */
-#define SG_LIB_CAT_RECOVERED 21 /* Successful command after recovered err */
- /* [sk,asc,ascq: 0x1,*,*] */
-#define SG_LIB_CAT_RES_CONFLICT SAM_STAT_RESERVATION_CONFLICT
- /* 24: this is a SCSI status, not sense. */
- /* It indicates reservation by another */
- /* machine blocks this command */
-#define SG_LIB_CAT_CONDITION_MET 25 /* SCSI status, not sense key. */
- /* Only from PRE-FETCH (SBC-4) */
-#define SG_LIB_CAT_BUSY 26 /* SCSI status, not sense. Invites retry */
-#define SG_LIB_CAT_TS_FULL 27 /* SCSI status, not sense. Wait then retry */
-#define SG_LIB_CAT_ACA_ACTIVE 28 /* SCSI status; ACA seldom used */
-#define SG_LIB_CAT_TASK_ABORTED 29 /* SCSI status, this command aborted by? */
-#define SG_LIB_CAT_PROTECTION 40 /* subset of aborted command (for PI, DIF) */
- /* [sk,asc,ascq: 0xb,0x10,*] */
-#define SG_LIB_NVME_STATUS 48 /* NVMe Status Field (SF) other than 0 */
-#define SG_LIB_WILD_RESID 49 /* Residual value for data-in transfer of a */
- /* SCSI command is nonsensical */
-#define SG_LIB_OS_BASE_ERR 50 /* in Linux: values found in: */
- /* include/uapi/asm-generic/errno-base.h */
- /* Example: ENOMEM reported as 62 (=50+12) */
-#define SG_LIB_CAT_MALFORMED 97 /* Response to SCSI command malformed */
-#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) */
-
-/* Returns a SG_LIB_CAT_* value. If cannot decode sense_buffer or a less
- * common sense key then return SG_LIB_CAT_SENSE .*/
-int sg_err_category_sense(const unsigned char * sense_buffer, int sb_len);
-
-/* Here are some additional sense data categories that are not returned
- * by sg_err_category_sense() but are returned by some related functions. */
-#define SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO 17 /* Illegal request (other than */
- /* invalid opcode) plus 'info' field: */
- /* [sk,asc,ascq: 0x5,*,*] */
-#define SG_LIB_CAT_MEDIUM_HARD_WITH_INFO 18 /* medium or hardware error */
- /* sense key plus 'info' field: */
- /* [sk,asc,ascq: 0x3/0x4,*,*] */
-#define SG_LIB_CAT_PROTECTION_WITH_INFO 41 /* aborted command sense key, */
- /* protection plus 'info' field: */
- /* [sk,asc,ascq: 0xb,0x10,*] */
-#define SG_LIB_CAT_TIMEOUT 33
-
-/* Yield string associated with sense category. Returns 'buff' (or pointer
- * to "Bad sense category" if 'buff' is NULL). If sense_cat unknown then
- * yield "Sense category: <sense_cat>" string. */
-const char * sg_get_category_sense_str(int sense_cat, int buff_len,
- char * buff, int verbose);
-
-
-/* Iterates to next designation descriptor in the device identification
- * VPD page. The 'initial_desig_desc' should point to start of first
- * descriptor with 'page_len' being the number of valid bytes in that
- * and following descriptors. To start, 'off' should point to a negative
- * value, thereafter it should point to the value yielded by the previous
- * call. If 0 returned then 'initial_desig_desc + *off' should be a valid
- * descriptor; returns -1 if normal end condition and -2 for an abnormal
- * termination. Matches association, designator_type and/or code_set when
- * any of those values are greater than or equal to zero. */
-int sg_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len,
- int * off, int m_assoc, int m_desig_type,
- int m_code_set);
-
-
-/* <<< General purpose (i.e. not SCSI specific) utility functions >>> */
-
-/* Always returns valid string even if errnum is wild (or library problem).
- * If errnum is negative, flip its sign. */
-char * safe_strerror(int errnum);
-
-
-/* Print (to stdout) 'str' of bytes in hex, 16 bytes per line optionally
- * followed at the right hand side of the line with an ASCII interpretation.
- * Each line is prefixed with an address, starting at 0 for str[0]..str[15].
- * All output numbers are in hex. 'no_ascii' allows for 3 output types:
- * > 0 each line has address then up to 16 ASCII-hex bytes
- * = 0 in addition, the bytes are listed in ASCII to the right
- * < 0 only the ASCII-hex bytes are listed (i.e. without address)
-*/
-void dStrHex(const char * str, int len, int no_ascii);
-
-/* Print (to sg_warnings_strm (stderr)) 'str' of bytes in hex, 16 bytes per
- * line optionally followed at right by its ASCII interpretation. Same
- * logic as dStrHex() with different output stream (i.e. stderr). */
-void dStrHexErr(const char * str, int len, int no_ascii);
-
-/* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space
- * separated) to 'b' not to exceed 'b_len' characters. Each line
- * starts with 'leadin' (NULL for no leadin) and there are 16 bytes
- * per line with an extra space between the 8th and 9th bytes. 'format'
- * is 0 for repeat in printable ASCII ('.' for non printable chars) to
- * right of each line; 1 don't (so just output ASCII hex). Returns
- * number of bytes written to 'b' excluding the trailing '\0'. */
-int dStrHexStr(const char * str, int len, const char * leadin, int format,
- int cb_len, char * cbp);
-
-/* The following 3 functions are equivalent to dStrHex(), dStrHexErr() and
- * dStrHexStr() respectively. The difference is the type of the first of
- * argument: uint8_t instead of char. The name of the argument is changed
- * to b_str to stress it is a pointer to the start of a binary string. */
-void hex2stdout(const uint8_t * b_str, int len, int no_ascii);
-void hex2stderr(const uint8_t * b_str, int len, int no_ascii);
-int hex2str(const uint8_t * b_str, int len, const char * leadin, int format,
- int cb_len, char * cbp);
-
-/* Returns true when executed on big endian machine; else returns false.
- * Useful for displaying ATA identify words (which need swapping on a
- * big endian machine). */
-bool sg_is_big_endian();
-
-/* Returns true if byte sequence starting at bp with a length of b_len is
- * all zeros (for sg_all_zeros()) or all 0xff_s (for sg_all_ffs());
- * otherwise returns false. If bp is NULL ir b_len <= 0 returns false. */
-bool sg_all_zeros(const uint8_t * bp, int b_len);
-bool sg_all_ffs(const uint8_t * bp, int b_len);
-
-/* Extract character sequence from ATA words as in the model string
- * in a IDENTIFY DEVICE response. Returns number of characters
- * written to 'ochars' before 0 character is found or 'num' words
- * are processed. */
-int sg_ata_get_chars(const uint16_t * word_arr, int start_word,
- int num_words, bool is_big_endian, char * ochars);
-
-/* Print (to stdout) 16 bit 'words' in hex, 8 words per line optionally
- * followed at the right hand side of the line with an ASCII interpretation
- * (pairs of ASCII characters in big endian order (upper first)).
- * Each line is prefixed with an address, starting at 0.
- * All output numbers are in hex. 'no_ascii' allows for 3 output types:
- * > 0 each line has address then up to 8 ASCII-hex words
- * = 0 in addition, the words are listed in ASCII pairs to the right
- * = -1 only the ASCII-hex words are listed (i.e. without address)
- * = -2 only the ASCII-hex words, formatted for "hdparm --Istdin"
- * < -2 same as -1
- * If 'swapb' is true then bytes in each word swapped. Needs to be set
- * for ATA IDENTIFY DEVICE response on big-endian machines.
-*/
-void dWordHex(const uint16_t * words, int num, int no_ascii, bool swapb);
-
-/* If the number in 'buf' can not be decoded or the multiplier is unknown
- * then -1 is returned. Accepts a hex prefix (0x or 0X) or a 'h' (or 'H')
- * suffix. Otherwise a decimal multiplier suffix may be given. Recognised
- * multipliers: c C *1; w W *2; b B *512; k K KiB *1,024;
- * KB *1,000; m M MiB *1,048,576; MB *1,000,000; g G GiB *1,073,741,824;
- * GB *1,000,000,000 and <n>x<m> which multiplies <n> by <m> . Ignore leading
- * spaces and tabs; accept comma, hyphen, space, tab and hash as terminator.
- */
-int sg_get_num(const char * buf);
-
-/* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
- * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is
- * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"),
- * a whitespace or newline as terminator. Only decimal numbers can represent
- * negative numbers and '-1' must be treated separately. */
-int sg_get_num_nomult(const char * buf);
-
-/* If the number in 'buf' can not be decoded or the multiplier is unknown
- * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a 'h' (or 'H')
- * suffix. Otherwise a decimal multiplier suffix may be given. In addition
- * to supporting the multipliers of sg_get_num(), this function supports:
- * t T TiB *(2**40); TB *(10**12); p P PiB *(2**50); PB *(10**15) .
- * Ignore leading spaces and tabs; accept comma, hyphen, space, tab and hash
- * as terminator. */
-int64_t sg_get_llnum(const char * buf);
-
-/* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
- * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is
- * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"),
- * a whitespace or newline as terminator. Only decimal numbers can represent
- * negative numbers and '-1' must be treated separately. */
-int64_t sg_get_llnum_nomult(const char * buf);
-
-/* Returns pointer to heap (or NULL) that is aligned to a align_to byte
- * boundary. Sends back *buff_to_free pointer in third argument that may be
- * different from the return value. If it is different then the *buff_to_free
- * pointer should be freed (rather than the returned value) when the heap is
- * no longer needed. If align_to is 0 then aligns to OS's page size. Sets all
- * returned heap to zeros. If num_bytes is 0 then set to page size. */
-uint8_t * sg_memalign(uint32_t num_bytes, uint32_t align_to,
- uint8_t ** buff_to_free, bool vb);
-
-/* Returns OS page size in bytes. If uncertain returns 4096. */
-uint32_t sg_get_page_size(void);
-
-/* If os_err_num is within bounds then the returned value is 'os_err_num +
- * SG_LIB_OS_BASE_ERR' otherwise -1 is returned. If os_err_num is 0 then 0
- * is returned. */
-int sg_convert_errno(int os_err_num);
-
-
-/* <<< Architectural support functions [is there a better place?] >>> */
-
-/* Non Unix OSes distinguish between text and binary files.
- * Set text mode on fd. Does nothing in Unix. Returns negative number on
- * failure. */
-int sg_set_text_mode(int fd);
-
-/* Set binary mode on fd. Does nothing in Unix. Returns negative number on
- * failure. */
-int sg_set_binary_mode(int fd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SG_LIB_H */
diff --git a/tools/sg_write_buffer/include/sg_lib_data.h b/tools/sg_write_buffer/include/sg_lib_data.h
deleted file mode 100644
index 09cd53c..0000000
--- a/tools/sg_write_buffer/include/sg_lib_data.h
+++ /dev/null
@@ -1,121 +0,0 @@
-#ifndef SG_LIB_DATA_H
-#define SG_LIB_DATA_H
-
-/*
- * Copyright (c) 2007-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-/*
- * This header file contains some structure declarations and array name
- * declarations which are defined in the sg_lib_data.c .
- * Typically this header does not need to be exposed to users of the
- * sg_lib interface declared in sg_libs.h .
- */
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Operation codes with associated service actions that change or qualify
- * the command name */
-#define SG_EXTENDED_COPY 0x83 /* since spc4r34 became next entry */
-#define SG_3PARTY_COPY_OUT 0x83 /* new in spc4r34: Third party copy out */
-#define SG_RECEIVE_COPY 0x84 /* since spc4r34 became next entry */
-#define SG_3PARTY_COPY_IN 0x84 /* new in spc4r34: 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_READ_ATTRIBUTE 0x8c
-#define SG_READ_BUFFER 0x3c /* now READ BUFFER(10) */
-#define SG_READ_BUFFER_16 0x9b
-#define SG_READ_POSITION 0x34 /* SSC command with service actions */
-#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_VARIABLE_LENGTH_CMD 0x7f
-#define SG_WRITE_BUFFER 0x3b
-#define SG_ZONING_OUT 0x94
-#define SG_ZONING_IN 0x95
-
-
-
-struct sg_lib_simple_value_name_t {
- int value;
- const char * name;
-};
-
-struct sg_lib_value_name_t {
- int value;
- int peri_dev_type; /* 0 -> SPC and/or PDT_DISK, >0 -> PDT */
- const char * name;
-};
-
-struct sg_lib_asc_ascq_t {
- unsigned char asc; /* additional sense code */
- unsigned char ascq; /* additional sense code qualifier */
- const char * text;
-};
-
-struct sg_lib_asc_ascq_range_t {
- unsigned char asc; /* additional sense code (ASC) */
- unsigned char ascq_min; /* ASCQ minimum in range */
- unsigned char ascq_max; /* ASCQ maximum in range */
- const char * text;
-};
-
-/* First use: SCSI status, sense_key, asc, ascq tuple */
-struct sg_lib_4tuple_u8 {
- uint8_t t1;
- uint8_t t2;
- uint8_t t3;
- uint8_t t4;
-};
-
-
-extern const char * sg_lib_version_str;
-
-extern struct sg_lib_value_name_t sg_lib_normal_opcodes[];
-extern struct sg_lib_value_name_t sg_lib_read_buff_arr[];
-extern struct sg_lib_value_name_t sg_lib_write_buff_arr[];
-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[];
-extern struct sg_lib_value_name_t sg_lib_serv_out16_arr[];
-extern struct sg_lib_value_name_t sg_lib_serv_bidi_arr[];
-extern struct sg_lib_value_name_t sg_lib_xcopy_sa_arr[];
-extern struct sg_lib_value_name_t sg_lib_rec_copy_sa_arr[];
-extern struct sg_lib_value_name_t sg_lib_variable_length_arr[];
-extern struct sg_lib_value_name_t sg_lib_zoning_out_arr[];
-extern struct sg_lib_value_name_t sg_lib_zoning_in_arr[];
-extern struct sg_lib_value_name_t sg_lib_read_attr_arr[];
-extern struct sg_lib_value_name_t sg_lib_read_pos_arr[];
-extern struct sg_lib_asc_ascq_range_t sg_lib_asc_ascq_range[];
-extern struct sg_lib_asc_ascq_t sg_lib_asc_ascq[];
-extern struct sg_lib_value_name_t sg_lib_scsi_feature_sets[];
-extern const char * sg_lib_sense_key_desc[];
-extern const char * sg_lib_pdt_strs[];
-extern const char * sg_lib_transport_proto_strs[];
-extern int sg_lib_pdt_decay_arr[];
-
-extern struct sg_lib_value_name_t sg_lib_nvme_cmd_status_arr[];
-extern struct sg_lib_4tuple_u8 sg_lib_scsi_status_sense_arr[];
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_linux_inc.h b/tools/sg_write_buffer/include/sg_linux_inc.h
deleted file mode 100644
index b587c6c..0000000
--- a/tools/sg_write_buffer/include/sg_linux_inc.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef SG_LINUX_INC_H
-#define SG_LINUX_INC_H
-
-#ifdef SG_KERNEL_INCLUDES
- #define __user
- typedef unsigned char u8;
- #include "/usr/src/linux/include/scsi/sg.h"
- #include "/usr/src/linux/include/scsi/scsi.h"
-#else
- #ifdef SG_TRICK_GNU_INCLUDES
- #include <linux/../scsi/sg.h>
- #include <linux/../scsi/scsi.h>
- #else
- #include <scsi/sg.h>
- #include <scsi/scsi.h>
- #endif
-#endif
-
-#ifdef BLKGETSIZE64
- #ifndef u64
- #include <stdint.h> /* C99 header for exact integer types */
- typedef uint64_t u64; /* problems with BLKGETSIZE64 ioctl in lk 2.4 */
- #endif
-#endif
-
-/*
- Getting the correct include files for the sg interface can be an ordeal.
- In a perfect world, one would just write:
- #include <scsi/sg.h>
- #include <scsi/scsi.h>
- This would include the files found in the /usr/include/scsi directory.
- Those files are maintained with the GNU library which may or may not
- agree with the kernel and version of sg driver that is running. Any
- many cases this will not matter. However in some it might, for example
- glibc 2.1's include files match the sg driver found in the lk 2.2
- series. Hence if glibc 2.1 is used with lk 2.4 then the additional
- sg v3 interface will not be visible.
- If this is a problem then defining SG_KERNEL_INCLUDES will access the
- kernel supplied header files (assuming they are in the normal place).
- The GNU library maintainers and various kernel people don't like
- this approach (but it does work).
- The technique selected by defining SG_TRICK_GNU_INCLUDES worked (and
- was used) prior to glibc 2.2 . Prior to that version /usr/include/linux
- was a symbolic link to /usr/src/linux/include/linux .
-
- There are other approaches if this include "mixup" causes pain. These
- would involve include files being copied or symbolic links being
- introduced.
-
- Sorry about the inconvenience. Typically neither SG_KERNEL_INCLUDES
- nor SG_TRICK_GNU_INCLUDES is defined.
-
- dpg 20010415, 20030522
-*/
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_pr2serr.h b/tools/sg_write_buffer/include/sg_pr2serr.h
deleted file mode 100644
index 4419087..0000000
--- a/tools/sg_write_buffer/include/sg_pr2serr.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef SG_PR2SERR_H
-#define SG_PR2SERR_H
-
-/*
- * Copyright (c) 2004-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-#if defined(__GNUC__) || defined(__clang__)
-int pr2serr(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-int pr2serr(const char * fmt, ...);
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_pt.h b/tools/sg_write_buffer/include/sg_pt.h
deleted file mode 100644
index b01215c..0000000
--- a/tools/sg_write_buffer/include/sg_pt.h
+++ /dev/null
@@ -1,215 +0,0 @@
-#ifndef SG_PT_H
-#define SG_PT_H
-
-/*
- * Copyright (c) 2005-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* This declaration hides the fact that each implementation has its own
- * structure "derived" (using a C++ term) from this one. It compiles
- * because 'struct sg_pt_base' is only referenced (by pointer: 'objp')
- * in this interface. An instance of this structure represents the
- * context of one SCSI command. */
-struct sg_pt_base;
-
-
-/* The format of the version string is like this: "2.01 20090201".
- * The leading digit will be incremented if this interface changes
- * in a way that may impact backward compatibility. */
-const char * scsi_pt_version();
-
-
-/* Returns >= 0 if successful. If error in Unix returns negated errno. */
-int scsi_pt_open_device(const char * device_name, bool read_only, int verbose);
-
-/* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed
- * together. Returns valid file descriptor( >= 0 ) if successful, otherwise
- * returns -1 or a negated errno.
- * In Win32 O_EXCL translated to equivalent. */
-int scsi_pt_open_flags(const char * device_name, int flags, int verbose);
-
-/* Returns 0 if successful. If error in Unix returns negated errno. */
-int scsi_pt_close_device(int device_fd);
-
-/* Assumes dev_fd is an "open" file handle associated with device_name. If
- * the implementation (possibly for one OS) cannot determine from dev_fd if
- * a SCSI or NVMe pass-through is referenced, then it might guess based on
- * device_name. Returns 1 if SCSI generic pass-though device, returns 2 if
- * secondary SCSI pass-through device (in Linux a bsg device); returns 3 is
- * char NVMe device (i.e. no NSID); returns 4 if block NVMe device (includes
- * NSID), or 0 if something else (e.g. ATA block device) or dev_fd < 0.
- * If error, returns negated errno (operating system) value. */
-int check_pt_file_handle(int dev_fd, const char * device_name, int verbose);
-
-
-/* Creates an object that can be used to issue one or more SCSI commands
- * (or task management functions). Returns NULL if problem.
- * Once this object has been created it should be destroyed with
- * destruct_scsi_pt_obj() when it is no longer needed. */
-struct sg_pt_base * construct_scsi_pt_obj(void);
-
-/* An alternate way to create an object that can be used to issue one or
- * more SCSI commands (or task management functions). This variant
- * associate a device file descriptor (handle) with the object and a
- * verbose argument that causes error messages if errors occur. The
- * reason for this is to optionally allow the detection of NVMe devices
- * that will cause pt_device_is_nvme() to return true. Set dev_fd to
- * -1 if no open device file descriptor is available. Caller should
- * additionally call get_scsi_pt_os_err() after this call. */
-struct sg_pt_base *
- construct_scsi_pt_obj_with_fd(int dev_fd, int verbose);
-
-/* Forget any previous dev_fd and install the one given. May attempt to
- * find file type (e.g. if pass-though) from OS so there could be an error.
- * Returns 0 for success or the same value as get_scsi_pt_os_err()
- * will return. dev_fd should be >= 0 for a valid file handle or -1 . */
-int set_pt_file_handle(struct sg_pt_base * objp, int dev_fd, int verbose);
-
-/* Valid file handles (which is the return value) are >= 0 . Returns -1
- * if there is no valid file handle. */
-int get_pt_file_handle(const struct sg_pt_base * objp);
-
-/* Clear state information held in *objp . This allows this object to be
- * used to issue more than one SCSI command. The dev_fd is remembered.
- * Use set_pt_file_handle() to change dev_fd. */
-void clear_scsi_pt_obj(struct sg_pt_base * objp);
-
-/* Set the CDB (command descriptor block) */
-void set_scsi_pt_cdb(struct sg_pt_base * objp, const unsigned char * cdb,
- int cdb_len);
-/* Set the sense buffer and the maximum length that it can handle */
-void set_scsi_pt_sense(struct sg_pt_base * objp, unsigned char * sense,
- int max_sense_len);
-/* Set a pointer and length to be used for data transferred from device */
-void set_scsi_pt_data_in(struct sg_pt_base * objp, /* from device */
- unsigned char * dxferp, int dxfer_ilen);
-/* Set a pointer and length to be used for data transferred to device */
-void set_scsi_pt_data_out(struct sg_pt_base * objp, /* to device */
- const unsigned char * dxferp, int dxfer_olen);
-/* Set a pointer and length to be used for metadata transferred to
- * (out_true=true) or from (out_true-false) device */
-void set_pt_metadata_xfer(struct sg_pt_base * objp, unsigned char * mdxferp,
- uint32_t mdxfer_len, bool out_true);
-/* The following "set_"s implementations may be dummies */
-void set_scsi_pt_packet_id(struct sg_pt_base * objp, int pack_id);
-void set_scsi_pt_tag(struct sg_pt_base * objp, uint64_t tag);
-void set_scsi_pt_task_management(struct sg_pt_base * objp, int tmf_code);
-void set_scsi_pt_task_attr(struct sg_pt_base * objp, int attribute,
- int priority);
-
-/* Following is a guard which is defined when set_scsi_pt_flags() is
- * present. Older versions of this library may not have this function. */
-#define SCSI_PT_FLAGS_FUNCTION 1
-/* If neither QUEUE_AT_HEAD nor QUEUE_AT_TAIL are given, or both
- * are given, use the pass-through default. */
-#define SCSI_PT_FLAGS_QUEUE_AT_TAIL 0x10
-#define SCSI_PT_FLAGS_QUEUE_AT_HEAD 0x20
-/* Set (potentially OS dependent) flags for pass-through mechanism.
- * Apart from contradictions, flags can be OR-ed together. */
-void set_scsi_pt_flags(struct sg_pt_base * objp, int flags);
-
-#define SCSI_PT_DO_START_OK 0
-#define SCSI_PT_DO_BAD_PARAMS 1
-#define SCSI_PT_DO_TIMEOUT 2
-#define SCSI_PT_DO_NVME_STATUS 48 /* == SG_LIB_NVME_STATUS */
-/* If OS error prior to or during command submission then returns negated
- * error value (e.g. Unix '-errno'). This includes interrupted system calls
- * (e.g. by a signal) in which case -EINTR would be returned. Note that
- * system call errors also can be fetched with get_scsi_pt_os_err().
- * Return 0 if okay (i.e. at the very least: command sent). Positive
- * return values are errors (see SCSI_PT_DO_* defines). If a file descriptor
- * has already been provided by construct_scsi_pt_obj_with_fd() then the
- * given 'fd' can be -1 or the same value as given to the constructor. */
-int do_scsi_pt(struct sg_pt_base * objp, int fd, int timeout_secs,
- int verbose);
-
-#define SCSI_PT_RESULT_GOOD 0
-#define SCSI_PT_RESULT_STATUS 1 /* other than GOOD and CHECK CONDITION */
-#define SCSI_PT_RESULT_SENSE 2
-#define SCSI_PT_RESULT_TRANSPORT_ERR 3
-#define SCSI_PT_RESULT_OS_ERR 4
-/* highest numbered applicable category returned */
-int get_scsi_pt_result_category(const struct sg_pt_base * objp);
-
-/* If not available return 0 which implies there is no residual
- * value. If supported the number of bytes actually sent back by
- * the device is 'dxfer_ilen - get_scsi_pt_len()' bytes. */
-int get_scsi_pt_resid(const struct sg_pt_base * objp);
-
-/* Returns SCSI status value (from device that received the command). If an
- * NVMe command was issued directly (i.e. through do_scsi_pt() then return
- * NVMe status (i.e. ((SCT << 8) | SC)) */
-int get_scsi_pt_status_response(const struct sg_pt_base * objp);
-
-/* Returns SCSI status value or, if NVMe command given to do_scsi_pt(),
- * then returns NVMe result (i.e. DWord(0) from completion queue). If
- * 'objp' is NULL then returns 0xffffffff. */
-uint32_t get_pt_result(const struct sg_pt_base * objp);
-
-/* Actual sense length returned. If sense data is present but
- actual sense length is not known, return 'max_sense_len' */
-int get_scsi_pt_sense_len(const struct sg_pt_base * objp);
-
-/* If not available return 0 (for success). */
-int get_scsi_pt_os_err(const struct sg_pt_base * objp);
-char * get_scsi_pt_os_err_str(const struct sg_pt_base * objp, int max_b_len,
- char * b);
-
-/* If not available return 0 (for success) */
-int get_scsi_pt_transport_err(const struct sg_pt_base * objp);
-void set_scsi_pt_transport_err(struct sg_pt_base * objp, int err);
-char * get_scsi_pt_transport_err_str(const struct sg_pt_base * objp,
- int max_b_len, char * b);
-
-/* If not available return -1 */
-int get_scsi_pt_duration_ms(const struct sg_pt_base * objp);
-
-/* Return true if device associated with 'objp' uses NVMe command set. To
- * be useful (in modifying the type of command sent (SCSI or NVMe) then
- * construct_scsi_pt_obj_with_fd() should be used followed by an invocation
- * of this function. */
-bool pt_device_is_nvme(const struct sg_pt_base * objp);
-
-/* If a NVMe block device (which includes the NSID) handle is associated
- * with 'objp', then its NSID is returned (values range from 0x1 to
- * 0xffffffe). Otherwise 0 is returned. */
-uint32_t get_pt_nvme_nsid(const struct sg_pt_base * objp);
-
-
-/* Should be invoked once per objp after other processing is complete in
- * order to clean up resources. For ever successful construct_scsi_pt_obj()
- * call there should be one destruct_scsi_pt_obj(). If the
- * construct_scsi_pt_obj_with_fd() function was used to create this object
- * then the dev_fd provided to that constructor is not altered by this
- * destructor. So the user should still close dev_fd (perhaps with
- * scsi_pt_close_device() ). */
-void destruct_scsi_pt_obj(struct sg_pt_base * objp);
-
-#ifdef SG_LIB_WIN32
-#define SG_LIB_WIN32_DIRECT 1
-
-/* Request SPT direct interface when state_direct is 1, state_direct set
- * to 0 for the SPT indirect interface. Default setting selected by build
- * (i.e. library compile time) and is usually indirect. */
-void scsi_pt_win32_direct(int state_direct);
-
-/* Returns current SPT interface state, 1 for direct, 0 for indirect */
-int scsi_pt_win32_spt_state(void);
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_pt_linux.h b/tools/sg_write_buffer/include/sg_pt_linux.h
deleted file mode 100644
index 5e22fd7..0000000
--- a/tools/sg_write_buffer/include/sg_pt_linux.h
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifndef SG_PT_LINUX_H
-#define SG_PT_LINUX_H
-
-/*
- * Copyright (c) 2017 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#include <linux/types.h>
-
-#include "sg_pt_nvme.h"
-
-/* This header is for internal use by the sg3_utils library (libsgutils)
- * and is Linux specific. Best not to include it directly in code that
- * is meant to be OS independent. */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef HAVE_LINUX_BSG_H
-
-#define BSG_PROTOCOL_SCSI 0
-
-#define BSG_SUB_PROTOCOL_SCSI_CMD 0
-#define BSG_SUB_PROTOCOL_SCSI_TMF 1
-#define BSG_SUB_PROTOCOL_SCSI_TRANSPORT 2
-
-/*
- * For flag constants below:
- * sg.h sg_io_hdr also has bits defined for it's flags member. These
- * two flag values (0x10 and 0x20) have the same meaning in sg.h . For
- * bsg the BSG_FLAG_Q_AT_HEAD flag is ignored since it is the default.
- */
-#define BSG_FLAG_Q_AT_TAIL 0x10 /* default is Q_AT_HEAD */
-#define BSG_FLAG_Q_AT_HEAD 0x20
-
-struct sg_io_v4 {
- __s32 guard; /* [i] 'Q' to differentiate from v3 */
- __u32 protocol; /* [i] 0 -> SCSI , .... */
- __u32 subprotocol; /* [i] 0 -> SCSI command, 1 -> SCSI task
- management function, .... */
-
- __u32 request_len; /* [i] in bytes */
- __u64 request; /* [i], [*i] {SCSI: cdb} */
- __u64 request_tag; /* [i] {SCSI: task tag (only if flagged)} */
- __u32 request_attr; /* [i] {SCSI: task attribute} */
- __u32 request_priority; /* [i] {SCSI: task priority} */
- __u32 request_extra; /* [i] {spare, for padding} */
- __u32 max_response_len; /* [i] in bytes */
- __u64 response; /* [i], [*o] {SCSI: (auto)sense data} */
-
- /* "dout_": data out (to device); "din_": data in (from device) */
- __u32 dout_iovec_count; /* [i] 0 -> "flat" dout transfer else
- dout_xfer points to array of iovec */
- __u32 dout_xfer_len; /* [i] bytes to be transferred to device */
- __u32 din_iovec_count; /* [i] 0 -> "flat" din transfer */
- __u32 din_xfer_len; /* [i] bytes to be transferred from device */
- __u64 dout_xferp; /* [i], [*i] */
- __u64 din_xferp; /* [i], [*o] */
-
- __u32 timeout; /* [i] units: millisecond */
- __u32 flags; /* [i] bit mask */
- __u64 usr_ptr; /* [i->o] unused internally */
- __u32 spare_in; /* [i] */
-
- __u32 driver_status; /* [o] 0 -> ok */
- __u32 transport_status; /* [o] 0 -> ok */
- __u32 device_status; /* [o] {SCSI: command completion status} */
- __u32 retry_delay; /* [o] {SCSI: status auxiliary information} */
- __u32 info; /* [o] additional information */
- __u32 duration; /* [o] time to complete, in milliseconds */
- __u32 response_len; /* [o] bytes of response actually written */
- __s32 din_resid; /* [o] din_xfer_len - actual_din_xfer_len */
- __s32 dout_resid; /* [o] dout_xfer_len - actual_dout_xfer_len */
- __u64 generated_tag; /* [o] {SCSI: transport generated task tag} */
- __u32 spare_out; /* [o] */
-
- __u32 padding;
-};
-
-#else
-
-#include <linux/bsg.h>
-
-#endif
-
-
-struct sg_pt_linux_scsi {
- struct sg_io_v4 io_hdr; /* use v4 header as it is more general */
- /* Leave io_hdr in first place of this structure */
- bool is_sg;
- bool is_bsg;
- bool is_nvme; /* OS device type, if false ignore nvme_direct */
- bool nvme_direct; /* false: our SNTL; true: received NVMe command */
- bool mdxfer_out; /* direction of metadata xfer, true->data-out */
- bool scsi_dsense; /* SCSI descriptor sense active when true */
- int dev_fd; /* -1 if not given (yet) */
- int in_err;
- int os_err;
- uint32_t nvme_nsid; /* 1 to 0xfffffffe are possibly valid, 0
- * implies dev_fd is not a NVMe device
- * (is_nvme=false) or it is a NVMe char
- * device (e.g. /dev/nvme0 ) */
- uint32_t nvme_result; /* DW0 from completion queue */
- uint32_t nvme_status; /* SCT|SC: DW3 27:17 from completion queue,
- * note: the DNR+More bit are not there.
- * The whole 16 byte completion q entry is
- * sent back as sense data */
- uint32_t mdxfer_len;
- void * mdxferp;
- uint8_t * nvme_id_ctlp; /* cached response to controller IDENTIFY */
- uint8_t * free_nvme_id_ctlp;
- unsigned char tmf_request[4];
-};
-
-struct sg_pt_base {
- struct sg_pt_linux_scsi impl;
-};
-
-
-#ifndef sg_nvme_admin_cmd
-#define sg_nvme_admin_cmd sg_nvme_passthru_cmd
-#endif
-
-/* Linux NVMe related ioctls */
-#ifndef NVME_IOCTL_ID
-#define NVME_IOCTL_ID _IO('N', 0x40)
-#endif
-#ifndef NVME_IOCTL_ADMIN_CMD
-#define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct sg_nvme_admin_cmd)
-#endif
-#ifndef NVME_IOCTL_SUBMIT_IO
-#define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct sg_nvme_user_io)
-#endif
-#ifndef NVME_IOCTL_IO_CMD
-#define NVME_IOCTL_IO_CMD _IOWR('N', 0x43, struct sg_nvme_passthru_cmd)
-#endif
-#ifndef NVME_IOCTL_RESET
-#define NVME_IOCTL_RESET _IO('N', 0x44)
-#endif
-#ifndef NVME_IOCTL_SUBSYS_RESET
-#define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45)
-#endif
-
-extern bool sg_bsg_nvme_char_major_checked;
-extern int sg_bsg_major;
-extern volatile int sg_nvme_char_major;
-extern long sg_lin_page_size;
-
-void sg_find_bsg_nvme_char_major(int verbose);
-int sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb);
-
-/* This trims given NVMe block device name in Linux (e.g. /dev/nvme0n1p5)
- * to the name of its associated char device (e.g. /dev/nvme0). If this
- * occurs true is returned and the char device name is placed in 'b' (as
- * long as b_len is sufficient). Otherwise false is returned. */
-bool sg_get_nvme_char_devname(const char * nvme_block_devname, uint32_t b_len,
- char * b);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* end of SG_PT_LINUX_H */
diff --git a/tools/sg_write_buffer/include/sg_pt_nvme.h b/tools/sg_write_buffer/include/sg_pt_nvme.h
deleted file mode 100644
index 3df98b4..0000000
--- a/tools/sg_write_buffer/include/sg_pt_nvme.h
+++ /dev/null
@@ -1,172 +0,0 @@
-#ifndef SG_PT_NVME_H
-#define SG_PT_NVME_H
-
-/*
- * Copyright (c) 2017-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* structures copied and slightly modified from <linux/nvme_ioctl.h> which
- * is Copyright (c) 2011-2014, Intel Corporation. */
-
-
-/* Note that the command input structure is in (packed) "cpu" format. That
- * means, for example, if the CPU is little endian (most are) then so is the
- * structure. However what comes out in the data-in buffer (e.g. for the
- * Admin Identify command response) is almost all little endian following ATA
- * (but no SCSI and IP which are big endian) and Intel's preference. There
- * are exceptions, for example the EUI-64 identifiers in the Admin Identify
- * response are big endian.
- *
- * Code online (e.g. nvme-cli at github.com) seems to like packed strcutures,
- * the author prefers byte offset plus a range of unaligned integer builders
- * such as those in sg_unaligned.h .
- */
-
-#ifdef __GNUC__
-#ifndef __clang__
- struct __attribute__((__packed__)) sg_nvme_user_io
-#else
- struct sg_nvme_user_io
-#endif
-#else
-struct sg_nvme_user_io
-#endif
-{
- uint8_t opcode;
- uint8_t flags;
- uint16_t control;
- uint16_t nblocks;
- uint16_t rsvd;
- uint64_t metadata;
- uint64_t addr;
- uint64_t slba;
- uint32_t dsmgmt;
- uint32_t reftag;
- uint16_t apptag;
- uint16_t appmask;
-}
-#ifdef SG_LIB_FREEBSD
-__packed;
-#else
-;
-#endif
-
-/* Using byte offsets and unaligned be/le copies safer than packed
- * structures. These are for sg_nvme_user_io . */
-#define SG_NVME_IO_OPCODE 0
-#define SG_NVME_IO_FLAGS 1
-#define SG_NVME_IO_CONTROL 2
-#define SG_NVME_IO_NBLOCKS 4
-#define SG_NVME_IO_RSVD 6
-#define SG_NVME_IO_METADATA 8
-#define SG_NVME_IO_ADDR 16
-#define SG_NVME_IO_SLBA 24
-#define SG_NVME_IO_DSMGMT 32
-#define SG_NVME_IO_REFTAG 36
-#define SG_NVME_IO_APPTAG 40
-#define SG_NVME_IO_APPMASK 42
-
-#ifdef __GNUC__
-#ifndef __clang__
- struct __attribute__((__packed__)) sg_nvme_passthru_cmd
-#else
- struct sg_nvme_passthru_cmd
-#endif
-#else
-struct sg_nvme_passthru_cmd
-#endif
-{
- uint8_t opcode;
- uint8_t flags;
- uint16_t rsvd1;
- uint32_t nsid;
- uint32_t cdw2;
- uint32_t cdw3;
- uint64_t metadata;
- uint64_t addr;
- uint32_t metadata_len;
- uint32_t data_len;
- uint32_t cdw10;
- uint32_t cdw11;
- uint32_t cdw12;
- uint32_t cdw13;
- uint32_t cdw14;
- uint32_t cdw15;
-#ifdef SG_LIB_LINUX
- uint32_t timeout_ms;
- uint32_t result; /* out: DWord(0) from completion queue */
-#endif
-}
-#ifdef SG_LIB_FREEBSD
-__packed;
-#else
-;
-#endif
-
-
-/* Using byte offsets and unaligned be/le copies safer than packed
- * structures. These are for sg_nvme_passthru_cmd . */
-#define SG_NVME_PT_OPCODE 0 /* length: 1 byte */
-#define SG_NVME_PT_FLAGS 1 /* length: 1 byte */
-#define SG_NVME_PT_RSVD1 2 /* length: 2 bytes */
-#define SG_NVME_PT_NSID 4 /* length: 4 bytes */
-#define SG_NVME_PT_CDW2 8 /* length: 4 bytes */
-#define SG_NVME_PT_CDW3 12 /* length: 4 bytes */
-#define SG_NVME_PT_METADATA 16 /* length: 8 bytes */
-#define SG_NVME_PT_ADDR 24 /* length: 8 bytes */
-#define SG_NVME_PT_METADATA_LEN 32 /* length: 4 bytes */
-#define SG_NVME_PT_DATA_LEN 36 /* length: 4 bytes */
-#define SG_NVME_PT_CDW10 40 /* length: 4 bytes */
-#define SG_NVME_PT_CDW11 44 /* length: 4 bytes */
-#define SG_NVME_PT_CDW12 48 /* length: 4 bytes */
-#define SG_NVME_PT_CDW13 52 /* length: 4 bytes */
-#define SG_NVME_PT_CDW14 56 /* length: 4 bytes */
-#define SG_NVME_PT_CDW15 60 /* length: 4 bytes */
-
-#ifdef SG_LIB_LINUX
-/* General references state that "all NVMe commands are 64 bytes long". If
- * so then the following are add-ons by Linux, go to the OS and not the
- * the NVMe device. */
-#define SG_NVME_PT_TIMEOUT_MS 64 /* length: 4 bytes */
-#define SG_NVME_PT_RESULT 68 /* length: 4 bytes */
-#endif
-
-/* Byte offset of Result and Status (plus phase bit) in CQ */
-#define SG_NVME_PT_CQ_RESULT 0 /* CDW0, length: 4 bytes */
-#define SG_NVME_PT_CQ_DW0 0 /* CDW0, length: 4 bytes */
-#define SG_NVME_PT_CQ_DW1 4 /* CDW1, length: 4 bytes */
-#define SG_NVME_PT_CQ_DW2 8 /* CDW2, length: 4 bytes */
-#define SG_NVME_PT_CQ_DW3 12 /* CDW3, length: 4 bytes */
-#define SG_NVME_PT_CQ_STATUS_P 14 /* CDW3 31:16, length: 2 bytes */
-
-
-/* Valid namespace IDs (nsid_s) range from 1 to 0xfffffffe, leaving: */
-#define SG_NVME_BROADCAST_NSID 0xffffffff /* all namespaces */
-#define SG_NVME_CTL_NSID 0x0 /* the "controller's" namespace */
-
-/* Given the NVMe Identify Controller response and optionally the NVMe
- * Identify Namespace response (NULL otherwise), generate the SCSI VPD
- * page 0x83 (device identification) descriptor(s) in dop. Return the
- * number of bytes written which will not exceed max_do_len. Probably use
- * Peripheral Device Type (pdt) of 0 (disk) for don't know. Transport
- * protocol (tproto) should be -1 if not known, else SCSI value.
- * N.B. Does not write total VPD page length into dop[2:3] . */
-int sg_make_vpd_devid_for_nvme(const uint8_t * nvme_id_ctl_p,
- const uint8_t * nvme_id_ns_p, int pdt,
- int tproto, uint8_t * dop, int max_do_len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SG_PT_NVME_H */
diff --git a/tools/sg_write_buffer/include/sg_pt_win32.h b/tools/sg_write_buffer/include/sg_pt_win32.h
deleted file mode 100644
index b49437f..0000000
--- a/tools/sg_write_buffer/include/sg_pt_win32.h
+++ /dev/null
@@ -1,473 +0,0 @@
-#ifndef SG_PT_WIN32_H
-#define SG_PT_WIN32_H
-/*
- * The information in this file was obtained from scsi-wnt.h by
- * Richard Stemmer, rs@epost.de . He in turn gives credit to
- * Jay A. Key (for scsipt.c).
- * The plscsi program (by Pat LaVarre <p.lavarre@ieee.org>) has
- * also been used as a reference.
- * Much of the information in this header can also be obtained
- * from msdn.microsoft.com .
- * Updated for cygwin version 1.7.17 changes 20121026
- */
-
-/* WIN32_LEAN_AND_MEAN may be required to prevent inclusion of <winioctl.h> */
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define SCSI_MAX_SENSE_LEN 64
-#define SCSI_MAX_CDB_LEN 16
-#define SCSI_MAX_INDIRECT_DATA 16384
-
-typedef struct {
- USHORT Length;
- UCHAR ScsiStatus;
- UCHAR PathId;
- UCHAR TargetId;
- UCHAR Lun;
- UCHAR CdbLength;
- UCHAR SenseInfoLength;
- UCHAR DataIn;
- ULONG DataTransferLength;
- ULONG TimeOutValue;
- ULONG_PTR DataBufferOffset; /* was ULONG; problem in 64 bit */
- ULONG SenseInfoOffset;
- UCHAR Cdb[SCSI_MAX_CDB_LEN];
-} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
-
-
-typedef struct {
- USHORT Length;
- UCHAR ScsiStatus;
- UCHAR PathId;
- UCHAR TargetId;
- UCHAR Lun;
- UCHAR CdbLength;
- UCHAR SenseInfoLength;
- UCHAR DataIn;
- ULONG DataTransferLength;
- ULONG TimeOutValue;
- PVOID DataBuffer;
- ULONG SenseInfoOffset;
- UCHAR Cdb[SCSI_MAX_CDB_LEN];
-} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
-
-
-typedef struct {
- SCSI_PASS_THROUGH spt;
- /* plscsi shows a follow on 16 bytes allowing 32 byte cdb */
- ULONG Filler;
- UCHAR ucSenseBuf[SCSI_MAX_SENSE_LEN];
- UCHAR ucDataBuf[SCSI_MAX_INDIRECT_DATA];
-} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
-
-
-typedef struct {
- SCSI_PASS_THROUGH_DIRECT spt;
- ULONG Filler;
- UCHAR ucSenseBuf[SCSI_MAX_SENSE_LEN];
-} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
-
-
-
-typedef struct {
- UCHAR NumberOfLogicalUnits;
- UCHAR InitiatorBusId;
- ULONG InquiryDataOffset;
-} SCSI_BUS_DATA, *PSCSI_BUS_DATA;
-
-
-typedef struct {
- UCHAR NumberOfBusses;
- SCSI_BUS_DATA BusData[1];
-} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO;
-
-
-typedef struct {
- UCHAR PathId;
- UCHAR TargetId;
- UCHAR Lun;
- BOOLEAN DeviceClaimed;
- ULONG InquiryDataLength;
- ULONG NextInquiryDataOffset;
- UCHAR InquiryData[1];
-} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA;
-
-
-typedef struct {
- ULONG Length;
- UCHAR PortNumber;
- UCHAR PathId;
- UCHAR TargetId;
- UCHAR Lun;
-} SCSI_ADDRESS, *PSCSI_ADDRESS;
-
-/*
- * Standard IOCTL define
- */
-#ifndef CTL_CODE
-#define CTL_CODE(DevType, Function, Method, Access) \
- (((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
-#endif
-
-/*
- * file access values
- */
-#ifndef FILE_ANY_ACCESS
-#define FILE_ANY_ACCESS 0
-#endif
-#ifndef FILE_READ_ACCESS
-#define FILE_READ_ACCESS 0x0001
-#endif
-#ifndef FILE_WRITE_ACCESS
-#define FILE_WRITE_ACCESS 0x0002
-#endif
-
-// IOCTL_STORAGE_QUERY_PROPERTY
-
-#define FILE_DEVICE_MASS_STORAGE 0x0000002d
-#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
-#define FILE_ANY_ACCESS 0
-
-// #define METHOD_BUFFERED 0
-
-#define IOCTL_STORAGE_QUERY_PROPERTY \
- CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-
-#ifndef _DEVIOCTL_
-typedef enum _STORAGE_BUS_TYPE {
- BusTypeUnknown = 0x00,
- BusTypeScsi = 0x01,
- BusTypeAtapi = 0x02,
- BusTypeAta = 0x03,
- BusType1394 = 0x04,
- BusTypeSsa = 0x05,
- BusTypeFibre = 0x06,
- BusTypeUsb = 0x07,
- BusTypeRAID = 0x08,
- BusTypeiScsi = 0x09,
- BusTypeSas = 0x0A,
- BusTypeSata = 0x0B,
- BusTypeSd = 0x0C,
- BusTypeMmc = 0x0D,
- BusTypeVirtual = 0xE,
- BusTypeFileBackedVirtual = 0xF,
- BusTypeSpaces = 0x10,
- BusTypeNvme = 0x11,
- BusTypeSCM = 0x12,
- BusTypeUfs = 0x13,
- BusTypeMax = 0x14,
- BusTypeMaxReserved = 0x7F
-} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
-
-typedef enum _STORAGE_PROTOCOL_TYPE {
- ProtocolTypeUnknown = 0,
- ProtocolTypeScsi,
- ProtocolTypeAta,
- ProtocolTypeNvme,
- ProtocolTypeSd
-} STORAGE_PROTOCOL_TYPE;
-
-typedef enum _STORAGE_PROTOCOL_NVME_DATA_TYPE {
- NVMeDataTypeUnknown = 0,
- NVMeDataTypeIdentify,
- NVMeDataTypeLogPage,
- NVMeDataTypeFeature
-} STORAGE_PROTOCOL_NVME_DATA_TYPE;
-
-typedef struct _STORAGE_PROTOCOL_SPECIFIC_DATA {
- STORAGE_PROTOCOL_TYPE ProtocolType;
- ULONG DataType;
- ULONG ProtocolDataRequestValue;
- ULONG ProtocolDataRequestSubValue;
- ULONG ProtocolDataOffset;
- ULONG ProtocolDataLength;
- ULONG FixedProtocolReturnData;
- ULONG Reserved[3];
-} STORAGE_PROTOCOL_SPECIFIC_DATA;
-
-
-typedef struct _STORAGE_DEVICE_DESCRIPTOR {
- ULONG Version;
- ULONG Size;
- UCHAR DeviceType;
- UCHAR DeviceTypeModifier;
- BOOLEAN RemovableMedia;
- BOOLEAN CommandQueueing;
- ULONG VendorIdOffset; /* 0 if not available */
- ULONG ProductIdOffset; /* 0 if not available */
- ULONG ProductRevisionOffset;/* 0 if not available */
- ULONG SerialNumberOffset; /* -1 if not available ?? */
- STORAGE_BUS_TYPE BusType;
- ULONG RawPropertiesLength;
- UCHAR RawDeviceProperties[1];
-} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
-
-#define STORAGE_PROTOCOL_STRUCTURE_VERSION 0x1
-
-#define IOCTL_STORAGE_PROTOCOL_COMMAND \
- CTL_CODE(IOCTL_STORAGE_BASE, 0x04F0, METHOD_BUFFERED, \
- FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
-typedef struct _STORAGE_PROTOCOL_COMMAND {
- DWORD Version; /* STORAGE_PROTOCOL_STRUCTURE_VERSION */
- DWORD Length;
- STORAGE_PROTOCOL_TYPE ProtocolType;
- DWORD Flags;
- DWORD ReturnStatus;
- DWORD ErrorCode;
- DWORD CommandLength;
- DWORD ErrorInfoLength;
- DWORD DataToDeviceTransferLength;
- DWORD DataFromDeviceTransferLength;
- DWORD TimeOutValue;
- DWORD ErrorInfoOffset;
- DWORD DataToDeviceBufferOffset;
- DWORD DataFromDeviceBufferOffset;
- DWORD CommandSpecific;
- DWORD Reserved0;
- DWORD FixedProtocolReturnData;
- DWORD Reserved1[3];
- BYTE Command[1]; /* has CommandLength elements */
-} STORAGE_PROTOCOL_COMMAND, *PSTORAGE_PROTOCOL_COMMAND;
-
-#endif /* _DEVIOCTL_ */
-
-typedef struct _STORAGE_DEVICE_UNIQUE_IDENTIFIER {
- ULONG Version;
- ULONG Size;
- ULONG StorageDeviceIdOffset;
- ULONG StorageDeviceOffset;
- ULONG DriveLayoutSignatureOffset;
-} STORAGE_DEVICE_UNIQUE_IDENTIFIER, *PSTORAGE_DEVICE_UNIQUE_IDENTIFIER;
-
-// Use CompareStorageDuids(PSTORAGE_DEVICE_UNIQUE_IDENTIFIER duid1, duid2)
-// to test for equality
-
-#ifndef _DEVIOCTL_
-typedef enum _STORAGE_QUERY_TYPE {
- PropertyStandardQuery = 0,
- PropertyExistsQuery,
- PropertyMaskQuery,
- PropertyQueryMaxDefined
-} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
-
-typedef enum _STORAGE_PROPERTY_ID {
- StorageDeviceProperty = 0,
- StorageAdapterProperty,
- StorageDeviceIdProperty,
- StorageDeviceUniqueIdProperty,
- StorageDeviceWriteCacheProperty,
- StorageMiniportProperty,
- StorageAccessAlignmentProperty,
- /* Identify controller goes to adapter; Identify namespace to device */
- StorageAdapterProtocolSpecificProperty = 49,
- StorageDeviceProtocolSpecificProperty = 50
-} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
-
-typedef struct _STORAGE_PROPERTY_QUERY {
- STORAGE_PROPERTY_ID PropertyId;
- STORAGE_QUERY_TYPE QueryType;
- UCHAR AdditionalParameters[1];
-} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
-
-typedef struct _STORAGE_PROTOCOL_DATA_DESCRIPTOR {
- DWORD Version;
- DWORD Size;
- STORAGE_PROTOCOL_SPECIFIC_DATA ProtocolSpecificData;
-} STORAGE_PROTOCOL_DATA_DESCRIPTOR, *PSTORAGE_PROTOCOL_DATA_DESCRIPTOR;
-
-// Command completion status
-// The "Phase Tag" field and "Status Field" are separated in spec. We define
-// them in the same data structure to ease the memory access from software.
-//
-typedef union {
- struct {
- USHORT P : 1; // Phase Tag (P)
-
- USHORT SC : 8; // Status Code (SC)
- USHORT SCT : 3; // Status Code Type (SCT)
- USHORT Reserved : 2;
- USHORT M : 1; // More (M)
- USHORT DNR : 1; // Do Not Retry (DNR)
- } DUMMYSTRUCTNAME;
- USHORT AsUshort;
-} NVME_COMMAND_STATUS, *PNVME_COMMAND_STATUS;
-
-// Information of log: NVME_LOG_PAGE_ERROR_INFO. Size: 64 bytes
-//
-typedef struct {
- ULONGLONG ErrorCount;
- USHORT SQID; // Submission Queue ID
- USHORT CMDID; // Command ID
- NVME_COMMAND_STATUS Status; // Status Field: This field indicates the
- // Status Field for the command that
- // completed. The Status Field is located in
- // bits 15:01, bit 00 corresponds to the Phase
- // Tag posted for the command.
- struct {
- USHORT Byte : 8; // Byte in command that contained error
- USHORT Bit : 3; // Bit in command that contained error
- USHORT Reserved : 5;
- } ParameterErrorLocation;
-
- ULONGLONG Lba; // LBA: This field indicates the first LBA
- // that experienced the error condition, if
- // applicable.
- ULONG NameSpace; // Namespace: This field indicates the nsid
- // that the error is associated with, if
- // applicable.
- UCHAR VendorInfoAvailable; // Vendor Specific Information Available
- UCHAR Reserved0[3];
- ULONGLONG CommandSpecificInfo; // This field contains command specific
- // information. If used, the command
- // definition specifies the information
- // returned.
- UCHAR Reserved1[24];
-} NVME_ERROR_INFO_LOG, *PNVME_ERROR_INFO_LOG;
-
-typedef struct {
-
- ULONG DW0;
- ULONG Reserved;
-
- union {
- struct {
- USHORT SQHD; // SQ Head Pointer (SQHD)
- USHORT SQID; // SQ Identifier (SQID)
- } DUMMYSTRUCTNAME;
-
- ULONG AsUlong;
- } DW2;
-
- union {
- struct {
- USHORT CID; // Command Identifier (CID)
- NVME_COMMAND_STATUS Status;
- } DUMMYSTRUCTNAME;
-
- ULONG AsUlong;
- } DW3;
-
-} NVME_COMPLETION_ENTRY, *PNVME_COMPLETION_ENTRY;
-
-
-// Bit-mask values for STORAGE_PROTOCOL_COMMAND - "Flags" field.
-//
-// Flag indicates the request targeting to adapter instead of device.
-#define STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST 0x80000000
-
-//
-// Status values for STORAGE_PROTOCOL_COMMAND - "ReturnStatus" field.
-//
-#define STORAGE_PROTOCOL_STATUS_PENDING 0x0
-#define STORAGE_PROTOCOL_STATUS_SUCCESS 0x1
-#define STORAGE_PROTOCOL_STATUS_ERROR 0x2
-#define STORAGE_PROTOCOL_STATUS_INVALID_REQUEST 0x3
-#define STORAGE_PROTOCOL_STATUS_NO_DEVICE 0x4
-#define STORAGE_PROTOCOL_STATUS_BUSY 0x5
-#define STORAGE_PROTOCOL_STATUS_DATA_OVERRUN 0x6
-#define STORAGE_PROTOCOL_STATUS_INSUFFICIENT_RESOURCES 0x7
-
-#define STORAGE_PROTOCOL_STATUS_NOT_SUPPORTED 0xFF
-
-// Command Length for Storage Protocols.
-//
-// NVMe commands are always 64 bytes.
-#define STORAGE_PROTOCOL_COMMAND_LENGTH_NVME 0x40
-
-// Command Specific Information for Storage Protocols - CommandSpecific field
-//
-#define STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND 0x01
-#define STORAGE_PROTOCOL_SPECIFIC_NVME_NVM_COMMAND 0x02
-
-#endif /* _DEVIOCTL_ */
-
-
-// NVME_PASS_THROUGH
-
-#ifndef STB_IO_CONTROL
-typedef struct _SRB_IO_CONTROL {
- ULONG HeaderLength;
- UCHAR Signature[8];
- ULONG Timeout;
- ULONG ControlCode;
- ULONG ReturnCode;
- ULONG Length;
-} SRB_IO_CONTROL, *PSRB_IO_CONTROL;
-#endif
-
-#ifndef NVME_PASS_THROUGH_SRB_IO_CODE
-
-#define NVME_SIG_STR "NvmeMini"
-#define NVME_STORPORT_DRIVER 0xe000
-
-#define NVME_PASS_THROUGH_SRB_IO_CODE \
- CTL_CODE(NVME_STORPORT_DRIVER, 0x0800, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#pragma pack(1)
-
-/* Following is pre-Win10; used with DeviceIoControl(IOCTL_SCSI_MINIPORT),
- * in Win10 need DeviceIoControl(IOCTL_STORAGE_PROTOCOL_COMMAND) for pure
- * pass-through. Win10 also has "Protocol specific queries" for things like
- * Identify and Get feature. */
-typedef struct _NVME_PASS_THROUGH_IOCTL
-{
- SRB_IO_CONTROL SrbIoCtrl;
- ULONG VendorSpecific[6];
- ULONG NVMeCmd[16]; /* Command DW[0...15] */
- ULONG CplEntry[4]; /* Completion DW[0...3] */
- ULONG Direction; /* 0=None, 1=Out, 2=In, 3=I/O */
- ULONG QueueId; /* 0=AdminQ */
- ULONG DataBufferLen; /* sizeof(DataBuffer) if Data In */
- ULONG MetaDataLen;
- ULONG ReturnBufferLen; /* offsetof(DataBuffer), plus
- * sizeof(DataBuffer) if Data Out */
- UCHAR DataBuffer[1];
-} NVME_PASS_THROUGH_IOCTL;
-#pragma pack()
-
-#endif // NVME_PASS_THROUGH_SRB_IO_CODE
-
-
-/*
- * method codes
- */
-#define METHOD_BUFFERED 0
-#define METHOD_IN_DIRECT 1
-#define METHOD_OUT_DIRECT 2
-#define METHOD_NEITHER 3
-
-
-#define IOCTL_SCSI_BASE 0x00000004
-
-/*
- * constants for DataIn member of SCSI_PASS_THROUGH* structures
- */
-#define SCSI_IOCTL_DATA_OUT 0
-#define SCSI_IOCTL_DATA_IN 1
-#define SCSI_IOCTL_DATA_UNSPECIFIED 2
-
-#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, \
- METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, \
- METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, \
- METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, \
- METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, \
- METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, \
- METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/tools/sg_write_buffer/include/sg_unaligned.h b/tools/sg_write_buffer/include/sg_unaligned.h
deleted file mode 100644
index 3b2c70a..0000000
--- a/tools/sg_write_buffer/include/sg_unaligned.h
+++ /dev/null
@@ -1,325 +0,0 @@
-#ifndef SG_UNALIGNED_H
-#define SG_UNALIGNED_H
-
-/*
- * Copyright (c) 2014-2017 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Borrowed from the Linux kernel, via mhvtl */
-
-/* In the first section below, functions that copy unsigned integers in a
- * computer's native format, to and from an unaligned big endian sequence of
- * bytes. Big endian byte format "on the wire" is the default used by SCSI
- * standards (www.t10.org). Big endian is also the network byte order. */
-
-static inline uint16_t __get_unaligned_be16(const uint8_t *p)
-{
- return p[0] << 8 | p[1];
-}
-
-static inline uint32_t __get_unaligned_be32(const uint8_t *p)
-{
- return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
-}
-
-/* Assume 48 bit value placed in uint64_t */
-static inline uint64_t __get_unaligned_be48(const uint8_t *p)
-{
- return (uint64_t)__get_unaligned_be16(p) << 32 |
- __get_unaligned_be32(p + 2);
-}
-
-static inline uint64_t __get_unaligned_be64(const uint8_t *p)
-{
- return (uint64_t)__get_unaligned_be32(p) << 32 |
- __get_unaligned_be32(p + 4);
-}
-
-static inline void __put_unaligned_be16(uint16_t val, uint8_t *p)
-{
- *p++ = val >> 8;
- *p++ = val;
-}
-
-static inline void __put_unaligned_be32(uint32_t val, uint8_t *p)
-{
- __put_unaligned_be16(val >> 16, p);
- __put_unaligned_be16(val, p + 2);
-}
-
-/* Assume 48 bit value placed in uint64_t */
-static inline void __put_unaligned_be48(uint64_t val, uint8_t *p)
-{
- __put_unaligned_be16(val >> 32, p);
- __put_unaligned_be32(val, p + 2);
-}
-
-static inline void __put_unaligned_be64(uint64_t val, uint8_t *p)
-{
- __put_unaligned_be32(val >> 32, p);
- __put_unaligned_be32(val, p + 4);
-}
-
-static inline uint16_t sg_get_unaligned_be16(const void *p)
-{
- return __get_unaligned_be16((const uint8_t *)p);
-}
-
-static inline uint32_t sg_get_unaligned_be24(const void *p)
-{
- return ((const uint8_t *)p)[0] << 16 | ((const uint8_t *)p)[1] << 8 |
- ((const uint8_t *)p)[2];
-}
-
-static inline uint32_t sg_get_unaligned_be32(const void *p)
-{
- return __get_unaligned_be32((const uint8_t *)p);
-}
-
-/* Assume 48 bit value placed in uint64_t */
-static inline uint64_t sg_get_unaligned_be48(const void *p)
-{
- return __get_unaligned_be48((const uint8_t *)p);
-}
-
-static inline uint64_t sg_get_unaligned_be64(const void *p)
-{
- return __get_unaligned_be64((const uint8_t *)p);
-}
-
-/* Returns 0 if 'num_bytes' is less than or equal to 0 or greater than
- * 8 (i.e. sizeof(uint64_t)). Else returns result in uint64_t which is
- * an 8 byte unsigned integer. */
-static inline uint64_t sg_get_unaligned_be(int num_bytes, const void *p)
-{
- if ((num_bytes <= 0) || (num_bytes > (int)sizeof(uint64_t)))
- return 0;
- else {
- const uint8_t * xp = (const uint8_t *)p;
- uint64_t res = *xp;
-
- for (++xp; num_bytes > 1; ++xp, --num_bytes)
- res = (res << 8) | *xp;
- return res;
- }
-}
-
-static inline void sg_put_unaligned_be16(uint16_t val, void *p)
-{
- __put_unaligned_be16(val, (uint8_t *)p);
-}
-
-static inline void sg_put_unaligned_be24(uint32_t val, void *p)
-{
- ((uint8_t *)p)[0] = (val >> 16) & 0xff;
- ((uint8_t *)p)[1] = (val >> 8) & 0xff;
- ((uint8_t *)p)[2] = val & 0xff;
-}
-
-static inline void sg_put_unaligned_be32(uint32_t val, void *p)
-{
- __put_unaligned_be32(val, (uint8_t *)p);
-}
-
-/* Assume 48 bit value placed in uint64_t */
-static inline void sg_put_unaligned_be48(uint64_t val, void *p)
-{
- __put_unaligned_be48(val, (uint8_t *)p);
-}
-
-static inline void sg_put_unaligned_be64(uint64_t val, void *p)
-{
- __put_unaligned_be64(val, (uint8_t *)p);
-}
-
-/* Since cdb and parameter blocks are often memset to zero before these
- * unaligned function partially fill them, then check for a val of zero
- * and ignore if it is with these variants. */
-static inline void sg_nz_put_unaligned_be16(uint16_t val, void *p)
-{
- if (val)
- __put_unaligned_be16(val, (uint8_t *)p);
-}
-
-static inline void sg_nz_put_unaligned_be24(uint32_t val, void *p)
-{
- if (val) {
- ((uint8_t *)p)[0] = (val >> 16) & 0xff;
- ((uint8_t *)p)[1] = (val >> 8) & 0xff;
- ((uint8_t *)p)[2] = val & 0xff;
- }
-}
-
-static inline void sg_nz_put_unaligned_be32(uint32_t val, void *p)
-{
- if (val)
- __put_unaligned_be32(val, (uint8_t *)p);
-}
-
-static inline void sg_nz_put_unaligned_be64(uint64_t val, void *p)
-{
- if (val)
- __put_unaligned_be64(val, (uint8_t *)p);
-}
-
-
-/* Below are the little endian equivalents of the big endian functions
- * above. Little endian is used by ATA, PCI and NVMe.
- */
-
-static inline uint16_t __get_unaligned_le16(const uint8_t *p)
-{
- return p[1] << 8 | p[0];
-}
-
-static inline uint32_t __get_unaligned_le32(const uint8_t *p)
-{
- return p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
-}
-
-static inline uint64_t __get_unaligned_le64(const uint8_t *p)
-{
- return (uint64_t)__get_unaligned_le32(p + 4) << 32 |
- __get_unaligned_le32(p);
-}
-
-static inline void __put_unaligned_le16(uint16_t val, uint8_t *p)
-{
- *p++ = val;
- *p++ = val >> 8;
-}
-
-static inline void __put_unaligned_le32(uint32_t val, uint8_t *p)
-{
- __put_unaligned_le16(val >> 16, p + 2);
- __put_unaligned_le16(val, p);
-}
-
-static inline void __put_unaligned_le64(uint64_t val, uint8_t *p)
-{
- __put_unaligned_le32(val >> 32, p + 4);
- __put_unaligned_le32(val, p);
-}
-
-static inline uint16_t sg_get_unaligned_le16(const void *p)
-{
- return __get_unaligned_le16((const uint8_t *)p);
-}
-
-static inline uint32_t sg_get_unaligned_le24(const void *p)
-{
- return (uint32_t)__get_unaligned_le16((const uint8_t *)p) |
- ((const uint8_t *)p)[2] << 16;
-}
-
-static inline uint32_t sg_get_unaligned_le32(const void *p)
-{
- return __get_unaligned_le32((const uint8_t *)p);
-}
-
-/* Assume 48 bit value placed in uint64_t */
-static inline uint64_t sg_get_unaligned_le48(const void *p)
-{
- return (uint64_t)__get_unaligned_le16((const uint8_t *)p + 4) << 32 |
- __get_unaligned_le32((const uint8_t *)p);
-}
-
-static inline uint64_t sg_get_unaligned_le64(const void *p)
-{
- return __get_unaligned_le64((const uint8_t *)p);
-}
-
-/* Returns 0 if 'num_bytes' is less than or equal to 0 or greater than
- * 8 (i.e. sizeof(uint64_t)). Else returns result in uint64_t which is
- * an 8 byte unsigned integer. */
-static inline uint64_t sg_get_unaligned_le(int num_bytes, const void *p)
-{
- if ((num_bytes <= 0) || (num_bytes > (int)sizeof(uint64_t)))
- return 0;
- else {
- const uint8_t * xp = (const uint8_t *)p + (num_bytes - 1);
- uint64_t res = *xp;
-
- for (--xp; num_bytes > 1; --xp, --num_bytes)
- res = (res << 8) | *xp;
- return res;
- }
-}
-
-static inline void sg_put_unaligned_le16(uint16_t val, void *p)
-{
- __put_unaligned_le16(val, (uint8_t *)p);
-}
-
-static inline void sg_put_unaligned_le24(uint32_t val, void *p)
-{
- ((uint8_t *)p)[2] = (val >> 16) & 0xff;
- ((uint8_t *)p)[1] = (val >> 8) & 0xff;
- ((uint8_t *)p)[0] = val & 0xff;
-}
-
-static inline void sg_put_unaligned_le32(uint32_t val, void *p)
-{
- __put_unaligned_le32(val, (uint8_t *)p);
-}
-
-/* Assume 48 bit value placed in uint64_t */
-static inline void sg_put_unaligned_le48(uint64_t val, void *p)
-{
- ((uint8_t *)p)[5] = (val >> 40) & 0xff;
- ((uint8_t *)p)[4] = (val >> 32) & 0xff;
- ((uint8_t *)p)[3] = (val >> 24) & 0xff;
- ((uint8_t *)p)[2] = (val >> 16) & 0xff;
- ((uint8_t *)p)[1] = (val >> 8) & 0xff;
- ((uint8_t *)p)[0] = val & 0xff;
-}
-
-static inline void sg_put_unaligned_le64(uint64_t val, void *p)
-{
- __put_unaligned_le64(val, (uint8_t *)p);
-}
-
-/* Since cdb and parameter blocks are often memset to zero before these
- * unaligned function partially fill them, then check for a val of zero
- * and ignore if it is with these variants. */
-static inline void sg_nz_put_unaligned_le16(uint16_t val, void *p)
-{
- if (val)
- __put_unaligned_le16(val, (uint8_t *)p);
-}
-
-static inline void sg_nz_put_unaligned_le24(uint32_t val, void *p)
-{
- if (val) {
- ((uint8_t *)p)[2] = (val >> 16) & 0xff;
- ((uint8_t *)p)[1] = (val >> 8) & 0xff;
- ((uint8_t *)p)[0] = val & 0xff;
- }
-}
-
-static inline void sg_nz_put_unaligned_le32(uint32_t val, void *p)
-{
- if (val)
- __put_unaligned_le32(val, (uint8_t *)p);
-}
-
-static inline void sg_nz_put_unaligned_le64(uint64_t val, void *p)
-{
- if (val)
- __put_unaligned_le64(val, (uint8_t *)p);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SG_UNALIGNED_H */
diff --git a/tools/sg_write_buffer/sg_cmds_basic.c b/tools/sg_write_buffer/sg_cmds_basic.c
deleted file mode 100644
index 35a4991..0000000
--- a/tools/sg_write_buffer/sg_cmds_basic.c
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Copyright (c) 1999-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-/*
- * CONTENTS
- * Some SCSI commands are executed in many contexts and hence began
- * to appear in several sg3_utils utilities. This files centralizes
- * some of the low level command execution code. In most cases the
- * interpretation of the command response is left to the each
- * utility.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sg_lib.h"
-#include "sg_cmds_basic.h"
-#include "sg_pt.h"
-#include "sg_unaligned.h"
-
-/* Needs to be after config.h */
-#ifdef SG_LIB_LINUX
-#include <errno.h>
-#endif
-
-
-static const char * const version_str = "1.83 20180204";
-
-
-#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
-#define EBUFF_SZ 256
-
-#define DEF_PT_TIMEOUT 60 /* 60 seconds */
-#define START_PT_TIMEOUT 120 /* 120 seconds == 2 minutes */
-#define LONG_PT_TIMEOUT 7200 /* 7,200 seconds == 120 minutes */
-
-#define INQUIRY_CMD 0x12
-#define INQUIRY_CMDLEN 6
-#define REQUEST_SENSE_CMD 0x3
-#define REQUEST_SENSE_CMDLEN 6
-#define REPORT_LUNS_CMD 0xa0
-#define REPORT_LUNS_CMDLEN 12
-#define TUR_CMD 0x0
-#define TUR_CMDLEN 6
-
-#define SAFE_STD_INQ_RESP_LEN 36 /* other lengths lock up some devices */
-
-
-const char *
-sg_cmds_version()
-{
- return version_str;
-}
-
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
-/* Returns file descriptor >= 0 if successful. If error in Unix returns
- negated errno. */
-int
-sg_cmds_open_device(const char * device_name, bool read_only, int verbose)
-{
- /* The following 2 lines are temporary. It is to avoid a NULL pointer
- * crash when an old utility is used with a newer library built after
- * the sg_warnings_strm cleanup */
- if (NULL == sg_warnings_strm)
- sg_warnings_strm = stderr;
-
- return scsi_pt_open_device(device_name, read_only, verbose);
-}
-
-/* Returns file descriptor >= 0 if successful. If error in Unix returns
- negated errno. */
-int
-sg_cmds_open_flags(const char * device_name, int flags, int verbose)
-{
- return scsi_pt_open_flags(device_name, flags, verbose);
-}
-
-/* Returns 0 if successful. If error in Unix returns negated errno. */
-int
-sg_cmds_close_device(int device_fd)
-{
- return scsi_pt_close_device(device_fd);
-}
-
-static const char * const pass_through_s = "pass-through";
-
-static int
-sg_cmds_process_helper(const char * leadin, int mx_di_len, int resid,
- const unsigned char * sbp, int slen, bool noisy,
- int verbose, int * o_sense_cat)
-{
- int scat, got;
- bool n = false;
- bool check_data_in = false;
- char b[512];
-
- scat = sg_err_category_sense(sbp, slen);
- switch (scat) {
- case SG_LIB_CAT_NOT_READY:
- case SG_LIB_CAT_INVALID_OP:
- case SG_LIB_CAT_ILLEGAL_REQ:
- case SG_LIB_CAT_ABORTED_COMMAND:
- case SG_LIB_CAT_COPY_ABORTED:
- case SG_LIB_CAT_DATA_PROTECT:
- case SG_LIB_CAT_PROTECTION:
- case SG_LIB_CAT_NO_SENSE:
- case SG_LIB_CAT_MISCOMPARE:
- n = false;
- break;
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_MEDIUM_HARD:
- check_data_in = true;
-#if defined(__GNUC__)
-#if (__GNUC__ >= 7)
- __attribute__((fallthrough));
- /* FALL THROUGH */
-#endif
-#endif
- case SG_LIB_CAT_UNIT_ATTENTION:
- case SG_LIB_CAT_SENSE:
- default:
- n = noisy;
- break;
- }
- if (verbose || n) {
- if (leadin && (strlen(leadin) > 0))
- pr2ws("%s:\n", leadin);
- sg_get_sense_str(NULL, sbp, slen, (verbose > 1),
- sizeof(b), b);
- pr2ws("%s", b);
- if ((mx_di_len > 0) && (resid > 0)) {
- got = mx_di_len - resid;
- if ((verbose > 2) || check_data_in || (got > 0))
- pr2ws(" %s requested %d bytes (data-in) but got %d "
- "bytes\n", pass_through_s, mx_di_len, got);
- }
- }
- if (o_sense_cat)
- *o_sense_cat = scat;
- return -2;
-}
-
-/* This is a helper function used by sg_cmds_* implementations after the
- * call to the pass-through. pt_res is returned from do_scsi_pt(). If valid
- * sense data is found it is decoded and output to sg_warnings_strm (def:
- * stderr); depending on the 'noisy' and 'verbose' settings. Returns -2 for
- * "sense" category (may not be fatal), -1 for failed, 0, or a positive
- * number. If 'mx_di_len > 0' then asks pass-through for resid and returns
- * (mx_di_len - resid); otherwise returns 0. So for data-in it should return
- * the actual number of bytes received. For data-out (to device) or no data
- * call with 'mx_di_len' set to 0 or less. If -2 returned then sense category
- * output via 'o_sense_cat' pointer (if not NULL). Note that several sense
- * categories also have data in bytes received; -2 is still returned. */
-int
-sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin,
- int pt_res, int mx_di_len, const unsigned char * sbp,
- bool noisy, int verbose, int * o_sense_cat)
-{
- int got, cat, duration, slen, resid, resp_code, sstat;
- bool transport_sense;
- char b[1024];
-
- if (NULL == leadin)
- leadin = "";
- if (pt_res < 0) {
-#ifdef SG_LIB_LINUX
- if (verbose)
- pr2ws("%s: %s os error: %s\n", leadin, pass_through_s,
- safe_strerror(-pt_res));
- if ((-ENXIO == pt_res) && o_sense_cat) {
- if (verbose > 2)
- pr2ws("map ENXIO to SG_LIB_CAT_NOT_READY\n");
- *o_sense_cat = SG_LIB_CAT_NOT_READY;
- return -2;
- } else if (noisy && (0 == verbose))
- pr2ws("%s: %s os error: %s\n", leadin, pass_through_s,
- safe_strerror(-pt_res));
-#else
- if (noisy || verbose)
- pr2ws("%s: %s os error: %s\n", leadin, pass_through_s,
- safe_strerror(-pt_res));
-#endif
- return -1;
- } else if (SCSI_PT_DO_BAD_PARAMS == pt_res) {
- pr2ws("%s: bad %s setup\n", leadin, pass_through_s);
- return -1;
- } else if (SCSI_PT_DO_TIMEOUT == pt_res) {
- pr2ws("%s: %s timeout\n", leadin, pass_through_s);
- return -1;
- }
- if ((verbose > 2) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0))
- pr2ws(" duration=%d ms\n", duration);
- resid = (mx_di_len > 0) ? get_scsi_pt_resid(ptvp) : 0;
- slen = get_scsi_pt_sense_len(ptvp);
- switch ((cat = get_scsi_pt_result_category(ptvp))) {
- case SCSI_PT_RESULT_GOOD:
- if (sbp && (slen > 7)) {
- resp_code = sbp[0] & 0x7f;
- /* SBC referrals can have status=GOOD and sense_key=COMPLETED */
- if (resp_code >= 0x70) {
- if (resp_code < 0x72) {
- if (SPC_SK_NO_SENSE != (0xf & sbp[2]))
- sg_err_category_sense(sbp, slen);
- } else if (resp_code < 0x74) {
- if (SPC_SK_NO_SENSE != (0xf & sbp[1]))
- sg_err_category_sense(sbp, slen);
- }
- }
- }
- if (mx_di_len > 0) {
- got = mx_di_len - resid;
- if ((verbose > 1) && (resid != 0))
- pr2ws(" %s: %s requested %d bytes (data-in) but got %d "
- "bytes\n", leadin, pass_through_s, mx_di_len, got);
- if (got >= 0)
- return got;
- else {
- if (verbose)
- pr2ws(" %s: %s can't get negative bytes, say it got "
- "none\n", leadin, pass_through_s);
- return 0;
- }
- } else
- return 0;
- case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */
- sstat = get_scsi_pt_status_response(ptvp);
- if (o_sense_cat) {
- switch (sstat) {
- case SAM_STAT_RESERVATION_CONFLICT:
- *o_sense_cat = SG_LIB_CAT_RES_CONFLICT;
- return -2;
- case SAM_STAT_CONDITION_MET:
- *o_sense_cat = SG_LIB_CAT_CONDITION_MET;
- return -2;
- case SAM_STAT_BUSY:
- *o_sense_cat = SG_LIB_CAT_BUSY;
- return -2;
- case SAM_STAT_TASK_SET_FULL:
- *o_sense_cat = SG_LIB_CAT_TS_FULL;
- return -2;
- case SAM_STAT_ACA_ACTIVE:
- *o_sense_cat = SG_LIB_CAT_ACA_ACTIVE;
- return -2;
- case SAM_STAT_TASK_ABORTED:
- *o_sense_cat = SG_LIB_CAT_TASK_ABORTED;
- return -2;
- default:
- break;
- }
- }
- if (verbose || noisy) {
- sg_get_scsi_status_str(sstat, sizeof(b), b);
- pr2ws("%s: scsi status: %s\n", leadin, b);
- }
- return -1;
- case SCSI_PT_RESULT_SENSE:
- return sg_cmds_process_helper(leadin, mx_di_len, resid, sbp, slen,
- noisy, verbose, o_sense_cat);
- case SCSI_PT_RESULT_TRANSPORT_ERR:
- if (verbose || noisy) {
- get_scsi_pt_transport_err_str(ptvp, sizeof(b), b);
- pr2ws("%s: transport: %s\n", leadin, b);
- }
-#ifdef SG_LIB_LINUX
- transport_sense = (slen > 0);
-#else
- transport_sense = ((SAM_STAT_CHECK_CONDITION ==
- get_scsi_pt_status_response(ptvp)) && (slen > 0));
-#endif
- if (transport_sense)
- return sg_cmds_process_helper(leadin, mx_di_len, resid, sbp,
- slen, noisy, verbose, o_sense_cat);
- else
- return -1;
- case SCSI_PT_RESULT_OS_ERR:
- if (verbose || noisy) {
- get_scsi_pt_os_err_str(ptvp, sizeof(b), b);
- pr2ws("%s: os: %s\n", leadin, b);
- }
- return -1;
- default:
- pr2ws("%s: unknown %s result category (%d)\n", leadin, pass_through_s,
- cat);
- return -1;
- }
-}
-
-bool
-sg_cmds_is_nvme(const struct sg_pt_base * ptvp)
-{
- return pt_device_is_nvme(ptvp);
-}
-
-static struct sg_pt_base *
-create_pt_obj(const char * cname)
-{
- struct sg_pt_base * ptvp = construct_scsi_pt_obj();
- if (NULL == ptvp)
- pr2ws("%s: out of memory\n", cname);
- return ptvp;
-}
-
-static const char * const inquiry_s = "inquiry";
-
-static int
-sg_ll_inquiry_com(int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp,
- int mx_resp_len, int timeout_secs, int * residp,
- bool noisy, int verbose)
-{
- int res, ret, k, sense_cat, resid;
- unsigned char inq_cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- unsigned char * up;
- struct sg_pt_base * ptvp;
-
- if (cmddt)
- inq_cdb[1] |= 0x2;
- if (evpd)
- inq_cdb[1] |= 0x1;
- inq_cdb[2] = (unsigned char)pg_op;
- /* 16 bit allocation length (was 8, increased in spc3r09, 200209) */
- sg_put_unaligned_be16((uint16_t)mx_resp_len, inq_cdb + 3);
- if (verbose) {
- pr2ws(" %s cdb: ", inquiry_s);
- for (k = 0; k < INQUIRY_CMDLEN; ++k)
- pr2ws("%02x ", inq_cdb[k]);
- pr2ws("\n");
- }
- if (resp && (mx_resp_len > 0)) {
- up = (unsigned char *)resp;
- up[0] = 0x7f; /* defensive prefill */
- if (mx_resp_len > 4)
- up[4] = 0;
- }
- if (timeout_secs <= 0)
- timeout_secs = DEF_PT_TIMEOUT;
- ptvp = construct_scsi_pt_obj();
- if (NULL == ptvp) {
- pr2ws("%s: out of memory\n", __func__);
- if (residp)
- *residp = 0;
- return -1;
- }
- set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
- ret = sg_cmds_process_resp(ptvp, inquiry_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- resid = get_scsi_pt_resid(ptvp);
- if (residp)
- *residp = resid;
- if (-1 == ret)
- ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
- else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else if (ret < 4) {
- if (verbose)
- pr2ws("%s: got too few bytes (%d)\n", __func__, ret);
- ret = SG_LIB_CAT_MALFORMED;
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
-
- if (resid > 0) {
- if (resid > mx_resp_len) {
- pr2ws("%s resid (%d) should never exceed requested "
- "len=%d\n", inquiry_s, resid, mx_resp_len);
- return ret ? ret : SG_LIB_CAT_MALFORMED;
- }
- /* zero unfilled section of response buffer, based on resid */
- memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
- }
- return ret;
-}
-
-/* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when
- * successful, various SG_LIB_CAT_* positive values or -1 -> other errors.
- * The CMDDT field is obsolete in the INQUIRY cdb. */
-int
-sg_ll_inquiry(int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp,
- int mx_resp_len, bool noisy, int verbose)
-{
- return sg_ll_inquiry_com(sg_fd, cmddt, evpd, pg_op, resp, mx_resp_len,
- 0 /* timeout_sec */, NULL, noisy, verbose);
-}
-
-/* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response.
- * Returns 0 when successful, various SG_LIB_CAT_* positive values or
- * -1 -> other errors */
-int
-sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
- bool noisy, int verbose)
-{
- int ret;
- unsigned char inq_resp[SAFE_STD_INQ_RESP_LEN];
-
- if (inq_data) {
- memset(inq_data, 0, sizeof(* inq_data));
- inq_data->peripheral_qualifier = 0x3;
- inq_data->peripheral_type = 0x1f;
- }
- ret = sg_ll_inquiry_com(sg_fd, false, false, 0, inq_resp,
- sizeof(inq_resp), 0, NULL, noisy, verbose);
-
- if (inq_data && (0 == ret)) {
- inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7;
- inq_data->peripheral_type = inq_resp[0] & 0x1f;
- inq_data->byte_1 = inq_resp[1];
- inq_data->version = inq_resp[2];
- inq_data->byte_3 = inq_resp[3];
- inq_data->byte_5 = inq_resp[5];
- inq_data->byte_6 = inq_resp[6];
- inq_data->byte_7 = inq_resp[7];
- memcpy(inq_data->vendor, inq_resp + 8, 8);
- memcpy(inq_data->product, inq_resp + 16, 16);
- memcpy(inq_data->revision, inq_resp + 32, 4);
- }
- return ret;
-}
-
-/* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when
- * successful, various SG_LIB_CAT_* positive values or -1 -> other errors.
- * The CMDDT field is obsolete in the INQUIRY cdb (since spc3r16 in 2003) so
- * an argument to set it has been removed (use the REPORT SUPPORTED OPERATION
- * CODES command instead). Adds the ability to set the command abort timeout
- * and the ability to report the residual count. If timeout_secs is zero
- * or less the default command abort timeout (60 seconds) is used.
- * If residp is non-NULL then the residual value is written where residp
- * points. A residual value of 0 implies mx_resp_len bytes have be written
- * where resp points. If the residual value equals mx_resp_len then no
- * bytes have been written. */
-int
-sg_ll_inquiry_v2(int sg_fd, bool evpd, int pg_op, void * resp,
- int mx_resp_len, int timeout_secs, int * residp,
- bool noisy, int verbose)
-{
- return sg_ll_inquiry_com(sg_fd, false, evpd, pg_op, resp, mx_resp_len,
- timeout_secs, residp, noisy, verbose);
-}
-
-/* Invokes a SCSI TEST UNIT READY command.
- * 'pack_id' is just for diagnostics, safe to set to 0.
- * Looks for progress indicator if 'progress' non-NULL;
- * if found writes value [0..65535] else write -1.
- * Returns 0 when successful, various SG_LIB_CAT_* positive values or
- * -1 -> other errors */
-int
-sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress,
- bool noisy, int verbose)
-{
- static const char * const tur_s = "test unit ready";
- int res, ret, k, sense_cat;
- unsigned char tur_cdb[TUR_CMDLEN] = {TUR_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (verbose) {
- pr2ws(" %s cdb: ", tur_s);
- for (k = 0; k < TUR_CMDLEN; ++k)
- pr2ws("%02x ", tur_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(tur_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, tur_cdb, sizeof(tur_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_packet_id(ptvp, pack_id);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, tur_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- if (progress) {
- int slen = get_scsi_pt_sense_len(ptvp);
-
- if (! sg_get_sense_progress_fld(sense_b, slen, progress))
- *progress = -1;
- }
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI TEST UNIT READY command.
- * 'pack_id' is just for diagnostics, safe to set to 0.
- * Returns 0 when successful, various SG_LIB_CAT_* positive values or
- * -1 -> other errors */
-int
-sg_ll_test_unit_ready(int sg_fd, int pack_id, bool noisy, int verbose)
-{
- return sg_ll_test_unit_ready_progress(sg_fd, pack_id, NULL, noisy,
- verbose);
-}
-
-/* Invokes a SCSI REQUEST SENSE command. Returns 0 when successful, various
- * SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_request_sense(int sg_fd, bool desc, void * resp, int mx_resp_len,
- bool noisy, int verbose)
-{
- static const char * const rq_s = "request sense";
- int k, ret, res, sense_cat;
- unsigned char rs_cdb[REQUEST_SENSE_CMDLEN] =
- {REQUEST_SENSE_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (desc)
- rs_cdb[1] |= 0x1;
- if (mx_resp_len > 0xff) {
- pr2ws("mx_resp_len cannot exceed 255\n");
- return -1;
- }
- rs_cdb[4] = mx_resp_len & 0xff;
- if (verbose) {
- pr2ws(" %s cmd: ", rq_s);
- for (k = 0; k < REQUEST_SENSE_CMDLEN; ++k)
- pr2ws("%02x ", rs_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(rq_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, rq_s, res, mx_resp_len, sense_b, noisy,
- verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((mx_resp_len >= 8) && (ret < 8)) {
- if (verbose)
- pr2ws(" %s: got %d bytes in response, too short\n", rq_s,
- ret);
- ret = -1;
- } else
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_report_luns(int sg_fd, int select_report, void * resp, int mx_resp_len,
- bool noisy, int verbose)
-{
- static const char * const report_luns_s = "report luns";
- int k, ret, res, sense_cat;
- unsigned char rl_cdb[REPORT_LUNS_CMDLEN] =
- {REPORT_LUNS_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- rl_cdb[2] = select_report & 0xff;
- sg_put_unaligned_be32((uint32_t)mx_resp_len, rl_cdb + 6);
- if (verbose) {
- pr2ws(" %s cdb: ", report_luns_s);
- for (k = 0; k < REPORT_LUNS_CMDLEN; ++k)
- pr2ws("%02x ", rl_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(report_luns_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, report_luns_s, res, mx_resp_len,
- sense_b, noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
diff --git a/tools/sg_write_buffer/sg_cmds_basic2.c b/tools/sg_write_buffer/sg_cmds_basic2.c
deleted file mode 100644
index 18b6cd7..0000000
--- a/tools/sg_write_buffer/sg_cmds_basic2.c
+++ /dev/null
@@ -1,1069 +0,0 @@
-/*
- * Copyright (c) 1999-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-/*
- * CONTENTS
- * Some SCSI commands are executed in many contexts and hence began
- * to appear in several sg3_utils utilities. This files centralizes
- * some of the low level command execution code. In most cases the
- * interpretation of the command response is left to the each
- * utility.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sg_lib.h"
-#include "sg_cmds_basic.h"
-#include "sg_pt.h"
-#include "sg_unaligned.h"
-
-
-
-#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
-#define EBUFF_SZ 256
-
-#define DEF_PT_TIMEOUT 60 /* 60 seconds */
-#define START_PT_TIMEOUT 120 /* 120 seconds == 2 minutes */
-#define LONG_PT_TIMEOUT 7200 /* 7,200 seconds == 120 minutes */
-
-#define SYNCHRONIZE_CACHE_CMD 0x35
-#define SYNCHRONIZE_CACHE_CMDLEN 10
-#define SERVICE_ACTION_IN_16_CMD 0x9e
-#define SERVICE_ACTION_IN_16_CMDLEN 16
-#define READ_CAPACITY_16_SA 0x10
-#define READ_CAPACITY_10_CMD 0x25
-#define READ_CAPACITY_10_CMDLEN 10
-#define MODE_SENSE6_CMD 0x1a
-#define MODE_SENSE6_CMDLEN 6
-#define MODE_SENSE10_CMD 0x5a
-#define MODE_SENSE10_CMDLEN 10
-#define MODE_SELECT6_CMD 0x15
-#define MODE_SELECT6_CMDLEN 6
-#define MODE_SELECT10_CMD 0x55
-#define MODE_SELECT10_CMDLEN 10
-#define LOG_SENSE_CMD 0x4d
-#define LOG_SENSE_CMDLEN 10
-#define LOG_SELECT_CMD 0x4c
-#define LOG_SELECT_CMDLEN 10
-#define START_STOP_CMD 0x1b
-#define START_STOP_CMDLEN 6
-#define PREVENT_ALLOW_CMD 0x1e
-#define PREVENT_ALLOW_CMDLEN 6
-
-#define MODE6_RESP_HDR_LEN 4
-#define MODE10_RESP_HDR_LEN 8
-#define MODE_RESP_ARB_LEN 1024
-
-#define INQUIRY_RESP_INITIAL_LEN 36
-
-
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
-static struct sg_pt_base *
-create_pt_obj(const char * cname)
-{
- struct sg_pt_base * ptvp = construct_scsi_pt_obj();
- if (NULL == ptvp)
- pr2ws("%s: out of memory\n", cname);
- return ptvp;
-}
-
-/* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_sync_cache_10(int sg_fd, bool sync_nv, bool immed, int group,
- unsigned int lba, unsigned int count, bool noisy,
- int verbose)
-{
- static const char * const cdb_name_s = "synchronize cache(10)";
- int res, ret, k, sense_cat;
- unsigned char sc_cdb[SYNCHRONIZE_CACHE_CMDLEN] =
- {SYNCHRONIZE_CACHE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (sync_nv)
- sc_cdb[1] |= 4;
- if (immed)
- sc_cdb[1] |= 2;
- sg_put_unaligned_be32((uint32_t)lba, sc_cdb + 2);
- sc_cdb[6] = group & 0x1f;
- if (count > 0xffff) {
- pr2ws("count too big\n");
- return -1;
- }
- sg_put_unaligned_be16((int16_t)count, sc_cdb + 7);
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SYNCHRONIZE_CACHE_CMDLEN; ++k)
- pr2ws("%02x ", sc_cdb[k]);
- pr2ws("\n");
- }
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, sc_cdb, sizeof(sc_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_readcap_16(int sg_fd, bool pmi, uint64_t llba, void * resp,
- int mx_resp_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "read capacity(16)";
- int k, ret, res, sense_cat;
- unsigned char rc_cdb[SERVICE_ACTION_IN_16_CMDLEN] =
- {SERVICE_ACTION_IN_16_CMD, READ_CAPACITY_16_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (pmi) { /* lbs only valid when pmi set */
- rc_cdb[14] |= 1;
- sg_put_unaligned_be64(llba, rc_cdb + 2);
- }
- /* Allocation length, no guidance in SBC-2 rev 15b */
- sg_put_unaligned_be32((uint32_t)mx_resp_len, rc_cdb + 10);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
- pr2ws("%02x ", rc_cdb[k]);
- pr2ws("\n");
- }
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI READ CAPACITY (10) command. Returns 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_readcap_10(int sg_fd, bool pmi, unsigned int lba, void * resp,
- int mx_resp_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "read capacity(10)";
- int k, ret, res, sense_cat;
- unsigned char rc_cdb[READ_CAPACITY_10_CMDLEN] =
- {READ_CAPACITY_10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (pmi) { /* lbs only valid when pmi set */
- rc_cdb[8] |= 1;
- sg_put_unaligned_be32((uint32_t)lba, rc_cdb + 2);
- }
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < READ_CAPACITY_10_CMDLEN; ++k)
- pr2ws("%02x ", rc_cdb[k]);
- pr2ws("\n");
- }
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI MODE SENSE (6) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_mode_sense6(int sg_fd, bool dbd, int pc, int pg_code, int sub_pg_code,
- void * resp, int mx_resp_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "mode sense(6)";
- int res, ret, k, sense_cat, resid;
- unsigned char modes_cdb[MODE_SENSE6_CMDLEN] =
- {MODE_SENSE6_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- modes_cdb[1] = (unsigned char)(dbd ? 0x8 : 0);
- modes_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
- modes_cdb[3] = (unsigned char)(sub_pg_code & 0xff);
- modes_cdb[4] = (unsigned char)(mx_resp_len & 0xff);
- if (mx_resp_len > 0xff) {
- pr2ws("mx_resp_len too big\n");
- return -1;
- }
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < MODE_SENSE6_CMDLEN; ++k)
- pr2ws("%02x ", modes_cdb[k]);
- pr2ws("\n");
- }
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- resid = get_scsi_pt_resid(ptvp);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
-
- if (resid > 0) {
- if (resid > mx_resp_len) {
- pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
- cdb_name_s, resid, mx_resp_len);
- return ret ? ret : SG_LIB_CAT_MALFORMED;
- }
- /* zero unfilled section of response buffer */
- memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
- }
- return ret;
-}
-
-/* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_mode_sense10(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
- int sub_pg_code, void * resp, int mx_resp_len,
- bool noisy, int verbose)
-{
- return sg_ll_mode_sense10_v2(sg_fd, llbaa, dbd, pc, pg_code, sub_pg_code,
- resp, mx_resp_len, 0, NULL, noisy, verbose);
-}
-
-/* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors.
- * Adds the ability to set the command abort timeout
- * and the ability to report the residual count. If timeout_secs is zero
- * or less the default command abort timeout (60 seconds) is used.
- * If residp is non-NULL then the residual value is written where residp
- * points. A residual value of 0 implies mx_resp_len bytes have be written
- * where resp points. If the residual value equals mx_resp_len then no
- * bytes have been written. */
-int
-sg_ll_mode_sense10_v2(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
- int sub_pg_code, void * resp, int mx_resp_len,
- int timeout_secs, int * residp, bool noisy, int verbose)
-{
- int res, ret, k, sense_cat, resid;
- static const char * const cdb_name_s = "mode sense(10)";
- struct sg_pt_base * ptvp;
- unsigned char modes_cdb[MODE_SENSE10_CMDLEN] =
- {MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
-
- modes_cdb[1] = (unsigned char)((dbd ? 0x8 : 0) | (llbaa ? 0x10 : 0));
- modes_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
- modes_cdb[3] = (unsigned char)(sub_pg_code & 0xff);
- sg_put_unaligned_be16((int16_t)mx_resp_len, modes_cdb + 7);
- if (mx_resp_len > 0xffff) {
- pr2ws("mx_resp_len too big\n");
- goto gen_err;
- }
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < MODE_SENSE10_CMDLEN; ++k)
- pr2ws("%02x ", modes_cdb[k]);
- pr2ws("\n");
- }
- if (timeout_secs <= 0)
- timeout_secs = DEF_PT_TIMEOUT;
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- goto gen_err;
- set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- resid = get_scsi_pt_resid(ptvp);
- if (residp)
- *residp = resid;
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
-
- if (resid > 0) {
- if (resid > mx_resp_len) {
- pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
- cdb_name_s, resid, mx_resp_len);
- return ret ? ret : SG_LIB_CAT_MALFORMED;
- }
- /* zero unfilled section of response buffer */
- memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
- }
- return ret;
-gen_err:
- if (residp)
- *residp = 0;
- return -1;
-}
-
-/* Invokes a SCSI MODE SELECT (6) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_mode_select6(int sg_fd, bool pf, bool sp, void * paramp, int param_len,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "mode select(6)";
- int res, ret, k, sense_cat;
- unsigned char modes_cdb[MODE_SELECT6_CMDLEN] =
- {MODE_SELECT6_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- modes_cdb[1] = (unsigned char)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
- modes_cdb[4] = (unsigned char)(param_len & 0xff);
- if (param_len > 0xff) {
- pr2ws("%s: param_len too big\n", cdb_name_s);
- return -1;
- }
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < MODE_SELECT6_CMDLEN; ++k)
- pr2ws("%02x ", modes_cdb[k]);
- pr2ws("\n");
- }
- if (verbose > 1) {
- pr2ws(" %s parameter list\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI MODE SELECT (10) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_mode_select10(int sg_fd, bool pf, bool sp, void * paramp, int param_len,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "mode select(10)";
- int res, ret, k, sense_cat;
- unsigned char modes_cdb[MODE_SELECT10_CMDLEN] =
- {MODE_SELECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- modes_cdb[1] = (unsigned char)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
- sg_put_unaligned_be16((int16_t)param_len, modes_cdb + 7);
- if (param_len > 0xffff) {
- pr2ws("%s: param_len too big\n", cdb_name_s);
- return -1;
- }
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < MODE_SELECT10_CMDLEN; ++k)
- pr2ws("%02x ", modes_cdb[k]);
- pr2ws("\n");
- }
- if (verbose > 1) {
- pr2ws(" %s parameter list\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* MODE SENSE commands yield a response that has header then zero or more
- * block descriptors followed by mode pages. In most cases users are
- * interested in the first mode page. This function returns the (byte)
- * offset of the start of the first mode page. Set mode_sense_6 to true for
- * MODE SENSE (6) and false for MODE SENSE (10). Returns >= 0 is successful
- * or -1 if failure. If there is a failure a message is written to err_buff
- * if it is non-NULL and err_buff_len > 0. */
-int
-sg_mode_page_offset(const unsigned char * resp, int resp_len,
- bool mode_sense_6, char * err_buff, int err_buff_len)
-{
- int bd_len, calc_len, offset;
- bool err_buff_ok = ((err_buff_len > 0) && err_buff);
-
- if ((NULL == resp) || (resp_len < 4))
- goto too_short;
- if (mode_sense_6) {
- calc_len = resp[0] + 1;
- bd_len = resp[3];
- offset = bd_len + MODE6_RESP_HDR_LEN;
- } else { /* Mode sense(10) */
- if (resp_len < 8)
- goto too_short;
- calc_len = sg_get_unaligned_be16(resp) + 2;
- bd_len = sg_get_unaligned_be16(resp + 6);
- /* LongLBA doesn't change this calculation */
- offset = bd_len + MODE10_RESP_HDR_LEN;
- }
- if ((offset + 2) > calc_len) {
- if (err_buff_ok)
- snprintf(err_buff, err_buff_len, "calculated response "
- "length too small, offset=%d calc_len=%d bd_len=%d\n",
- offset, calc_len, bd_len);
- offset = -1;
- }
- return offset;
-too_short:
- if (err_buff_ok)
- snprintf(err_buff, err_buff_len, "given MS(%d) response length (%d) "
- "too short\n", (mode_sense_6 ? 6 : 10), resp_len);
- return -1;
-}
-
-/* MODE SENSE commands yield a response that has header then zero or more
- * block descriptors followed by mode pages. This functions returns the
- * length (in bytes) of those three components. Note that the return value
- * can exceed resp_len in which case the MODE SENSE command should be
- * re-issued with a larger response buffer. If bd_lenp is non-NULL and if
- * successful the block descriptor length (in bytes) is written to *bd_lenp.
- * Set mode_sense_6 to true for MODE SENSE (6) and false for MODE SENSE (10)
- * responses. Returns -1 if there is an error (e.g. response too short). */
-int
-sg_msense_calc_length(const unsigned char * resp, int resp_len,
- bool mode_sense_6, int * bd_lenp)
-{
- int calc_len;
-
- if (NULL == resp)
- goto an_err;
- if (mode_sense_6) {
- if (resp_len < 4)
- goto an_err;
- calc_len = resp[0] + 1;
- } else {
- if (resp_len < 8)
- goto an_err;
- calc_len = sg_get_unaligned_be16(resp + 0) + 2;
- }
- if (bd_lenp)
- *bd_lenp = mode_sense_6 ? resp[3] : sg_get_unaligned_be16(resp + 6);
- return calc_len;
-an_err:
- if (bd_lenp)
- *bd_lenp = 0;
- return -1;
-}
-
-/* Fetches current, changeable, default and/or saveable modes pages as
- * indicated by pcontrol_arr for given pg_code and sub_pg_code. If
- * mode6==false then use MODE SENSE (10) else use MODE SENSE (6). If
- * flexible set and mode data length seems wrong then try and
- * fix (compensating hack for bad device or driver). pcontrol_arr
- * should have 4 elements for output of current, changeable, default
- * and saved values respectively. Each element should be NULL or
- * at least mx_mpage_len bytes long.
- * Return of 0 -> overall success, various SG_LIB_CAT_* positive values or
- * -1 -> other errors.
- * If success_mask pointer is not NULL then first zeros it. Then set bits
- * 0, 1, 2 and/or 3 if the current, changeable, default and saved values
- * respectively have been fetched. If error on current page
- * then stops and returns that error; otherwise continues if an error is
- * detected but returns the first error encountered. */
-int
-sg_get_mode_page_controls(int sg_fd, bool mode6, int pg_code, int sub_pg_code,
- bool dbd, bool flexible, int mx_mpage_len,
- int * success_mask, void * pcontrol_arr[],
- int * reported_lenp, int verbose)
-{
- bool resp_mode6;
- int k, n, res, offset, calc_len, xfer_len;
- int resid = 0;
- const int msense10_hlen = MODE10_RESP_HDR_LEN;
- unsigned char buff[MODE_RESP_ARB_LEN];
- char ebuff[EBUFF_SZ];
- int first_err = 0;
-
- if (success_mask)
- *success_mask = 0;
- if (reported_lenp)
- *reported_lenp = 0;
- if (mx_mpage_len < 4)
- return 0;
- memset(ebuff, 0, sizeof(ebuff));
- /* first try to find length of current page response */
- memset(buff, 0, msense10_hlen);
- if (mode6) /* want first 8 bytes just in case */
- res = sg_ll_mode_sense6(sg_fd, dbd, 0 /* pc */, pg_code,
- sub_pg_code, buff, msense10_hlen, true,
- verbose);
- else /* MODE SENSE(10) obviously */
- res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
- 0 /* pc */, pg_code, sub_pg_code, buff,
- msense10_hlen, 0, &resid, true, verbose);
- if (0 != res)
- return res;
- n = buff[0];
- if (reported_lenp) {
- int m;
-
- m = sg_msense_calc_length(buff, msense10_hlen, mode6, NULL) - resid;
- if (m < 0) /* Grrr, this should not happen */
- m = 0;
- *reported_lenp = m;
- }
- resp_mode6 = mode6;
- if (flexible) {
- if (mode6 && (n < 3)) {
- resp_mode6 = false;
- if (verbose)
- pr2ws(">>> msense(6) but resp[0]=%d so try msense(10) "
- "response processing\n", n);
- }
- if ((! mode6) && (n > 5)) {
- if ((n > 11) && (0 == (n % 2)) && (0 == buff[4]) &&
- (0 == buff[5]) && (0 == buff[6])) {
- buff[1] = n;
- buff[0] = 0;
- if (verbose)
- pr2ws(">>> msense(10) but resp[0]=%d and not msense(6) "
- "response so fix length\n", n);
- } else
- resp_mode6 = true;
- }
- }
- if (verbose && (resp_mode6 != mode6))
- pr2ws(">>> msense(%d) but resp[0]=%d so switch response "
- "processing\n", (mode6 ? 6 : 10), buff[0]);
- calc_len = sg_msense_calc_length(buff, msense10_hlen, resp_mode6, NULL);
- if (calc_len > MODE_RESP_ARB_LEN)
- calc_len = MODE_RESP_ARB_LEN;
- offset = sg_mode_page_offset(buff, calc_len, resp_mode6, ebuff, EBUFF_SZ);
- if (offset < 0) {
- if (('\0' != ebuff[0]) && (verbose > 0))
- pr2ws("%s: %s\n", __func__, ebuff);
- return SG_LIB_CAT_MALFORMED;
- }
- xfer_len = calc_len - offset;
- if (xfer_len > mx_mpage_len)
- xfer_len = mx_mpage_len;
-
- for (k = 0; k < 4; ++k) {
- if (NULL == pcontrol_arr[k])
- continue;
- memset(pcontrol_arr[k], 0, mx_mpage_len);
- resid = 0;
- if (mode6)
- res = sg_ll_mode_sense6(sg_fd, dbd, k /* pc */,
- pg_code, sub_pg_code, buff,
- calc_len, true, verbose);
- else
- res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
- k /* pc */, pg_code, sub_pg_code,
- buff, calc_len, 0, &resid, true,
- verbose);
- if (res || resid) {
- if (0 == first_err) {
- if (res)
- first_err = res;
- else {
- first_err = -49; /* unexpected resid != 0 */
- if (verbose)
- pr2ws("%s: unexpected resid=%d, page=0x%x, "
- "pcontrol=%d\n", __func__, resid, pg_code, k);
- }
- }
- if (0 == k)
- break; /* if problem on current page, it won't improve */
- else
- continue;
- }
- if (xfer_len > 0)
- memcpy(pcontrol_arr[k], buff + offset, xfer_len);
- if (success_mask)
- *success_mask |= (1 << k);
- }
- return first_err;
-}
-
-/* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors. */
-int
-sg_ll_log_sense(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
- int subpg_code, int paramp, unsigned char * resp,
- int mx_resp_len, bool noisy, int verbose)
-{
- return sg_ll_log_sense_v2(sg_fd, ppc, sp, pc, pg_code, subpg_code,
- paramp, resp, mx_resp_len, 0, NULL, noisy,
- verbose);
-}
-
-/* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors.
- * Adds the ability to set the command abort timeout
- * and the ability to report the residual count. If timeout_secs is zero
- * or less the default command abort timeout (60 seconds) is used.
- * If residp is non-NULL then the residual value is written where residp
- * points. A residual value of 0 implies mx_resp_len bytes have be written
- * where resp points. If the residual value equals mx_resp_len then no
- * bytes have been written. */
-int
-sg_ll_log_sense_v2(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
- int subpg_code, int paramp, unsigned char * resp,
- int mx_resp_len, int timeout_secs, int * residp,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "log sense";
- int res, ret, k, sense_cat, resid;
- unsigned char logs_cdb[LOG_SENSE_CMDLEN] =
- {LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (mx_resp_len > 0xffff) {
- pr2ws("mx_resp_len too big\n");
- goto gen_err;
- }
- logs_cdb[1] = (unsigned char)((ppc ? 2 : 0) | (sp ? 1 : 0));
- logs_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
- logs_cdb[3] = (unsigned char)(subpg_code & 0xff);
- sg_put_unaligned_be16((int16_t)paramp, logs_cdb + 5);
- sg_put_unaligned_be16((int16_t)mx_resp_len, logs_cdb + 7);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < LOG_SENSE_CMDLEN; ++k)
- pr2ws("%02x ", logs_cdb[k]);
- pr2ws("\n");
- }
- if (timeout_secs <= 0)
- timeout_secs = DEF_PT_TIMEOUT;
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- goto gen_err;
- set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len,
- sense_b, noisy, verbose, &sense_cat);
- resid = get_scsi_pt_resid(ptvp);
- if (residp)
- *residp = resid;
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((mx_resp_len > 3) && (ret < 4)) {
- /* resid indicates LOG SENSE response length bad, so zero it */
- resp[2] = 0;
- resp[3] = 0;
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
-
- if (resid > 0) {
- if (resid > mx_resp_len) {
- pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
- cdb_name_s, resid, mx_resp_len);
- return ret ? ret : SG_LIB_CAT_MALFORMED;
- }
- /* zero unfilled section of response buffer */
- memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
- }
- return ret;
-gen_err:
- if (residp)
- *residp = 0;
- return -1;
-}
-
-/* Invokes a SCSI LOG SELECT command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_log_select(int sg_fd, bool pcr, bool sp, int pc, int pg_code,
- int subpg_code, unsigned char * paramp, int param_len,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "log select";
- int res, ret, k, sense_cat;
- unsigned char logs_cdb[LOG_SELECT_CMDLEN] =
- {LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (param_len > 0xffff) {
- pr2ws("%s: param_len too big\n", cdb_name_s);
- return -1;
- }
- logs_cdb[1] = (unsigned char)((pcr ? 2 : 0) | (sp ? 1 : 0));
- logs_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
- logs_cdb[3] = (unsigned char)(subpg_code & 0xff);
- sg_put_unaligned_be16((int16_t)param_len, logs_cdb + 7);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < LOG_SELECT_CMDLEN; ++k)
- pr2ws("%02x ", logs_cdb[k]);
- pr2ws("\n");
- }
- if ((verbose > 1) && (param_len > 0)) {
- pr2ws(" %s parameter list\n", cdb_name_s);
- hex2stderr(paramp, param_len, -1);
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI START STOP UNIT command (SBC + MMC).
- * Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors.
- * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and
- * format_layer_number(mmc) fields. They also overlap on the noflush(sbc)
- * and fl(mmc) one bit field. This is the cause of the awkardly named
- * pc_mod__fl_num and noflush__fl arguments to this function.
- * */
-int
-sg_ll_start_stop_unit(int sg_fd, bool immed, int pc_mod__fl_num,
- int power_cond, bool noflush__fl, bool loej, bool start,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "start stop unit";
- int k, res, ret, sense_cat;
- struct sg_pt_base * ptvp;
- unsigned char ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
-
- if (immed)
- ssuBlk[1] = 0x1;
- ssuBlk[3] = pc_mod__fl_num & 0xf; /* bits 2 and 3 are reserved in MMC */
- ssuBlk[4] = ((power_cond & 0xf) << 4);
- if (noflush__fl)
- ssuBlk[4] |= 0x4;
- if (loej)
- ssuBlk[4] |= 0x2;
- if (start)
- ssuBlk[4] |= 0x1;
- if (verbose) {
- pr2ws(" %s command:", cdb_name_s);
- for (k = 0; k < (int)sizeof(ssuBlk); ++k)
- pr2ws(" %02x", ssuBlk[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- res = do_scsi_pt(ptvp, sg_fd, START_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI PREVENT ALLOW MEDIUM REMOVAL command
- * [was in SPC-3 but displaced from SPC-4 into SBC-3, MMC-5, SSC-3]
- * prevent==0 allows removal, prevent==1 prevents removal ...
- * Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_prevent_allow(int sg_fd, int prevent, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "prevent allow medium removal";
- int k, res, ret, sense_cat;
- unsigned char p_cdb[PREVENT_ALLOW_CMDLEN] =
- {PREVENT_ALLOW_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if ((prevent < 0) || (prevent > 3)) {
- pr2ws("prevent argument should be 0, 1, 2 or 3\n");
- return -1;
- }
- p_cdb[4] |= (prevent & 0x3);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < PREVENT_ALLOW_CMDLEN; ++k)
- pr2ws("%02x ", p_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, p_cdb, sizeof(p_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
diff --git a/tools/sg_write_buffer/sg_cmds_extra.c b/tools/sg_write_buffer/sg_cmds_extra.c
deleted file mode 100644
index bebc859..0000000
--- a/tools/sg_write_buffer/sg_cmds_extra.c
+++ /dev/null
@@ -1,2524 +0,0 @@
-/*
- * Copyright (c) 1999-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#define __STDC_FORMAT_MACROS 1
-#include <inttypes.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sg_lib.h"
-#include "sg_lib_data.h"
-#include "sg_cmds_basic.h"
-#include "sg_cmds_extra.h"
-#include "sg_pt.h"
-#include "sg_unaligned.h"
-
-
-#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
-
-#define DEF_PT_TIMEOUT 60 /* 60 seconds */
-#define LONG_PT_TIMEOUT 7200 /* 7,200 seconds == 120 minutes */
-
-#define SERVICE_ACTION_IN_16_CMD 0x9e
-#define SERVICE_ACTION_IN_16_CMDLEN 16
-#define SERVICE_ACTION_OUT_16_CMD 0x9f
-#define SERVICE_ACTION_OUT_16_CMDLEN 16
-#define MAINTENANCE_IN_CMD 0xa3
-#define MAINTENANCE_IN_CMDLEN 12
-#define MAINTENANCE_OUT_CMD 0xa4
-#define MAINTENANCE_OUT_CMDLEN 12
-
-#define ATA_PT_12_CMD 0xa1
-#define ATA_PT_12_CMDLEN 12
-#define ATA_PT_16_CMD 0x85
-#define ATA_PT_16_CMDLEN 16
-#define ATA_PT_32_SA 0x1ff0
-#define ATA_PT_32_CMDLEN 32
-#define FORMAT_UNIT_CMD 0x4
-#define FORMAT_UNIT_CMDLEN 6
-#define PERSISTENT_RESERVE_IN_CMD 0x5e
-#define PERSISTENT_RESERVE_IN_CMDLEN 10
-#define PERSISTENT_RESERVE_OUT_CMD 0x5f
-#define PERSISTENT_RESERVE_OUT_CMDLEN 10
-#define READ_BLOCK_LIMITS_CMD 0x5
-#define READ_BLOCK_LIMITS_CMDLEN 6
-#define READ_BUFFER_CMD 0x3c
-#define READ_BUFFER_CMDLEN 10
-#define READ_DEFECT10_CMD 0x37
-#define READ_DEFECT10_CMDLEN 10
-#define REASSIGN_BLKS_CMD 0x7
-#define REASSIGN_BLKS_CMDLEN 6
-#define RECEIVE_DIAGNOSTICS_CMD 0x1c
-#define RECEIVE_DIAGNOSTICS_CMDLEN 6
-#define THIRD_PARTY_COPY_OUT_CMD 0x83 /* was EXTENDED_COPY_CMD */
-#define THIRD_PARTY_COPY_OUT_CMDLEN 16
-#define THIRD_PARTY_COPY_IN_CMD 0x84 /* was RECEIVE_COPY_RESULTS_CMD */
-#define THIRD_PARTY_COPY_IN_CMDLEN 16
-#define SEND_DIAGNOSTIC_CMD 0x1d
-#define SEND_DIAGNOSTIC_CMDLEN 6
-#define SERVICE_ACTION_IN_12_CMD 0xab
-#define SERVICE_ACTION_IN_12_CMDLEN 12
-#define READ_LONG10_CMD 0x3e
-#define READ_LONG10_CMDLEN 10
-#define UNMAP_CMD 0x42
-#define UNMAP_CMDLEN 10
-#define VERIFY10_CMD 0x2f
-#define VERIFY10_CMDLEN 10
-#define VERIFY16_CMD 0x8f
-#define VERIFY16_CMDLEN 16
-#define WRITE_LONG10_CMD 0x3f
-#define WRITE_LONG10_CMDLEN 10
-#define WRITE_BUFFER_CMD 0x3b
-#define WRITE_BUFFER_CMDLEN 10
-#define PRE_FETCH10_CMD 0x34
-#define PRE_FETCH10_CMDLEN 10
-#define PRE_FETCH16_CMD 0x90
-#define PRE_FETCH16_CMDLEN 16
-#define SEEK10_CMD 0x2b
-#define SEEK10_CMDLEN 10
-
-#define GET_LBA_STATUS16_SA 0x12
-#define GET_LBA_STATUS32_SA 0x12
-#define READ_LONG_16_SA 0x11
-#define READ_MEDIA_SERIAL_NUM_SA 0x1
-#define REPORT_IDENTIFYING_INFORMATION_SA 0x5
-#define REPORT_TGT_PRT_GRP_SA 0xa
-#define SET_IDENTIFYING_INFORMATION_SA 0x6
-#define SET_TGT_PRT_GRP_SA 0xa
-#define WRITE_LONG_16_SA 0x11
-#define REPORT_REFERRALS_SA 0x13
-#define EXTENDED_COPY_LID1_SA 0x0
-
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
-static struct sg_pt_base *
-create_pt_obj(const char * cname)
-{
- struct sg_pt_base * ptvp = construct_scsi_pt_obj();
- if (NULL == ptvp)
- pr2ws("%s: out of memory\n", cname);
- return ptvp;
-}
-
-
-/* Invokes a SCSI GET LBA STATUS(16) command (SBC). Returns 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_get_lba_status16(int sg_fd, uint64_t start_llba, uint8_t rt,
- void * resp, int alloc_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Get LBA status(16)";
- int k, res, sense_cat, ret;
- unsigned char getLbaStatCmd[SERVICE_ACTION_IN_16_CMDLEN];
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- memset(getLbaStatCmd, 0, sizeof(getLbaStatCmd));
- getLbaStatCmd[0] = SERVICE_ACTION_IN_16_CMD;
- getLbaStatCmd[1] = GET_LBA_STATUS16_SA;
-
- sg_put_unaligned_be64(start_llba, getLbaStatCmd + 2);
- sg_put_unaligned_be32((uint32_t)alloc_len, getLbaStatCmd + 10);
- getLbaStatCmd[14] = rt;
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
- pr2ws("%02x ", getLbaStatCmd[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, getLbaStatCmd, sizeof(getLbaStatCmd));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, alloc_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, alloc_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response\n", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-int
-sg_ll_get_lba_status(int sg_fd, uint64_t start_llba, void * resp,
- int alloc_len, bool noisy, int verbose)
-{
- return sg_ll_get_lba_status16(sg_fd, start_llba, /* rt = */ 0x0, resp,
- alloc_len, noisy, verbose);
-}
-
-#define GLS32_CMD_LEN 32
-
-int
-sg_ll_get_lba_status32(int sg_fd, uint64_t start_llba, uint32_t scan_len,
- uint32_t element_id, uint8_t rt,
- void * resp, int alloc_len, bool noisy,
- int verbose)
-{
- static const char * const cdb_name_s = "Get LBA status(32)";
- int k, res, sense_cat, ret;
- unsigned char gls32_cmd[GLS32_CMD_LEN];
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- memset(gls32_cmd, 0, sizeof(gls32_cmd));
- gls32_cmd[0] = SG_VARIABLE_LENGTH_CMD;
- gls32_cmd[7] = GLS32_CMD_LEN - 8;
- sg_put_unaligned_be16((uint16_t)GET_LBA_STATUS32_SA, gls32_cmd + 8);
- gls32_cmd[10] = rt;
- sg_put_unaligned_be64(start_llba, gls32_cmd + 12);
- sg_put_unaligned_be32(scan_len, gls32_cmd + 20);
- sg_put_unaligned_be32(element_id, gls32_cmd + 24);
- sg_put_unaligned_be32((uint32_t)alloc_len, gls32_cmd + 28);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < GLS32_CMD_LEN; ++k)
- pr2ws("%02x ", gls32_cmd[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, gls32_cmd, sizeof(gls32_cmd));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, alloc_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, alloc_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response\n", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-int
-sg_ll_report_tgt_prt_grp(int sg_fd, void * resp, int mx_resp_len,
- bool noisy, int verbose)
-{
- return sg_ll_report_tgt_prt_grp2(sg_fd, resp, mx_resp_len, false, noisy,
- verbose);
-}
-
-/* Invokes a SCSI REPORT TARGET PORT GROUPS command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_report_tgt_prt_grp2(int sg_fd, void * resp, int mx_resp_len,
- bool extended, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Report target port groups";
- int k, res, ret, sense_cat;
- unsigned char rtpg_cdb[MAINTENANCE_IN_CMDLEN] =
- {MAINTENANCE_IN_CMD, REPORT_TGT_PRT_GRP_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (extended)
- rtpg_cdb[1] |= 0x20;
- sg_put_unaligned_be32((uint32_t)mx_resp_len, rtpg_cdb + 6);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < MAINTENANCE_IN_CMDLEN; ++k)
- pr2ws("%02x ", rtpg_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rtpg_cdb, sizeof(rtpg_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI SET TARGET PORT GROUPS command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_set_tgt_prt_grp(int sg_fd, void * paramp, int param_len, bool noisy,
- int verbose)
-{
- static const char * const cdb_name_s = "Set target port groups";
- int k, res, ret, sense_cat;
- unsigned char stpg_cdb[MAINTENANCE_OUT_CMDLEN] =
- {MAINTENANCE_OUT_CMD, SET_TGT_PRT_GRP_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- sg_put_unaligned_be32((uint32_t)param_len, stpg_cdb + 6);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < MAINTENANCE_OUT_CMDLEN; ++k)
- pr2ws("%02x ", stpg_cdb[k]);
- pr2ws("\n");
- if ((verbose > 1) && paramp && param_len) {
- pr2ws(" %s parameter list:\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, stpg_cdb, sizeof(stpg_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI REPORT REFERRALS command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_report_referrals(int sg_fd, uint64_t start_llba, bool one_seg,
- void * resp, int mx_resp_len, bool noisy,
- int verbose)
-{
- static const char * const cdb_name_s = "Report referrals";
- int k, res, ret, sense_cat;
- unsigned char repRef_cdb[SERVICE_ACTION_IN_16_CMDLEN] =
- {SERVICE_ACTION_IN_16_CMD, REPORT_REFERRALS_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- sg_put_unaligned_be64(start_llba, repRef_cdb + 2);
- sg_put_unaligned_be32((uint32_t)mx_resp_len, repRef_cdb + 10);
- if (one_seg)
- repRef_cdb[14] = 0x1;
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
- pr2ws("%02x ", repRef_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, repRef_cdb, sizeof(repRef_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI SEND DIAGNOSTIC command. Foreground, extended self tests can
- * take a long time, if so set long_duration flag in which case the timeout
- * is set to 7200 seconds; if the value of long_duration is > 7200 then that
- * value is taken as the timeout value in seconds. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_send_diag(int sg_fd, int st_code, bool pf_bit, bool st_bit,
- bool devofl_bit, bool unitofl_bit, int long_duration,
- void * paramp, int param_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Send diagnostic";
- int k, res, ret, sense_cat, tmout;
- unsigned char senddiag_cdb[SEND_DIAGNOSTIC_CMDLEN] =
- {SEND_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- senddiag_cdb[1] = (unsigned char)(st_code << 5);
- if (pf_bit)
- senddiag_cdb[1] |= 0x10;
- if (st_bit)
- senddiag_cdb[1] |= 0x4;
- if (devofl_bit)
- senddiag_cdb[1] |= 0x2;
- if (unitofl_bit)
- senddiag_cdb[1] |= 0x1;
- sg_put_unaligned_be16((uint16_t)param_len, senddiag_cdb + 3);
- if (long_duration > LONG_PT_TIMEOUT)
- tmout = long_duration;
- else
- tmout = long_duration ? LONG_PT_TIMEOUT : DEF_PT_TIMEOUT;
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SEND_DIAGNOSTIC_CMDLEN; ++k)
- pr2ws("%02x ", senddiag_cdb[k]);
- pr2ws("\n");
- if (verbose > 1) {
- if (paramp && param_len) {
- pr2ws(" %s parameter list:\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
- pr2ws(" %s timeout: %d seconds\n", cdb_name_s, tmout);
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, senddiag_cdb, sizeof(senddiag_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_receive_diag(int sg_fd, bool pcv, int pg_code, void * resp,
- int mx_resp_len, bool noisy, int verbose)
-{
- return sg_ll_receive_diag_v2(sg_fd, pcv, pg_code, resp, mx_resp_len, 0,
- NULL, noisy, verbose);
-}
-
-/* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_receive_diag_v2(int sg_fd, bool pcv, int pg_code, void * resp,
- int mx_resp_len, int timeout_secs, int * residp,
- bool noisy, int verbose)
-{
- int resid = 0;
- int k, res, ret, sense_cat;
- static const char * const cdb_name_s = "Receive diagnostic results";
- struct sg_pt_base * ptvp;
- unsigned char rcvdiag_cdb[RECEIVE_DIAGNOSTICS_CMDLEN] =
- {RECEIVE_DIAGNOSTICS_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
-
- if (pcv)
- rcvdiag_cdb[1] = 0x1;
- rcvdiag_cdb[2] = (unsigned char)(pg_code);
- sg_put_unaligned_be16((uint16_t)mx_resp_len, rcvdiag_cdb + 3);
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < RECEIVE_DIAGNOSTICS_CMDLEN; ++k)
- pr2ws("%02x ", rcvdiag_cdb[k]);
- pr2ws("\n");
- }
- if (timeout_secs <= 0)
- timeout_secs = DEF_PT_TIMEOUT;
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s)))) {
- if (residp)
- *residp = 0;
- return -1;
- }
- set_scsi_pt_cdb(ptvp, rcvdiag_cdb, sizeof(rcvdiag_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- resid = get_scsi_pt_resid(ptvp);
- if (residp)
- *residp = resid;
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI READ DEFECT DATA (10) command (SBC). Return of 0 -> success
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_read_defect10(int sg_fd, bool req_plist, bool req_glist, int dl_format,
- void * resp, int mx_resp_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Read defect(10)";
- int res, k, ret, sense_cat;
- unsigned char rdef_cdb[READ_DEFECT10_CMDLEN] =
- {READ_DEFECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- rdef_cdb[2] = (dl_format & 0x7);
- if (req_plist)
- rdef_cdb[2] |= 0x10;
- if (req_glist)
- rdef_cdb[2] |= 0x8;
- sg_put_unaligned_be16((uint16_t)mx_resp_len, rdef_cdb + 7);
- if (mx_resp_len > 0xffff) {
- pr2ws("mx_resp_len too big\n");
- return -1;
- }
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < READ_DEFECT10_CMDLEN; ++k)
- pr2ws("%02x ", rdef_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rdef_cdb, sizeof(rdef_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response\n", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI READ MEDIA SERIAL NUMBER command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_read_media_serial_num(int sg_fd, void * resp, int mx_resp_len,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Read media serial number";
- int k, res, ret, sense_cat;
- unsigned char rmsn_cdb[SERVICE_ACTION_IN_12_CMDLEN] =
- {SERVICE_ACTION_IN_12_CMD, READ_MEDIA_SERIAL_NUM_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- sg_put_unaligned_be32((uint32_t)mx_resp_len, rmsn_cdb + 6);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SERVICE_ACTION_IN_12_CMDLEN; ++k)
- pr2ws("%02x ", rmsn_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rmsn_cdb, sizeof(rmsn_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI REPORT IDENTIFYING INFORMATION command. This command was
- * called REPORT DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_report_id_info(int sg_fd, int itype, void * resp, int max_resp_len,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Report identifying information";
- int k, res, ret, sense_cat;
- unsigned char rii_cdb[MAINTENANCE_IN_CMDLEN] = {MAINTENANCE_IN_CMD,
- REPORT_IDENTIFYING_INFORMATION_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- sg_put_unaligned_be32((uint32_t)max_resp_len, rii_cdb + 6);
- rii_cdb[10] |= (itype << 1) & 0xfe;
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < MAINTENANCE_IN_CMDLEN; ++k)
- pr2ws("%02x ", rii_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rii_cdb, sizeof(rii_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, max_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, max_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI SET IDENTIFYING INFORMATION command. This command was
- * called SET DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_set_id_info(int sg_fd, int itype, void * paramp, int param_len,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Set identifying information";
- int k, res, ret, sense_cat;
- unsigned char sii_cdb[MAINTENANCE_OUT_CMDLEN] = {MAINTENANCE_OUT_CMD,
- SET_IDENTIFYING_INFORMATION_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- sg_put_unaligned_be32((uint32_t)param_len, sii_cdb + 6);
- sii_cdb[10] |= (itype << 1) & 0xfe;
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < MAINTENANCE_OUT_CMDLEN; ++k)
- pr2ws("%02x ", sii_cdb[k]);
- pr2ws("\n");
- if ((verbose > 1) && paramp && param_len) {
- pr2ws(" %s parameter list:\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, sii_cdb, sizeof(sii_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a FORMAT UNIT (SBC-3) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_format_unit(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata,
- bool cmplst, int dlist_format, int timeout_secs,
- void * paramp, int param_len, bool noisy, int verbose)
-{
- return sg_ll_format_unit_v2(sg_fd, fmtpinfo, longlist, fmtdata, cmplst,
- dlist_format, 0, timeout_secs, paramp,
- param_len, noisy, verbose);
-}
-
-/* Invokes a FORMAT UNIT (SBC-3) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_format_unit2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata,
- bool cmplst, int dlist_format, int ffmt, int timeout_secs,
- void * paramp, int param_len, bool noisy, int verbose)
-{
- return sg_ll_format_unit_v2(sg_fd, fmtpinfo, longlist, fmtdata, cmplst,
- dlist_format, ffmt, timeout_secs, paramp,
- param_len, noisy, verbose);
-}
-
-/* Invokes a FORMAT UNIT (SBC-4) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors.
- * FFMT field added in sbc4r10 [20160121] */
-int
-sg_ll_format_unit_v2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata,
- bool cmplst, int dlist_format, int ffmt,
- int timeout_secs, void * paramp, int param_len,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Format unit";
- int k, res, ret, sense_cat, tmout;
- unsigned char fu_cdb[FORMAT_UNIT_CMDLEN] =
- {FORMAT_UNIT_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (fmtpinfo)
- fu_cdb[1] |= (fmtpinfo << 6);
- if (longlist)
- fu_cdb[1] |= 0x20;
- if (fmtdata)
- fu_cdb[1] |= 0x10;
- if (cmplst)
- fu_cdb[1] |= 0x8;
- if (dlist_format)
- fu_cdb[1] |= (dlist_format & 0x7);
- if (ffmt)
- fu_cdb[4] |= (ffmt & 0x3);
- tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < 6; ++k)
- pr2ws("%02x ", fu_cdb[k]);
- pr2ws("\n");
- if (verbose > 1) {
- if (param_len > 0) {
- pr2ws(" %s parameter list:\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
- pr2ws(" %s timeout: %d seconds\n", cdb_name_s, tmout);
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, fu_cdb, sizeof(fu_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI REASSIGN BLOCKS command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_reassign_blocks(int sg_fd, bool longlba, bool longlist, void * paramp,
- int param_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Reassign blocks";
- int res, k, ret, sense_cat;
- unsigned char reass_cdb[REASSIGN_BLKS_CMDLEN] =
- {REASSIGN_BLKS_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (longlba)
- reass_cdb[1] = 0x2;
- if (longlist)
- reass_cdb[1] |= 0x1;
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < REASSIGN_BLKS_CMDLEN; ++k)
- pr2ws("%02x ", reass_cdb[k]);
- pr2ws("\n");
- }
- if (verbose > 1) {
- pr2ws(" %s parameter list\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, reass_cdb, sizeof(reass_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI PERSISTENT RESERVE IN command (SPC). Returns 0
- * when successful, various SG_LIB_CAT_* positive values or
- * -1 -> other errors */
-int
-sg_ll_persistent_reserve_in(int sg_fd, int rq_servact, void * resp,
- int mx_resp_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Persistent reservation in";
- int res, k, ret, sense_cat;
- unsigned char prin_cdb[PERSISTENT_RESERVE_IN_CMDLEN] =
- {PERSISTENT_RESERVE_IN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (rq_servact > 0)
- prin_cdb[1] = (unsigned char)(rq_servact & 0x1f);
- sg_put_unaligned_be16((uint16_t)mx_resp_len, prin_cdb + 7);
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < PERSISTENT_RESERVE_IN_CMDLEN; ++k)
- pr2ws("%02x ", prin_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, prin_cdb, sizeof(prin_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI PERSISTENT RESERVE OUT command (SPC). Returns 0
- * when successful, various SG_LIB_CAT_* positive values or
- * -1 -> other errors */
-int
-sg_ll_persistent_reserve_out(int sg_fd, int rq_servact, int rq_scope,
- unsigned int rq_type, void * paramp,
- int param_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "Persistent reservation out";
- int res, k, ret, sense_cat;
- unsigned char prout_cdb[PERSISTENT_RESERVE_OUT_CMDLEN] =
- {PERSISTENT_RESERVE_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (rq_servact > 0)
- prout_cdb[1] = (unsigned char)(rq_servact & 0x1f);
- prout_cdb[2] = (((rq_scope & 0xf) << 4) | (rq_type & 0xf));
- sg_put_unaligned_be16((uint16_t)param_len, prout_cdb + 7);
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < PERSISTENT_RESERVE_OUT_CMDLEN; ++k)
- pr2ws("%02x ", prout_cdb[k]);
- pr2ws("\n");
- if (verbose > 1) {
- pr2ws(" %s parameters:\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, 0);
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, prout_cdb, sizeof(prout_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-static bool
-has_blk_ili(unsigned char * sensep, int sb_len)
-{
- int resp_code;
- const unsigned char * cup;
-
- if (sb_len < 8)
- return false;
- resp_code = (0x7f & sensep[0]);
- if (resp_code >= 0x72) { /* descriptor format */
- /* find block command descriptor */
- if ((cup = sg_scsi_sense_desc_find(sensep, sb_len, 0x5)))
- return (cup[3] & 0x20);
- } else /* fixed */
- return (sensep[2] & 0x20);
- return false;
-}
-
-/* Invokes a SCSI READ LONG (10) command (SBC). Note that 'xfer_len'
- * is in bytes. Returns 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_read_long10(int sg_fd, bool pblock, bool correct, unsigned int lba,
- void * resp, int xfer_len, int * offsetp, bool noisy,
- int verbose)
-{
- static const char * const cdb_name_s = "read long(10)";
- int k, res, sense_cat, ret;
- unsigned char readLong_cdb[READ_LONG10_CMDLEN];
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- memset(readLong_cdb, 0, READ_LONG10_CMDLEN);
- readLong_cdb[0] = READ_LONG10_CMD;
- if (pblock)
- readLong_cdb[1] |= 0x4;
- if (correct)
- readLong_cdb[1] |= 0x2;
-
- sg_put_unaligned_be32((uint32_t)lba, readLong_cdb + 2);
- sg_put_unaligned_be16((uint16_t)xfer_len, readLong_cdb + 7);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < READ_LONG10_CMDLEN; ++k)
- pr2ws("%02x ", readLong_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, readLong_cdb, sizeof(readLong_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, xfer_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, xfer_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- case SG_LIB_CAT_ILLEGAL_REQ:
- {
- bool valid, ili;
- int slen;
- uint64_t ull = 0;
-
- slen = get_scsi_pt_sense_len(ptvp);
- valid = sg_get_sense_info_fld(sense_b, slen, &ull);
- ili = has_blk_ili(sense_b, slen);
- if (valid && ili) {
- if (offsetp)
- *offsetp = (int)(int64_t)ull;
- ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
- } else {
- if (verbose > 1)
- pr2ws(" info field: 0x%" PRIx64 ", valid: %d, "
- "ili: %d\n", ull, valid, ili);
- ret = SG_LIB_CAT_ILLEGAL_REQ;
- }
- }
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI READ LONG (16) command (SBC). Note that 'xfer_len'
- * is in bytes. Returns 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_read_long16(int sg_fd, bool pblock, bool correct, uint64_t llba,
- void * resp, int xfer_len, int * offsetp, bool noisy,
- int verbose)
-{
- static const char * const cdb_name_s = "read long(16)";
- int k, res, sense_cat, ret;
- unsigned char readLong_cdb[SERVICE_ACTION_IN_16_CMDLEN];
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- memset(readLong_cdb, 0, sizeof(readLong_cdb));
- readLong_cdb[0] = SERVICE_ACTION_IN_16_CMD;
- readLong_cdb[1] = READ_LONG_16_SA;
- if (pblock)
- readLong_cdb[14] |= 0x2;
- if (correct)
- readLong_cdb[14] |= 0x1;
-
- sg_put_unaligned_be64(llba, readLong_cdb + 2);
- sg_put_unaligned_be16((uint16_t)xfer_len, readLong_cdb + 12);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
- pr2ws("%02x ", readLong_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, readLong_cdb, sizeof(readLong_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, xfer_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, xfer_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- case SG_LIB_CAT_ILLEGAL_REQ:
- {
- bool valid, ili;
- int slen;
- uint64_t ull = 0;
-
- slen = get_scsi_pt_sense_len(ptvp);
- valid = sg_get_sense_info_fld(sense_b, slen, &ull);
- ili = has_blk_ili(sense_b, slen);
- if (valid && ili) {
- if (offsetp)
- *offsetp = (int)(int64_t)ull;
- ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
- } else {
- if (verbose > 1)
- pr2ws(" info field: 0x%" PRIx64 ", valid: %d, "
- "ili: %d\n", ull, (int)valid, (int)ili);
- ret = SG_LIB_CAT_ILLEGAL_REQ;
- }
- }
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI WRITE LONG (10) command (SBC). Note that 'xfer_len'
- * is in bytes. Returns 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_write_long10(int sg_fd, bool cor_dis, bool wr_uncor, bool pblock,
- unsigned int lba, void * data_out, int xfer_len,
- int * offsetp, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "write long(10)";
- int k, res, sense_cat, ret;
- unsigned char writeLong_cdb[WRITE_LONG10_CMDLEN];
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- memset(writeLong_cdb, 0, WRITE_LONG10_CMDLEN);
- writeLong_cdb[0] = WRITE_LONG10_CMD;
- if (cor_dis)
- writeLong_cdb[1] |= 0x80;
- if (wr_uncor)
- writeLong_cdb[1] |= 0x40;
- if (pblock)
- writeLong_cdb[1] |= 0x20;
-
- sg_put_unaligned_be32((uint32_t)lba, writeLong_cdb + 2);
- sg_put_unaligned_be16((uint16_t)xfer_len, writeLong_cdb + 7);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < (int)sizeof(writeLong_cdb); ++k)
- pr2ws("%02x ", writeLong_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, writeLong_cdb, sizeof(writeLong_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, xfer_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret)
- ;
- else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- case SG_LIB_CAT_ILLEGAL_REQ:
- {
- int valid, slen, ili;
- uint64_t ull = 0;
-
- slen = get_scsi_pt_sense_len(ptvp);
- valid = sg_get_sense_info_fld(sense_b, slen, &ull);
- ili = has_blk_ili(sense_b, slen);
- if (valid && ili) {
- if (offsetp)
- *offsetp = (int)(int64_t)ull;
- ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
- } else {
- if (verbose > 1)
- pr2ws(" info field: 0x%" PRIx64 ", valid: %d, "
- "ili: %d\n", ull, (int)valid, (int)ili);
- ret = SG_LIB_CAT_ILLEGAL_REQ;
- }
- }
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI WRITE LONG (16) command (SBC). Note that 'xfer_len'
- * is in bytes. Returns 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_write_long16(int sg_fd, bool cor_dis, bool wr_uncor, bool pblock,
- uint64_t llba, void * data_out, int xfer_len,
- int * offsetp, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "write long(16)";
- int k, res, sense_cat, ret;
- unsigned char writeLong_cdb[SERVICE_ACTION_OUT_16_CMDLEN];
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- memset(writeLong_cdb, 0, sizeof(writeLong_cdb));
- writeLong_cdb[0] = SERVICE_ACTION_OUT_16_CMD;
- writeLong_cdb[1] = WRITE_LONG_16_SA;
- if (cor_dis)
- writeLong_cdb[1] |= 0x80;
- if (wr_uncor)
- writeLong_cdb[1] |= 0x40;
- if (pblock)
- writeLong_cdb[1] |= 0x20;
-
- sg_put_unaligned_be64(llba, writeLong_cdb + 2);
- sg_put_unaligned_be16((uint16_t)xfer_len, writeLong_cdb + 12);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SERVICE_ACTION_OUT_16_CMDLEN; ++k)
- pr2ws("%02x ", writeLong_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, writeLong_cdb, sizeof(writeLong_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, xfer_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- case SG_LIB_CAT_ILLEGAL_REQ:
- {
- bool valid, ili;
- int slen;
- uint64_t ull = 0;
-
- slen = get_scsi_pt_sense_len(ptvp);
- valid = sg_get_sense_info_fld(sense_b, slen, &ull);
- ili = has_blk_ili(sense_b, slen);
- if (valid && ili) {
- if (offsetp)
- *offsetp = (int)(int64_t)ull;
- ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
- } else {
- if (verbose > 1)
- pr2ws(" info field: 0x%" PRIx64 ", valid: %d, "
- "ili: %d\n", ull, (int)valid, (int)ili);
- ret = SG_LIB_CAT_ILLEGAL_REQ;
- }
- }
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI VERIFY (10) command (SBC and MMC).
- * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes.
- * Returns of 0 -> success, * various SG_LIB_CAT_* positive values or
- * -1 -> other errors */
-int
-sg_ll_verify10(int sg_fd, int vrprotect, bool dpo, int bytchk,
- unsigned int lba, int veri_len, void * data_out,
- int data_out_len, unsigned int * infop, bool noisy,
- int verbose)
-{
- static const char * const cdb_name_s = "verify(10)";
- int k, res, ret, sense_cat, slen;
- unsigned char v_cdb[VERIFY10_CMDLEN] =
- {VERIFY10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- /* N.B. BYTCHK field expanded to 2 bits sbc3r34 */
- v_cdb[1] = (((vrprotect & 0x7) << 5) | ((bytchk & 0x3) << 1)) ;
- if (dpo)
- v_cdb[1] |= 0x10;
- sg_put_unaligned_be32((uint32_t)lba, v_cdb + 2);
- sg_put_unaligned_be16((uint16_t)veri_len, v_cdb + 7);
- if (verbose > 1) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < VERIFY10_CMDLEN; ++k)
- pr2ws("%02x ", v_cdb[k]);
- pr2ws("\n");
- if ((verbose > 3) && bytchk && data_out && (data_out_len > 0)) {
- k = data_out_len > 4104 ? 4104 : data_out_len;
- pr2ws(" data_out buffer%s\n",
- (data_out_len > 4104 ? ", first 4104 bytes" : ""));
- hex2stderr((const uint8_t *)data_out, k, verbose < 5);
- }
- }
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, v_cdb, sizeof(v_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- if (data_out_len > 0)
- set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, data_out_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- case SG_LIB_CAT_MEDIUM_HARD:
- {
- bool valid;
- uint64_t ull = 0;
-
- slen = get_scsi_pt_sense_len(ptvp);
- valid = sg_get_sense_info_fld(sense_b, slen, &ull);
- if (valid) {
- if (infop)
- *infop = (unsigned int)ull;
- ret = SG_LIB_CAT_MEDIUM_HARD_WITH_INFO;
- } else
- ret = SG_LIB_CAT_MEDIUM_HARD;
- }
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI VERIFY (16) command (SBC and MMC).
- * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes.
- * Returns of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_verify16(int sg_fd, int vrprotect, bool dpo, int bytchk, uint64_t llba,
- int veri_len, int group_num, void * data_out,
- int data_out_len, uint64_t * infop, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "verify(16)";
- int k, res, ret, sense_cat, slen;
- unsigned char v_cdb[VERIFY16_CMDLEN] =
- {VERIFY16_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- /* N.B. BYTCHK field expanded to 2 bits sbc3r34 */
- v_cdb[1] = (((vrprotect & 0x7) << 5) | ((bytchk & 0x3) << 1)) ;
- if (dpo)
- v_cdb[1] |= 0x10;
- sg_put_unaligned_be64(llba, v_cdb + 2);
- sg_put_unaligned_be32((uint32_t)veri_len, v_cdb + 10);
- v_cdb[14] = group_num & 0x1f;
- if (verbose > 1) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < VERIFY16_CMDLEN; ++k)
- pr2ws("%02x ", v_cdb[k]);
- pr2ws("\n");
- if ((verbose > 3) && bytchk && data_out && (data_out_len > 0)) {
- k = data_out_len > 4104 ? 4104 : data_out_len;
- pr2ws(" data_out buffer%s\n",
- (data_out_len > 4104 ? ", first 4104 bytes" : ""));
- hex2stderr((const uint8_t *)data_out, k, verbose < 5);
- }
- }
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, v_cdb, sizeof(v_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- if (data_out_len > 0)
- set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, data_out_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- case SG_LIB_CAT_MEDIUM_HARD:
- {
- bool valid;
- uint64_t ull = 0;
-
- slen = get_scsi_pt_sense_len(ptvp);
- valid = sg_get_sense_info_fld(sense_b, slen, &ull);
- if (valid) {
- if (infop)
- *infop = ull;
- ret = SG_LIB_CAT_MEDIUM_HARD_WITH_INFO;
- } else
- ret = SG_LIB_CAT_MEDIUM_HARD;
- }
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a ATA PASS-THROUGH (12, 16 or 32) SCSI command (SAT). This is
- * selected by the cdb_len argument that can take values of 12, 16 or 32
- * only (else -1 is returned). The byte at offset 0 (and bytes 0 to 9
- * inclusive for ATA PT(32)) pointed to be cdbp are ignored and apart from
- * the control byte, the rest is copied into an internal cdb which is then
- * sent to the device. The control byte is byte 11 for ATA PT(12), byte 15
- * for ATA PT(16) and byte 1 for ATA PT(32). If timeout_secs <= 0 then the
- * timeout is set to 60 seconds. For data in or out transfers set dinp or
- * doutp, and dlen to the number of bytes to transfer. If dlen is zero then
- * no data transfer is assumed. If sense buffer obtained then it is written
- * to sensep, else sensep[0] is set to 0x0. If ATA return descriptor is
- * obtained then written to ata_return_dp, else ata_return_dp[0] is set to
- * 0x0. Either sensep or ata_return_dp (or both) may be NULL pointers.
- * Returns SCSI status value (>= 0) or -1 if other error. Users are
- * expected to check the sense buffer themselves. If available the data in
- * resid is written to residp. Note in SAT-2 and later, fixed format sense
- * data may be placed in *sensep in which case sensep[0]==0x70, prior to
- * SAT-2 descriptor sense format was required (i.e. sensep[0]==0x72).
- */
-int
-sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
- int timeout_secs, void * dinp, void * doutp, int dlen,
- unsigned char * sensep, int max_sense_len,
- unsigned char * ata_return_dp, int max_ata_return_len,
- int * residp, int verbose)
-{
- int k, res, slen, duration;
- int ret = -1;
- unsigned char apt_cdb[ATA_PT_32_CMDLEN];
- unsigned char sense_b[SENSE_BUFF_LEN];
- unsigned char * sp;
- const unsigned char * bp;
- struct sg_pt_base * ptvp;
- const char * cnamep;
- char b[256];
-
- memset(apt_cdb, 0, sizeof(apt_cdb));
- b[0] = '\0';
- switch (cdb_len) {
- case 12:
- cnamep = "ATA pass-through(12)";
- apt_cdb[0] = ATA_PT_12_CMD;
- memcpy(apt_cdb + 1, cdbp + 1, 10);
- /* control byte at cdb[11] left at zero */
- break;
- case 16:
- cnamep = "ATA pass-through(16)";
- apt_cdb[0] = ATA_PT_16_CMD;
- memcpy(apt_cdb + 1, cdbp + 1, 14);
- /* control byte at cdb[15] left at zero */
- break;
- case 32:
- cnamep = "ATA pass-through(32)";
- apt_cdb[0] = SG_VARIABLE_LENGTH_CMD;
- /* control byte at cdb[1] left at zero */
- apt_cdb[7] = 0x18; /* length starting at next byte */
- sg_put_unaligned_be16(ATA_PT_32_SA, apt_cdb + 8);
- memcpy(apt_cdb + 10, cdbp + 10, 32 - 10);
- break;
- default:
- pr2ws("cdb_len must be 12, 16 or 32\n");
- return -1;
- }
- if (NULL == cdbp) {
- if (verbose)
- pr2ws("%s NULL cdb pointer\n", cnamep);
- return -1;
- }
- if (sensep && (max_sense_len >= (int)sizeof(sense_b))) {
- sp = sensep;
- slen = max_sense_len;
- } else {
- sp = sense_b;
- slen = sizeof(sense_b);
- }
- if (verbose) {
- pr2ws(" %s cdb: ", cnamep);
- if (cdb_len < 32) {
- for (k = 0; k < cdb_len; ++k)
- pr2ws("%02x ", apt_cdb[k]);
- pr2ws("\n");
- } else {
- pr2ws("\n");
- hex2stderr(apt_cdb, cdb_len, -1);
- }
- }
- if (NULL == ((ptvp = create_pt_obj(cnamep))))
- return -1;
- set_scsi_pt_cdb(ptvp, apt_cdb, cdb_len);
- set_scsi_pt_sense(ptvp, sp, slen);
- if (dlen > 0) {
- if (dinp)
- set_scsi_pt_data_in(ptvp, (unsigned char *)dinp, dlen);
- else if (doutp)
- set_scsi_pt_data_out(ptvp, (unsigned char *)doutp, dlen);
- }
- res = do_scsi_pt(ptvp, sg_fd,
- ((timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT),
- verbose);
- if (SCSI_PT_DO_BAD_PARAMS == res) {
- if (verbose)
- pr2ws("%s: bad parameters\n", cnamep);
- goto out;
- } else if (SCSI_PT_DO_TIMEOUT == res) {
- if (verbose)
- pr2ws("%s: timeout\n", cnamep);
- goto out;
- } else if (res > 2) {
- if (verbose)
- pr2ws("%s: do_scsi_pt: errno=%d\n", cnamep, -res);
- }
-
- if ((verbose > 2) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0))
- pr2ws(" duration=%d ms\n", duration);
-
- switch (get_scsi_pt_result_category(ptvp)) {
- case SCSI_PT_RESULT_GOOD:
- if ((sensep) && (max_sense_len > 0))
- *sensep = 0;
- if ((ata_return_dp) && (max_ata_return_len > 0))
- *ata_return_dp = 0;
- if (residp && (dlen > 0))
- *residp = get_scsi_pt_resid(ptvp);
- ret = 0;
- break;
- case SCSI_PT_RESULT_STATUS: /* other than GOOD + CHECK CONDITION */
- if ((sensep) && (max_sense_len > 0))
- *sensep = 0;
- if ((ata_return_dp) && (max_ata_return_len > 0))
- *ata_return_dp = 0;
- ret = get_scsi_pt_status_response(ptvp);
- break;
- case SCSI_PT_RESULT_SENSE:
- if (sensep && (sp != sensep)) {
- k = get_scsi_pt_sense_len(ptvp);
- k = (k > max_sense_len) ? max_sense_len : k;
- memcpy(sensep, sp, k);
- }
- if (ata_return_dp && (max_ata_return_len > 0)) {
- /* search for ATA return descriptor */
- bp = sg_scsi_sense_desc_find(sp, slen, 0x9);
- if (bp) {
- k = bp[1] + 2;
- k = (k > max_ata_return_len) ? max_ata_return_len : k;
- memcpy(ata_return_dp, bp, k);
- } else
- ata_return_dp[0] = 0x0;
- }
- if (residp && (dlen > 0))
- *residp = get_scsi_pt_resid(ptvp);
- ret = get_scsi_pt_status_response(ptvp);
- break;
- case SCSI_PT_RESULT_TRANSPORT_ERR:
- if (verbose)
- pr2ws("%s: transport error: %s\n", cnamep,
- get_scsi_pt_transport_err_str(ptvp, sizeof(b), b));
- break;
- case SCSI_PT_RESULT_OS_ERR:
- if (verbose)
- pr2ws("%s: os error: %s\n", cnamep,
- get_scsi_pt_os_err_str(ptvp, sizeof(b) , b));
- break;
- default:
- if (verbose)
- pr2ws("%s: unknown pt_result_category=%d\n", cnamep,
- get_scsi_pt_result_category(ptvp));
- break;
- }
-
-out:
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI READ BUFFER(10) command (SPC). Return of 0 -> success
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_read_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset,
- void * resp, int mx_resp_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "read buffer(10)";
- int res, k, ret, sense_cat;
- unsigned char rbuf_cdb[READ_BUFFER_CMDLEN] =
- {READ_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- rbuf_cdb[1] = (unsigned char)(mode & 0x1f);
- rbuf_cdb[2] = (unsigned char)(buffer_id & 0xff);
- sg_put_unaligned_be24((uint32_t)buffer_offset, rbuf_cdb + 3);
- sg_put_unaligned_be24((uint32_t)mx_resp_len, rbuf_cdb + 6);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < READ_BUFFER_CMDLEN; ++k)
- pr2ws("%02x ", rbuf_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rbuf_cdb, sizeof(rbuf_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 -> success
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_write_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset,
- void * paramp, int param_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "write buffer";
- int k, res, ret, sense_cat;
- unsigned char wbuf_cdb[WRITE_BUFFER_CMDLEN] =
- {WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- wbuf_cdb[1] = (unsigned char)(mode & 0x1f);
- wbuf_cdb[2] = (unsigned char)(buffer_id & 0xff);
- sg_put_unaligned_be24((uint32_t)buffer_offset, wbuf_cdb + 3);
- sg_put_unaligned_be24((uint32_t)param_len, wbuf_cdb + 6);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < WRITE_BUFFER_CMDLEN; ++k)
- pr2ws("%02x ", wbuf_cdb[k]);
- pr2ws("\n");
- if ((verbose > 1) && paramp && param_len) {
- pr2ws(" %s parameter list", cdb_name_s);
- if (2 == verbose) {
- pr2ws("%s:\n", (param_len > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)paramp,
- (param_len > 256 ? 256 : param_len), -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)paramp, param_len, 0);
- }
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, wbuf_cdb, sizeof(wbuf_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 ->
- * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure. Adds mode specific field (spc4r32) and timeout
- * to command abort to override default of 60 seconds. If timeout_secs is
- * 0 or less then the default timeout is used instead. */
-int
-sg_ll_write_buffer_v2(int sg_fd, int mode, int m_specific, int buffer_id,
- uint32_t buffer_offset, void * paramp,
- uint32_t param_len, int timeout_secs, bool noisy,
- int verbose)
-{
- int k, res, ret, sense_cat;
- uint8_t wbuf_cdb[WRITE_BUFFER_CMDLEN] =
- {WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- uint8_t sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (buffer_offset > 0xffffff) {
- pr2ws("%s: buffer_offset value too large for 24 bits\n", __func__);
- return -1;
- }
- if (param_len > 0xffffff) {
- pr2ws("%s: param_len value too large for 24 bits\n", __func__);
- return -1;
- }
- wbuf_cdb[1] = (uint8_t)(mode & 0x1f);
- wbuf_cdb[1] |= (uint8_t)((m_specific & 0x7) << 5);
- wbuf_cdb[2] = (uint8_t)(buffer_id & 0xff);
- sg_put_unaligned_be24(buffer_offset, wbuf_cdb + 3);
- sg_put_unaligned_be24(param_len, wbuf_cdb + 6);
- if (verbose) {
- pr2ws(" Write buffer cdb: ");
- for (k = 0; k < WRITE_BUFFER_CMDLEN; ++k)
- pr2ws("%02x ", wbuf_cdb[k]);
- pr2ws("\n");
- if ((verbose > 1) && paramp && param_len) {
- pr2ws(" Write buffer parameter list%s:\n",
- ((param_len > 256) ? " (first 256 bytes)" : ""));
- hex2stderr((const uint8_t *)paramp,
- ((param_len > 256) ? 256 : param_len), -1);
- }
- }
- if (timeout_secs <= 0)
- timeout_secs = DEF_PT_TIMEOUT;
-
- ptvp = construct_scsi_pt_obj();
- if (NULL == ptvp) {
- pr2ws("%s: out of memory\n", __func__);
- return -1;
- }
- set_scsi_pt_cdb(ptvp, wbuf_cdb, sizeof(wbuf_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
- ret = sg_cmds_process_resp(ptvp, "Write buffer", res, SG_NO_DATA_IN,
- sense_b, noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI UNMAP command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_unmap(int sg_fd, int group_num, int timeout_secs, void * paramp,
- int param_len, bool noisy, int verbose)
-{
- return sg_ll_unmap_v2(sg_fd, false, group_num, timeout_secs, paramp,
- param_len, noisy, verbose);
-}
-
-/* Invokes a SCSI UNMAP (SBC-3) command. Version 2 adds anchor field
- * (sbc3r22). Otherwise same as sg_ll_unmap() . */
-int
-sg_ll_unmap_v2(int sg_fd, bool anchor, int group_num, int timeout_secs,
- void * paramp, int param_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "unmap";
- int k, res, ret, sense_cat, tmout;
- unsigned char u_cdb[UNMAP_CMDLEN] =
- {UNMAP_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (anchor)
- u_cdb[1] |= 0x1;
- tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
- u_cdb[6] = group_num & 0x1f;
- sg_put_unaligned_be16((uint16_t)param_len, u_cdb + 7);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < UNMAP_CMDLEN; ++k)
- pr2ws("%02x ", u_cdb[k]);
- pr2ws("\n");
- if ((verbose > 1) && paramp && param_len) {
- pr2ws(" %s parameter list:\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, u_cdb, sizeof(u_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI READ BLOCK LIMITS command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_read_block_limits(int sg_fd, void * resp, int mx_resp_len,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "read block limits";
- int k, ret, res, sense_cat;
- unsigned char rl_cdb[READ_BLOCK_LIMITS_CMDLEN] =
- {READ_BLOCK_LIMITS_CMD, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < READ_BLOCK_LIMITS_CMDLEN; ++k)
- pr2ws("%02x ", rl_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 0)) {
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, ret, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI RECEIVE COPY RESULTS command. Actually cover all current
- * uses of opcode 0x84 (Third-party copy IN). Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_receive_copy_results(int sg_fd, int sa, int list_id, void * resp,
- int mx_resp_len, bool noisy, int verbose)
-{
- int k, res, ret, sense_cat;
- unsigned char rcvcopyres_cdb[THIRD_PARTY_COPY_IN_CMDLEN] =
- {THIRD_PARTY_COPY_IN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
- char b[64];
-
- sg_get_opcode_sa_name(THIRD_PARTY_COPY_IN_CMD, sa, 0, (int)sizeof(b), b);
- rcvcopyres_cdb[1] = (unsigned char)(sa & 0x1f);
- if (sa <= 4) /* LID1 variants */
- rcvcopyres_cdb[2] = (unsigned char)(list_id);
- else if ((sa >= 5) && (sa <= 7)) /* LID4 variants */
- sg_put_unaligned_be32((uint32_t)list_id, rcvcopyres_cdb + 2);
- sg_put_unaligned_be32((uint32_t)mx_resp_len, rcvcopyres_cdb + 10);
-
- if (verbose) {
- pr2ws(" %s cdb: ", b);
- for (k = 0; k < THIRD_PARTY_COPY_IN_CMDLEN; ++k)
- pr2ws("%02x ", rcvcopyres_cdb[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(b))))
- return -1;
- set_scsi_pt_cdb(ptvp, rcvcopyres_cdb, sizeof(rcvcopyres_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, b, res, mx_resp_len, sense_b, noisy,
- verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-
-/* SPC-4 rev 35 and later calls this opcode (0x83) "Third-party copy OUT"
- * The original EXTENDED COPY command (now called EXTENDED COPY (LID1))
- * is the only one supported by sg_ll_extended_copy(). See function
- * sg_ll_3party_copy_out() for the other service actions ( > 0 ). */
-
-/* Invokes a SCSI EXTENDED COPY (LID1) command. Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_extended_copy(int sg_fd, void * paramp, int param_len, bool noisy,
- int verbose)
-{
- int k, res, ret, sense_cat;
- unsigned char xcopy_cdb[THIRD_PARTY_COPY_OUT_CMDLEN] =
- {THIRD_PARTY_COPY_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
- const char * opcode_name = "Extended copy (LID1)";
-
- xcopy_cdb[1] = (unsigned char)(EXTENDED_COPY_LID1_SA & 0x1f);
- sg_put_unaligned_be32((uint32_t)param_len, xcopy_cdb + 10);
-
- if (verbose) {
- pr2ws(" %s cdb: ", opcode_name);
- for (k = 0; k < THIRD_PARTY_COPY_OUT_CMDLEN; ++k)
- pr2ws("%02x ", xcopy_cdb[k]);
- pr2ws("\n");
- if ((verbose > 1) && paramp && param_len) {
- pr2ws(" %s parameter list:\n", opcode_name);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(opcode_name))))
- return -1;
- set_scsi_pt_cdb(ptvp, xcopy_cdb, sizeof(xcopy_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, opcode_name, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Handles various service actions associated with opcode 0x83 which is
- * called THIRD PARTY COPY OUT. These include the EXTENDED COPY(LID1 and
- * LID4), POPULATE TOKEN and WRITE USING TOKEN commands.
- * Return of 0 -> success,
- * various SG_LIB_CAT_* positive values or -1 -> other errors */
-int
-sg_ll_3party_copy_out(int sg_fd, int sa, unsigned int list_id, int group_num,
- int timeout_secs, void * paramp, int param_len,
- bool noisy, int verbose)
-{
- int k, res, ret, sense_cat, tmout;
- unsigned char xcopy_cdb[THIRD_PARTY_COPY_OUT_CMDLEN] =
- {THIRD_PARTY_COPY_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
- char cname[80];
-
- sg_get_opcode_sa_name(THIRD_PARTY_COPY_OUT_CMD, sa, 0, sizeof(cname),
- cname);
- xcopy_cdb[1] = (unsigned char)(sa & 0x1f);
- switch (sa) {
- case 0x0: /* XCOPY(LID1) */
- case 0x1: /* XCOPY(LID4) */
- sg_put_unaligned_be32((uint32_t)param_len, xcopy_cdb + 10);
- break;
- case 0x10: /* POPULATE TOKEN (SBC-3) */
- case 0x11: /* WRITE USING TOKEN (SBC-3) */
- sg_put_unaligned_be32((uint32_t)list_id, xcopy_cdb + 6);
- sg_put_unaligned_be32((uint32_t)param_len, xcopy_cdb + 10);
- xcopy_cdb[14] = (unsigned char)(group_num & 0x1f);
- break;
- case 0x1c: /* COPY OPERATION ABORT */
- sg_put_unaligned_be32((uint32_t)list_id, xcopy_cdb + 2);
- break;
- default:
- pr2ws("%s: unknown service action 0x%x\n", __func__, sa);
- return -1;
- }
- tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
-
- if (verbose) {
- pr2ws(" %s cdb: ", cname);
- for (k = 0; k < THIRD_PARTY_COPY_OUT_CMDLEN; ++k)
- pr2ws("%02x ", xcopy_cdb[k]);
- pr2ws("\n");
- if ((verbose > 1) && paramp && param_len) {
- pr2ws(" %s parameter list:\n", cname);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(cname))))
- return -1;
- set_scsi_pt_cdb(ptvp, xcopy_cdb, sizeof(xcopy_cdb));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
- ret = sg_cmds_process_resp(ptvp, cname, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI PRE-FETCH(10), PRE-FETCH(16) or SEEK(10) command (SBC).
- * Returns 0 -> success, 25 (SG_LIB_CAT_CONDITION_MET), various SG_LIB_CAT_*
- * positive values or -1 -> other errors. Note that CONDITION MET status
- * is returned when immed=true and num_blocks can fit in device's cache,
- * somewaht strangely, GOOD status (return 0) is returned if num_blocks
- * cannot fit in device's cache. If do_seek10==true then does a SEEK(10)
- * command with given lba, if that LBA is < 2**32 . Unclear what SEEK(10)
- * does, assume it is like PRE-FETCH. If timeout_secs is 0 (or less) then
- * use DEF_PT_TIMEOUT (60 seconds) as command timeout. */
-int
-sg_ll_pre_fetch_x(int sg_fd, bool do_seek10, bool cdb16, bool immed,
- uint64_t lba, uint32_t num_blocks, int group_num,
- int timeout_secs, bool noisy, int verbose)
-{
- static const char * const cdb10_name_s = "Pre-fetch(10)";
- static const char * const cdb16_name_s = "Pre-fetch(16)";
- static const char * const cdb_seek_name_s = "Seek(10)";
- int k, res, sense_cat, ret, cdb_len, tmout;
- const char *cdb_name_s;
- unsigned char preFetchCdb[PRE_FETCH16_CMDLEN]; /* all use longest cdb */
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- memset(preFetchCdb, 0, sizeof(preFetchCdb));
- if (do_seek10) {
- if (lba > UINT32_MAX) {
- if (verbose)
- pr2ws("%s: LBA exceeds 2**32 in %s\n", __func__,
- cdb_seek_name_s);
- return -1;
- }
- preFetchCdb[0] = SEEK10_CMD;
- cdb_len = SEEK10_CMDLEN;
- cdb_name_s = cdb_seek_name_s;
- sg_put_unaligned_be32((uint32_t)lba, preFetchCdb + 2);
- } else {
- if ((! cdb16) &&
- ((lba > UINT32_MAX) || (num_blocks > UINT16_MAX))) {
- cdb16 = true;
- if (noisy || verbose)
- pr2ws("%s: do %s due to %s size\n", __func__, cdb16_name_s,
- (lba > UINT32_MAX) ? "LBA" : "NUM_BLOCKS");
- }
- if (cdb16) {
- preFetchCdb[0] = PRE_FETCH16_CMD;
- cdb_len = PRE_FETCH16_CMDLEN;
- cdb_name_s = cdb16_name_s;
- if (immed)
- preFetchCdb[1] = 0x2;
- sg_put_unaligned_be64(lba, preFetchCdb + 2);
- sg_put_unaligned_be32(num_blocks, preFetchCdb + 10);
- preFetchCdb[14] = 0x3f & group_num;
- } else {
- preFetchCdb[0] = PRE_FETCH10_CMD;
- cdb_len = PRE_FETCH10_CMDLEN;
- cdb_name_s = cdb10_name_s;
- if (immed)
- preFetchCdb[1] = 0x2;
- sg_put_unaligned_be32((uint32_t)lba, preFetchCdb + 2);
- preFetchCdb[6] = 0x3f & group_num;
- sg_put_unaligned_be16((uint16_t)num_blocks, preFetchCdb + 7);
- }
- }
- tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < cdb_len; ++k)
- pr2ws("%02x ", preFetchCdb[k]);
- pr2ws("\n");
- }
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, preFetchCdb, cdb_len);
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
- if (0 == res) {
- int sstat = get_scsi_pt_status_response(ptvp);
-
- if (SG_LIB_CAT_CONDITION_MET == sstat) {
- ret = SG_LIB_CAT_CONDITION_MET;
- if (verbose > 2)
- pr2ws("%s: returns SG_LIB_CAT_CONDITION_MET\n", __func__);
- goto fini;
- }
- }
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-fini:
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
diff --git a/tools/sg_write_buffer/sg_cmds_mmc.c b/tools/sg_write_buffer/sg_cmds_mmc.c
deleted file mode 100644
index 18f6ae1..0000000
--- a/tools/sg_write_buffer/sg_cmds_mmc.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (c) 2008-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#define __STDC_FORMAT_MACROS 1
-#include <inttypes.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sg_lib.h"
-#include "sg_cmds_basic.h"
-#include "sg_cmds_mmc.h"
-#include "sg_pt.h"
-#include "sg_unaligned.h"
-
-
-#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
-
-#define DEF_PT_TIMEOUT 60 /* 60 seconds */
-
-#define GET_CONFIG_CMD 0x46
-#define GET_CONFIG_CMD_LEN 10
-#define GET_PERFORMANCE_CMD 0xac
-#define GET_PERFORMANCE_CMD_LEN 12
-#define SET_CD_SPEED_CMD 0xbb
-#define SET_CD_SPEED_CMDLEN 12
-#define SET_STREAMING_CMD 0xb6
-#define SET_STREAMING_CMDLEN 12
-
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
-static struct sg_pt_base *
-create_pt_obj(const char * cname)
-{
- struct sg_pt_base * ptvp = construct_scsi_pt_obj();
- if (NULL == ptvp)
- pr2ws("%s: out of memory\n", cname);
- return ptvp;
-}
-
-/* Invokes a SCSI SET CD SPEED command (MMC).
- * Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> command not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
- * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
-int
-sg_ll_set_cd_speed(int sg_fd, int rot_control, int drv_read_speed,
- int drv_write_speed, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "set cd speed";
- int res, ret, k, sense_cat;
- unsigned char scsCmdBlk[SET_CD_SPEED_CMDLEN] = {SET_CD_SPEED_CMD, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- scsCmdBlk[1] |= (rot_control & 0x3);
- sg_put_unaligned_be16((uint16_t)drv_read_speed, scsCmdBlk + 2);
- sg_put_unaligned_be16((uint16_t)drv_write_speed, scsCmdBlk + 4);
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SET_CD_SPEED_CMDLEN; ++k)
- pr2ws("%02x ", scsCmdBlk[k]);
- pr2ws("\n");
- }
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, scsCmdBlk, sizeof(scsCmdBlk));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_NOT_READY:
- case SG_LIB_CAT_UNIT_ATTENTION:
- case SG_LIB_CAT_INVALID_OP:
- case SG_LIB_CAT_ILLEGAL_REQ:
- case SG_LIB_CAT_ABORTED_COMMAND:
- ret = sense_cat;
- break;
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = -1;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI GET CONFIGURATION command (MMC-3,4,5).
- * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not
- * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */
-int
-sg_ll_get_config(int sg_fd, int rt, int starting, void * resp,
- int mx_resp_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "get configuration";
- int res, k, ret, sense_cat;
- unsigned char gcCmdBlk[GET_CONFIG_CMD_LEN] = {GET_CONFIG_CMD, 0, 0, 0,
- 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if ((rt < 0) || (rt > 3)) {
- pr2ws("Bad rt value: %d\n", rt);
- return -1;
- }
- gcCmdBlk[1] = (rt & 0x3);
- if ((starting < 0) || (starting > 0xffff)) {
- pr2ws("Bad starting field number: 0x%x\n", starting);
- return -1;
- }
- sg_put_unaligned_be16((uint16_t)starting, gcCmdBlk + 2);
- if ((mx_resp_len < 0) || (mx_resp_len > 0xffff)) {
- pr2ws("Bad mx_resp_len: 0x%x\n", starting);
- return -1;
- }
- sg_put_unaligned_be16((uint16_t)mx_resp_len, gcCmdBlk + 7);
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < GET_CONFIG_CMD_LEN; ++k)
- pr2ws("%02x ", gcCmdBlk[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, gcCmdBlk, sizeof(gcCmdBlk));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len,
- sense_b, noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_INVALID_OP:
- case SG_LIB_CAT_ILLEGAL_REQ:
- case SG_LIB_CAT_UNIT_ATTENTION:
- case SG_LIB_CAT_ABORTED_COMMAND:
- ret = sense_cat;
- break;
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = -1;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 3)) {
- unsigned char * bp;
- int len;
-
- bp = (unsigned char *)resp;
- len = sg_get_unaligned_be32(bp + 0);
- if (len < 0)
- len = 0;
- len = (ret < len) ? ret : len;
- pr2ws(" %s: response:\n", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (len > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (len > 256 ? 256 : len),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, len, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI GET PERFORMANCE command (MMC-3...6).
- * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not
- * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */
-int
-sg_ll_get_performance(int sg_fd, int data_type, unsigned int starting_lba,
- int max_num_desc, int ttype, void * resp,
- int mx_resp_len, bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "get performance";
- int res, k, ret, sense_cat;
- unsigned char gpCmdBlk[GET_PERFORMANCE_CMD_LEN] = {GET_PERFORMANCE_CMD, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if ((data_type < 0) || (data_type > 0x1f)) {
- pr2ws("Bad data_type value: %d\n", data_type);
- return -1;
- }
- gpCmdBlk[1] = (data_type & 0x1f);
- sg_put_unaligned_be32((uint32_t)starting_lba, gpCmdBlk + 2);
- if ((max_num_desc < 0) || (max_num_desc > 0xffff)) {
- pr2ws("Bad max_num_desc: 0x%x\n", max_num_desc);
- return -1;
- }
- sg_put_unaligned_be16((uint16_t)max_num_desc, gpCmdBlk + 8);
- if ((ttype < 0) || (ttype > 0xff)) {
- pr2ws("Bad type: 0x%x\n", ttype);
- return -1;
- }
- gpCmdBlk[10] = (unsigned char)ttype;
-
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < GET_PERFORMANCE_CMD_LEN; ++k)
- pr2ws("%02x ", gpCmdBlk[k]);
- pr2ws("\n");
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, gpCmdBlk, sizeof(gpCmdBlk));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_INVALID_OP:
- case SG_LIB_CAT_ILLEGAL_REQ:
- case SG_LIB_CAT_UNIT_ATTENTION:
- case SG_LIB_CAT_ABORTED_COMMAND:
- ret = sense_cat;
- break;
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = -1;
- break;
- }
- } else {
- if ((verbose > 2) && (ret > 3)) {
- unsigned char * bp;
- int len;
-
- bp = (unsigned char *)resp;
- len = sg_get_unaligned_be32(bp + 0);
- if (len < 0)
- len = 0;
- len = (ret < len) ? ret : len;
- pr2ws(" %s: response", cdb_name_s);
- if (3 == verbose) {
- pr2ws("%s:\n", (len > 256 ? ", first 256 bytes" : ""));
- hex2stderr((const uint8_t *)resp, (len > 256 ? 256 : len),
- -1);
- } else {
- pr2ws(":\n");
- hex2stderr((const uint8_t *)resp, len, 0);
- }
- }
- ret = 0;
- }
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-/* Invokes a SCSI SET STREAMING command (MMC). Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> Set Streaming not supported,
- * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_NOT_READY -> device not ready,
- * -1 -> other failure */
-int
-sg_ll_set_streaming(int sg_fd, int type, void * paramp, int param_len,
- bool noisy, int verbose)
-{
- static const char * const cdb_name_s = "set streaming";
- int k, res, ret, sense_cat;
- unsigned char ssCmdBlk[SET_STREAMING_CMDLEN] =
- {SET_STREAMING_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- ssCmdBlk[8] = type;
- sg_put_unaligned_be16((uint16_t)param_len, ssCmdBlk + 9);
- if (verbose) {
- pr2ws(" %s cdb: ", cdb_name_s);
- for (k = 0; k < SET_STREAMING_CMDLEN; ++k)
- pr2ws("%02x ", ssCmdBlk[k]);
- pr2ws("\n");
- if ((verbose > 1) && paramp && param_len) {
- pr2ws(" %s parameter list:\n", cdb_name_s);
- hex2stderr((const uint8_t *)paramp, param_len, -1);
- }
- }
-
- if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
- return -1;
- set_scsi_pt_cdb(ptvp, ssCmdBlk, sizeof(ssCmdBlk));
- set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
- noisy, verbose, &sense_cat);
- if (-1 == ret) {
- int os_err = get_scsi_pt_os_err(ptvp);
-
- if ((os_err > 0) && (os_err < 47))
- ret = SG_LIB_OS_BASE_ERR + os_err;
- } else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_NOT_READY:
- case SG_LIB_CAT_INVALID_OP:
- case SG_LIB_CAT_ILLEGAL_REQ:
- case SG_LIB_CAT_UNIT_ATTENTION:
- case SG_LIB_CAT_ABORTED_COMMAND:
- ret = sense_cat;
- break;
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = -1;
- break;
- }
- } else
- ret = 0;
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
diff --git a/tools/sg_write_buffer/sg_io_linux.c b/tools/sg_write_buffer/sg_io_linux.c
deleted file mode 100644
index f9f08e7..0000000
--- a/tools/sg_write_buffer/sg_io_linux.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (c) 1999-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef SG_LIB_LINUX
-
-#include "sg_io_linux.h"
-
-
-/* Version 1.07 20160405 */
-
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
-
-void
-sg_print_masked_status(int masked_status)
-{
- int scsi_status = (masked_status << 1) & 0x7e;
-
- sg_print_scsi_status(scsi_status);
-}
-
-static const char * linux_host_bytes[] = {
- "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT",
- "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR",
- "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR",
- "DID_IMM_RETRY", "DID_REQUEUE", "DID_TRANSPORT_DISRUPTED",
- "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE", "DID_NEXUS_FAILURE",
- "DID_ALLOC_FAILURE", "DID_MEDIUM_ERROR",
-};
-
-#define LINUX_HOST_BYTES_SZ \
- (int)(sizeof(linux_host_bytes) / sizeof(linux_host_bytes[0]))
-
-void
-sg_print_host_status(int host_status)
-{
- pr2ws("Host_status=0x%02x ", host_status);
- if ((host_status < 0) || (host_status >= LINUX_HOST_BYTES_SZ))
- pr2ws("is invalid ");
- else
- pr2ws("[%s] ", linux_host_bytes[host_status]);
-}
-
-static const char * linux_driver_bytes[] = {
- "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA",
- "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",
- "DRIVER_SENSE"
-};
-
-#define LINUX_DRIVER_BYTES_SZ \
- (int)(sizeof(linux_driver_bytes) / sizeof(linux_driver_bytes[0]))
-
-#if 0
-static const char * linux_driver_suggests[] = {
- "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP",
- "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN",
- "SUGGEST_SENSE"
-};
-
-#define LINUX_DRIVER_SUGGESTS_SZ \
- (int)(sizeof(linux_driver_suggests) / sizeof(linux_driver_suggests[0]))
-#endif
-
-
-void
-sg_print_driver_status(int driver_status)
-{
- int driv;
- const char * driv_cp = "invalid";
-
- driv = driver_status & SG_LIB_DRIVER_MASK;
- if (driv < LINUX_DRIVER_BYTES_SZ)
- driv_cp = linux_driver_bytes[driv];
-#if 0
- sugg = (driver_status & SG_LIB_SUGGEST_MASK) >> 4;
- if (sugg < LINUX_DRIVER_SUGGESTS_SZ)
- sugg_cp = linux_driver_suggests[sugg];
-#endif
- pr2ws("Driver_status=0x%02x", driver_status);
- pr2ws(" [%s] ", driv_cp);
-}
-
-/* Returns 1 if no errors found and thus nothing printed; otherwise
- prints error/warning (prefix by 'leadin') and returns 0. */
-static int
-sg_linux_sense_print(const char * leadin, int scsi_status, int host_status,
- int driver_status, const unsigned char * sense_buffer,
- int sb_len, bool raw_sinfo)
-{
- bool done_leadin = false;
- bool done_sense = false;
-
- scsi_status &= 0x7e; /*sanity */
- if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status))
- return 1; /* No problems */
- if (0 != scsi_status) {
- if (leadin)
- pr2ws("%s: ", leadin);
- done_leadin = true;
- pr2ws("SCSI status: ");
- sg_print_scsi_status(scsi_status);
- pr2ws("\n");
- if (sense_buffer && ((scsi_status == SAM_STAT_CHECK_CONDITION) ||
- (scsi_status == SAM_STAT_COMMAND_TERMINATED))) {
- /* SAM_STAT_COMMAND_TERMINATED is obsolete */
- sg_print_sense(0, sense_buffer, sb_len, raw_sinfo);
- done_sense = true;
- }
- }
- if (0 != host_status) {
- if (leadin && (! done_leadin))
- pr2ws("%s: ", leadin);
- if (done_leadin)
- pr2ws("plus...: ");
- else
- done_leadin = true;
- sg_print_host_status(host_status);
- pr2ws("\n");
- }
- if (0 != driver_status) {
- if (done_sense &&
- (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status)))
- return 0;
- if (leadin && (! done_leadin))
- pr2ws("%s: ", leadin);
- if (done_leadin)
- pr2ws("plus...: ");
- sg_print_driver_status(driver_status);
- pr2ws("\n");
- if (sense_buffer && (! done_sense) &&
- (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status)))
- sg_print_sense(0, sense_buffer, sb_len, raw_sinfo);
- }
- return 0;
-}
-
-#ifdef SG_IO
-
-bool
-sg_normalize_sense(const struct sg_io_hdr * hp,
- struct sg_scsi_sense_hdr * sshp)
-{
- if ((NULL == hp) || (0 == hp->sb_len_wr)) {
- if (sshp)
- memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
- return 0;
- }
- return sg_scsi_normalize_sense(hp->sbp, hp->sb_len_wr, sshp);
-}
-
-/* Returns 1 if no errors found and thus nothing printed; otherwise
- returns 0. */
-int
-sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp,
- bool raw_sinfo)
-{
- return sg_linux_sense_print(leadin, hp->status, hp->host_status,
- hp->driver_status, hp->sbp, hp->sb_len_wr,
- raw_sinfo);
-}
-#endif
-
-/* Returns 1 if no errors found and thus nothing printed; otherwise
- returns 0. */
-int
-sg_chk_n_print(const char * leadin, int masked_status, int host_status,
- int driver_status, const unsigned char * sense_buffer,
- int sb_len, bool raw_sinfo)
-{
- int scsi_status = (masked_status << 1) & 0x7e;
-
- return sg_linux_sense_print(leadin, scsi_status, host_status,
- driver_status, sense_buffer, sb_len,
- raw_sinfo);
-}
-
-#ifdef SG_IO
-int
-sg_err_category3(struct sg_io_hdr * hp)
-{
- return sg_err_category_new(hp->status, hp->host_status,
- hp->driver_status, hp->sbp, hp->sb_len_wr);
-}
-#endif
-
-int
-sg_err_category(int masked_status, int host_status, int driver_status,
- const unsigned char * sense_buffer, int sb_len)
-{
- int scsi_status = (masked_status << 1) & 0x7e;
-
- return sg_err_category_new(scsi_status, host_status, driver_status,
- sense_buffer, sb_len);
-}
-
-int
-sg_err_category_new(int scsi_status, int host_status, int driver_status,
- const unsigned char * sense_buffer, int sb_len)
-{
- int masked_driver_status = (SG_LIB_DRIVER_MASK & driver_status);
-
- scsi_status &= 0x7e;
- if ((0 == scsi_status) && (0 == host_status) &&
- (0 == masked_driver_status))
- return SG_LIB_CAT_CLEAN;
- if ((SAM_STAT_CHECK_CONDITION == scsi_status) ||
- (SAM_STAT_COMMAND_TERMINATED == scsi_status) ||
- (SG_LIB_DRIVER_SENSE == masked_driver_status))
- return sg_err_category_sense(sense_buffer, sb_len);
- if (0 != host_status) {
- if ((SG_LIB_DID_NO_CONNECT == host_status) ||
- (SG_LIB_DID_BUS_BUSY == host_status) ||
- (SG_LIB_DID_TIME_OUT == host_status))
- return SG_LIB_CAT_TIMEOUT;
- if (SG_LIB_DID_NEXUS_FAILURE == host_status)
- return SG_LIB_CAT_RES_CONFLICT;
- }
- if (SG_LIB_DRIVER_TIMEOUT == masked_driver_status)
- return SG_LIB_CAT_TIMEOUT;
- return SG_LIB_CAT_OTHER;
-}
-
-#endif /* if SG_LIB_LINUX defined */
diff --git a/tools/sg_write_buffer/sg_lib.c b/tools/sg_write_buffer/sg_lib.c
deleted file mode 100644
index e31c816..0000000
--- a/tools/sg_write_buffer/sg_lib.c
+++ /dev/null
@@ -1,3494 +0,0 @@
-/*
- * Copyright (c) 1999-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-/* NOTICE:
- * On 5th October 2004 (v1.00) this file name was changed from sg_err.c
- * to sg_lib.c and the previous GPL was changed to a FreeBSD license.
- * The intention is to maintain this file and the related sg_lib.h file
- * as open source and encourage their unencumbered use.
- *
- * CONTRIBUTIONS:
- * This file started out as a copy of SCSI opcodes, sense keys and
- * additional sense codes (ASC/ASCQ) kept in the Linux SCSI subsystem
- * in the kernel source file: drivers/scsi/constant.c . That file
- * bore this notice: "Copyright (C) 1993, 1994, 1995 Eric Youngdale"
- * and a GPL notice.
- *
- * Much of the data in this file is derived from SCSI draft standards
- * found at http://www.t10.org with the "SCSI Primary Commands-4" (SPC-4)
- * being the central point of reference.
- *
- * Contributions:
- * sense key specific field decoding [Trent Piepho 20031116]
- *
- */
-
-#define _POSIX_C_SOURCE 200809L /* for posix_memalign() */
-#define __STDC_FORMAT_MACROS 1
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-#include <inttypes.h>
-#include <errno.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sg_lib.h"
-#include "sg_lib_data.h"
-#include "sg_unaligned.h"
-#include "sg_pr2serr.h"
-
-/* sg_lib_version_str (and datestamp) defined in sg_lib_data.c file */
-
-#define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d /* corresponding ASC is 0 */
-
-FILE * sg_warnings_strm = NULL; /* would like to default to stderr */
-
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
-#if defined(__GNUC__) || defined(__clang__)
-static int scnpr(char * cp, int cp_max_len, const char * fmt, ...)
- __attribute__ ((format (printf, 3, 4)));
-#else
-static int scnpr(char * cp, int cp_max_len, const char * fmt, ...);
-#endif
-
-/* Want safe, 'n += snprintf(b + n, blen - n, ...)' style sequence of
- * functions. Returns number of chars placed in cp excluding the
- * trailing null char. So for cp_max_len > 0 the return value is always
- * < cp_max_len; for cp_max_len <= 1 the return value is 0 and no chars are
- * written to cp. Note this means that when cp_max_len = 1, this function
- * assumes that cp[0] is the null character and does nothing (and returns
- * 0). Linux kernel has a similar function called scnprintf(). */
-static int
-scnpr(char * cp, int cp_max_len, const char * fmt, ...)
-{
- va_list args;
- int n;
-
- if (cp_max_len < 2)
- return 0;
- va_start(args, fmt);
- n = vsnprintf(cp, cp_max_len, fmt, args);
- va_end(args);
- return (n < cp_max_len) ? n : (cp_max_len - 1);
-}
-
-/* Simple ASCII printable (does not use locale), includes space and excludes
- * DEL (0x7f). */
-static inline int my_isprint(int ch)
-{
- return ((ch >= ' ') && (ch < 0x7f));
-}
-
-/* Searches 'arr' for match on 'value' then 'peri_type'. If matches
- 'value' but not 'peri_type' then yields first 'value' match entry.
- Last element of 'arr' has NULL 'name'. If no match returns NULL. */
-static const struct sg_lib_value_name_t *
-get_value_name(const struct sg_lib_value_name_t * arr, int value,
- int peri_type)
-{
- const struct sg_lib_value_name_t * vp = arr;
- const struct sg_lib_value_name_t * holdp;
-
- if (peri_type < 0)
- peri_type = 0;
- for (; vp->name; ++vp) {
- if (value == vp->value) {
- if (peri_type == vp->peri_dev_type)
- return vp;
- holdp = vp;
- while ((vp + 1)->name && (value == (vp + 1)->value)) {
- ++vp;
- if (peri_type == vp->peri_dev_type)
- return vp;
- }
- return holdp;
- }
- }
- return NULL;
-}
-
-/* If this function is not called, sg_warnings_strm will be NULL and all users
- * (mainly fprintf() ) need to check and substitute stderr as required */
-void
-sg_set_warnings_strm(FILE * warnings_strm)
-{
- sg_warnings_strm = warnings_strm;
-}
-
-#define CMD_NAME_LEN 128
-
-void
-sg_print_command(const unsigned char * command)
-{
- int k, sz;
- char buff[CMD_NAME_LEN];
-
- sg_get_command_name(command, 0, CMD_NAME_LEN, buff);
- buff[CMD_NAME_LEN - 1] = '\0';
-
- pr2ws("%s [", buff);
- if (SG_VARIABLE_LENGTH_CMD == command[0])
- sz = command[7] + 8;
- else
- sz = sg_get_command_size(command[0]);
- for (k = 0; k < sz; ++k)
- pr2ws("%02x ", command[k]);
- pr2ws("]\n");
-}
-
-void
-sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff)
-{
- const char * ccp = NULL;
- bool unknown = false;
-
- if ((NULL == buff) || (buff_len < 1))
- return;
- else if (1 == buff_len) {
- buff[0] = '\0';
- return;
- }
- scsi_status &= 0x7e; /* sanitize as much as possible */
- switch (scsi_status) {
- case 0: ccp = "Good"; break;
- case 0x2: ccp = "Check Condition"; break;
- case 0x4: ccp = "Condition Met"; break;
- case 0x8: ccp = "Busy"; break;
- case 0x10: ccp = "Intermediate (obsolete)"; break;
- case 0x14: ccp = "Intermediate-Condition Met (obsolete)"; break;
- case 0x18: ccp = "Reservation Conflict"; break;
- case 0x22: ccp = "Command Terminated (obsolete)"; break;
- case 0x28: ccp = "Task set Full"; break;
- case 0x30: ccp = "ACA Active"; break;
- case 0x40: ccp = "Task Aborted"; break;
- default:
- unknown = true;
- break;
- }
- if (unknown)
- scnpr(buff, buff_len, "Unknown status [0x%x]", scsi_status);
- else
- scnpr(buff, buff_len, "%s", ccp);
-}
-
-void
-sg_print_scsi_status(int scsi_status)
-{
- char buff[128];
-
- sg_get_scsi_status_str(scsi_status, sizeof(buff) - 1, buff);
- buff[sizeof(buff) - 1] = '\0';
- pr2ws("%s ", buff);
-}
-
-/* Get sense key from sense buffer. If successful returns a sense key value
- * between 0 and 15. If sense buffer cannot be decode, returns -1 . */
-int
-sg_get_sense_key(const unsigned char * sbp, int sb_len)
-{
- if ((NULL == sbp) || (sb_len < 2))
- return -1;
- switch (sbp[0] & 0x7f) {
- case 0x70:
- case 0x71:
- return (sb_len < 3) ? -1 : (sbp[2] & 0xf);
- case 0x72:
- case 0x73:
- return sbp[1] & 0xf;
- default:
- return -1;
- }
-}
-
-/* Yield string associated with sense_key value. Returns 'buff'. */
-char *
-sg_get_sense_key_str(int sense_key, int buff_len, char * buff)
-{
- if (1 == buff_len) {
- buff[0] = '\0';
- return buff;
- }
- if ((sense_key >= 0) && (sense_key < 16))
- scnpr(buff, buff_len, "%s", sg_lib_sense_key_desc[sense_key]);
- else
- scnpr(buff, buff_len, "invalid value: 0x%x", sense_key);
- return buff;
-}
-
-/* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
-char *
-sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
-{
- int k, num, rlen;
- bool found = false;
- struct sg_lib_asc_ascq_t * eip;
- struct sg_lib_asc_ascq_range_t * ei2p;
-
- if (1 == buff_len) {
- buff[0] = '\0';
- return buff;
- }
- for (k = 0; sg_lib_asc_ascq_range[k].text; ++k) {
- ei2p = &sg_lib_asc_ascq_range[k];
- if ((ei2p->asc == asc) &&
- (ascq >= ei2p->ascq_min) &&
- (ascq <= ei2p->ascq_max)) {
- found = true;
- num = scnpr(buff, buff_len, "Additional sense: ");
- rlen = buff_len - num;
- scnpr(buff + num, ((rlen > 0) ? rlen : 0), ei2p->text, ascq);
- }
- }
- if (found)
- return buff;
-
- for (k = 0; sg_lib_asc_ascq[k].text; ++k) {
- eip = &sg_lib_asc_ascq[k];
- if (eip->asc == asc &&
- eip->ascq == ascq) {
- found = true;
- scnpr(buff, buff_len, "Additional sense: %s", eip->text);
- }
- }
- if (! found) {
- if (asc >= 0x80)
- scnpr(buff, buff_len, "vendor specific ASC=%02x, ASCQ=%02x "
- "(hex)", asc, ascq);
- else if (ascq >= 0x80)
- scnpr(buff, buff_len, "ASC=%02x, vendor specific qualification "
- "ASCQ=%02x (hex)", asc, ascq);
- else
- scnpr(buff, buff_len, "ASC=%02x, ASCQ=%02x (hex)", asc, ascq);
- }
- return buff;
-}
-
-/* Attempt to find the first SCSI sense data descriptor that matches the
- * given 'desc_type'. If found return pointer to start of sense data
- * descriptor; otherwise (including fixed format sense data) returns NULL. */
-const unsigned char *
-sg_scsi_sense_desc_find(const unsigned char * sbp, int sb_len,
- int desc_type)
-{
- int add_sb_len, add_d_len, desc_len, k;
- const unsigned char * descp;
-
- if ((sb_len < 8) || (0 == (add_sb_len = sbp[7])))
- return NULL;
- if ((sbp[0] < 0x72) || (sbp[0] > 0x73))
- return NULL;
- add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8);
- descp = &sbp[8];
- for (desc_len = 0, k = 0; k < add_sb_len; k += desc_len) {
- descp += desc_len;
- add_d_len = (k < (add_sb_len - 1)) ? descp[1]: -1;
- desc_len = add_d_len + 2;
- if (descp[0] == desc_type)
- return descp;
- if (add_d_len < 0) /* short descriptor ?? */
- break;
- }
- return NULL;
-}
-
-/* Returns true if valid bit set, false if valid bit clear. Irrespective the
- * information field is written out via 'info_outp' (except when it is
- * NULL). Handles both fixed and descriptor sense formats. */
-bool
-sg_get_sense_info_fld(const unsigned char * sbp, int sb_len,
- uint64_t * info_outp)
-{
- const unsigned char * bp;
- uint64_t ull;
-
- if (info_outp)
- *info_outp = 0;
- if (sb_len < 7)
- return false;
- switch (sbp[0] & 0x7f) {
- case 0x70:
- case 0x71:
- if (info_outp)
- *info_outp = sg_get_unaligned_be32(sbp + 3);
- return !!(sbp[0] & 0x80);
- case 0x72:
- case 0x73:
- bp = sg_scsi_sense_desc_find(sbp, sb_len, 0 /* info desc */);
- if (bp && (0xa == bp[1])) {
- ull = sg_get_unaligned_be64(bp + 4);
- if (info_outp)
- *info_outp = ull;
- return !!(bp[2] & 0x80); /* since spc3r23 should be set */
- } else
- return false;
- default:
- return false;
- }
-}
-
-/* Returns true if fixed format or command specific information descriptor
- * is found in the descriptor sense; else false. If available the command
- * specific information field (4 byte integer in fixed format, 8 byte
- * integer in descriptor format) is written out via 'cmd_spec_outp'.
- * Handles both fixed and descriptor sense formats. */
-bool
-sg_get_sense_cmd_spec_fld(const unsigned char * sbp, int sb_len,
- uint64_t * cmd_spec_outp)
-{
- const unsigned char * bp;
-
- if (cmd_spec_outp)
- *cmd_spec_outp = 0;
- if (sb_len < 7)
- return false;
- switch (sbp[0] & 0x7f) {
- case 0x70:
- case 0x71:
- if (cmd_spec_outp)
- *cmd_spec_outp = sg_get_unaligned_be32(sbp + 8);
- return true;
- case 0x72:
- case 0x73:
- bp = sg_scsi_sense_desc_find(sbp, sb_len,
- 1 /* command specific info desc */);
- if (bp && (0xa == bp[1])) {
- if (cmd_spec_outp)
- *cmd_spec_outp = sg_get_unaligned_be64(bp + 4);
- return true;
- } else
- return false;
- default:
- return false;
- }
-}
-
-/* Returns true if any of the 3 bits (i.e. FILEMARK, EOM or ILI) are set.
- * In descriptor format if the stream commands descriptor not found
- * then returns false. Writes true or false corresponding to these bits to
- * the last three arguments if they are non-NULL. */
-bool
-sg_get_sense_filemark_eom_ili(const unsigned char * sbp, int sb_len,
- bool * filemark_p, bool * eom_p, bool * ili_p)
-{
- const unsigned char * bp;
-
- if (sb_len < 7)
- return false;
- switch (sbp[0] & 0x7f) {
- case 0x70:
- case 0x71:
- if (sbp[2] & 0xe0) {
- if (filemark_p)
- *filemark_p = !!(sbp[2] & 0x80);
- if (eom_p)
- *eom_p = !!(sbp[2] & 0x40);
- if (ili_p)
- *ili_p = !!(sbp[2] & 0x20);
- return true;
- } else
- return false;
- case 0x72:
- case 0x73:
- /* Look for stream commands sense data descriptor */
- bp = sg_scsi_sense_desc_find(sbp, sb_len, 4);
- if (bp && (bp[1] >= 2)) {
- if (bp[3] & 0xe0) {
- if (filemark_p)
- *filemark_p = !!(bp[3] & 0x80);
- if (eom_p)
- *eom_p = !!(bp[3] & 0x40);
- if (ili_p)
- *ili_p = !!(bp[3] & 0x20);
- return true;
- }
- }
- return false;
- default:
- return false;
- }
-}
-
-/* Returns true if SKSV is set and sense key is NO_SENSE or NOT_READY. Also
- * returns true if progress indication sense data descriptor found. Places
- * progress field from sense data where progress_outp points. If progress
- * field is not available returns false and *progress_outp is unaltered.
- * Handles both fixed and descriptor sense formats.
- * Hint: if true is returned *progress_outp may be multiplied by 100 then
- * divided by 65536 to get the percentage completion. */
-bool
-sg_get_sense_progress_fld(const unsigned char * sbp, int sb_len,
- int * progress_outp)
-{
- const unsigned char * bp;
- int sk, sk_pr;
-
- if (sb_len < 7)
- return false;
- switch (sbp[0] & 0x7f) {
- case 0x70:
- case 0x71:
- sk = (sbp[2] & 0xf);
- if ((sb_len < 18) ||
- ((SPC_SK_NO_SENSE != sk) && (SPC_SK_NOT_READY != sk)))
- return false;
- if (sbp[15] & 0x80) { /* SKSV bit set */
- if (progress_outp)
- *progress_outp = sg_get_unaligned_be16(sbp + 16);
- return true;
- } else
- return false;
- case 0x72:
- case 0x73:
- /* sense key specific progress (0x2) or progress descriptor (0xa) */
- sk = (sbp[1] & 0xf);
- sk_pr = (SPC_SK_NO_SENSE == sk) || (SPC_SK_NOT_READY == sk);
- if (sk_pr && ((bp = sg_scsi_sense_desc_find(sbp, sb_len, 2))) &&
- (0x6 == bp[1]) && (0x80 & bp[4])) {
- if (progress_outp)
- *progress_outp = sg_get_unaligned_be16(bp + 5);
- return true;
- } else if (((bp = sg_scsi_sense_desc_find(sbp, sb_len, 0xa))) &&
- ((0x6 == bp[1]))) {
- if (progress_outp)
- *progress_outp = sg_get_unaligned_be16(bp + 6);
- return true;
- } else
- return false;
- default:
- return false;
- }
-}
-
-char *
-sg_get_pdt_str(int pdt, int buff_len, char * buff)
-{
- if ((pdt < 0) || (pdt > 31))
- scnpr(buff, buff_len, "bad pdt");
- else
- scnpr(buff, buff_len, "%s", sg_lib_pdt_strs[pdt]);
- return buff;
-}
-
-int
-sg_lib_pdt_decay(int pdt)
-{
- if ((pdt < 0) || (pdt > 31))
- return 0;
- return sg_lib_pdt_decay_arr[pdt];
-}
-
-char *
-sg_get_trans_proto_str(int tpi, int buff_len, char * buff)
-{
- if ((tpi < 0) || (tpi > 15))
- scnpr(buff, buff_len, "bad tpi");
- else
- scnpr(buff, buff_len, "%s", sg_lib_transport_proto_strs[tpi]);
- return buff;
-}
-
-#define TRANSPORT_ID_MIN_LEN 24
-
-char *
-sg_decode_transportid_str(const char * lip, unsigned char * bp, int bplen,
- bool only_one, int blen, char * b)
-{
- int proto_id, num, k, n, normal_len, tpid_format;
- uint64_t ull;
- int bump;
-
- if ((NULL == b) || (blen < 1))
- return b;
- else if (1 == blen) {
- b[0] = '\0';
- return b;
- }
- if (NULL == lip)
- lip = "";
- bump = TRANSPORT_ID_MIN_LEN; /* should be overwritten in all loop paths */
- for (k = 0, n = 0; bplen > 0; ++k, bp += bump, bplen -= bump) {
- if ((k > 0) && only_one)
- break;
- if ((bplen < 24) || (0 != (bplen % 4)))
- n += scnpr(b + n, blen - n, "%sTransport Id short or not "
- "multiple of 4 [length=%d]:\n", lip, blen);
- else
- n += scnpr(b + n, blen - n, "%sTransport Id of initiator:\n",
- lip);
- tpid_format = ((bp[0] >> 6) & 0x3);
- proto_id = (bp[0] & 0xf);
- normal_len = (bplen > TRANSPORT_ID_MIN_LEN) ?
- TRANSPORT_ID_MIN_LEN : bplen;
- switch (proto_id) {
- case TPROTO_FCP: /* Fibre channel */
- n += scnpr(b + n, blen - n, "%s FCP-2 World Wide Name:\n", lip);
- if (0 != tpid_format)
- n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
- "%d]\n", lip, tpid_format);
- n += hex2str(bp + 8, 8, lip, 1, blen - n, b + n);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_SPI: /* Scsi Parallel Interface, obsolete */
- n += scnpr(b + n, blen - n, "%s Parallel SCSI initiator SCSI "
- "address: 0x%x\n", lip, sg_get_unaligned_be16(bp + 2));
- if (0 != tpid_format)
- n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
- "%d]\n", lip, tpid_format);
- n += scnpr(b + n, blen - n, "%s relative port number (of "
- "corresponding target): 0x%x\n", lip,
- sg_get_unaligned_be16(bp + 6));
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_SSA:
- n += scnpr(b + n, blen - n, "%s SSA (transport id not "
- "defined):\n", lip);
- n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
- tpid_format);
- n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_1394: /* IEEE 1394 */
- n += scnpr(b + n, blen - n, "%s IEEE 1394 EUI-64 name:\n", lip);
- if (0 != tpid_format)
- n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
- "%d]\n", lip, tpid_format);
- n += hex2str(&bp[8], 8, lip, 1, blen - n, b + n);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_SRP: /* SCSI over RDMA */
- n += scnpr(b + n, blen - n, "%s RDMA initiator port "
- "identifier:\n", lip);
- if (0 != tpid_format)
- n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
- "%d]\n", lip, tpid_format);
- n += hex2str(bp + 8, 16, lip, 1, blen - n, b + n);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_ISCSI:
- n += scnpr(b + n, blen - n, "%s iSCSI ", lip);
- num = sg_get_unaligned_be16(bp + 2);
- if (0 == tpid_format)
- n += scnpr(b + n, blen - n, "name: %.*s\n", num, &bp[4]);
- else if (1 == tpid_format)
- n += scnpr(b + n, blen - n, "world wide unique port id: "
- "%.*s\n", num, &bp[4]);
- else {
- n += scnpr(b + n, blen - n, " [Unexpected TPID format: "
- "%d]\n", tpid_format);
- n += hex2str(bp, num + 4, lip, 0, blen - n, b + n);
- }
- bump = (((num + 4) < TRANSPORT_ID_MIN_LEN) ?
- TRANSPORT_ID_MIN_LEN : num + 4);
- break;
- case TPROTO_SAS:
- ull = sg_get_unaligned_be64(bp + 4);
- n += scnpr(b + n, blen - n, "%s SAS address: 0x%" PRIx64 "\n",
- lip, ull);
- if (0 != tpid_format)
- n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
- "%d]\n", lip, tpid_format);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_ADT: /* no TransportID defined by T10 yet */
- n += scnpr(b + n, blen - n, "%s ADT:\n", lip);
- n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
- tpid_format);
- n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_ATA: /* no TransportID defined by T10 yet */
- n += scnpr(b + n, blen - n, "%s ATAPI:\n", lip);
- n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
- tpid_format);
- n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_UAS: /* no TransportID defined by T10 yet */
- n += scnpr(b + n, blen - n, "%s UAS:\n", lip);
- n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
- tpid_format);
- n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_SOP:
- n += scnpr(b + n, blen - n, "%s SOP ", lip);
- num = sg_get_unaligned_be16(bp + 2);
- if (0 == tpid_format)
- n += scnpr(b + n, blen - n, "Routing ID: 0x%x\n", num);
- else {
- n += scnpr(b + n, blen - n, " [Unexpected TPID format: "
- "%d]\n", tpid_format);
- n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
- }
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_PCIE: /* no TransportID defined by T10 yet */
- n += scnpr(b + n, blen - n, "%s PCIE:\n", lip);
- n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
- tpid_format);
- n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- case TPROTO_NONE: /* no TransportID defined by T10 */
- n += scnpr(b + n, blen - n, "%s No specified protocol\n", lip);
- /* n += hex2str(bp, ((bplen > 24) ? 24 : bplen),
- * lip, 0, blen - n, b + n); */
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- default:
- n += scnpr(b + n, blen - n, "%s unknown protocol id=0x%x "
- "TPID format=%d\n", lip, proto_id, tpid_format);
- n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
- bump = TRANSPORT_ID_MIN_LEN;
- break;
- }
- }
- return b;
-}
-
-
-static const char * desig_code_set_str_arr[] =
-{
- "Reserved [0x0]",
- "Binary",
- "ASCII",
- "UTF-8",
- "Reserved [0x4]", "Reserved [0x5]", "Reserved [0x6]", "Reserved [0x7]",
- "Reserved [0x8]", "Reserved [0x9]", "Reserved [0xa]", "Reserved [0xb]",
- "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
-};
-
-const char *
-sg_get_desig_code_set_str(int val)
-{
- if ((val >= 0) && (val < 16))
- return desig_code_set_str_arr[val];
- else
- return NULL;
-}
-
-static const char * desig_assoc_str_arr[] =
-{
- "Addressed logical unit",
- "Target port", /* that received request; unless SCSI ports VPD */
- "Target device that contains addressed lu",
- "Reserved [0x3]",
-};
-
-const char *
-sg_get_desig_assoc_str(int val)
-{
- if ((val >= 0) && (val < 4))
- return desig_assoc_str_arr[val];
- else
- return NULL;
-}
-
-static const char * desig_type_str_arr[] =
-{
- "vendor specific [0x0]",
- "T10 vendor identification",
- "EUI-64 based",
- "NAA",
- "Relative target port",
- "Target port group", /* spc4r09: _primary_ target port group */
- "Logical unit group",
- "MD5 logical unit identifier",
- "SCSI name string",
- "Protocol specific port identifier", /* spc4r36 */
- "UUID identifier", /* spc5r08 */
- "Reserved [0xb]",
- "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
-};
-
-const char *
-sg_get_desig_type_str(int val)
-{
- if ((val >= 0) && (val < 16))
- return desig_type_str_arr[val];
- else
- return NULL;
-}
-
-int
-sg_get_designation_descriptor_str(const char * lip, const unsigned char * ddp,
- int dd_len, bool print_assoc, bool do_long,
- int blen, char * b)
-{
- int m, p_id, piv, c_set, assoc, desig_type, ci_off, c_id, d_id, naa;
- int vsi, k, n, dlen;
- const unsigned char * ip;
- uint64_t vsei;
- uint64_t id_ext;
- char e[64];
- const char * cp;
-
- n = 0;
- if (NULL == lip)
- lip = "";
- if (dd_len < 4) {
- n += scnpr(b + n, blen - n, "%sdesignator desc too short: got "
- "length of %d want 4 or more\n", lip, dd_len);
- return n;
- }
- dlen = ddp[3];
- if (dlen > (dd_len - 4)) {
- n += scnpr(b + n, blen - n, "%sdesignator too long: says it is %d "
- "bytes, but given %d bytes\n", lip, dlen, dd_len - 4);
- return n;
- }
- ip = ddp + 4;
- p_id = ((ddp[0] >> 4) & 0xf);
- c_set = (ddp[0] & 0xf);
- piv = ((ddp[1] & 0x80) ? 1 : 0);
- assoc = ((ddp[1] >> 4) & 0x3);
- desig_type = (ddp[1] & 0xf);
- if (print_assoc && ((cp = sg_get_desig_assoc_str(assoc))))
- n += scnpr(b + n, blen - n, "%s %s:\n", lip, cp);
- n += scnpr(b + n, blen - n, "%s designator type: ", lip);
- cp = sg_get_desig_type_str(desig_type);
- if (cp)
- n += scnpr(b + n, blen - n, "%s", cp);
- n += scnpr(b + n, blen - n, ", code set: ");
- cp = sg_get_desig_code_set_str(c_set);
- if (cp)
- n += scnpr(b + n, blen - n, "%s", cp);
- n += scnpr(b + n, blen - n, "\n");
- if (piv && ((1 == assoc) || (2 == assoc)))
- n += scnpr(b + n, blen - n, "%s transport: %s\n", lip,
- sg_get_trans_proto_str(p_id, sizeof(e), e));
- /* printf(" associated with the %s\n", sdparm_assoc_arr[assoc]); */
- switch (desig_type) {
- case 0: /* vendor specific */
- k = 0;
- if ((1 == c_set) || (2 == c_set)) { /* ASCII or UTF-8 */
- for (k = 0; (k < dlen) && my_isprint(ip[k]); ++k)
- ;
- if (k >= dlen)
- k = 1;
- }
- if (k)
- n += scnpr(b + n, blen - n, "%s vendor specific: %.*s\n",
- lip, dlen, ip);
- else {
- n += scnpr(b + n, blen - n, "%s vendor specific:\n", lip);
- n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
- }
- break;
- case 1: /* T10 vendor identification */
- n += scnpr(b + n, blen - n, "%s vendor id: %.8s\n", lip, ip);
- if (dlen > 8) {
- if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
- n += scnpr(b + n, blen - n, "%s vendor specific: "
- "%.*s\n", lip, dlen - 8, ip + 8);
- } else {
- n += scnpr(b + n, blen - n, "%s vendor specific: 0x",
- lip);
- for (m = 8; m < dlen; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
- n += scnpr(b + n, blen - n, "\n");
- }
- }
- break;
- case 2: /* EUI-64 based */
- if (! do_long) {
- if ((8 != dlen) && (12 != dlen) && (16 != dlen)) {
- n += scnpr(b + n, blen - n, "%s << expect 8, 12 and 16 "
- "byte EUI, got %d >>\n", lip, dlen);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- n += scnpr(b + n, blen - n, "%s 0x", lip);
- for (m = 0; m < dlen; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
- n += scnpr(b + n, blen - n, "\n");
- break;
- }
- n += scnpr(b + n, blen - n, "%s EUI-64 based %d byte "
- "identifier\n", lip, dlen);
- if (1 != c_set) {
- n += scnpr(b + n, blen - n, "%s << expected binary code_set "
- "(1) >>\n", lip);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- ci_off = 0;
- if (16 == dlen) {
- ci_off = 8;
- id_ext = sg_get_unaligned_be64(ip);
- n += scnpr(b + n, blen - n, "%s Identifier extension: 0x%"
- PRIx64 "\n", lip, id_ext);
- } else if ((8 != dlen) && (12 != dlen)) {
- n += scnpr(b + n, blen - n, "%s << can only decode 8, 12 "
- "and 16 byte ids >>\n", lip);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- c_id = sg_get_unaligned_be24(ip + ci_off);
- n += scnpr(b + n, blen - n, "%s IEEE Company_id: 0x%x\n", lip,
- c_id);
- vsei = 0;
- for (m = 0; m < 5; ++m) {
- if (m > 0)
- vsei <<= 8;
- vsei |= ip[ci_off + 3 + m];
- }
- n += scnpr(b + n, blen - n, "%s Vendor Specific Extension "
- "Identifier: 0x%" PRIx64 "\n", lip, vsei);
- if (12 == dlen) {
- d_id = sg_get_unaligned_be32(ip + 8);
- n += scnpr(b + n, blen - n, "%s Directory ID: 0x%x\n", lip,
- d_id);
- }
- break;
- case 3: /* NAA <n> */
- if (1 != c_set) {
- n += scnpr(b + n, blen - n, "%s << unexpected code set %d "
- "for NAA >>\n", lip, c_set);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- naa = (ip[0] >> 4) & 0xff;
- switch (naa) {
- case 2: /* NAA 2: IEEE Extended */
- if (8 != dlen) {
- n += scnpr(b + n, blen - n, "%s << unexpected NAA 2 "
- "identifier length: 0x%x >>\n", lip, dlen);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- d_id = (((ip[0] & 0xf) << 8) | ip[1]);
- c_id = sg_get_unaligned_be24(ip + 2);
- vsi = sg_get_unaligned_be24(ip + 5);
- if (do_long) {
- n += scnpr(b + n, blen - n, "%s NAA 2, vendor specific "
- "identifier A: 0x%x\n", lip, d_id);
- n += scnpr(b + n, blen - n, "%s IEEE Company_id: 0x%x\n",
- lip, c_id);
- n += scnpr(b + n, blen - n, "%s vendor specific "
- "identifier B: 0x%x\n", lip, vsi);
- n += scnpr(b + n, blen - n, "%s [0x", lip);
- for (m = 0; m < 8; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
- n += scnpr(b + n, blen - n, "]\n");
- }
- n += scnpr(b + n, blen - n, "%s 0x", lip);
- for (m = 0; m < 8; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
- n += scnpr(b + n, blen - n, "\n");
- break;
- case 3: /* NAA 3: Locally assigned */
- if (8 != dlen) {
- n += scnpr(b + n, blen - n, "%s << unexpected NAA 3 "
- "identifier length: 0x%x >>\n", lip, dlen);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- if (do_long)
- n += scnpr(b + n, blen - n, "%s NAA 3, Locally "
- "assigned:\n", lip);
- n += scnpr(b + n, blen - n, "%s 0x", lip);
- for (m = 0; m < 8; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
- n += scnpr(b + n, blen - n, "\n");
- break;
- case 5: /* NAA 5: IEEE Registered */
- if (8 != dlen) {
- n += scnpr(b + n, blen - n, "%s << unexpected NAA 5 "
- "identifier length: 0x%x >>\n", lip, dlen);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
- (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
- vsei = ip[3] & 0xf;
- for (m = 1; m < 5; ++m) {
- vsei <<= 8;
- vsei |= ip[3 + m];
- }
- if (do_long) {
- n += scnpr(b + n, blen - n, "%s NAA 5, IEEE "
- "Company_id: 0x%x\n", lip, c_id);
- n += scnpr(b + n, blen - n, "%s Vendor Specific "
- "Identifier: 0x%" PRIx64 "\n", lip, vsei);
- n += scnpr(b + n, blen - n, "%s [0x", lip);
- for (m = 0; m < 8; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
- n += scnpr(b + n, blen - n, "]\n");
- } else {
- n += scnpr(b + n, blen - n, "%s 0x", lip);
- for (m = 0; m < 8; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
- n += scnpr(b + n, blen - n, "\n");
- }
- break;
- case 6: /* NAA 6: IEEE Registered extended */
- if (16 != dlen) {
- n += scnpr(b + n, blen - n, "%s << unexpected NAA 6 "
- "identifier length: 0x%x >>\n", lip, dlen);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
- (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
- vsei = ip[3] & 0xf;
- for (m = 1; m < 5; ++m) {
- vsei <<= 8;
- vsei |= ip[3 + m];
- }
- if (do_long) {
- n += scnpr(b + n, blen - n, "%s NAA 6, IEEE "
- "Company_id: 0x%x\n", lip, c_id);
- n += scnpr(b + n, blen - n, "%s Vendor Specific "
- "Identifier: 0x%" PRIx64 "\n", lip, vsei);
- vsei = sg_get_unaligned_be64(ip + 8);
- n += scnpr(b + n, blen - n, "%s Vendor Specific "
- "Identifier Extension: 0x%" PRIx64 "\n", lip,
- vsei);
- n += scnpr(b + n, blen - n, "%s [0x", lip);
- for (m = 0; m < 16; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
- n += scnpr(b + n, blen - n, "]\n");
- } else {
- n += scnpr(b + n, blen - n, "%s 0x", lip);
- for (m = 0; m < 16; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]);
- n += scnpr(b + n, blen - n, "\n");
- }
- break;
- default:
- n += scnpr(b + n, blen - n, "%s << unexpected NAA [0x%x] "
- ">>\n", lip, naa);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- break;
- case 4: /* Relative target port */
- if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
- n += scnpr(b + n, blen - n, "%s << expected binary "
- "code_set, target port association, length 4 >>\n",
- lip);
- n += hex2str(ip, dlen, "", 1, blen - n, b + n);
- break;
- }
- d_id = sg_get_unaligned_be16(ip + 2);
- n += scnpr(b + n, blen - n, "%s Relative target port: 0x%x\n",
- lip, d_id);
- break;
- case 5: /* (primary) Target port group */
- if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
- n += scnpr(b + n, blen - n, "%s << expected binary "
- "code_set, target port association, length 4 >>\n",
- lip);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- d_id = sg_get_unaligned_be16(ip + 2);
- n += scnpr(b + n, blen - n, "%s Target port group: 0x%x\n", lip,
- d_id);
- break;
- case 6: /* Logical unit group */
- if ((1 != c_set) || (0 != assoc) || (4 != dlen)) {
- n += scnpr(b + n, blen - n, "%s << expected binary "
- "code_set, logical unit association, length 4 >>\n",
- lip);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- d_id = sg_get_unaligned_be16(ip + 2);
- n += scnpr(b + n, blen - n, "%s Logical unit group: 0x%x\n", lip,
- d_id);
- break;
- case 7: /* MD5 logical unit identifier */
- if ((1 != c_set) || (0 != assoc)) {
- n += scnpr(b + n, blen - n, "%s << expected binary "
- "code_set, logical unit association >>\n", lip);
- n += hex2str(ip, dlen, "", 1, blen - n, b + n);
- break;
- }
- n += scnpr(b + n, blen - n, "%s MD5 logical unit identifier:\n",
- lip);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- case 8: /* SCSI name string */
- if (3 != c_set) { /* accept ASCII as subset of UTF-8 */
- if (2 == c_set) {
- if (do_long)
- n += scnpr(b + n, blen - n, "%s << expected UTF-8, "
- "use ASCII >>\n", lip);
- } else {
- n += scnpr(b + n, blen - n, "%s << expected UTF-8 "
- "code_set >>\n", lip);
- n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
- break;
- }
- }
- n += scnpr(b + n, blen - n, "%s SCSI name string:\n", lip);
- /* does %s print out UTF-8 ok??
- * Seems to depend on the locale. Looks ok here with my
- * locale setting: en_AU.UTF-8
- */
- n += scnpr(b + n, blen - n, "%s %.*s\n", lip, dlen,
- (const char *)ip);
- break;
- case 9: /* Protocol specific port identifier */
- /* added in spc4r36, PIV must be set, proto_id indicates */
- /* whether UAS (USB) or SOP (PCIe) or ... */
- if (! piv)
- n += scnpr(b + n, blen - n, " %s >>>> Protocol specific "
- "port identifier expects protocol\n"
- "%s identifier to be valid and it is not\n",
- lip, lip);
- if (TPROTO_UAS == p_id) {
- n += scnpr(b + n, blen - n, "%s USB device address: 0x%x\n",
- lip, 0x7f & ip[0]);
- n += scnpr(b + n, blen - n, "%s USB interface number: "
- "0x%x\n", lip, ip[2]);
- } else if (TPROTO_SOP == p_id) {
- n += scnpr(b + n, blen - n, "%s PCIe routing ID, bus "
- "number: 0x%x\n", lip, ip[0]);
- n += scnpr(b + n, blen - n, "%s function number: 0x%x\n",
- lip, ip[1]);
- n += scnpr(b + n, blen - n, "%s [or device number: "
- "0x%x, function number: 0x%x]\n", lip,
- (0x1f & (ip[1] >> 3)), 0x7 & ip[1]);
- } else
- n += scnpr(b + n, blen - n, "%s >>>> unexpected protocol "
- "indentifier: %s\n%s with Protocol specific "
- "port identifier\n", lip,
- sg_get_trans_proto_str(p_id, sizeof(e), e), lip);
- break;
- case 0xa: /* UUID identifier */
- if (1 != c_set) {
- n += scnpr(b + n, blen - n, "%s << expected binary "
- "code_set >>\n", lip);
- n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
- break;
- }
- if ((1 != ((ip[0] >> 4) & 0xf)) || (18 != dlen)) {
- n += scnpr(b + n, blen - n, "%s << expected locally "
- "assigned UUID, 16 bytes long >>\n", lip);
- n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
- break;
- }
- n += scnpr(b + n, blen - n, "%s Locally assigned UUID: ", lip);
- for (m = 0; m < 16; ++m) {
- if ((4 == m) || (6 == m) || (8 == m) || (10 == m))
- n += scnpr(b + n, blen - n, "-");
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[2 + m]);
- }
- n += scnpr(b + n, blen - n, "\n");
- if (do_long) {
- n += scnpr(b + n, blen - n, "%s [0x", lip);
- for (m = 0; m < 16; ++m)
- n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[2 + m]);
- n += scnpr(b + n, blen - n, "]\n");
- }
- break;
- default: /* reserved */
- n += scnpr(b + n, blen - n, "%s reserved designator=0x%x\n", lip,
- desig_type);
- n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
- break;
- }
- return n;
-}
-
-static int
-decode_sks(const char * lip, const unsigned char * descp, int add_d_len,
- int sense_key, bool * processedp, int blen, char * b)
-{
- int progress, pr, rem, n;
-
- n = 0;
- if (NULL == lip)
- lip = "";
- switch (sense_key) {
- case SPC_SK_ILLEGAL_REQUEST:
- if (add_d_len < 6) {
- n += scnpr(b + n, blen - n, "Field pointer: ");
- goto too_short;
- }
- /* abbreviate to fit on one line */
- n += scnpr(b + n, blen - n, "Field pointer:\n");
- n += scnpr(b + n, blen - n, "%s Error in %s: byte %d", lip,
- (descp[4] & 0x40) ? "Command" :
- "Data parameters",
- sg_get_unaligned_be16(descp + 5));
- if (descp[4] & 0x08) {
- n += scnpr(b + n, blen - n, " bit %d\n", descp[4] & 0x07);
- } else
- n += scnpr(b + n, blen - n, "\n");
- break;
- case SPC_SK_HARDWARE_ERROR:
- case SPC_SK_MEDIUM_ERROR:
- case SPC_SK_RECOVERED_ERROR:
- n += scnpr(b + n, blen - n, "Actual retry count: ");
- if (add_d_len < 6)
- goto too_short;
- n += scnpr(b + n, blen - n,"%u\n", sg_get_unaligned_be16(descp + 5));
- break;
- case SPC_SK_NO_SENSE:
- case SPC_SK_NOT_READY:
- n += scnpr(b + n, blen - n, "Progress indication: ");
- if (add_d_len < 6)
- goto too_short;
- progress = sg_get_unaligned_be16(descp + 5);
- pr = (progress * 100) / 65536;
- rem = ((progress * 100) % 65536) / 656;
- n += scnpr(b + n, blen - n, "%d.%02d%%\n", pr, rem);
- break;
- case SPC_SK_COPY_ABORTED:
- n += scnpr(b + n, blen - n, "Segment pointer:\n");
- if (add_d_len < 6)
- goto too_short;
- n += scnpr(b + n, blen - n, "%s Relative to start of %s, byte "
- "%d", lip, (descp[4] & 0x20) ? "segment descriptor" :
- "parameter list",
- sg_get_unaligned_be16(descp + 5));
- if (descp[4] & 0x08)
- n += scnpr(b + n, blen - n, " bit %d\n", descp[4] & 0x07);
- else
- n += scnpr(b + n, blen - n, "\n");
- break;
- case SPC_SK_UNIT_ATTENTION:
- n += scnpr(b + n, blen - n, "Unit attention condition queue:\n");
- n += scnpr(b + n, blen - n, "%s overflow flag is %d\n", lip,
- !!(descp[4] & 0x1));
- break;
- default:
- n += scnpr(b + n, blen - n, "Sense_key: 0x%x unexpected\n",
- sense_key);
- *processedp = false;
- break;
- }
- return n;
-
-too_short:
- n += scnpr(b + n, blen - n, "%s\n", " >> descriptor too short");
- *processedp = false;
- return n;
-}
-
-#define TPGS_STATE_OPTIMIZED 0x0
-#define TPGS_STATE_NONOPTIMIZED 0x1
-#define TPGS_STATE_STANDBY 0x2
-#define TPGS_STATE_UNAVAILABLE 0x3
-#define TPGS_STATE_OFFLINE 0xe
-#define TPGS_STATE_TRANSITIONING 0xf
-
-static int
-decode_tpgs_state(int st, char * b, int blen)
-{
- switch (st) {
- case TPGS_STATE_OPTIMIZED:
- return scnpr(b, blen, "active/optimized");
- case TPGS_STATE_NONOPTIMIZED:
- return scnpr(b, blen, "active/non optimized");
- case TPGS_STATE_STANDBY:
- return scnpr(b, blen, "standby");
- case TPGS_STATE_UNAVAILABLE:
- return scnpr(b, blen, "unavailable");
- case TPGS_STATE_OFFLINE:
- return scnpr(b, blen, "offline");
- case TPGS_STATE_TRANSITIONING:
- return scnpr(b, blen, "transitioning between states");
- default:
- return scnpr(b, blen, "unknown: 0x%x", st);
- }
-}
-
-static int
-uds_referral_descriptor_str(char * b, int blen, const unsigned char * dp,
- int alen, const char * lip)
-{
- int n = 0;
- int dlen = alen - 2;
- int k, j, g, f, tpgd;
- const unsigned char * tp;
- uint64_t ull;
- char c[40];
-
- if (NULL == lip)
- lip = "";
- n += scnpr(b + n, blen - n, "%s Not all referrals: %d\n", lip,
- !!(dp[2] & 0x1));
- dp += 4;
- for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) {
- tpgd = dp[3];
- g = (tpgd * 4) + 20;
- n += scnpr(b + n, blen - n, "%s Descriptor %d\n", lip, f);
- if ((k + g) > dlen) {
- n += scnpr(b + n, blen - n, "%s truncated descriptor, "
- "stop\n", lip);
- return n;
- }
- ull = sg_get_unaligned_be64(dp + 4);
- n += scnpr(b + n, blen - n, "%s first uds LBA: 0x%" PRIx64 "\n",
- lip, ull);
- ull = sg_get_unaligned_be64(dp + 12);
- n += scnpr(b + n, blen - n, "%s last uds LBA: 0x%" PRIx64 "\n",
- lip, ull);
- for (j = 0; j < tpgd; ++j) {
- tp = dp + 20 + (j * 4);
- decode_tpgs_state(tp[0] & 0xf, c, sizeof(c));
- n += scnpr(b + n, blen - n, "%s tpg: %d state: %s\n",
- lip, sg_get_unaligned_be16(tp + 2), c);
- }
- }
- return n;
-}
-
-static const char * dd_usage_reason_str_arr[] = {
- "Unknown",
- "resend this and further commands to:",
- "resend this command to:",
- "new subsiduary lu added to this administrative lu:",
- "administrative lu associated with a preferred binding:",
- };
-
-
-/* Decode descriptor format sense descriptors (assumes sense buffer is
- * in descriptor format) */
-int
-sg_get_sense_descriptors_str(const char * lip, const unsigned char * sbp,
- int sb_len, int blen, char * b)
-{
- int add_sb_len, add_d_len, desc_len, k, j, sense_key;
- int n, progress, pr, rem;
- bool processed;
- const unsigned char * descp;
- const char * dtsp = " >> descriptor too short";
- const char * eccp = "Extended copy command";
- const char * ddp = "destination device";
- char z[64];
-
- if ((NULL == b) || (blen <= 0))
- return 0;
- b[0] = '\0';
- if (lip)
- scnpr(z, sizeof(z), "%.60s ", lip);
- else
- scnpr(z, sizeof(z), " ");
- if ((sb_len < 8) || (0 == (add_sb_len = sbp[7])))
- return 0;
- add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8);
- sense_key = (sbp[1] & 0xf);
-
- for (descp = (sbp + 8), k = 0, n = 0;
- (k < add_sb_len) && (n < blen);
- k += desc_len, descp += desc_len) {
- add_d_len = (k < (add_sb_len - 1)) ? descp[1] : -1;
- if ((k + add_d_len + 2) > add_sb_len)
- add_d_len = add_sb_len - k - 2;
- desc_len = add_d_len + 2;
- n += scnpr(b + n, blen - n, "%s Descriptor type: ", lip);
- processed = true;
- switch (descp[0]) {
- case 0:
- n += scnpr(b + n, blen - n, "Information: ");
- if ((add_d_len >= 10) && (0x80 & descp[2])) {
- n += scnpr(b + n, blen - n, "0x");
- for (j = 0; j < 8; ++j)
- n += scnpr(b + n, blen - n, "%02x", descp[4 + j]);
- n += scnpr(b + n, blen - n, "\n");
- } else {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- }
- break;
- case 1:
- n += scnpr(b + n, blen - n, "Command specific: ");
- if (add_d_len >= 10) {
- n += scnpr(b + n, blen - n, "0x");
- for (j = 0; j < 8; ++j)
- n += scnpr(b + n, blen - n, "%02x", descp[4 + j]);
- n += scnpr(b + n, blen - n, "\n");
- } else {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- }
- break;
- case 2: /* Sense Key Specific */
- n += scnpr(b + n, blen - n, "Sense key specific: ");
- n += decode_sks(lip, descp, add_d_len, sense_key, &processed,
- blen - n, b + n);
- break;
- case 3:
- n += scnpr(b + n, blen - n, "Field replaceable unit code: ");
- if (add_d_len >= 2)
- n += scnpr(b + n, blen - n, "0x%x\n", descp[3]);
- else {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- }
- break;
- case 4:
- n += scnpr(b + n, blen - n, "Stream commands: ");
- if (add_d_len >= 2) {
- if (descp[3] & 0x80)
- n += scnpr(b + n, blen - n, "FILEMARK");
- if (descp[3] & 0x40)
- n += scnpr(b + n, blen - n, "End Of Medium (EOM)");
- if (descp[3] & 0x20)
- n += scnpr(b + n, blen - n, "Incorrect Length Indicator "
- "(ILI)");
- n += scnpr(b + n, blen - n, "\n");
- } else {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- }
- break;
- case 5:
- n += scnpr(b + n, blen - n, "Block commands: ");
- if (add_d_len >= 2)
- n += scnpr(b + n, blen - n, "Incorrect Length Indicator "
- "(ILI) %s\n", (descp[3] & 0x20) ? "set" : "clear");
- else {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- }
- break;
- case 6:
- n += scnpr(b + n, blen - n, "OSD object identification\n");
- processed = false;
- break;
- case 7:
- n += scnpr(b + n, blen - n, "OSD response integrity check "
- "value\n");
- processed = false;
- break;
- case 8:
- n += scnpr(b + n, blen - n, "OSD attribute identification\n");
- processed = false;
- break;
- case 9: /* this is defined in SAT (SAT-2) */
- n += scnpr(b + n, blen - n, "ATA Status Return: ");
- if (add_d_len >= 12) {
- int extend, count;
-
- extend = descp[2] & 1;
- count = descp[5] + (extend ? (descp[4] << 8) : 0);
- n += scnpr(b + n, blen - n, "extend=%d error=0x%x \n%s"
- " count=0x%x ", extend, descp[3], lip,
- count);
- if (extend)
- n += scnpr(b + n, blen - n,
- "lba=0x%02x%02x%02x%02x%02x%02x ",
- descp[10], descp[8], descp[6], descp[11],
- descp[9], descp[7]);
- else
- n += scnpr(b + n, blen - n, "lba=0x%02x%02x%02x ",
- descp[11], descp[9], descp[7]);
- n += scnpr(b + n, blen - n, "device=0x%x status=0x%x\n",
- descp[12], descp[13]);
- } else {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- }
- break;
- case 0xa:
- /* Added in SPC-4 rev 17, became 'Another ...' in rev 34 */
- n += scnpr(b + n, blen - n, "Another progress indication: ");
- if (add_d_len < 6) {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- break;
- }
- progress = sg_get_unaligned_be16(descp + 6);
- pr = (progress * 100) / 65536;
- rem = ((progress * 100) % 65536) / 656;
- n += scnpr(b + n, blen - n, "%d.02%d%%\n", pr, rem);
- n += scnpr(b + n, blen - n, "%s [sense_key=0x%x "
- "asc,ascq=0x%x,0x%x]\n", lip, descp[2], descp[3],
- descp[4]);
- break;
- case 0xb: /* Added in SPC-4 rev 23, defined in SBC-3 rev 22 */
- n += scnpr(b + n, blen - n, "User data segment referral: ");
- if (add_d_len < 2) {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- break;
- }
- n += scnpr(b + n, blen - n, "\n");
- n += uds_referral_descriptor_str(b + n, blen - n, descp,
- add_d_len, lip);
- break;
- case 0xc: /* Added in SPC-4 rev 28 */
- n += scnpr(b + n, blen - n, "Forwarded sense data\n");
- if (add_d_len < 2) {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- break;
- }
- n += scnpr(b + n, blen - n, "%s FSDT: %s\n", lip,
- (descp[2] & 0x80) ? "set" : "clear");
- j = descp[2] & 0xf;
- n += scnpr(b + n, blen - n, "%s Sense data source: ", lip);
- switch (j) {
- case 0:
- n += scnpr(b + n, blen - n, "%s source device\n", eccp);
- break;
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- n += scnpr(b + n, blen - n, "%s %s %d\n", eccp, ddp, j - 1);
- break;
- default:
- n += scnpr(b + n, blen - n, "unknown [%d]\n", j);
- }
- {
- char c[480];
-
- sg_get_scsi_status_str(descp[3], sizeof(c) - 1, c);
- c[sizeof(c) - 1] = '\0';
- n += scnpr(b + n, blen - n, "%s Forwarded status: %s\n",
- lip, c);
- if (add_d_len > 2) {
- /* recursing; hope not to get carried away */
- n += scnpr(b + n, blen - n, "%s vvvvvvvvvvvvvvvv\n", lip);
- sg_get_sense_str(lip, descp + 4, add_d_len - 2, false,
- sizeof(c), c);
- n += scnpr(b + n, blen - n, "%s", c);
- n += scnpr(b + n, blen - n, "%s ^^^^^^^^^^^^^^^^\n", lip);
- }
- }
- break;
- case 0xd: /* Added in SBC-3 rev 36d */
- /* this descriptor combines descriptors 0, 1, 2 and 3 */
- n += scnpr(b + n, blen - n, "Direct-access block device\n");
- if (add_d_len < 28) {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- break;
- }
- if (0x20 & descp[2])
- n += scnpr(b + n, blen - n, "%s ILI (incorrect length "
- "indication) set\n", lip);
- if (0x80 & descp[4]) {
- n += scnpr(b + n, blen - n, "%s Sense key specific: ",
- lip);
- n += decode_sks(lip, descp, add_d_len, sense_key, &processed,
- blen - n, b + n);
- }
- n += scnpr(b + n, blen - n, "%s Field replaceable unit code: "
- "0x%x\n", lip, descp[7]);
- if (0x80 & descp[2]) {
- n += scnpr(b + n, blen - n, "%s Information: 0x", lip);
- for (j = 0; j < 8; ++j)
- n += scnpr(b + n, blen - n, "%02x", descp[8 + j]);
- n += scnpr(b + n, blen - n, "\n");
- }
- n += scnpr(b + n, blen - n, "%s Command specific: 0x", lip);
- for (j = 0; j < 8; ++j)
- n += scnpr(b + n, blen - n, "%02x", descp[16 + j]);
- n += scnpr(b + n, blen - n, "\n");
- break;
- case 0xe: /* Added in SPC-5 rev 6 (for Bind/Unbind) */
- n += scnpr(b + n, blen - n, "Device designation\n");
- j = (int)(sizeof(dd_usage_reason_str_arr) /
- sizeof(dd_usage_reason_str_arr[0]));
- if (descp[3] < j)
- n += scnpr(b + n, blen - n, "%s Usage reason: %s\n", lip,
- dd_usage_reason_str_arr[descp[3]]);
- else
- n += scnpr(b + n, blen - n, "%s Usage reason: "
- "reserved[%d]\n", lip, descp[3]);
- n += sg_get_designation_descriptor_str(z, descp + 4, descp[1] - 2,
- true, false, blen - n,
- b + n);
- break;
- case 0xf: /* Added in SPC-5 rev 10 (for Write buffer) */
- n += scnpr(b + n, blen - n, "Microcode activation ");
- if (add_d_len < 6) {
- n += scnpr(b + n, blen - n, "%s\n", dtsp);
- processed = false;
- break;
- }
- progress = sg_get_unaligned_be16(descp + 6);
- n += scnpr(b + n, blen - n, "time: ");
- if (0 == progress)
- n += scnpr(b + n, blen - n, "unknown\n");
- else
- n += scnpr(b + n, blen - n, "%d seconds\n", progress);
- break;
- default:
- if (descp[0] >= 0x80)
- n += scnpr(b + n, blen - n, "Vendor specific [0x%x]\n",
- descp[0]);
- else
- n += scnpr(b + n, blen - n, "Unknown [0x%x]\n", descp[0]);
- processed = false;
- break;
- }
- if (! processed) {
- if (add_d_len > 0) {
- n += scnpr(b + n, blen - n, "%s ", lip);
- for (j = 0; j < add_d_len; ++j) {
- if ((j > 0) && (0 == (j % 24)))
- n += scnpr(b + n, blen - n, "\n%s ", lip);
- n += scnpr(b + n, blen - n, "%02x ", descp[j + 2]);
- }
- n += scnpr(b + n, blen - n, "\n");
- }
- }
- if (add_d_len < 0)
- n += scnpr(b + n, blen - n, "%s short descriptor\n", lip);
- }
- return n;
-}
-
-/* Decode SAT ATA PASS-THROUGH fixed format sense. Shows "+" after 'count'
- * and/or 'lba' values to indicate that not all data in those fields is shown.
- * That extra field information may be available in the ATA pass-through
- * results log page parameter with the corresponding 'log_index'. */
-static int
-sg_get_sense_sat_pt_fixed_str(const char * lip, const unsigned char * sp,
- int slen, int blen, char * b)
-{
- int n = 0;
- bool extend, count_upper_nz, lba_upper_nz;
-
- if ((blen < 1) || (slen < 12))
- return n;
- if (NULL == lip)
- lip = "";
- if (SPC_SK_RECOVERED_ERROR != (0xf & sp[2]))
- n += scnpr(b + n, blen - n, "%s >> expected Sense key: Recovered "
- "Error ??\n", lip);
- /* Fixed sense command-specific information field starts at sp + 8 */
- extend = !!(0x80 & sp[8]);
- count_upper_nz = !!(0x40 & sp[8]);
- lba_upper_nz = !!(0x20 & sp[8]);
- /* Fixed sense information field starts at sp + 3 */
- n += scnpr(b + n, blen - n, "%s error=0x%x, status=0x%x, device=0x%x, "
- "count(7:0)=0x%x%c\n", lip, sp[3], sp[4], sp[5], sp[6],
- (count_upper_nz ? '+' : ' '));
- n += scnpr(b + n, blen - n, "%s extend=%d, log_index=0x%x, "
- "lba_high,mid,low(7:0)=0x%x,0x%x,0x%x%c\n", lip, (int)extend,
- (0xf & sp[8]), sp[9], sp[10], sp[11],
- (lba_upper_nz ? '+' : ' '));
- return n;
-}
-
-/* Fetch sense information */
-int
-sg_get_sense_str(const char * lip, const unsigned char * sbp, int sb_len,
- bool raw_sinfo, int cblen, char * cbp)
-{
- bool descriptor_format = false;
- bool sdat_ovfl = false;
- bool valid;
- int len, progress, n, r, pr, rem, blen;
- unsigned int info;
- uint8_t resp_code;
- const char * ebp = NULL;
- char ebuff[64];
- char b[256];
- struct sg_scsi_sense_hdr ssh;
-
- if ((NULL == cbp) || (cblen <= 0))
- return 0;
- else if (1 == cblen) {
- cbp[0] = '\0';
- return 0;
- }
- blen = sizeof(b);
- n = 0;
- if (NULL == lip)
- lip = "";
- if ((NULL == sbp) || (sb_len < 1)) {
- n += scnpr(cbp, cblen, "%s >>> sense buffer empty\n", lip);
- return n;
- }
- resp_code = 0x7f & sbp[0];
- valid = !!(sbp[0] & 0x80);
- len = sb_len;
- if (sg_scsi_normalize_sense(sbp, sb_len, &ssh)) {
- switch (ssh.response_code) {
- case 0x70: /* fixed, current */
- ebp = "Fixed format, current";
- len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
- len = (len > sb_len) ? sb_len : len;
- sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
- break;
- case 0x71: /* fixed, deferred */
- /* error related to a previous command */
- ebp = "Fixed format, <<<deferred>>>";
- len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
- len = (len > sb_len) ? sb_len : len;
- sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
- break;
- case 0x72: /* descriptor, current */
- descriptor_format = true;
- ebp = "Descriptor format, current";
- sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
- break;
- case 0x73: /* descriptor, deferred */
- descriptor_format = true;
- ebp = "Descriptor format, <<<deferred>>>";
- sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
- break;
- case 0x0:
- ebp = "Response code: 0x0 (?)";
- break;
- default:
- scnpr(ebuff, sizeof(ebuff), "Unknown response code: 0x%x",
- ssh.response_code);
- ebp = ebuff;
- break;
- }
- n += scnpr(cbp + n, cblen - n, "%s%s; Sense key: %s\n", lip, ebp,
- sg_lib_sense_key_desc[ssh.sense_key]);
- if (sdat_ovfl)
- n += scnpr(cbp + n, cblen - n, "%s<<<Sense data overflow>>>\n",
- lip);
- if (descriptor_format) {
- n += scnpr(cbp + n, cblen - n, "%s%s\n", lip,
- sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
- n += sg_get_sense_descriptors_str(lip, sbp, len,
- cblen - n, cbp + n);
- } else if ((len > 12) && (0 == ssh.asc) &&
- (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) {
- /* SAT ATA PASS-THROUGH fixed format */
- n += scnpr(cbp + n, cblen - n, "%s%s\n", lip,
- sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
- n += sg_get_sense_sat_pt_fixed_str(lip, sbp, len,
- cblen - n, cbp + n);
- } else if (len > 2) { /* fixed format */
- if (len > 12)
- n += scnpr(cbp + n, cblen - n, "%s%s\n", lip,
- sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
- r = 0;
- if (strlen(lip) > 0)
- r += scnpr(b + r, blen - r, "%s", lip);
- if (len > 6) {
- info = sg_get_unaligned_be32(sbp + 3);
- if (valid)
- r += scnpr(b + r, blen - r, " Info fld=0x%x [%u] ",
- info, info);
- else if (info > 0)
- r += scnpr(b + r, blen - r, " Valid=0, Info fld=0x%x "
- "[%u] ", info, info);
- } else
- info = 0;
- if (sbp[2] & 0xe0) {
- if (sbp[2] & 0x80)
- r += scnpr(b + r, blen - r, " FMK");
- /* current command has read a filemark */
- if (sbp[2] & 0x40)
- r += scnpr(b + r, blen - r, " EOM");
- /* end-of-medium condition exists */
- if (sbp[2] & 0x20)
- r += scnpr(b + r, blen - r, " ILI");
- /* incorrect block length requested */
- r += scnpr(b + r, blen - r, "\n");
- } else if (valid || (info > 0))
- r += scnpr(b + r, blen - r, "\n");
- if ((len >= 14) && sbp[14])
- r += scnpr(b + r, blen - r, "%s Field replaceable unit "
- "code: %d\n", lip, sbp[14]);
- if ((len >= 18) && (sbp[15] & 0x80)) {
- /* sense key specific decoding */
- switch (ssh.sense_key) {
- case SPC_SK_ILLEGAL_REQUEST:
- r += scnpr(b + r, blen - r, "%s Sense Key Specific: "
- "Error in %s: byte %d", lip,
- ((sbp[15] & 0x40) ? "Command" :
- "Data parameters"),
- sg_get_unaligned_be16(sbp + 16));
- if (sbp[15] & 0x08)
- r += scnpr(b + r, blen - r, " bit %d\n",
- sbp[15] & 0x07);
- else
- r += scnpr(b + r, blen - r, "\n");
- break;
- case SPC_SK_NO_SENSE:
- case SPC_SK_NOT_READY:
- progress = sg_get_unaligned_be16(sbp + 16);
- pr = (progress * 100) / 65536;
- rem = ((progress * 100) % 65536) / 656;
- r += scnpr(b + r, blen - r, "%s Progress indication: "
- "%d.%02d%%\n", lip, pr, rem);
- break;
- case SPC_SK_HARDWARE_ERROR:
- case SPC_SK_MEDIUM_ERROR:
- case SPC_SK_RECOVERED_ERROR:
- r += scnpr(b + r, blen - r, "%s Actual retry count: "
- "0x%02x%02x\n", lip, sbp[16], sbp[17]);
- break;
- case SPC_SK_COPY_ABORTED:
- r += scnpr(b + r, blen - r, "%s Segment pointer: ", lip);
- r += scnpr(b + r, blen - r, "Relative to start of %s, "
- "byte %d", ((sbp[15] & 0x20) ?
- "segment descriptor" : "parameter list"),
- sg_get_unaligned_be16(sbp + 16));
- if (sbp[15] & 0x08)
- r += scnpr(b + r, blen - r, " bit %d\n",
- sbp[15] & 0x07);
- else
- r += scnpr(b + r, blen - r, "\n");
- break;
- case SPC_SK_UNIT_ATTENTION:
- r += scnpr(b + r, blen - r, "%s Unit attention "
- "condition queue: ", lip);
- r += scnpr(b + r, blen - r, "overflow flag is %d\n",
- !!(sbp[15] & 0x1));
- break;
- default:
- r += scnpr(b + r, blen - r, "%s Sense_key: 0x%x "
- "unexpected\n", lip, ssh.sense_key);
- break;
- }
- }
- if (r > 0)
- n += scnpr(cbp + n, cblen - n, "%s", b);
- } else
- n += scnpr(cbp + n, cblen - n, "%s fixed descriptor length "
- "too short, len=%d\n", lip, len);
- } else { /* unable to normalise sense buffer, something irregular */
- if (sb_len < 4) { /* Too short */
- n += scnpr(cbp + n, cblen - n, "%ssense buffer too short (4 "
- "byte minimum)\n", lip);
- goto check_raw;
- }
- if (0x7f == resp_code) { /* Vendor specific */
- n += scnpr(cbp + n, cblen - n, "%sVendor specific sense buffer, "
- "in hex:\n", lip);
- n += hex2str(sbp, sb_len, lip, -1, cblen - n, cbp + n);
- return n; /* no need to check raw, just output in hex */
- }
- /* non-extended SCSI-1 sense data ?? */
- r = 0;
- if (strlen(lip) > 0)
- r += scnpr(b + r, blen - r, "%s", lip);
- r += scnpr(b + r, blen - r, "Probably uninitialized data.\n%s Try "
- "to view as SCSI-1 non-extended sense:\n", lip);
- r += scnpr(b + r, blen - r, " AdValid=%d Error class=%d Error "
- "code=%d\n", valid, ((sbp[0] >> 4) & 0x7),
- (sbp[0] & 0xf));
- if (valid)
- scnpr(b + r, blen - r, "%s lba=0x%x\n", lip,
- sg_get_unaligned_be24(sbp + 1) & 0x1fffff);
- n += scnpr(cbp + n, cblen - n, "%s\n", b);
- len = sb_len;
- if (len > 32)
- len = 32; /* trim in case there is a lot of rubbish */
- }
-check_raw:
- if (raw_sinfo) {
- char z[64];
-
- n += scnpr(cbp + n, cblen - n, "%s Raw sense data (in hex):\n",
- lip);
- if (n >= (cblen - 1))
- return n;
- scnpr(z, sizeof(z), "%.50s ", lip);
- n += hex2str(sbp, len, z, -1, cblen - n, cbp + n);
- }
- return n;
-}
-
-/* Print sense information */
-void
-sg_print_sense(const char * leadin, const unsigned char * sbp, int sb_len,
- bool raw_sinfo)
-{
- uint32_t pg_sz = sg_get_page_size();
- char *cp;
- uint8_t *free_cp;
-
- cp = (char *)sg_memalign(pg_sz, pg_sz, &free_cp, 0);
- if (NULL == cp)
- return;
- sg_get_sense_str(leadin, sbp, sb_len, raw_sinfo, pg_sz, cp);
- pr2ws("%s", cp);
- free(free_cp);
-}
-
-/* Following examines exit_status and outputs a clear error message to
- * warnings_strm (usually stderr) if one is known and returns true.
- * Otherwise it doesn't print anything and returns false. Note that
- * if exit_status==0 then returns true but prints nothing and if
- * exit_status<0 ("some error occurred") false is returned. If leadin is
- * non-NULL then it is printed before the error message. */
-bool
-sg_if_can2stderr(const char * leadin, int exit_status)
-{
- const char * s = leadin ? leadin : "";
-
- if (exit_status < 0)
- return false;
- else if (0 == exit_status)
- return true;
-
- switch (exit_status) {
- case SG_LIB_CAT_NOT_READY: /* 2 */
- pr2ws("%sDevice not ready\n", s);
- return true;
- case SG_LIB_CAT_MEDIUM_HARD: /* 3 */
- pr2ws("%sMedium or hardware error\n", s); /* 3 sense keys: Medium, */
- return true; /* hardware error or 'Blank check' for tapes */
- case SG_LIB_CAT_UNIT_ATTENTION: /* 6 */
- pr2ws("%sDevice reported 'Unit attention'\n", s);
- return true;
- case SG_LIB_CAT_DATA_PROTECT: /* 7 */
- pr2ws("%sDevice reported 'Data protect', read-only?\n", s);
- return true;
- case SG_LIB_CAT_COPY_ABORTED: /* 10 */
- pr2ws("%sCopy aborted\n", s);
- return true;
- case SG_LIB_CAT_ABORTED_COMMAND: /* 11 */
- pr2ws("%sCommand aborted\n", s);
- return true;
- case SG_LIB_CAT_MISCOMPARE: /* 14 */
- pr2ws("%sMiscompare\n", s);
- return true;
- case SG_LIB_CAT_RES_CONFLICT: /* 24 */
- pr2ws("%sReservation conflict\n", s);
- return true;
- case SG_LIB_CAT_BUSY: /* 26 */
- pr2ws("%sDevice is busy, try again\n", s);
- return true;
- case SG_LIB_CAT_TASK_ABORTED: /* 29 */
- pr2ws("%sTask aborted\n", s);
- return true;
- case SG_LIB_CAT_TIMEOUT: /* 33 */
- pr2ws("%sTime out\n", s);
- return true;
- case SG_LIB_CAT_PROTECTION: /* 40 */
- pr2ws("%sProtection error\n", s);
- return true;
- case SG_LIB_NVME_STATUS: /* 48 */
- pr2ws("%sNVMe error (non-zero status)\n", s);
- return true;
- case SG_LIB_OS_BASE_ERR + EACCES: /* 50 + */
- pr2ws("%sPermission denied\n", s);
- return true;
- case SG_LIB_OS_BASE_ERR + ENOMEM:
- pr2ws("%sUtility unable to allocate memory\n", s);
- return true;
- case SG_LIB_OS_BASE_ERR + ENOTTY:
- pr2ws("%sInappropriate I/O control operation\n", s);
- return true;
- case SG_LIB_OS_BASE_ERR + EPERM:
- pr2ws("%sNot permitted\n", s);
- return true;
- case SG_LIB_OS_BASE_ERR + EINTR:
- pr2ws("%sInterrupted system call\n", s);
- return true;
- case SG_LIB_OS_BASE_ERR + EIO:
- pr2ws("%sInput/output error\n", s);
- return true;
- case SG_LIB_OS_BASE_ERR + ENODEV:
- pr2ws("%sNo such device\n", s);
- return true;
- case SG_LIB_OS_BASE_ERR + ENOENT:
- pr2ws("%sNo such file or directory\n", s);
- return true;
- default:
- return false;
- }
- return false;
-}
-
-/* If os_err_num is within bounds then the returned value is 'os_err_num +
- * SG_LIB_OS_BASE_ERR' otherwise -1 is returned. If os_err_num is 0 then 0
- * is returned. */
-int
-sg_convert_errno(int os_err_num)
-{
- if (os_err_num <= 0) {
- if (os_err_num < -1)
- return -1;
- return os_err_num;
- }
- if (os_err_num < (SG_LIB_CAT_MALFORMED - SG_LIB_OS_BASE_ERR))
- return SG_LIB_OS_BASE_ERR + os_err_num;
- return -1;
-}
-
-/* See description in sg_lib.h header file */
-bool
-sg_scsi_normalize_sense(const unsigned char * sbp, int sb_len,
- struct sg_scsi_sense_hdr * sshp)
-{
- uint8_t resp_code;
- if (sshp)
- memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
- if ((NULL == sbp) || (sb_len < 1))
- return false;
- resp_code = 0x7f & sbp[0];
- if ((resp_code < 0x70) || (resp_code > 0x73))
- return false;
- if (sshp) {
- sshp->response_code = resp_code;
- if (sshp->response_code >= 0x72) { /* descriptor format */
- if (sb_len > 1)
- sshp->sense_key = (0xf & sbp[1]);
- if (sb_len > 2)
- sshp->asc = sbp[2];
- if (sb_len > 3)
- sshp->ascq = sbp[3];
- if (sb_len > 7)
- sshp->additional_length = sbp[7];
- } else { /* fixed format */
- if (sb_len > 2)
- sshp->sense_key = (0xf & sbp[2]);
- if (sb_len > 7) {
- sb_len = (sb_len < (sbp[7] + 8)) ? sb_len : (sbp[7] + 8);
- if (sb_len > 12)
- sshp->asc = sbp[12];
- if (sb_len > 13)
- sshp->ascq = sbp[13];
- }
- }
- }
- return true;
-}
-
-/* Returns a SG_LIB_CAT_* value. If cannot decode sense buffer (sbp) or a
- * less common sense key then return SG_LIB_CAT_SENSE .*/
-int
-sg_err_category_sense(const unsigned char * sbp, int sb_len)
-{
- struct sg_scsi_sense_hdr ssh;
-
- if ((sbp && (sb_len > 2)) &&
- (sg_scsi_normalize_sense(sbp, sb_len, &ssh))) {
- switch (ssh.sense_key) { /* 0 to 0x1f */
- case SPC_SK_NO_SENSE:
- return SG_LIB_CAT_NO_SENSE;
- case SPC_SK_RECOVERED_ERROR:
- return SG_LIB_CAT_RECOVERED;
- case SPC_SK_NOT_READY:
- return SG_LIB_CAT_NOT_READY;
- case SPC_SK_MEDIUM_ERROR:
- case SPC_SK_HARDWARE_ERROR:
- case SPC_SK_BLANK_CHECK:
- return SG_LIB_CAT_MEDIUM_HARD;
- case SPC_SK_UNIT_ATTENTION:
- return SG_LIB_CAT_UNIT_ATTENTION;
- /* used to return SG_LIB_CAT_MEDIA_CHANGED when ssh.asc==0x28 */
- case SPC_SK_ILLEGAL_REQUEST:
- if ((0x20 == ssh.asc) && (0x0 == ssh.ascq))
- return SG_LIB_CAT_INVALID_OP;
- else
- return SG_LIB_CAT_ILLEGAL_REQ;
- break;
- case SPC_SK_ABORTED_COMMAND:
- if (0x10 == ssh.asc)
- return SG_LIB_CAT_PROTECTION;
- else
- return SG_LIB_CAT_ABORTED_COMMAND;
- case SPC_SK_MISCOMPARE:
- return SG_LIB_CAT_MISCOMPARE;
- case SPC_SK_DATA_PROTECT:
- return SG_LIB_CAT_DATA_PROTECT;
- case SPC_SK_COPY_ABORTED:
- return SG_LIB_CAT_COPY_ABORTED;
- case SPC_SK_COMPLETED:
- case SPC_SK_VOLUME_OVERFLOW:
- return SG_LIB_CAT_SENSE;
- default:
- ; /* reserved and vendor specific sense keys fall through */
- }
- }
- return SG_LIB_CAT_SENSE;
-}
-
-/* Beware: gives wrong answer for variable length command (opcode=0x7f) */
-int
-sg_get_command_size(unsigned char opcode)
-{
- switch ((opcode >> 5) & 0x7) {
- case 0:
- return 6;
- case 1: case 2: case 6: case 7:
- return 10;
- case 3: case 5:
- return 12;
- break;
- case 4:
- return 16;
- default:
- return 10;
- }
-}
-
-void
-sg_get_command_name(const unsigned char * cmdp, int peri_type, int buff_len,
- char * buff)
-{
- int service_action;
-
- if ((NULL == buff) || (buff_len < 1))
- return;
- else if (1 == buff_len) {
- buff[0] = '\0';
- return;
- }
- if (NULL == cmdp) {
- scnpr(buff, buff_len, "%s", "<null> command pointer");
- return;
- }
- service_action = (SG_VARIABLE_LENGTH_CMD == cmdp[0]) ?
- sg_get_unaligned_be16(cmdp + 8) : (cmdp[1] & 0x1f);
- sg_get_opcode_sa_name(cmdp[0], service_action, peri_type, buff_len, buff);
-}
-
-struct op_code2sa_t {
- int op_code;
- int pdt_match; /* -1->all; 0->disk,ZBC,RCB, 1->tape+adc+smc */
- struct sg_lib_value_name_t * arr;
- const char * prefix;
-};
-
-static struct op_code2sa_t op_code2sa_arr[] = {
- {SG_VARIABLE_LENGTH_CMD, -1, sg_lib_variable_length_arr, NULL},
- {SG_MAINTENANCE_IN, -1, sg_lib_maint_in_arr, NULL},
- {SG_MAINTENANCE_OUT, -1, sg_lib_maint_out_arr, NULL},
- {SG_SERVICE_ACTION_IN_12, -1, sg_lib_serv_in12_arr, NULL},
- {SG_SERVICE_ACTION_OUT_12, -1, sg_lib_serv_out12_arr, NULL},
- {SG_SERVICE_ACTION_IN_16, -1, sg_lib_serv_in16_arr, NULL},
- {SG_SERVICE_ACTION_OUT_16, -1, sg_lib_serv_out16_arr, NULL},
- {SG_SERVICE_ACTION_BIDI, -1, sg_lib_serv_bidi_arr, NULL},
- {SG_PERSISTENT_RESERVE_IN, -1, sg_lib_pr_in_arr, "Persistent reserve in"},
- {SG_PERSISTENT_RESERVE_OUT, -1, sg_lib_pr_out_arr,
- "Persistent reserve out"},
- {SG_3PARTY_COPY_OUT, -1, sg_lib_xcopy_sa_arr, NULL},
- {SG_3PARTY_COPY_IN, -1, sg_lib_rec_copy_sa_arr, NULL},
- {SG_READ_BUFFER, -1, sg_lib_read_buff_arr, "Read buffer(10)"},
- {SG_READ_BUFFER_16, -1, sg_lib_read_buff_arr, "Read buffer(16)"},
- {SG_READ_ATTRIBUTE, -1, sg_lib_read_attr_arr, "Read attribute"},
- {SG_READ_POSITION, 1, sg_lib_read_pos_arr, "Read position"},
- {SG_SANITIZE, 0, sg_lib_sanitize_sa_arr, "Sanitize"},
- {SG_WRITE_BUFFER, -1, sg_lib_write_buff_arr, "Write buffer"},
- {SG_ZONING_IN, 0, sg_lib_zoning_in_arr, NULL},
- {SG_ZONING_OUT, 0, sg_lib_zoning_out_arr, NULL},
- {0xffff, -1, NULL, NULL},
-};
-
-void
-sg_get_opcode_sa_name(unsigned char cmd_byte0, int service_action,
- int peri_type, int buff_len, char * buff)
-{
- int d_pdt;
- const struct sg_lib_value_name_t * vnp;
- const struct op_code2sa_t * osp;
- char b[80];
-
- if ((NULL == buff) || (buff_len < 1))
- return;
- else if (1 == buff_len) {
- buff[0] = '\0';
- return;
- }
-
- if (peri_type < 0)
- peri_type = 0;
- d_pdt = sg_lib_pdt_decay(peri_type);
- for (osp = op_code2sa_arr; osp->arr; ++osp) {
- if ((int)cmd_byte0 == osp->op_code) {
- if ((osp->pdt_match < 0) || (d_pdt == osp->pdt_match)) {
- vnp = get_value_name(osp->arr, service_action, peri_type);
- if (vnp) {
- if (osp->prefix)
- scnpr(buff, buff_len, "%s, %s", osp->prefix,
- vnp->name);
- else
- scnpr(buff, buff_len, "%s", vnp->name);
- } else {
- sg_get_opcode_name(cmd_byte0, peri_type, sizeof(b), b);
- scnpr(buff, buff_len, "%s service action=0x%x", b,
- service_action);
- }
- } else
- sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff);
- return;
- }
- }
- sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff);
-}
-
-void
-sg_get_opcode_name(unsigned char cmd_byte0, int peri_type, int buff_len,
- char * buff)
-{
- const struct sg_lib_value_name_t * vnp;
- int grp;
-
- if ((NULL == buff) || (buff_len < 1))
- return;
- else if (1 == buff_len) {
- buff[0] = '\0';
- return;
- }
- if (SG_VARIABLE_LENGTH_CMD == cmd_byte0) {
- scnpr(buff, buff_len, "%s", "Variable length");
- return;
- }
- grp = (cmd_byte0 >> 5) & 0x7;
- switch (grp) {
- case 0:
- case 1:
- case 2:
- case 4:
- case 5:
- vnp = get_value_name(sg_lib_normal_opcodes, cmd_byte0, peri_type);
- if (vnp)
- scnpr(buff, buff_len, "%s", vnp->name);
- else
- scnpr(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0);
- break;
- case 3:
- scnpr(buff, buff_len, "Reserved [0x%x]", (int)cmd_byte0);
- break;
- case 6:
- case 7:
- scnpr(buff, buff_len, "Vendor specific [0x%x]", (int)cmd_byte0);
- break;
- default:
- scnpr(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0);
- break;
- }
-}
-
-/* Iterates to next designation descriptor in the device identification
- * VPD page. The 'initial_desig_desc' should point to start of first
- * descriptor with 'page_len' being the number of valid bytes in that
- * and following descriptors. To start, 'off' should point to a negative
- * value, thereafter it should point to the value yielded by the previous
- * call. If 0 returned then 'initial_desig_desc + *off' should be a valid
- * descriptor; returns -1 if normal end condition and -2 for an abnormal
- * termination. Matches association, designator_type and/or code_set when
- * any of those values are greater than or equal to zero. */
-int
-sg_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len,
- int * off, int m_assoc, int m_desig_type, int m_code_set)
-{
- bool fltr = ((m_assoc >= 0) || (m_desig_type >= 0) || (m_code_set >= 0));
- int k = *off;
- const unsigned char * bp = initial_desig_desc;
-
- while ((k + 3) < page_len) {
- k = (k < 0) ? 0 : (k + bp[k + 3] + 4);
- if ((k + 4) > page_len)
- break;
- if (fltr) {
- if (m_code_set >= 0) {
- if ((bp[k] & 0xf) != m_code_set)
- continue;
- }
- if (m_assoc >= 0) {
- if (((bp[k + 1] >> 4) & 0x3) != m_assoc)
- continue;
- }
- if (m_desig_type >= 0) {
- if ((bp[k + 1] & 0xf) != m_desig_type)
- continue;
- }
- }
- *off = k;
- return 0;
- }
- return (k == page_len) ? -1 : -2;
-}
-
-static const char * const bad_sense_cat = "Bad sense category";
-
-/* Yield string associated with sense category. Returns 'buff' (or pointer
- * to "Bad sense category" if 'buff' is NULL). If sense_cat unknown then
- * yield "Sense category: <sense_cat>" string. */
-const char *
-sg_get_category_sense_str(int sense_cat, int buff_len, char * buff,
- int verbose)
-{
- int n;
-
- if (NULL == buff)
- return bad_sense_cat;
- if (buff_len <= 0)
- return buff;
- switch (sense_cat) {
- case SG_LIB_CAT_CLEAN: /* 0 */
- scnpr(buff, buff_len, "No errors");
- break;
- case SG_LIB_SYNTAX_ERROR: /* 1 */
- scnpr(buff, buff_len, "Syntax error");
- break;
- case SG_LIB_CAT_NOT_READY: /* 2 */
- n = scnpr(buff, buff_len, "Not ready");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key");
- break;
- case SG_LIB_CAT_MEDIUM_HARD: /* 3 */
- n = scnpr(buff, buff_len, "Medium or hardware error");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key (plus blank check)");
- break;
- case SG_LIB_CAT_ILLEGAL_REQ: /* 5 */
- n = scnpr(buff, buff_len, "Illegal request");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key, apart from Invalid "
- "opcode");
- break;
- case SG_LIB_CAT_UNIT_ATTENTION: /* 6 */
- n = scnpr(buff, buff_len, "Unit attention");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key");
- break;
- case SG_LIB_CAT_DATA_PROTECT: /* 7 */
- n = scnpr(buff, buff_len, "Data protect");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key, write protected "
- "media?");
- break;
- case SG_LIB_CAT_INVALID_OP: /* 9 */
- n = scnpr(buff, buff_len, "Illegal request, invalid opcode");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key");
- break;
- case SG_LIB_CAT_COPY_ABORTED: /* 10 */
- n = scnpr(buff, buff_len, "Copy aborted");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key");
- break;
- case SG_LIB_CAT_ABORTED_COMMAND: /* 11 */
- n = scnpr(buff, buff_len, "Aborted command");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key, other than "
- "protection related (asc=0x10)");
- break;
- case SG_LIB_CAT_MISCOMPARE: /* 14 */
- n = scnpr(buff, buff_len, "Miscompare");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key");
- break;
- case SG_LIB_FILE_ERROR: /* 15 */
- scnpr(buff, buff_len, "File error");
- break;
- case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: /* 17 */
- scnpr(buff, buff_len, "Illegal request with info");
- break;
- case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO: /* 18 */
- scnpr(buff, buff_len, "Medium or hardware error with info");
- break;
- case SG_LIB_CAT_NO_SENSE: /* 20 */
- n = scnpr(buff, buff_len, "No sense key");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " probably additional sense "
- "information");
- break;
- case SG_LIB_CAT_RECOVERED: /* 21 */
- n = scnpr(buff, buff_len, "Recovered error");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " sense key");
- break;
- case SG_LIB_CAT_RES_CONFLICT: /* 24 */
- n = scnpr(buff, buff_len, "Reservation conflict");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " SCSI status");
- break;
- case SG_LIB_CAT_CONDITION_MET: /* 25 */
- n = scnpr(buff, buff_len, "Condition met");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " SCSI status");
- break;
- case SG_LIB_CAT_BUSY: /* 26 */
- n = scnpr(buff, buff_len, "Busy");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " SCSI status");
- break;
- case SG_LIB_CAT_TS_FULL: /* 27 */
- n = scnpr(buff, buff_len, "Task set full");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " SCSI status");
- break;
- case SG_LIB_CAT_ACA_ACTIVE: /* 28 */
- n = scnpr(buff, buff_len, "ACA active");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " SCSI status");
- break;
- case SG_LIB_CAT_TASK_ABORTED: /* 29 */
- n = scnpr(buff, buff_len, "Task aborted");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " SCSI status");
- break;
- case SG_LIB_CAT_TIMEOUT: /* 33 */
- scnpr(buff, buff_len, "SCSI command timeout");
- break;
- case SG_LIB_CAT_PROTECTION: /* 40 */
- n = scnpr(buff, buff_len, "Aborted command, protection");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " information (PI) problem");
- break;
- case SG_LIB_CAT_PROTECTION_WITH_INFO: /* 41 */
- n = scnpr(buff, buff_len, "Aborted command with info, protection");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " information (PI) problem");
- break;
- case SG_LIB_CAT_MALFORMED: /* 97 */
- n = scnpr(buff, buff_len, "Malformed response");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, " to SCSI command");
- break;
- case SG_LIB_CAT_SENSE: /* 98 */
- n = scnpr(buff, buff_len, "Some other sense data problem");
- if (verbose && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, ", try '-v' option for more "
- "information");
- break;
- case SG_LIB_CAT_OTHER: /* 99 */
- n = scnpr(buff, buff_len, "Some other error/warning has occurred");
- if ((0 == verbose) && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, ", possible transport of driver "
- "issue");
- break;
- default:
- if ((sense_cat > SG_LIB_OS_BASE_ERR) &&
- (sense_cat < (SG_LIB_OS_BASE_ERR + 47))) {
- int k = sense_cat - SG_LIB_OS_BASE_ERR;
-
- n = scnpr(buff, buff_len, "OS error: %s [%d]", safe_strerror(k),
- k);
- } else {
- n = scnpr(buff, buff_len, "Sense category: %d", sense_cat);
- if ((0 == verbose) && (n < (buff_len - 1)))
- scnpr(buff + n, buff_len - n, ", try '-v' option for more "
- "information");
- }
- break;
- }
- return buff;
-}
-
-static const char * sg_sfs_spc_reserved = "SPC Reserved";
-static const char * sg_sfs_sbc_reserved = "SBC Reserved";
-static const char * sg_sfs_ssc_reserved = "SSC Reserved";
-static const char * sg_sfs_zbc_reserved = "ZBC Reserved";
-static const char * sg_sfs_reserved = "Reserved";
-
-/* Yield SCSI Feature Set (sfs) string. When 'peri_type' is < -1 (or > 31)
- * returns pointer to string (same as 'buff') associated with 'sfs_code'.
- * When 'peri_type' is between -1 (for SPC) and 31 (inclusive) then a match
- * on both 'sfs_code' and 'peri_type' is required. If 'foundp' is not NULL
- * then where it points is set to true if a match is found else it is set to
- * false. If 'buff' is not NULL then in the case of a match a descriptive
- * string is written to 'buff' while if there is not a not then a string
- * ending in "Reserved" is written (and may be prefixed with SPC, SBC, SSC
- * or ZBC). Returns 'buff' (i.e. a pointer value) even if it is NULL.
- * Example:
- * char b[64];
- * ...
- * printf("%s\n", sg_get_sfs_str(sfs_code, -2, sizeof(b), b, NULL, 0));
- */
-const char *
-sg_get_sfs_str(uint16_t sfs_code, int peri_type, int buff_len, char * buff,
- bool * foundp, int verbose)
-{
- const struct sg_lib_value_name_t * vnp = NULL;
- int n = 0;
- int my_pdt;
-
- if ((NULL == buff) || (buff_len < 1)) {
- if (foundp)
- *foundp = false;
- return NULL;
- } else if (1 == buff_len) {
- buff[0] = '\0';
- if (foundp)
- *foundp = false;
- return NULL;
- }
- my_pdt = ((peri_type < -1) || (peri_type > 0x1f)) ? -2 : peri_type;
- vnp = get_value_name(sg_lib_scsi_feature_sets, sfs_code, my_pdt);
- if (vnp && (-2 != my_pdt)) {
- if (peri_type != vnp->peri_dev_type)
- vnp = NULL; /* shouldn't really happen */
- }
- if (foundp)
- *foundp = vnp ? true : false;
- if (sfs_code < 0x100) { /* SPC Feature Sets */
- if (vnp) {
- if (verbose)
- n += scnpr(buff, buff_len, "SPC %s", vnp->name);
- else
- n += scnpr(buff, buff_len, "%s", vnp->name);
- } else
- n += scnpr(buff, buff_len, "%s", sg_sfs_spc_reserved);
- } else if (sfs_code < 0x200) { /* SBC Feature Sets */
- if (vnp) {
- if (verbose)
- n += scnpr(buff, buff_len, "SBC %s", vnp->name);
- else
- n += scnpr(buff, buff_len, "%s", vnp->name);
- } else
- n += scnpr(buff, buff_len, "%s", sg_sfs_sbc_reserved);
- } else if (sfs_code < 0x300) { /* SSC Feature Sets */
- if (vnp) {
- if (verbose)
- n += scnpr(buff, buff_len, "SSC %s", vnp->name);
- else
- n += scnpr(buff, buff_len, "%s", vnp->name);
- } else
- n += scnpr(buff, buff_len, "%s", sg_sfs_ssc_reserved);
- } else if (sfs_code < 0x400) { /* ZBC Feature Sets */
- if (vnp) {
- if (verbose)
- n += scnpr(buff, buff_len, "ZBC %s", vnp->name);
- else
- n += scnpr(buff, buff_len, "%s", vnp->name);
- } else
- n += scnpr(buff, buff_len, "%s", sg_sfs_zbc_reserved);
- } else { /* Other SCSI Feature Sets */
- if (vnp) {
- if (verbose)
- n += scnpr(buff, buff_len, "[unrecognized PDT] %s",
- vnp->name);
- else
- n += scnpr(buff, buff_len, "%s", vnp->name);
- } else
- n += scnpr(buff, buff_len, "%s", sg_sfs_reserved);
-
- }
- if (verbose > 4)
- pr2serr("%s: length of returned string (n) %d\n", __func__, n);
- return buff;
-}
-
-/* This is a heuristic that takes into account the command bytes and length
- * to decide whether the presented unstructured sequence of bytes could be
- * a SCSI command. If so it returns true otherwise false. Vendor specific
- * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
- * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
- * only SCSI commands considered above 16 bytes of length are the Variable
- * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
- * Both have an inbuilt length field which can be cross checked with clen.
- * No NVMe commands (64 bytes long plus some extra added by some OSes) have
- * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
- * structures that are sent across the wire. The FIS register structure is
- * used to move a command from a SATA host to device, but the ATA 'command'
- * is not the first byte. So it is harder to say what will happen if a
- * FIS structure is presented as a SCSI command, hopfully there is a low
- * probability this function will yield true in that case. */
-bool
-sg_is_scsi_cdb(const uint8_t * cdbp, int clen)
-{
- int ilen, sa;
- uint8_t opcode;
- uint8_t top3bits;
-
- if (clen < 6)
- return false;
- opcode = cdbp[0];
- top3bits = opcode >> 5;
- if (0x3 == top3bits) {
- if ((clen < 12) || (clen % 4))
- return false; /* must be modulo 4 and 12 or more bytes */
- switch (opcode) {
- case 0x7e: /* Extended cdb (XCDB) */
- ilen = 4 + sg_get_unaligned_be16(cdbp + 2);
- return (ilen == clen);
- case 0x7f: /* Variable Length cdb */
- ilen = 8 + cdbp[7];
- sa = sg_get_unaligned_be16(cdbp + 8);
- /* service action (sa) 0x0 is reserved */
- return ((ilen == clen) && sa);
- default:
- return false;
- }
- } else if (clen <= 16) {
- switch (clen) {
- case 6:
- if (top3bits > 0x5) /* vendor */
- return true;
- return (0x0 == top3bits); /* 6 byte cdb */
- case 10:
- if (top3bits > 0x5) /* vendor */
- return true;
- return ((0x1 == top3bits) || (0x2 == top3bits)); /* 10 byte cdb */
- case 16:
- if (top3bits > 0x5) /* vendor */
- return true;
- return (0x4 == top3bits); /* 16 byte cdb */
- case 12:
- if (top3bits > 0x5) /* vendor */
- return true;
- return (0x5 == top3bits); /* 12 byte cdb */
- default:
- return false;
- }
- }
- /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or
- * opcode > 0x7f). */
- return false;
-}
-
-/* Yield string associated with NVMe command status value in sct_sc. It
- * expects to decode DW3 bits 27:17 from the completion queue. Bits 27:25
- * are the Status Code Type (SCT) and bits 24:17 are the Status Code (SC).
- * Bit 17 in DW3 should be bit 0 in sct_sc. If no status string is found
- * a string of the form "Reserved [0x<sct_sc_in_hex>]" is generated.
- * Returns 'buff'. Does nothing if buff_len<=0 or if buff is NULL.*/
-char *
-sg_get_nvme_cmd_status_str(uint16_t sct_sc, int b_len, char * b)
-{
- int k;
- uint16_t s = 0x3ff & sct_sc;
- const struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr;
-
- if ((b_len <= 0) || (NULL == b))
- return b;
- else if (1 == b_len) {
- b[0] = '\0';
- return b;
- }
- for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) {
- if (s == (uint16_t)vp->value) {
- strncpy(b, vp->name, b_len);
- b[b_len - 1] = '\0';
- return b;
- }
- }
- if (k >= 1000)
- pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n",
- __func__);
- snprintf(b, b_len, "Reserved [0x%x]", sct_sc);
- return b;
-}
-
-/* Attempts to map NVMe status value ((SCT << 8) | SC) to SCSI status,
- * sense_key, asc and ascq tuple. If successful returns true and writes to
- * non-NULL pointer arguments; otherwise returns false. */
-bool
-sg_nvme_status2scsi(uint16_t sct_sc, uint8_t * status_p, uint8_t * sk_p,
- uint8_t * asc_p, uint8_t * ascq_p)
-{
- int k, ind;
- uint16_t s = 0x3ff & sct_sc;
- struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr;
- struct sg_lib_4tuple_u8 * mp = sg_lib_scsi_status_sense_arr;
-
- for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) {
- if (s == (uint16_t)vp->value)
- break;
- }
- if (k >= 1000) {
- pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n",
- __func__);
- return false;
- }
- if (NULL == vp->name)
- return false;
- ind = vp->peri_dev_type;
-
-
- for (k = 0; (0xff != mp->t2) && k < 1000; ++k, ++mp)
- ; /* count entries for valid index range */
- if (k >= 1000) {
- pr2ws("%s: where is sentinel for sg_lib_scsi_status_sense_arr ??\n",
- __func__);
- return false;
- } else if (ind >= k)
- return false;
- mp = sg_lib_scsi_status_sense_arr + ind;
- if (status_p)
- *status_p = mp->t1;
- if (sk_p)
- *sk_p = mp->t2;
- if (asc_p)
- *asc_p = mp->t3;
- if (ascq_p)
- *ascq_p = mp->t4;
- return true;
-}
-
-/* safe_strerror() contributed by Clayton Weaver <cgweav at email dot com>
- * Allows for situation in which strerror() is given a wild value (or the
- * C library is incomplete) and returns NULL. Still not thread safe.
- */
-
-static char safe_errbuf[64] = {'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ',
- 'e', 'r', 'r', 'n', 'o', ':', ' ', 0};
-
-char *
-safe_strerror(int errnum)
-{
- size_t len;
- char * errstr;
-
- if (errnum < 0)
- errnum = -errnum;
- errstr = strerror(errnum);
- if (NULL == errstr) {
- len = strlen(safe_errbuf);
- scnpr(safe_errbuf + len, sizeof(safe_errbuf) - len, "%i", errnum);
- return safe_errbuf;
- }
- return errstr;
-}
-
-static void
-trimTrailingSpaces(char * b)
-{
- int k;
-
- for (k = ((int)strlen(b) - 1); k >= 0; --k) {
- if (' ' != b[k])
- break;
- }
- if ('\0' != b[k + 1])
- b[k + 1] = '\0';
-}
-
-/* Note the ASCII-hex output goes to stdout. [Most other output from functions
- * in this file go to sg_warnings_strm (default stderr).]
- * 'no_ascii' allows for 3 output types:
- * > 0 each line has address then up to 16 ASCII-hex bytes
- * = 0 in addition, the bytes are listed in ASCII to the right
- * < 0 only the ASCII-hex bytes are listed (i.e. without address) */
-static void
-dStrHexFp(const char* str, int len, int no_ascii, FILE * fp)
-{
- const char * p = str;
- const char * formatstr;
- unsigned char c;
- char buff[82];
- int a = 0;
- int bpstart = 5;
- const int cpstart = 60;
- int cpos = cpstart;
- int bpos = bpstart;
- int i, k, blen;
-
- if (len <= 0)
- return;
- blen = (int)sizeof(buff);
- if (0 == no_ascii) /* address at left and ASCII at right */
- formatstr = "%.76s\n";
- else /* previously when > 0 str was "%.58s\n" */
- formatstr = "%s\n"; /* when < 0 str was: "%.48s\n" */
- memset(buff, ' ', 80);
- buff[80] = '\0';
- if (no_ascii < 0) {
- bpstart = 0;
- bpos = bpstart;
- for (k = 0; k < len; k++) {
- c = *p++;
- if (bpos == (bpstart + (8 * 3)))
- bpos++;
- scnpr(&buff[bpos], blen - bpos, "%.2x", (int)(unsigned char)c);
- buff[bpos + 2] = ' ';
- if ((k > 0) && (0 == ((k + 1) % 16))) {
- trimTrailingSpaces(buff);
- fprintf(fp, formatstr, buff);
- bpos = bpstart;
- memset(buff, ' ', 80);
- } else
- bpos += 3;
- }
- if (bpos > bpstart) {
- buff[bpos + 2] = '\0';
- trimTrailingSpaces(buff);
- fprintf(fp, "%s\n", buff);
- }
- return;
- }
- /* no_ascii>=0, start each line with address (offset) */
- k = scnpr(buff + 1, blen - 1, "%.2x", a);
- buff[k + 1] = ' ';
-
- for (i = 0; i < len; i++) {
- c = *p++;
- bpos += 3;
- if (bpos == (bpstart + (9 * 3)))
- bpos++;
- scnpr(&buff[bpos], blen - bpos, "%.2x", (int)(unsigned char)c);
- buff[bpos + 2] = ' ';
- if (no_ascii)
- buff[cpos++] = ' ';
- else {
- if (! my_isprint(c))
- c = '.';
- buff[cpos++] = c;
- }
- if (cpos > (cpstart + 15)) {
- if (no_ascii)
- trimTrailingSpaces(buff);
- fprintf(fp, formatstr, buff);
- bpos = bpstart;
- cpos = cpstart;
- a += 16;
- memset(buff, ' ', 80);
- k = scnpr(buff + 1, blen - 1, "%.2x", a);
- buff[k + 1] = ' ';
- }
- }
- if (cpos > cpstart) {
- buff[cpos] = '\0';
- if (no_ascii)
- trimTrailingSpaces(buff);
- fprintf(fp, "%s\n", buff);
- }
-}
-
-void
-dStrHex(const char* str, int len, int no_ascii)
-{
- dStrHexFp(str, len, no_ascii, stdout);
-}
-
-void
-dStrHexErr(const char* str, int len, int no_ascii)
-{
- dStrHexFp(str, len, no_ascii,
- (sg_warnings_strm ? sg_warnings_strm : stderr));
-}
-
-#define DSHS_LINE_BLEN 160
-#define DSHS_BPL 16
-
-/* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space
- * separated) to 'b' not to exceed 'b_len' characters. Each line
- * starts with 'leadin' (NULL for no leadin) and there are 16 bytes
- * per line with an extra space between the 8th and 9th bytes. 'format'
- * is 0 for repeat in printable ASCII ('.' for non printable) to
- * right of each line; 1 don't (so just output ASCII hex). Returns
- * number of bytes written to 'b' excluding the trailing '\0'. */
-int
-dStrHexStr(const char * str, int len, const char * leadin, int format,
- int b_len, char * b)
-{
- unsigned char c;
- int bpstart, bpos, k, n, prior_ascii_len;
- bool want_ascii;
- char buff[DSHS_LINE_BLEN + 2];
- char a[DSHS_BPL + 1];
- const char * p = str;
-
- if (len <= 0) {
- if (b_len > 0)
- b[0] = '\0';
- return 0;
- }
- if (b_len <= 0)
- return 0;
- want_ascii = !format;
- if (want_ascii) {
- memset(a, ' ', DSHS_BPL);
- a[DSHS_BPL] = '\0';
- }
- if (leadin) {
- bpstart = strlen(leadin);
- /* Cap leadin at (DSHS_LINE_BLEN - 70) characters */
- if (bpstart > (DSHS_LINE_BLEN - 70))
- bpstart = DSHS_LINE_BLEN - 70;
- } else
- bpstart = 0;
- bpos = bpstart;
- prior_ascii_len = bpstart + (DSHS_BPL * 3) + 1;
- n = 0;
- memset(buff, ' ', DSHS_LINE_BLEN);
- buff[DSHS_LINE_BLEN] = '\0';
- if (bpstart > 0)
- memcpy(buff, leadin, bpstart);
- for (k = 0; k < len; k++) {
- c = *p++;
- if (bpos == (bpstart + ((DSHS_BPL / 2) * 3)))
- bpos++; /* for extra space in middle of each line's hex */
- scnpr(buff + bpos, (int)sizeof(buff) - bpos, "%.2x",
- (int)(unsigned char)c);
- buff[bpos + 2] = ' ';
- if (want_ascii)
- a[k % DSHS_BPL] = my_isprint(c) ? c : '.';
- if ((k > 0) && (0 == ((k + 1) % DSHS_BPL))) {
- trimTrailingSpaces(buff);
- if (want_ascii) {
- n += scnpr(b + n, b_len - n, "%-*s %s\n", prior_ascii_len,
- buff, a);
- memset(a, ' ', DSHS_BPL);
- } else
- n += scnpr(b + n, b_len - n, "%s\n", buff);
- if (n >= (b_len - 1))
- return n;
- memset(buff, ' ', DSHS_LINE_BLEN);
- bpos = bpstart;
- if (bpstart > 0)
- memcpy(buff, leadin, bpstart);
- } else
- bpos += 3;
- }
- if (bpos > bpstart) {
- trimTrailingSpaces(buff);
- if (want_ascii)
- n += scnpr(b + n, b_len - n, "%-*s %s\n", prior_ascii_len,
- buff, a);
- else
- n += scnpr(b + n, b_len - n, "%s\n", buff);
- }
- return n;
-}
-
-void
-hex2stdout(const uint8_t * b_str, int len, int no_ascii)
-{
- dStrHex((const char *)b_str, len, no_ascii);
-}
-
-void
-hex2stderr(const uint8_t * b_str, int len, int no_ascii)
-{
- dStrHexErr((const char *)b_str, len, no_ascii);
-}
-
-int
-hex2str(const uint8_t * b_str, int len, const char * leadin, int format,
- int b_len, char * b)
-{
- return dStrHexStr((const char *)b_str, len, leadin, format, b_len, b);
-}
-
-/* Returns true when executed on big endian machine; else returns false.
- * Useful for displaying ATA identify words (which need swapping on a
- * big endian machine). */
-bool
-sg_is_big_endian()
-{
- union u_t {
- uint16_t s;
- unsigned char c[sizeof(uint16_t)];
- } u;
-
- u.s = 0x0102;
- return (u.c[0] == 0x01); /* The lowest address contains
- the most significant byte */
-}
-
-bool
-sg_all_zeros(const uint8_t * bp, int b_len)
-{
- if ((NULL == bp) || (b_len <= 0))
- return false;
- for (--b_len; b_len >= 0; --b_len) {
- if (0x0 != bp[b_len])
- return false;
- }
- return true;
-}
-
-bool
-sg_all_ffs(const uint8_t * bp, int b_len)
-{
- if ((NULL == bp) || (b_len <= 0))
- return false;
- for (--b_len; b_len >= 0; --b_len) {
- if (0xff != bp[b_len])
- return false;
- }
- return true;
-}
-
-static uint16_t
-swapb_uint16(uint16_t u)
-{
- uint16_t r;
-
- r = (u >> 8) & 0xff;
- r |= ((u & 0xff) << 8);
- return r;
-}
-
-/* Note the ASCII-hex output goes to stdout. [Most other output from functions
- * in this file go to sg_warnings_strm (default stderr).]
- * 'no_ascii' allows for 3 output types:
- * > 0 each line has address then up to 8 ASCII-hex 16 bit words
- * = 0 in addition, the ASCI bytes pairs are listed to the right
- * = -1 only the ASCII-hex words are listed (i.e. without address)
- * = -2 only the ASCII-hex words, formatted for "hdparm --Istdin"
- * < -2 same as -1
- * If 'swapb' is true then bytes in each word swapped. Needs to be set
- * for ATA IDENTIFY DEVICE response on big-endian machines. */
-void
-dWordHex(const uint16_t* words, int num, int no_ascii, bool swapb)
-{
- const uint16_t * p = words;
- uint16_t c;
- char buff[82];
- unsigned char upp, low;
- int a = 0;
- const int bpstart = 3;
- const int cpstart = 52;
- int cpos = cpstart;
- int bpos = bpstart;
- int i, k, blen;
-
- if (num <= 0)
- return;
- blen = (int)sizeof(buff);
- memset(buff, ' ', 80);
- buff[80] = '\0';
- if (no_ascii < 0) {
- for (k = 0; k < num; k++) {
- c = *p++;
- if (swapb)
- c = swapb_uint16(c);
- bpos += 5;
- scnpr(buff + bpos, blen - bpos, "%.4x", (unsigned int)c);
- buff[bpos + 4] = ' ';
- if ((k > 0) && (0 == ((k + 1) % 8))) {
- if (-2 == no_ascii)
- printf("%.39s\n", buff +8);
- else
- printf("%.47s\n", buff);
- bpos = bpstart;
- memset(buff, ' ', 80);
- }
- }
- if (bpos > bpstart) {
- if (-2 == no_ascii)
- printf("%.39s\n", buff +8);
- else
- printf("%.47s\n", buff);
- }
- return;
- }
- /* no_ascii>=0, start each line with address (offset) */
- k = scnpr(buff + 1, blen - 1, "%.2x", a);
- buff[k + 1] = ' ';
-
- for (i = 0; i < num; i++) {
- c = *p++;
- if (swapb)
- c = swapb_uint16(c);
- bpos += 5;
- scnpr(buff + bpos, blen - bpos, "%.4x", (unsigned int)c);
- buff[bpos + 4] = ' ';
- if (no_ascii) {
- buff[cpos++] = ' ';
- buff[cpos++] = ' ';
- buff[cpos++] = ' ';
- } else {
- upp = (c >> 8) & 0xff;
- low = c & 0xff;
- if (! my_isprint(upp))
- upp = '.';
- buff[cpos++] = upp;
- if (! my_isprint(low))
- low = '.';
- buff[cpos++] = low;
- buff[cpos++] = ' ';
- }
- if (cpos > (cpstart + 23)) {
- printf("%.76s\n", buff);
- bpos = bpstart;
- cpos = cpstart;
- a += 8;
- memset(buff, ' ', 80);
- k = scnpr(buff + 1, blen - 1, "%.2x", a);
- buff[k + 1] = ' ';
- }
- }
- if (cpos > cpstart)
- printf("%.76s\n", buff);
-}
-
-/* If the number in 'buf' can be decoded or the multiplier is unknown
- * then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal
- * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
- * Main (SI) multipliers supported: K, M, G. Ignore leading spaces and
- * tabs; accept comma, hyphen, space, tab and hash as terminator. */
-int
-sg_get_num(const char * buf)
-{
- int res, num, n, len;
- unsigned int unum;
- char * cp;
- const char * b;
- char c = 'c';
- char c2 = '\0'; /* keep static checker happy */
- char c3 = '\0'; /* keep static checker happy */
- char lb[16];
-
- if ((NULL == buf) || ('\0' == buf[0]))
- return -1;
- len = strlen(buf);
- n = strspn(buf, " \t");
- if (n > 0) {
- if (n == len)
- return -1;
- buf += n;
- len -= n;
- }
- /* following hack to keep C++ happy */
- cp = strpbrk((char *)buf, " \t,#-");
- if (cp) {
- len = cp - buf;
- n = (int)sizeof(lb) - 1;
- len = (len < n) ? len : n;
- memcpy(lb, buf, len);
- lb[len] = '\0';
- b = lb;
- } else
- b = buf;
- if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) {
- res = sscanf(b + 2, "%x", &unum);
- num = unum;
- } else if ('H' == toupper((int)b[len - 1])) {
- res = sscanf(b, "%x", &unum);
- num = unum;
- } else
- res = sscanf(b, "%d%c%c%c", &num, &c, &c2, &c3);
- if (res < 1)
- return -1LL;
- else if (1 == res)
- return num;
- else {
- if (res > 2)
- c2 = toupper((int)c2);
- if (res > 3)
- c3 = toupper((int)c3);
- switch (toupper((int)c)) {
- case 'C':
- return num;
- case 'W':
- return num * 2;
- case 'B':
- return num * 512;
- case 'K':
- if (2 == res)
- return num * 1024;
- if (('B' == c2) || ('D' == c2))
- return num * 1000;
- if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1024;
- return -1;
- case 'M':
- if (2 == res)
- return num * 1048576;
- if (('B' == c2) || ('D' == c2))
- return num * 1000000;
- if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1048576;
- return -1;
- case 'G':
- if (2 == res)
- return num * 1073741824;
- if (('B' == c2) || ('D' == c2))
- return num * 1000000000;
- if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1073741824;
- return -1;
- case 'X':
- cp = (char *)strchr(b, 'x');
- if (NULL == cp)
- cp = (char *)strchr(b, 'X');
- if (cp) {
- n = sg_get_num(cp + 1);
- if (-1 != n)
- return num * n;
- }
- return -1;
- default:
- pr2ws("unrecognized multiplier\n");
- return -1;
- }
- }
-}
-
-/* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
- * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is
- * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"),
- * a whitespace or newline as terminator. */
-int
-sg_get_num_nomult(const char * buf)
-{
- int res, len, num;
- unsigned int unum;
- char * commap;
-
- if ((NULL == buf) || ('\0' == buf[0]))
- return -1;
- len = strlen(buf);
- commap = (char *)strchr(buf + 1, ',');
- if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
- res = sscanf(buf + 2, "%x", &unum);
- num = unum;
- } else if (commap && ('H' == toupper((int)*(commap - 1)))) {
- res = sscanf(buf, "%x", &unum);
- num = unum;
- } else if ((NULL == commap) && ('H' == toupper((int)buf[len - 1]))) {
- res = sscanf(buf, "%x", &unum);
- num = unum;
- } else
- res = sscanf(buf, "%d", &num);
- if (1 == res)
- return num;
- else
- return -1;
-}
-
-/* If the number in 'buf' can be decoded or the multiplier is unknown
- * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a decimal
- * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
- * Main (SI) multipliers supported: K, M, G, T, P. Ignore leading spaces
- * and tabs; accept comma, hyphen, space, tab and hash as terminator. */
-int64_t
-sg_get_llnum(const char * buf)
-{
- int res, len, n;
- int64_t num, ll;
- uint64_t unum;
- char * cp;
- const char * b;
- char c = 'c';
- char c2 = '\0'; /* keep static checker happy */
- char c3 = '\0'; /* keep static checker happy */
- char lb[32];
-
- if ((NULL == buf) || ('\0' == buf[0]))
- return -1LL;
- len = strlen(buf);
- n = strspn(buf, " \t");
- if (n > 0) {
- if (n == len)
- return -1LL;
- buf += n;
- len -= n;
- }
- /* following hack to keep C++ happy */
- cp = strpbrk((char *)buf, " \t,#-");
- if (cp) {
- len = cp - buf;
- n = (int)sizeof(lb) - 1;
- len = (len < n) ? len : n;
- memcpy(lb, buf, len);
- lb[len] = '\0';
- b = lb;
- } else
- b = buf;
- if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) {
- res = sscanf(b + 2, "%" SCNx64 , &unum);
- num = unum;
- } else if ('H' == toupper((int)b[len - 1])) {
- res = sscanf(b, "%" SCNx64 , &unum);
- num = unum;
- } else
- res = sscanf(b, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3);
- if (res < 1)
- return -1LL;
- else if (1 == res)
- return num;
- else {
- if (res > 2)
- c2 = toupper((int)c2);
- if (res > 3)
- c3 = toupper((int)c3);
- switch (toupper((int)c)) {
- case 'C':
- return num;
- case 'W':
- return num * 2;
- case 'B':
- return num * 512;
- case 'K':
- if (2 == res)
- return num * 1024;
- if (('B' == c2) || ('D' == c2))
- return num * 1000;
- if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1024;
- return -1LL;
- case 'M':
- if (2 == res)
- return num * 1048576;
- if (('B' == c2) || ('D' == c2))
- return num * 1000000;
- if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1048576;
- return -1LL;
- case 'G':
- if (2 == res)
- return num * 1073741824;
- if (('B' == c2) || ('D' == c2))
- return num * 1000000000;
- if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1073741824;
- return -1LL;
- case 'T':
- if (2 == res)
- return num * 1099511627776LL;
- if (('B' == c2) || ('D' == c2))
- return num * 1000000000000LL;
- if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1099511627776LL;
- return -1LL;
- case 'P':
- if (2 == res)
- return num * 1099511627776LL * 1024;
- if (('B' == c2) || ('D' == c2))
- return num * 1000000000000LL * 1000;
- if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1099511627776LL * 1024;
- return -1LL;
- case 'X':
- cp = (char *)strchr(b, 'x');
- if (NULL == cp)
- cp = (char *)strchr(b, 'X');
- if (cp) {
- ll = sg_get_llnum(cp + 1);
- if (-1LL != ll)
- return num * ll;
- }
- return -1LL;
- default:
- pr2ws("unrecognized multiplier\n");
- return -1LL;
- }
- }
-}
-
-/* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
- * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is
- * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"),
- * a whitespace or newline as terminator. Only decimal numbers can represent
- * negative numbers and '-1' must be treated separately. */
-int64_t
-sg_get_llnum_nomult(const char * buf)
-{
- int res, len;
- int64_t num;
- uint64_t unum;
-
- if ((NULL == buf) || ('\0' == buf[0]))
- return -1;
- len = strlen(buf);
- if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
- res = sscanf(buf + 2, "%" SCNx64 "", &unum);
- num = unum;
- } else if ('H' == toupper(buf[len - 1])) {
- res = sscanf(buf, "%" SCNx64 "", &unum);
- num = unum;
- } else
- res = sscanf(buf, "%" SCNd64 "", &num);
- return (1 == res) ? num : -1;
-}
-
-/* Extract character sequence from ATA words as in the model string
- * in a IDENTIFY DEVICE response. Returns number of characters
- * written to 'ochars' before 0 character is found or 'num' words
- * are processed. */
-int
-sg_ata_get_chars(const uint16_t * word_arr, int start_word,
- int num_words, bool is_big_endian, char * ochars)
-{
- int k;
- uint16_t s;
- char a, b;
- char * op = ochars;
-
- for (k = start_word; k < (start_word + num_words); ++k) {
- s = word_arr[k];
- if (is_big_endian) {
- a = s & 0xff;
- b = (s >> 8) & 0xff;
- } else {
- a = (s >> 8) & 0xff;
- b = s & 0xff;
- }
- if (a == 0)
- break;
- *op++ = a;
- if (b == 0)
- break;
- *op++ = b;
- }
- return op - ochars;
-}
-
-int
-pr2serr(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(stderr, fmt, args);
- va_end(args);
- return n;
-}
-
-#ifdef SG_LIB_FREEBSD
-#include <sys/param.h>
-#elif defined(SG_LIB_WIN32)
-#include <windows.h>
-
-static bool got_page_size = false;
-static uint32_t win_page_size;
-#endif
-
-uint32_t
-sg_get_page_size(void)
-{
-#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
- return sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */
-#elif defined(SG_LIB_WIN32)
- if (! got_page_size) {
- SYSTEM_INFO si;
-
- GetSystemInfo(&si);
- win_page_size = si.dwPageSize;
- got_page_size = true;
- }
- return win_page_size;
-#elif defined(SG_LIB_FREEBSD)
- return PAGE_SIZE;
-#else
- return 4096; /* give up, pick likely figure */
-#endif
-}
-
-/* Returns pointer to heap (or NULL) that is aligned to a align_to byte
- * boundary. Sends back *buff_to_free pointer in third argument that may be
- * different from the return value. If it is different then the *buff_to_free
- * pointer should be freed (rather than the returned value) when the heap is
- * no longer needed. If align_to is 0 then aligns to OS's page size. Sets all
- * returned heap to zeros. If num_bytes is 0 then set to page size. */
-uint8_t *
-sg_memalign(uint32_t num_bytes, uint32_t align_to, uint8_t ** buff_to_free,
- bool vb)
-{
- size_t psz;
- uint8_t * res;
-
- if (buff_to_free) /* make sure buff_to_free is NULL if alloc fails */
- *buff_to_free = NULL;
- psz = (align_to > 0) ? align_to : sg_get_page_size();
- if (0 == num_bytes)
- num_bytes = psz; /* ugly to handle otherwise */
-
-#ifdef HAVE_POSIX_MEMALIGN
- {
- int err;
- void * wp = NULL;
-
- err = posix_memalign(&wp, psz, num_bytes);
- if (err || (NULL == wp)) {
- pr2ws("%s: posix_memalign: error [%d], out of memory?\n",
- __func__, err);
- return NULL;
- }
- memset(wp, 0, num_bytes);
- if (buff_to_free)
- *buff_to_free = (uint8_t *)wp;
- res = (uint8_t *)wp;
- if (vb) {
- pr2ws("%s: posix_ma, len=%d, ", __func__, num_bytes);
- if (buff_to_free)
- pr2ws("wrkBuffp=%p, ", (void *)res);
- pr2ws("psz=%u, rp=%p\n", (unsigned int)psz, (void *)res);
- }
- return res;
- }
-#else
- {
- void * wrkBuff;
- sg_uintptr_t align_1 = psz - 1;
-
- wrkBuff = (uint8_t *)calloc(num_bytes + psz, 1);
- if (NULL == wrkBuff) {
- if (buff_to_free)
- *buff_to_free = NULL;
- return NULL;
- } else if (buff_to_free)
- *buff_to_free = (uint8_t *)wrkBuff;
- res = (uint8_t *)(void *)
- (((sg_uintptr_t)wrkBuff + align_1) & (~align_1));
- if (vb) {
- pr2ws("%s: hack, len=%d, ", __func__, num_bytes);
- if (buff_to_free)
- pr2ws("buff_to_free=%p, ", wrkBuff);
- pr2ws("align_1=%lu, rp=%p\n", (unsigned long)align_1, (void *)res);
- }
- return res;
- }
-#endif
-}
-
-const char *
-sg_lib_version()
-{
- return sg_lib_version_str;
-}
-
-
-#ifdef SG_LIB_MINGW
-/* Non Unix OSes distinguish between text and binary files.
- Set text mode on fd. Does nothing in Unix. Returns negative number on
- failure. */
-
-#include <unistd.h>
-#include <fcntl.h>
-
-int
-sg_set_text_mode(int fd)
-{
- return setmode(fd, O_TEXT);
-}
-
-/* Set binary mode on fd. Does nothing in Unix. Returns negative number on
- failure. */
-int
-sg_set_binary_mode(int fd)
-{
- return setmode(fd, O_BINARY);
-}
-
-#else
-/* For Unix the following functions are dummies. */
-int
-sg_set_text_mode(int fd)
-{
- return fd; /* fd should be >= 0 */
-}
-
-int
-sg_set_binary_mode(int fd)
-{
- return fd;
-}
-
-#endif
diff --git a/tools/sg_write_buffer/sg_lib_data.c b/tools/sg_write_buffer/sg_lib_data.c
deleted file mode 100644
index e59c355..0000000
--- a/tools/sg_write_buffer/sg_lib_data.c
+++ /dev/null
@@ -1,1688 +0,0 @@
-/*
- * Copyright (c) 2007-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdlib.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#else
-#define SG_SCSI_STRINGS 1
-#endif
-
-#include "sg_lib.h"
-#include "sg_lib_data.h"
-
-
-const char * sg_lib_version_str = "2.38 20180122";/* spc5r17, sbc4r15 */
-
-
-/* indexed by pdt; those that map to own index do not decay */
-int sg_lib_pdt_decay_arr[32] = {
- PDT_DISK, PDT_TAPE, PDT_TAPE /* printer */, PDT_PROCESSOR,
- PDT_DISK /* WO */, PDT_MMC, PDT_SCANNER, PDT_DISK /* optical */,
- PDT_MCHANGER, PDT_COMMS, 0xa, 0xb,
- PDT_SAC, PDT_SES, PDT_DISK /* rbc */, PDT_OCRW,
- PDT_BCC, PDT_OSD, PDT_TAPE /* adc */, PDT_SMD,
- PDT_DISK /* zbc */, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, PDT_WLUN, PDT_UNKNOWN
-};
-
-#ifdef SG_SCSI_STRINGS
-struct sg_lib_value_name_t sg_lib_normal_opcodes[] = {
- {0, 0, "Test Unit Ready"},
- {0x1, 0, "Rezero Unit"},
- {0x1, PDT_TAPE, "Rewind"},
- {0x3, 0, "Request Sense"},
- {0x4, 0, "Format Unit"},
- {0x4, PDT_TAPE, "Format medium"},
- {0x4, PDT_PRINTER, "Format"},
- {0x5, 0, "Read Block Limits"},
- {0x7, 0, "Reassign Blocks"},
- {0x7, PDT_MCHANGER, "Initialize element status"},
- {0x8, 0, "Read(6)"}, /* obsolete in sbc3r30 */
- {0x8, PDT_PROCESSOR, "Receive"},
- {0xa, 0, "Write(6)"}, /* obsolete in sbc3r30 */
- {0xa, PDT_PRINTER, "Print"},
- {0xa, PDT_PROCESSOR, "Send"},
- {0xb, 0, "Seek(6)"},
- {0xb, PDT_TAPE, "Set capacity"},
- {0xb, PDT_PRINTER, "Slew and print"},
- {0xf, 0, "Read reverse(6)"},
- {0x10, 0, "Write filemarks(6)"},
- {0x10, PDT_PRINTER, "Synchronize buffer"},
- {0x11, 0, "Space(6)"},
- {0x12, 0, "Inquiry"},
- {0x13, 0, "Verify(6)"}, /* SSC */
- {0x14, 0, "Recover buffered data"},
- {0x15, 0, "Mode select(6)"}, /* SBC-3 r31 recommends Mode select(10) */
- {0x16, 0, "Reserve(6)"}, /* obsolete in SPC-4 r11 */
- {0x16, PDT_MCHANGER, "Reserve element(6)"},
- {0x17, 0, "Release(6)"}, /* obsolete in SPC-4 r11 */
- {0x17, PDT_MCHANGER, "Release element(6)"},
- {0x18, 0, "Copy"}, /* obsolete in SPC-4 r11 */
- {0x19, 0, "Erase(6)"},
- {0x1a, 0, "Mode sense(6)"}, /* SBC-3 r31 recommends Mode sense(10) */
- {0x1b, 0, "Start stop unit"},
- {0x1b, PDT_TAPE, "Load unload"},
- {0x1b, PDT_ADC, "Load unload"},
- {0x1b, PDT_PRINTER, "Stop print"},
- {0x1c, 0, "Receive diagnostic results"},
- {0x1d, 0, "Send diagnostic"},
- {0x1e, 0, "Prevent allow medium removal"},
- {0x23, 0, "Read Format capacities"},
- {0x24, 0, "Set window"},
- {0x25, 0, "Read capacity(10)"},
- /* SBC-3 r31 recommends Read capacity(16) */
- {0x25, PDT_OCRW, "Read card capacity"},
- {0x28, 0, "Read(10)"}, /* SBC-3 r31 recommends Read(16) */
- {0x29, 0, "Read generation"},
- {0x2a, 0, "Write(10)"}, /* SBC-3 r31 recommends Write(16) */
- {0x2b, 0, "Seek(10)"},
- {0x2b, PDT_TAPE, "Locate(10)"},
- {0x2b, PDT_MCHANGER, "Position to element"},
- {0x2c, 0, "Erase(10)"},
- {0x2d, 0, "Read updated block"},
- {0x2e, 0, "Write and verify(10)"},
- /* SBC-3 r31 recommends Write and verify(16) */
- {0x2f, 0, "Verify(10)"}, /* SBC-3 r31 recommends Verify(16) */
- {0x30, 0, "Search data high(10)"},
- {0x31, 0, "Search data equal(10)"},
- {0x32, 0, "Search data low(10)"},
- {0x33, 0, "Set limits(10)"},
- {0x34, 0, "Pre-fetch(10)"}, /* SBC-3 r31 recommends Pre-fetch(16) */
- {0x34, PDT_TAPE, "Read position"},
- {0x35, 0, "Synchronize cache(10)"},
- /* SBC-3 r31 recommends Synchronize cache(16) */
- {0x36, 0, "Lock unlock cache(10)"},
- {0x37, 0, "Read defect data(10)"},
- /* SBC-3 r31 recommends Read defect data(12) */
- {0x37, PDT_MCHANGER, "Initialize element status with range"},
- {0x38, 0, "Medium scan"},
- {0x39, 0, "Compare"}, /* obsolete in SPC-4 r11 */
- {0x3a, 0, "Copy and verify"}, /* obsolete in SPC-4 r11 */
- {0x3b, 0, "Write buffer"},
- {0x3c, 0, "Read buffer(10)"},
- {0x3d, 0, "Update block"},
- {0x3e, 0, "Read long(10)"}, /* obsolete in SBC-4 r7 */
- {0x3f, 0, "Write long(10)"}, /* SBC-3 r31 recommends Write long(16) */
- {0x40, 0, "Change definition"}, /* obsolete in SPC-4 r11 */
- {0x41, 0, "Write same(10)"}, /* SBC-3 r31 recommends Write same(16) */
- {0x42, 0, "Unmap"}, /* added SPC-4 rev 18 */
- {0x42, PDT_MMC, "Read sub-channel"},
- {0x43, PDT_MMC, "Read TOC/PMA/ATIP"},
- {0x44, 0, "Report density support"},
- {0x45, PDT_MMC, "Play audio(10)"},
- {0x46, PDT_MMC, "Get configuration"},
- {0x47, PDT_MMC, "Play audio msf"},
- {0x48, 0, "Sanitize"},
- {0x4a, PDT_MMC, "Get event status notification"},
- {0x4b, PDT_MMC, "Pause/resume"},
- {0x4c, 0, "Log select"},
- {0x4d, 0, "Log sense"},
- {0x4e, 0, "Stop play/scan"},
- {0x50, 0, "Xdwrite(10)"}, /* obsolete in SBC-3 r31 */
- {0x51, 0, "Xpwrite(10)"}, /* obsolete in SBC-4 r15 */
- {0x51, PDT_MMC, "Read disk information"},
- {0x52, 0, "Xdread(10)"}, /* obsolete in SBC-3 r31 */
- {0x52, PDT_MMC, "Read track information"},
- {0x53, 0, "Xdwriteread(10)"}, /* obsolete in SBC-4 r15 */
- {0x54, 0, "Send OPC information"},
- {0x55, 0, "Mode select(10)"},
- {0x56, 0, "Reserve(10)"}, /* obsolete in SPC-4 r11 */
- {0x56, PDT_MCHANGER, "Reserve element(10)"},
- {0x57, 0, "Release(10)"}, /* obsolete in SPC-4 r11 */
- {0x57, PDT_MCHANGER, "Release element(10)"},
- {0x58, 0, "Repair track"},
- {0x5a, 0, "Mode sense(10)"},
- {0x5b, 0, "Close track/session"},
- {0x5c, 0, "Read buffer capacity"},
- {0x5d, 0, "Send cue sheet"},
- {0x5e, 0, "Persistent reserve in"},
- {0x5f, 0, "Persistent reserve out"},
- {0x7e, 0, "Extended cdb (XCBD)"}, /* added in SPC-4 r12 */
- {0x80, 0, "Xdwrite extended(16)"}, /* obsolete in SBC-4 r15 */
- {0x80, PDT_TAPE, "Write filemarks(16)"},
- {0x81, 0, "Rebuild(16)"},
- {0x81, PDT_TAPE, "Read reverse(16)"},
- {0x82, 0, "Regenerate(16)"},
- {0x83, 0, "Third party copy out"}, /* Extended copy, before spc4r34 */
- /* Following was "Receive copy results", before spc4r34 */
- {0x84, 0, "Third party copy in"},
- {0x85, 0, "ATA pass-through(16)"}, /* was 0x98 in spc3 rev21c */
- {0x86, 0, "Access control in"},
- {0x87, 0, "Access control out"},
- {0x88, 0, "Read(16)"},
- {0x89, 0, "Compare and write"},
- {0x8a, 0, "Write(16)"},
- {0x8b, 0, "Orwrite(16)"},
- {0x8c, 0, "Read attribute"},
- {0x8d, 0, "Write attribute"},
- {0x8e, 0, "Write and verify(16)"},
- {0x8f, 0, "Verify(16)"},
- {0x90, 0, "Pre-fetch(16)"},
- {0x91, 0, "Synchronize cache(16)"},
- {0x91, PDT_TAPE, "Space(16)"},
- {0x92, 0, "Lock unlock cache(16)"},
- {0x92, PDT_TAPE, "Locate(16)"},
- {0x93, 0, "Write same(16)"},
- {0x93, PDT_TAPE, "Erase(16)"},
- {0x94, PDT_ZBC, "ZBC out"}, /* new sbc4r04, has service actions */
- {0x95, PDT_ZBC, "ZBC in"}, /* new sbc4r04, has service actions */
- {0x9a, 0, "Write stream(16)"}, /* added sbc4r07 */
- {0x9b, 0, "Read buffer(16)"}, /* added spc5r02 */
- {0x9c, 0, "Write atomic(16)"},
- {0x9d, 0, "Service action bidirectional"}, /* added spc4r35 */
- {0x9e, 0, "Service action in(16)"},
- {0x9f, 0, "Service action out(16)"},
- {0xa0, 0, "Report luns"},
- {0xa1, 0, "ATA pass-through(12)"},
- {0xa1, PDT_MMC, "Blank"},
- {0xa2, 0, "Security protocol in"},
- {0xa3, 0, "Maintenance in"},
- {0xa3, PDT_MMC, "Send key"},
- {0xa4, 0, "Maintenance out"},
- {0xa4, PDT_MMC, "Report key"},
- {0xa5, 0, "Move medium"},
- {0xa5, PDT_MMC, "Play audio(12)"},
- {0xa6, 0, "Exchange medium"},
- {0xa6, PDT_MMC, "Load/unload medium"},
- {0xa7, 0, "Move medium attached"},
- {0xa7, PDT_MMC, "Set read ahead"},
- {0xa8, 0, "Read(12)"}, /* SBC-3 r31 recommends Read(16) */
- {0xa9, 0, "Service action out(12)"},
- {0xaa, 0, "Write(12)"}, /* SBC-3 r31 recommends Write(16) */
- {0xab, 0, "Service action in(12)"},
- {0xac, 0, "erase(12)"},
- {0xac, PDT_MMC, "Get performance"},
- {0xad, PDT_MMC, "Read DVD/BD structure"},
- {0xae, 0, "Write and verify(12)"},
- /* SBC-3 r31 recommends Write and verify(16) */
- {0xaf, 0, "Verify(12)"}, /* SBC-3 r31 recommends Verify(16) */
- {0xb0, 0, "Search data high(12)"},
- {0xb1, 0, "Search data equal(12)"},
- {0xb1, PDT_MCHANGER, "Open/close import/export element"},
- {0xb2, 0, "Search data low(12)"},
- {0xb3, 0, "Set limits(12)"},
- {0xb4, 0, "Read element status attached"},
- {0xb5, 0, "Security protocol out"},
- {0xb5, PDT_MCHANGER, "Request volume element address"},
- {0xb6, 0, "Send volume tag"},
- {0xb6, PDT_MMC, "Set streaming"},
- {0xb7, 0, "Read defect data(12)"},
- {0xb8, 0, "Read element status"},
- {0xb9, 0, "Read CD msf"},
- {0xba, 0, "Redundancy group in"},
- {0xba, PDT_MMC, "Scan"},
- {0xbb, 0, "Redundancy group out"},
- {0xbb, PDT_MMC, "Set CD speed"},
- {0xbc, 0, "Spare in"},
- {0xbd, 0, "Spare out"},
- {0xbd, PDT_MMC, "Mechanism status"},
- {0xbe, 0, "Volume set in"},
- {0xbe, PDT_MMC, "Read CD"},
- {0xbf, 0, "Volume set out"},
- {0xbf, PDT_MMC, "Send DVD/BD structure"},
- {0xffff, 0, NULL},
-};
-
-/* Read buffer(10) [0x3c] and Read buffer(16) [0x9b] service actions (sa),
- * need prefix */
-struct sg_lib_value_name_t sg_lib_read_buff_arr[] = {
- {0x0, 0, "combined header and data [or multiple modes]"},
- {0x2, 0, "data"},
- {0x3, 0, "descriptor"},
- {0xa, 0, "read data from echo buffer"},
- {0xb, 0, "echo buffer descriptor"},
- {0x1a, 0, "enable expander comms protocol and echo buffer"},
- {0x1c, 0, "error history"},
- {0xffff, 0, NULL},
-};
-
-/* Write buffer [0x3b] service actions, need prefix */
-struct sg_lib_value_name_t sg_lib_write_buff_arr[] = {
- {0x0, 0, "combined header and data [or multiple modes]"},
- {0x2, 0, "data"},
- {0x4, 0, "download microcode and activate"},
- {0x5, 0, "download microcode, save, and activate"},
- {0x6, 0, "download microcode with offsets and activate"},
- {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"},
- {0xe, 0, "download microcode with offsets, save and defer activate"},
- {0xf, 0, "activate deferred microcode"},
- {0x1a, 0, "enable expander comms protocol and echo buffer"},
- {0x1b, 0, "disable expander comms protocol"},
- {0x1c, 0, "download application client error history"},
- {0xffff, 0, NULL},
-};
-
-/* Read position (SSC) [0x34] service actions, need prefix */
-struct sg_lib_value_name_t sg_lib_read_pos_arr[] = {
- {0x0, PDT_TAPE, "short form - block id"},
- {0x1, PDT_TAPE, "short form - vendor specific"},
- {0x6, PDT_TAPE, "long form"},
- {0x8, PDT_TAPE, "extended form"},
- {0xffff, 0, NULL},
-};
-
-/* Maintenance in [0xa3] service actions */
-struct sg_lib_value_name_t sg_lib_maint_in_arr[] = {
- {0x0, PDT_SAC, "Report assigned/unassigned p_extent"},
- {0x1, PDT_SAC, "Report component device"},
- {0x2, PDT_SAC, "Report component device attachments"},
- {0x3, PDT_SAC, "Report peripheral device"},
- {0x4, PDT_SAC, "Report peripheral device associations"},
- {0x5, 0, "Report identifying information"},
- /* was "Report device identifier" prior to spc4r07 */
- {0x6, PDT_SAC, "Report states"},
- {0x7, PDT_SAC, "Report device identification"},
- {0x8, PDT_SAC, "Report unconfigured capacity"},
- {0x9, PDT_SAC, "Report supported configuration method"},
- {0xa, 0, "Report target port groups"},
- {0xb, 0, "Report aliases"},
- {0xc, 0, "Report supported operation codes"},
- {0xd, 0, "Report supported task management functions"},
- {0xe, 0, "Report priority"},
- {0xf, 0, "Report timestamp"},
- {0x10, 0, "Management protocol in"},
- {0x1d, PDT_DISK, "Report provisioning initialization pattern"},
- /* added in sbc4r07, shares sa 0x1d with ssc5r01 (tape) */
- {0x1d, PDT_TAPE, "Receive recommended access order"},
- {0x1e, PDT_TAPE, "Read dynamic runtime attribute"},
- {0x1e, PDT_ADC, "Report automation device attributes"},
- {0x1f, 0, "Maintenance in vendor specific"},
- {0xffff, 0, NULL},
-};
-
-/* Maintenance out [0xa4] service actions */
-struct sg_lib_value_name_t sg_lib_maint_out_arr[] = {
- {0x0, PDT_SAC, "Add peripheral device / component device"},
- {0x1, PDT_SAC, "Attach to component device"},
- {0x2, PDT_SAC, "Exchange p_extent"},
- {0x3, PDT_SAC, "Exchange peripheral device / component device"},
- {0x4, PDT_SAC, "Instruct component device"},
- {0x5, PDT_SAC, "Remove peripheral device / component device"},
- {0x6, 0, "Set identifying information"},
- /* was "Set device identifier" prior to spc4r07 */
- {0x7, PDT_SAC, "Break peripheral device / component device"},
- {0xa, 0, "Set target port groups"},
- {0xb, 0, "Change aliases"},
- {0xc, 0, "Remove I_T nexus"},
- {0xe, 0, "Set priority"},
- {0xf, 0, "Set timestamp"},
- {0x10, 0, "Management protocol out"},
- {0x1d, PDT_TAPE, "Generate recommended access order"},
- {0x1e, PDT_TAPE, "write dynamic runtime attribute"},
- {0x1e, PDT_ADC, "Set automation device attributes"},
- {0x1f, 0, "Maintenance out vendor specific"},
- {0xffff, 0, NULL},
-};
-
-/* Sanitize [0x48] service actions, need prefix */
-struct sg_lib_value_name_t sg_lib_sanitize_sa_arr[] = {
- {0x1, 0, "overwrite"},
- {0x2, 0, "block erase"},
- {0x3, 0, "cryptographic erase"},
- {0x1f, 0, "exit failure mode"},
- {0xffff, 0, NULL},
-};
-
-/* Service action in(12) [0xab] service actions */
-struct sg_lib_value_name_t sg_lib_serv_in12_arr[] = {
- {0x1, 0, "Read media serial number"},
- {0xffff, 0, NULL},
-};
-
-/* Service action out(12) [0xa9] service actions */
-struct sg_lib_value_name_t sg_lib_serv_out12_arr[] = {
- {0xff, 0, "Impossible command name"},
- {0xffff, 0, NULL},
-};
-
-/* Service action in(16) [0x9e] service actions */
-struct sg_lib_value_name_t sg_lib_serv_in16_arr[] = {
- {0xf, 0, "Receive binding report"}, /* added spc5r11 */
- {0x10, 0, "Read capacity(16)"},
- {0x11, 0, "Read long(16)"}, /* obsolete in SBC-4 r7 */
- {0x12, 0, "Get LBA status(16)"}, /* 32 byte variant added in sbc4r14 */
- {0x13, 0, "Report referrals"},
- {0x14, 0, "Stream control"},
- {0x15, 0, "Background control"},
- {0x16, 0, "Get stream status"},
- {0x17, 0, "Get physical element status"}, /* added sbc4r13 */
- {0x18, 0, "Remove element and truncate"}, /* added sbc4r13 */
- {0xffff, 0, NULL},
-};
-
-/* Service action out(16) [0x9f] service actions */
-struct sg_lib_value_name_t sg_lib_serv_out16_arr[] = {
- {0x0b, 0, "Test bind"}, /* added spc5r13 */
- {0x0c, 0, "Prepare bind report"}, /* added spc5r11 */
- {0x0d, 0, "Set affiliation"},
- {0x0e, 0, "Bind"},
- {0x0f, 0, "Unbind"},
- {0x11, 0, "Write long(16)"},
- {0x12, 0, "Write scattered(16)"}, /* added sbc4r11 */
- {0x14, PDT_ZBC, "Reset write pointer"},
- {0x1f, PDT_ADC, "Notify data transfer device(16)"},
- {0xffff, 0, NULL},
-};
-
-/* Service action bidirectional [0x9d] service actions */
-struct sg_lib_value_name_t sg_lib_serv_bidi_arr[] = {
- {0xffff, 0, NULL},
-};
-
-/* Persistent reserve in [0x5e] service actions, need prefix */
-struct sg_lib_value_name_t sg_lib_pr_in_arr[] = {
- {0x0, 0, "read keys"},
- {0x1, 0, "read reservation"},
- {0x2, 0, "report capabilities"},
- {0x3, 0, "read full status"},
- {0xffff, 0, NULL},
-};
-
-/* Persistent reserve out [0x5f] service actions, need prefix */
-struct sg_lib_value_name_t sg_lib_pr_out_arr[] = {
- {0x0, 0, "register"},
- {0x1, 0, "reserve"},
- {0x2, 0, "release"},
- {0x3, 0, "clear"},
- {0x4, 0, "preempt"},
- {0x5, 0, "preempt and abort"},
- {0x6, 0, "register and ignore existing key"},
- {0x7, 0, "register and move"},
- {0x8, 0, "replace lost reservation"},
- {0xffff, 0, NULL},
-};
-
-/* Third party copy in [0x83] service actions
- * Opcode 'Receive copy results' was renamed 'Third party copy in' in spc4r34
- * LID1 is an abbreviation of List Identifier length of 1 byte */
-struct sg_lib_value_name_t sg_lib_xcopy_sa_arr[] = {
- {0x0, 0, "Extended copy(LID1)"},
- {0x1, 0, "Extended copy(LID4)"},
- {0x10, 0, "Populate token"},
- {0x11, 0, "Write using token"},
- {0x1c, 0, "Copy operation abort"},
- {0xffff, 0, NULL},
-};
-
-/* Third party copy out [0x84] service actions
- * Opcode 'Extended copy' was renamed 'Third party copy out' in spc4r34
- * LID4 is an abbreviation of List Identifier length of 4 bytes */
-struct sg_lib_value_name_t sg_lib_rec_copy_sa_arr[] = {
- {0x0, 0, "Receive copy status(LID1)"},
- {0x1, 0, "Receive copy data(LID1)"},
- {0x3, 0, "Receive copy operating parameters"},
- {0x4, 0, "Receive copy failure details(LID1)"},
- {0x5, 0, "Receive copy status(LID4)"},
- {0x6, 0, "Receive copy data(LID4)"},
- {0x7, 0, "Receive ROD token information"},
- {0x8, 0, "Report all ROD tokens"},
- {0xffff, 0, NULL},
-};
-
-/* Variable length cdb [0x7f] service actions (more than 16 bytes long) */
-struct sg_lib_value_name_t sg_lib_variable_length_arr[] = {
- {0x1, 0, "Rebuild(32)"},
- {0x2, 0, "Regenerate(32)"},
- {0x3, 0, "Xdread(32)"}, /* obsolete in SBC-3 r31 */
- {0x4, 0, "Xdwrite(32)"}, /* obsolete in SBC-3 r31 */
- {0x5, 0, "Xdwrite extended(32)"}, /* obsolete in SBC-4 r15 */
- {0x6, 0, "Xpwrite(32)"}, /* obsolete in SBC-4 r15 */
- {0x7, 0, "Xdwriteread(32)"}, /* obsolete in SBC-4 r15 */
- {0x8, 0, "Xdwrite extended(64)"}, /* obsolete in SBC-4 r15 */
- {0x9, 0, "Read(32)"},
- {0xa, 0, "Verify(32)"},
- {0xb, 0, "Write(32)"},
- {0xc, 0, "Write and verify(32)"},
- {0xd, 0, "Write same(32)"},
- {0xe, 0, "Orwrite(32)"}, /* added sbc3r25 */
- {0xf, 0, "Atomic write(32)"}, /* added sbc4r02 */
- {0x10, 0, "Write stream(32)"}, /* added sbc4r07 */
- {0x11, 0, "Write scattered(32)"}, /* added sbc4r11 */
- {0x12, 0, "Get LBA status(32)"}, /* added sbc4r14 */
- {0x1800, 0, "Receive credential"},
- {0x1ff0, 0, "ATA pass-through(32)"},/* added sat4r05 */
- {0x8801, 0, "Format OSD (osd)"},
- {0x8802, 0, "Create (osd)"},
- {0x8803, 0, "List (osd)"},
- {0x8805, 0, "Read (osd)"},
- {0x8806, 0, "Write (osd)"},
- {0x8807, 0, "Append (osd)"},
- {0x8808, 0, "Flush (osd)"},
- {0x880a, 0, "Remove (osd)"},
- {0x880b, 0, "Create partition (osd)"},
- {0x880c, 0, "Remove partition (osd)"},
- {0x880e, 0, "Get attributes (osd)"},
- {0x880f, 0, "Set attributes (osd)"},
- {0x8812, 0, "Create and write (osd)"},
- {0x8815, 0, "Create collection (osd)"},
- {0x8816, 0, "Remove collection (osd)"},
- {0x8817, 0, "List collection (osd)"},
- {0x8818, 0, "Set key (osd)"},
- {0x8819, 0, "Set master key (osd)"},
- {0x881a, 0, "Flush collection (osd)"},
- {0x881b, 0, "Flush partition (osd)"},
- {0x881c, 0, "Flush OSD (osd)"},
- {0x8880, 0, "Object structure check (osd-2)"},
- {0x8881, 0, "Format OSD (osd-2)"},
- {0x8882, 0, "Create (osd-2)"},
- {0x8883, 0, "List (osd-2)"},
- {0x8884, 0, "Punch (osd-2)"},
- {0x8885, 0, "Read (osd-2)"},
- {0x8886, 0, "Write (osd-2)"},
- {0x8887, 0, "Append (osd-2)"},
- {0x8888, 0, "Flush (osd-2)"},
- {0x8889, 0, "Clear (osd-2)"},
- {0x888a, 0, "Remove (osd-2)"},
- {0x888b, 0, "Create partition (osd-2)"},
- {0x888c, 0, "Remove partition (osd-2)"},
- {0x888e, 0, "Get attributes (osd-2)"},
- {0x888f, 0, "Set attributes (osd-2)"},
- {0x8892, 0, "Create and write (osd-2)"},
- {0x8895, 0, "Create collection (osd-2)"},
- {0x8896, 0, "Remove collection (osd-2)"},
- {0x8897, 0, "List collection (osd-2)"},
- {0x8898, 0, "Set key (osd-2)"},
- {0x8899, 0, "Set master key (osd-2)"},
- {0x889a, 0, "Flush collection (osd-2)"},
- {0x889b, 0, "Flush partition (osd-2)"},
- {0x889c, 0, "Flush OSD (osd-2)"},
- {0x88a0, 0, "Query (osd-2)"},
- {0x88a1, 0, "Remove member objects (osd-2)"},
- {0x88a2, 0, "Get member attributes (osd-2)"},
- {0x88a3, 0, "Set member attributes (osd-2)"},
- {0x88b1, 0, "Read map (osd-2)"},
- {0x8f7c, 0, "Perform SCSI command (osd-2)"},
- {0x8f7d, 0, "Perform task management function (osd-2)"},
- {0x8f7e, 0, "Perform SCSI command (osd)"},
- {0x8f7f, 0, "Perform task management function (osd)"},
- {0xffff, 0, NULL},
-};
-
-/* Zoning out [0x94] service actions */
-struct sg_lib_value_name_t sg_lib_zoning_out_arr[] = {
- {0x1, PDT_ZBC, "Close zone"},
- {0x2, PDT_ZBC, "Finish zone"},
- {0x3, PDT_ZBC, "Open zone"},
- {0x4, PDT_ZBC, "Reset write pointer"},
- {0xffff, 0, NULL},
-};
-
-/* Zoning in [0x95] service actions */
-struct sg_lib_value_name_t sg_lib_zoning_in_arr[] = {
- {0x0, PDT_ZBC, "Report zones"},
- {0xffff, 0, NULL},
-};
-
-/* Read attribute [0x8c] service actions */
-struct sg_lib_value_name_t sg_lib_read_attr_arr[] = {
- {0x0, 0, "attribute values"},
- {0x1, 0, "attribute list"},
- {0x2, 0, "logical volume list"},
- {0x3, 0, "partition list"},
- {0x5, 0, "supported attributes"},
- {0xffff, 0, NULL},
-};
-
-#else /* SG_SCSI_STRINGS */
-
-struct sg_lib_value_name_t sg_lib_normal_opcodes[] = {
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_read_buff_arr[] = { /* opcode 0x3c */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_write_buff_arr[] = { /* opcode 0x3b */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_read_pos_arr[] = { /* opcode 0x34 */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_maint_in_arr[] = { /* opcode 0xa3 */
- {0xffff, 0, NULL},
-};
-
-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 0x94 */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_serv_in12_arr[] = { /* opcode 0xab */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_serv_out12_arr[] = { /* opcode 0xa9 */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_serv_in16_arr[] = { /* opcode 0x9e */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_serv_out16_arr[] = { /* opcode 0x9f */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_serv_bidi_arr[] = { /* opcode 0x9d */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_pr_in_arr[] = { /* opcode 0x5e */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_pr_out_arr[] = { /* opcode 0x5f */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_xcopy_sa_arr[] = { /* opcode 0x83 */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_rec_copy_sa_arr[] = { /* opcode 0x84 */
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_variable_length_arr[] = {
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_zoning_out_arr[] = {
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_zoning_in_arr[] = {
- {0xffff, 0, NULL},
-};
-
-struct sg_lib_value_name_t sg_lib_read_attr_arr[] = {
- {0xffff, 0, NULL},
-};
-
-#endif /* SG_SCSI_STRINGS */
-
-/* A conveniently formatted list of SCSI ASC/ASCQ codes and their
- * corresponding text can be found at: www.t10.org/lists/asc-num.txt
- * The following should match asc-num.txt dated 20150423 */
-
-#ifdef SG_SCSI_STRINGS
-struct sg_lib_asc_ascq_range_t sg_lib_asc_ascq_range[] =
-{
- {0x40,0x01,0x7f,"Ram failure [0x%x]"},
- {0x40,0x80,0xff,"Diagnostic failure on component [0x%x]"},
- {0x41,0x01,0xff,"Data path failure [0x%x]"},
- {0x42,0x01,0xff,"Power-on or self-test failure [0x%x]"},
- {0x4d,0x00,0xff,"Tagged overlapped commands [0x%x]"},
- {0x70,0x00,0xff,"Decompression exception short algorithm id of 0x%x"},
- {0, 0, 0, NULL}
-};
-
-struct sg_lib_asc_ascq_t sg_lib_asc_ascq[] =
-{
- {0x00,0x00,"No additional sense information"},
- {0x00,0x01,"Filemark detected"},
- {0x00,0x02,"End-of-partition/medium detected"},
- {0x00,0x03,"Setmark detected"},
- {0x00,0x04,"Beginning-of-partition/medium detected"},
- {0x00,0x05,"End-of-data detected"},
- {0x00,0x06,"I/O process terminated"},
- {0x00,0x07,"Programmable early warning detected"},
- {0x00,0x11,"Audio play operation in progress"},
- {0x00,0x12,"Audio play operation paused"},
- {0x00,0x13,"Audio play operation successfully completed"},
- {0x00,0x14,"Audio play operation stopped due to error"},
- {0x00,0x15,"No current audio status to return"},
- {0x00,0x16,"operation in progress"},
- {0x00,0x17,"Cleaning requested"},
- {0x00,0x18,"Erase operation in progress"},
- {0x00,0x19,"Locate operation in progress"},
- {0x00,0x1a,"Rewind operation in progress"},
- {0x00,0x1b,"Set capacity operation in progress"},
- {0x00,0x1c,"Verify operation in progress"},
- {0x00,0x1d,"ATA pass through information available"},
- {0x00,0x1e,"Conflicting SA creation request"},
- {0x00,0x1f,"Logical unit transitioning to another power condition"},
- {0x00,0x20,"Extended copy information available"},
- {0x00,0x21,"Atomic command aborted due to ACA"},
- {0x00,0x22,"Deferred microcode is pending"},
- {0x01,0x00,"No index/sector signal"},
- {0x02,0x00,"No seek complete"},
- {0x03,0x00,"Peripheral device write fault"},
- {0x03,0x01,"No write current"},
- {0x03,0x02,"Excessive write errors"},
- {0x04,0x00,"Logical unit not ready, cause not reportable"},
- {0x04,0x01,"Logical unit is in process of becoming ready"},
- {0x04,0x02,"Logical unit not ready, "
- "initializing command required"},
- {0x04,0x03,"Logical unit not ready, "
- "manual intervention required"},
- {0x04,0x04,"Logical unit not ready, format in progress"},
- {0x04,0x05,"Logical unit not ready, rebuild in progress"},
- {0x04,0x06,"Logical unit not ready, recalculation in progress"},
- {0x04,0x07,"Logical unit not ready, operation in progress"},
- {0x04,0x08,"Logical unit not ready, long write in progress"},
- {0x04,0x09,"Logical unit not ready, self-test in progress"},
- {0x04,0x0a,"Logical unit "
- "not accessible, asymmetric access state transition"},
- {0x04,0x0b,"Logical unit "
- "not accessible, target port in standby state"},
- {0x04,0x0c,"Logical unit "
- "not accessible, target port in unavailable state"},
- {0x04,0x0d,"Logical unit not ready, structure check required"},
- {0x04,0x0e,"Logical unit not ready, security session in progress"},
- {0x04,0x10,"Logical unit not ready, "
- "auxiliary memory not accessible"},
- {0x04,0x11,"Logical unit not ready, "
- "notify (enable spinup) required"},
- {0x04,0x12,"Logical unit not ready, offline"},
- {0x04,0x13,"Logical unit not ready, SA creation in progress"},
- {0x04,0x14,"Logical unit not ready, space allocation in progress"},
- {0x04,0x15,"Logical unit not ready, robotics disabled"},
- {0x04,0x16,"Logical unit not ready, configuration required"},
- {0x04,0x17,"Logical unit not ready, calibration required"},
- {0x04,0x18,"Logical unit not ready, a door is open"},
- {0x04,0x19,"Logical unit not ready, operating in sequential mode"},
- {0x04,0x1a,"Logical unit not ready, start stop unit command in progress"},
- {0x04,0x1b,"Logical unit not ready, sanitize in progress"},
- {0x04,0x1c,"Logical unit not ready, additional power use not yet "
- "granted"},
- {0x04,0x1d,"Logical unit not ready, configuration in progress"},
- {0x04,0x1e,"Logical unit not ready, microcode activation required"},
- {0x04,0x1f,"Logical unit not ready, microcode download required"},
- {0x04,0x20,"Logical unit not ready, logical unit reset required"},
- {0x04,0x21,"Logical unit not ready, hard reset required"},
- {0x04,0x22,"Logical unit not ready, power cycle required"},
- {0x04,0x23,"Logical unit not ready, affiliation required"},
- {0x05,0x00,"Logical unit does not respond to selection"},
- {0x06,0x00,"No reference position found"},
- {0x07,0x00,"Multiple peripheral devices selected"},
- {0x08,0x00,"Logical unit communication failure"},
- {0x08,0x01,"Logical unit communication time-out"},
- {0x08,0x02,"Logical unit communication parity error"},
- {0x08,0x03,"Logical unit communication CRC error (Ultra-DMA/32)"},
- {0x08,0x04,"Unreachable copy target"},
- {0x09,0x00,"Track following error"},
- {0x09,0x01,"Tracking servo failure"},
- {0x09,0x02,"Focus servo failure"},
- {0x09,0x03,"Spindle servo failure"},
- {0x09,0x04,"Head select fault"},
- {0x09,0x05,"Vibration induced tracking error"},
- {0x0A,0x00,"Error log overflow"},
- {0x0B,0x00,"Warning"},
- {0x0B,0x01,"Warning - specified temperature exceeded"},
- {0x0B,0x02,"Warning - enclosure degraded"},
- {0x0B,0x03,"Warning - background self-test failed"},
- {0x0B,0x04,"Warning - background pre-scan detected medium error"},
- {0x0B,0x05,"Warning - background medium scan detected medium error"},
- {0x0B,0x06,"Warning - non-volatile cache now volatile"},
- {0x0B,0x07,"Warning - degraded power to non-volatile cache"},
- {0x0B,0x08,"Warning - power loss expected"},
- {0x0B,0x09,"Warning - device statistics notification active"},
- {0x0B,0x0A,"Warning - high critical temperature limit exceeded"},
- {0x0B,0x0B,"Warning - low critical temperature limit exceeded"},
- {0x0B,0x0C,"Warning - high operating temperature limit exceeded"},
- {0x0B,0x0D,"Warning - low operating temperature limit exceeded"},
- {0x0B,0x0E,"Warning - high critical humidity limit exceeded"},
- {0x0B,0x0F,"Warning - low critical humidity limit exceeded"},
- {0x0B,0x10,"Warning - high operating humidity limit exceeded"},
- {0x0B,0x11,"Warning - low operating humidity limit exceeded"},
- {0x0B,0x12,"Warning - microcode security at risk"},
- {0x0B,0x13,"Warning - microcode digital signature validation failure"},
- {0x0C,0x00,"Write error"},
- {0x0C,0x01,"Write error - recovered with auto reallocation"},
- {0x0C,0x02,"Write error - auto reallocation failed"},
- {0x0C,0x03,"Write error - recommend reassignment"},
- {0x0C,0x04,"Compression check miscompare error"},
- {0x0C,0x05,"Data expansion occurred during compression"},
- {0x0C,0x06,"Block not compressible"},
- {0x0C,0x07,"Write error - recovery needed"},
- {0x0C,0x08,"Write error - recovery failed"},
- {0x0C,0x09,"Write error - loss of streaming"},
- {0x0C,0x0A,"Write error - padding blocks added"},
- {0x0C,0x0B,"Auxiliary memory write error"},
- {0x0C,0x0C,"Write error - unexpected unsolicited data"},
- {0x0C,0x0D,"Write error - not enough unsolicited data"},
- {0x0C,0x0E,"Multiple write errors"},
- {0x0C,0x0F,"Defects in error window"},
- {0x0C,0x10,"Incomplete multiple atomic write operations"},
- {0x0C,0x11,"Write error - recovery scan needed"},
- {0x0C,0x12,"Write error - insufficient zone resources"},
- {0x0D,0x00,"Error detected by third party temporary initiator"},
- {0x0D,0x01,"Third party device failure"},
- {0x0D,0x02,"Copy target device not reachable"},
- {0x0D,0x03,"Incorrect copy target device type"},
- {0x0D,0x04,"Copy target device data underrun"},
- {0x0D,0x05,"Copy target device data overrun"},
- {0x0E,0x00,"Invalid information unit"},
- {0x0E,0x01,"Information unit too short"},
- {0x0E,0x02,"Information unit too long"},
- {0x0E,0x03,"Invalid field in command information unit"},
- {0x10,0x00,"Id CRC or ECC error"},
- {0x10,0x01,"Logical block guard check failed"},
- {0x10,0x02,"Logical block application tag check failed"},
- {0x10,0x03,"Logical block reference tag check failed"},
- {0x10,0x04,"Logical block protection error on recover buffered data"},
- {0x10,0x05,"Logical block protection method error"},
- {0x11,0x00,"Unrecovered read error"},
- {0x11,0x01,"Read retries exhausted"},
- {0x11,0x02,"Error too long to correct"},
- {0x11,0x03,"Multiple read errors"},
- {0x11,0x04,"Unrecovered read error - auto reallocate failed"},
- {0x11,0x05,"L-EC uncorrectable error"},
- {0x11,0x06,"CIRC unrecovered error"},
- {0x11,0x07,"Data re-synchronization error"},
- {0x11,0x08,"Incomplete block read"},
- {0x11,0x09,"No gap found"},
- {0x11,0x0A,"Miscorrected error"},
- {0x11,0x0B,"Unrecovered read error - recommend reassignment"},
- {0x11,0x0C,"Unrecovered read error - recommend rewrite the data"},
- {0x11,0x0D,"De-compression CRC error"},
- {0x11,0x0E,"Cannot decompress using declared algorithm"},
- {0x11,0x0F,"Error reading UPC/EAN number"},
- {0x11,0x10,"Error reading ISRC number"},
- {0x11,0x11,"Read error - loss of streaming"},
- {0x11,0x12,"Auxiliary memory read error"},
- {0x11,0x13,"Read error - failed retransmission request"},
- {0x11,0x14,"Read error - LBA marked bad by application client"},
- {0x11,0x15,"Write after sanitize required"},
- {0x12,0x00,"Address mark not found for id field"},
- {0x13,0x00,"Address mark not found for data field"},
- {0x14,0x00,"Recorded entity not found"},
- {0x14,0x01,"Record not found"},
- {0x14,0x02,"Filemark or setmark not found"},
- {0x14,0x03,"End-of-data not found"},
- {0x14,0x04,"Block sequence error"},
- {0x14,0x05,"Record not found - recommend reassignment"},
- {0x14,0x06,"Record not found - data auto-reallocated"},
- {0x14,0x07,"Locate operation failure"},
- {0x15,0x00,"Random positioning error"},
- {0x15,0x01,"Mechanical positioning error"},
- {0x15,0x02,"Positioning error detected by read of medium"},
- {0x16,0x00,"Data synchronization mark error"},
- {0x16,0x01,"Data sync error - data rewritten"},
- {0x16,0x02,"Data sync error - recommend rewrite"},
- {0x16,0x03,"Data sync error - data auto-reallocated"},
- {0x16,0x04,"Data sync error - recommend reassignment"},
- {0x17,0x00,"Recovered data with no error correction applied"},
- {0x17,0x01,"Recovered data with retries"},
- {0x17,0x02,"Recovered data with positive head offset"},
- {0x17,0x03,"Recovered data with negative head offset"},
- {0x17,0x04,"Recovered data with retries and/or circ applied"},
- {0x17,0x05,"Recovered data using previous sector id"},
- {0x17,0x06,"Recovered data without ECC - data auto-reallocated"},
- {0x17,0x07,"Recovered data without ECC - recommend reassignment"},
- {0x17,0x08,"Recovered data without ECC - recommend rewrite"},
- {0x17,0x09,"Recovered data without ECC - data rewritten"},
- {0x18,0x00,"Recovered data with error correction applied"},
- {0x18,0x01,"Recovered data with error corr. & retries applied"},
- {0x18,0x02,"Recovered data - data auto-reallocated"},
- {0x18,0x03,"Recovered data with CIRC"},
- {0x18,0x04,"Recovered data with L-EC"},
- {0x18,0x05,"Recovered data - recommend reassignment"},
- {0x18,0x06,"Recovered data - recommend rewrite"},
- {0x18,0x07,"Recovered data with ECC - data rewritten"},
- {0x18,0x08,"Recovered data with linking"},
- {0x19,0x00,"Defect list error"},
- {0x19,0x01,"Defect list not available"},
- {0x19,0x02,"Defect list error in primary list"},
- {0x19,0x03,"Defect list error in grown list"},
- {0x1A,0x00,"Parameter list length error"},
- {0x1B,0x00,"Synchronous data transfer error"},
- {0x1C,0x00,"Defect list not found"},
- {0x1C,0x01,"Primary defect list not found"},
- {0x1C,0x02,"Grown defect list not found"},
- {0x1D,0x00,"Miscompare during verify operation"},
- {0x1D,0x01,"Miscompare verify of unmapped lba"},
- {0x1E,0x00,"Recovered id with ECC correction"},
- {0x1F,0x00,"Partial defect list transfer"},
- {0x20,0x00,"Invalid command operation code"},
- {0x20,0x01,"Access denied - initiator pending-enrolled"},
- {0x20,0x02,"Access denied - no access rights"},
- {0x20,0x03,"Access denied - invalid mgmt id key"},
- {0x20,0x04,"Illegal command while in write capable state"},
- {0x20,0x05,"Write type operation while in read capable state (obs)"},
- {0x20,0x06,"Illegal command while in explicit address mode"},
- {0x20,0x07,"Illegal command while in implicit address mode"},
- {0x20,0x08,"Access denied - enrollment conflict"},
- {0x20,0x09,"Access denied - invalid LU identifier"},
- {0x20,0x0A,"Access denied - invalid proxy token"},
- {0x20,0x0B,"Access denied - ACL LUN conflict"},
- {0x20,0x0C,"Illegal command when not in append-only mode"},
- {0x20,0x0D,"Not an administrative logical unit"},
- {0x20,0x0E,"Not a subsidiary logical unit"},
- {0x20,0x0F,"Not a conglomerate logical unit"},
- {0x21,0x00,"Logical block address out of range"},
- {0x21,0x01,"Invalid element address"},
- {0x21,0x02,"Invalid address for write"},
- {0x21,0x03,"Invalid write crossing layer jump"},
- {0x21,0x04,"Unaligned write command"},
- {0x21,0x05,"Write boundary violation"},
- {0x21,0x06,"Attempt to read invalid data"},
- {0x21,0x07,"Read boundary violation"},
- {0x21,0x08,"Misaligned write command"},
- {0x22,0x00,"Illegal function (use 20 00, 24 00, or 26 00)"},
- {0x23,0x00,"Invalid token operation, cause not reportable"},
- {0x23,0x01,"Invalid token operation, unsupported token type"},
- {0x23,0x02,"Invalid token operation, remote token usage not supported"},
- {0x23,0x03,"invalid token operation, remote rod token creation not "
- "supported"},
- {0x23,0x04,"Invalid token operation, token unknown"},
- {0x23,0x05,"Invalid token operation, token corrupt"},
- {0x23,0x06,"Invalid token operation, token revoked"},
- {0x23,0x07,"Invalid token operation, token expired"},
- {0x23,0x08,"Invalid token operation, token cancelled"},
- {0x23,0x09,"Invalid token operation, token deleted"},
- {0x23,0x0a,"Invalid token operation, invalid token length"},
- {0x24,0x00,"Invalid field in cdb"},
- {0x24,0x01,"CDB decryption error"},
- {0x24,0x02,"Invalid cdb field while in explicit block model (obs)"},
- {0x24,0x03,"Invalid cdb field while in implicit block model (obs)"},
- {0x24,0x04,"Security audit value frozen"},
- {0x24,0x05,"Security working key frozen"},
- {0x24,0x06,"Nonce not unique"},
- {0x24,0x07,"Nonce timestamp out of range"},
- {0x24,0x08,"Invalid xcdb"},
- {0x24,0x09,"Invalid fast format"},
- {0x25,0x00,"Logical unit not supported"},
- {0x26,0x00,"Invalid field in parameter list"},
- {0x26,0x01,"Parameter not supported"},
- {0x26,0x02,"Parameter value invalid"},
- {0x26,0x03,"Threshold parameters not supported"},
- {0x26,0x04,"Invalid release of persistent reservation"},
- {0x26,0x05,"Data decryption error"},
- {0x26,0x06,"Too many target descriptors"},
- {0x26,0x07,"Unsupported target descriptor type code"},
- {0x26,0x08,"Too many segment descriptors"},
- {0x26,0x09,"Unsupported segment descriptor type code"},
- {0x26,0x0A,"Unexpected inexact segment"},
- {0x26,0x0B,"Inline data length exceeded"},
- {0x26,0x0C,"Invalid operation for copy source or destination"},
- {0x26,0x0D,"Copy segment granularity violation"},
- {0x26,0x0E,"Invalid parameter while port is enabled"},
- {0x26,0x0F,"Invalid data-out buffer integrity check value"},
- {0x26,0x10,"Data decryption key fail limit reached"},
- {0x26,0x11,"Incomplete key-associated data set"},
- {0x26,0x12,"Vendor specific key reference not found"},
- {0x26,0x13,"Application tag mode page is invalid"},
- {0x26,0x14,"Tape stream mirroring prevented"},
- {0x26,0x15,"Copy source or copy destination not authorized"},
- {0x27,0x00,"Write protected"},
- {0x27,0x01,"Hardware write protected"},
- {0x27,0x02,"Logical unit software write protected"},
- {0x27,0x03,"Associated write protect"},
- {0x27,0x04,"Persistent write protect"},
- {0x27,0x05,"Permanent write protect"},
- {0x27,0x06,"Conditional write protect"},
- {0x27,0x07,"Space allocation failed write protect"},
- {0x27,0x08,"Zone is read only"},
- {0x28,0x00,"Not ready to ready change, medium may have changed"},
- {0x28,0x01,"Import or export element accessed"},
- {0x28,0x02,"Format-layer may have changed"},
- {0x28,0x03,"Import/export element accessed, medium changed"},
- {0x29,0x00,"Power on, reset, or bus device reset occurred"},
- {0x29,0x01,"Power on occurred"},
- {0x29,0x02,"SCSI bus reset occurred"},
- {0x29,0x03,"Bus device reset function occurred"},
- {0x29,0x04,"Device internal reset"},
- {0x29,0x05,"Transceiver mode changed to single-ended"},
- {0x29,0x06,"Transceiver mode changed to lvd"},
- {0x29,0x07,"I_T nexus loss occurred"},
- {0x2A,0x00,"Parameters changed"},
- {0x2A,0x01,"Mode parameters changed"},
- {0x2A,0x02,"Log parameters changed"},
- {0x2A,0x03,"Reservations preempted"},
- {0x2A,0x04,"Reservations released"},
- {0x2A,0x05,"Registrations preempted"},
- {0x2A,0x06,"Asymmetric access state changed"},
- {0x2A,0x07,"Implicit asymmetric access state transition failed"},
- {0x2A,0x08,"Priority changed"},
- {0x2A,0x09,"Capacity data has changed"},
- {0x2A,0x0c, "Error recovery attributes have changed"},
- {0x2A,0x0d, "Data encryption capabilities changed"},
- {0x2A,0x10,"Timestamp changed"},
- {0x2A,0x11,"Data encryption parameters changed by another i_t nexus"},
- {0x2A,0x12,"Data encryption parameters changed by vendor specific event"},
- {0x2A,0x13,"Data encryption key instance counter has changed"},
- {0x2A,0x0a,"Error history i_t nexus cleared"},
- {0x2A,0x0b,"Error history snapshot released"},
- {0x2A,0x14,"SA creation capabilities data has changed"},
- {0x2A,0x15,"Medium removal prevention preempted"},
- {0x2A,0x16,"Zone reset write pointer recommended"},
- {0x2B,0x00,"Copy cannot execute since host cannot disconnect"},
- {0x2C,0x00,"Command sequence error"},
- {0x2C,0x01,"Too many windows specified"},
- {0x2C,0x02,"Invalid combination of windows specified"},
- {0x2C,0x03,"Current program area is not empty"},
- {0x2C,0x04,"Current program area is empty"},
- {0x2C,0x05,"Illegal power condition request"},
- {0x2C,0x06,"Persistent prevent conflict"},
- {0x2C,0x07,"Previous busy status"},
- {0x2C,0x08,"Previous task set full status"},
- {0x2C,0x09,"Previous reservation conflict status"},
- {0x2C,0x0A,"Partition or collection contains user objects"},
- {0x2C,0x0B,"Not reserved"},
- {0x2C,0x0C,"ORWRITE generation does not match"},
- {0x2C,0x0D,"Reset write pointer not allowed"},
- {0x2C,0x0E,"Zone is offline"},
- {0x2C,0x0F,"Stream not open"},
- {0x2C,0x10,"Unwritten data in zone"},
- {0x2C,0x11,"Descriptor format sense data required"},
- {0x2D,0x00,"Overwrite error on update in place"},
- {0x2E,0x00,"Insufficient time for operation"},
- {0x2E,0x01,"Command timeout before processing"},
- {0x2E,0x02,"Command timeout during processing"},
- {0x2E,0x03,"Command timeout during processing due to error recovery"},
- {0x2F,0x00,"Commands cleared by another initiator"},
- {0x2F,0x01,"Commands cleared by power loss notification"},
- {0x2F,0x02,"Commands cleared by device server"},
- {0x2F,0x03,"Some commands cleared by queuing layer event"},
- {0x30,0x00,"Incompatible medium installed"},
- {0x30,0x01,"Cannot read medium - unknown format"},
- {0x30,0x02,"Cannot read medium - incompatible format"},
- {0x30,0x03,"Cleaning cartridge installed"},
- {0x30,0x04,"Cannot write medium - unknown format"},
- {0x30,0x05,"Cannot write medium - incompatible format"},
- {0x30,0x06,"Cannot format medium - incompatible medium"},
- {0x30,0x07,"Cleaning failure"},
- {0x30,0x08,"Cannot write - application code mismatch"},
- {0x30,0x09,"Current session not fixated for append"},
- {0x30,0x0A,"Cleaning request rejected"},
- {0x30,0x0B,"Cleaning tape expired"},
- {0x30,0x0C,"WORM medium - overwrite attempted"},
- {0x30,0x0D,"WORM medium - integrity check"},
- {0x30,0x10,"Medium not formatted"},
- {0x30,0x11,"Incompatible volume type"},
- {0x30,0x12,"Incompatible volume qualifier"},
- {0x30,0x13,"Cleaning volume expired"},
- {0x31,0x00,"Medium format corrupted"},
- {0x31,0x01,"Format command failed"},
- {0x31,0x02,"Zoned formatting failed due to spare linking"},
- {0x31,0x03,"Sanitize command failed"},
- {0x32,0x00,"No defect spare location available"},
- {0x32,0x01,"Defect list update failure"},
- {0x33,0x00,"Tape length error"},
- {0x34,0x00,"Enclosure failure"},
- {0x35,0x00,"Enclosure services failure"},
- {0x35,0x01,"Unsupported enclosure function"},
- {0x35,0x02,"Enclosure services unavailable"},
- {0x35,0x03,"Enclosure services transfer failure"},
- {0x35,0x04,"Enclosure services transfer refused"},
- {0x35,0x05,"Enclosure services checksum error"},
- {0x36,0x00,"Ribbon, ink, or toner failure"},
- {0x37,0x00,"Rounded parameter"},
- {0x38,0x00,"Event status notification"},
- {0x38,0x02,"Esn - power management class event"},
- {0x38,0x04,"Esn - media class event"},
- {0x38,0x06,"Esn - device busy class event"},
- {0x38,0x07,"Thin provisioning soft threshold reached"},
- {0x39,0x00,"Saving parameters not supported"},
- {0x3A,0x00,"Medium not present"},
- {0x3A,0x01,"Medium not present - tray closed"},
- {0x3A,0x02,"Medium not present - tray open"},
- {0x3A,0x03,"Medium not present - loadable"},
- {0x3A,0x04,"Medium not present - medium auxiliary memory accessible"},
- {0x3B,0x00,"Sequential positioning error"},
- {0x3B,0x01,"Tape position error at beginning-of-medium"},
- {0x3B,0x02,"Tape position error at end-of-medium"},
- {0x3B,0x03,"Tape or electronic vertical forms unit not ready"},
- {0x3B,0x04,"Slew failure"},
- {0x3B,0x05,"Paper jam"},
- {0x3B,0x06,"Failed to sense top-of-form"},
- {0x3B,0x07,"Failed to sense bottom-of-form"},
- {0x3B,0x08,"Reposition error"},
- {0x3B,0x09,"Read past end of medium"},
- {0x3B,0x0A,"Read past beginning of medium"},
- {0x3B,0x0B,"Position past end of medium"},
- {0x3B,0x0C,"Position past beginning of medium"},
- {0x3B,0x0D,"Medium destination element full"},
- {0x3B,0x0E,"Medium source element empty"},
- {0x3B,0x0F,"End of medium reached"},
- {0x3B,0x11,"Medium magazine not accessible"},
- {0x3B,0x12,"Medium magazine removed"},
- {0x3B,0x13,"Medium magazine inserted"},
- {0x3B,0x14,"Medium magazine locked"},
- {0x3B,0x15,"Medium magazine unlocked"},
- {0x3B,0x16,"Mechanical positioning or changer error"},
- {0x3B,0x17,"Read past end of user object"},
- {0x3B,0x18,"Element disabled"},
- {0x3B,0x19,"Element enabled"},
- {0x3B,0x1a,"Data transfer device removed"},
- {0x3B,0x1b,"Data transfer device inserted"},
- {0x3B,0x1c,"Too many logical objects on partition to support operation"},
- {0x3D,0x00,"Invalid bits in identify message"},
- {0x3E,0x00,"Logical unit has not self-configured yet"},
- {0x3E,0x01,"Logical unit failure"},
- {0x3E,0x02,"Timeout on logical unit"},
- {0x3E,0x03,"Logical unit failed self-test"},
- {0x3E,0x04,"Logical unit unable to update self-test log"},
- {0x3F,0x00,"Target operating conditions have changed"},
- {0x3F,0x01,"Microcode has been changed"},
- {0x3F,0x02,"Changed operating definition"},
- {0x3F,0x03,"Inquiry data has changed"},
- {0x3F,0x04,"Component device attached"},
- {0x3F,0x05,"Device identifier changed"},
- {0x3F,0x06,"Redundancy group created or modified"},
- {0x3F,0x07,"Redundancy group deleted"},
- {0x3F,0x08,"Spare created or modified"},
- {0x3F,0x09,"Spare deleted"},
- {0x3F,0x0A,"Volume set created or modified"},
- {0x3F,0x0B,"Volume set deleted"},
- {0x3F,0x0C,"Volume set deassigned"},
- {0x3F,0x0D,"Volume set reassigned"},
- {0x3F,0x0E,"Reported luns data has changed"},
- {0x3F,0x0F,"Echo buffer overwritten"},
- {0x3F,0x10,"Medium loadable"},
- {0x3F,0x11,"Medium auxiliary memory accessible"},
- {0x3F,0x12,"iSCSI IP address added"},
- {0x3F,0x13,"iSCSI IP address removed"},
- {0x3F,0x14,"iSCSI IP address changed"},
- {0x3F,0x15,"Inspect referrals sense descriptors"},
- {0x3F,0x16,"Microcode has been changed without reset"},
- {0x3F,0x17,"Zone transition to full"},
- {0x3F,0x18,"Bind completed"},
- {0x3F,0x19,"Bind redirected"},
- {0x3F,0x1A,"Subsidiary binding changed"},
-
- /*
- * ASC 0x40, 0x41 and 0x42 overridden by "additional2" array entries
- * for ascq > 1. Preferred error message for this group is
- * "Diagnostic failure on component nn (80h-ffh)".
- */
- {0x40,0x00,"Ram failure (should use 40 nn)"},
- {0x41,0x00,"Data path failure (should use 40 nn)"},
- {0x42,0x00,"Power-on or self-test failure (should use 40 nn)"},
-
- {0x43,0x00,"Message error"},
- {0x44,0x00,"Internal target failure"},
- {0x44,0x01,"Persistent reservation information lost"},
- {0x44,0x71,"ATA device failed Set Features"},
- {0x45,0x00,"Select or reselect failure"},
- {0x46,0x00,"Unsuccessful soft reset"},
- {0x47,0x00,"SCSI parity error"},
- {0x47,0x01,"Data phase CRC error detected"},
- {0x47,0x02,"SCSI parity error detected during st data phase"},
- {0x47,0x03,"Information unit iuCRC error detected"},
- {0x47,0x04,"Asynchronous information protection error detected"},
- {0x47,0x05,"Protocol service CRC error"},
- {0x47,0x06,"Phy test function in progress"},
- {0x47,0x7F,"Some commands cleared by iSCSI protocol event"},
- {0x48,0x00,"Initiator detected error message received"},
- {0x49,0x00,"Invalid message error"},
- {0x4A,0x00,"Command phase error"},
- {0x4B,0x00,"Data phase error"},
- {0x4B,0x01,"Invalid target port transfer tag received"},
- {0x4B,0x02,"Too much write data"},
- {0x4B,0x03,"Ack/nak timeout"},
- {0x4B,0x04,"Nak received"},
- {0x4B,0x05,"Data offset error"},
- {0x4B,0x06,"Initiator response timeout"},
- {0x4B,0x07,"Connection lost"},
- {0x4B,0x08,"Data-in buffer overflow - data buffer size"},
- {0x4B,0x09,"Data-in buffer overflow - data buffer descriptor area"},
- {0x4B,0x0A,"Data-in buffer error"},
- {0x4B,0x0B,"Data-out buffer overflow - data buffer size"},
- {0x4B,0x0C,"Data-out buffer overflow - data buffer descriptor area"},
- {0x4B,0x0D,"Data-out buffer error"},
- {0x4B,0x0E,"PCIe fabric error"},
- {0x4B,0x0f,"PCIe completion timeout"},
- {0x4B,0x10,"PCIe completer abort"},
- {0x4B,0x11,"PCIe poisoned tlp received"},
- {0x4B,0x12,"PCIe ecrc check failed"},
- {0x4B,0x13,"PCIe unsupported request"},
- {0x4B,0x14,"PCIe acs violation"},
- {0x4B,0x15,"PCIe tlp prefix blocked"},
- {0x4C,0x00,"Logical unit failed self-configuration"},
- /*
- * ASC 0x4D overridden by an "additional2" array entry
- * so there is no need to have them here.
- */
- /* {0x4D,0x00,"Tagged overlapped commands (nn = queue tag)"}, */
-
- {0x4E,0x00,"Overlapped commands attempted"},
- {0x50,0x00,"Write append error"},
- {0x50,0x01,"Write append position error"},
- {0x50,0x02,"Position error related to timing"},
- {0x51,0x00,"Erase failure"},
- {0x51,0x01,"Erase failure - incomplete erase operation detected"},
- {0x52,0x00,"Cartridge fault"},
- {0x53,0x00,"Media load or eject failed"},
- {0x53,0x01,"Unload tape failure"},
- {0x53,0x02,"Medium removal prevented"},
- {0x53,0x03,"Medium removal prevented by data transfer element"},
- {0x53,0x04,"Medium thread or unthread failure"},
- {0x53,0x05,"Volume identifier invalid"},
- {0x53,0x06,"Volume identifier missing"},
- {0x53,0x07,"Duplicate volume identifier"},
- {0x53,0x08,"Element status unknown"},
- {0x53,0x09,"Data transfer device error - load failed"},
- {0x53,0x0A,"Data transfer device error - unload failed"},
- {0x53,0x0B,"Data transfer device error - unload missing"},
- {0x53,0x0C,"Data transfer device error - eject failed"},
- {0x53,0x0D,"Data transfer device error - library communication failed"},
- {0x54,0x00,"SCSI to host system interface failure"},
- {0x55,0x00,"System resource failure"},
- {0x55,0x01,"System buffer full"},
- {0x55,0x02,"Insufficient reservation resources"},
- {0x55,0x03,"Insufficient resources"},
- {0x55,0x04,"Insufficient registration resources"},
- {0x55,0x05,"Insufficient access control resources"},
- {0x55,0x06,"Auxiliary memory out of space"},
- {0x55,0x07,"Quota error"},
- {0x55,0x08,"Maximum number of supplemental decryption keys exceeded"},
- {0x55,0x09,"Medium auxiliary memory not accessible"},
- {0x55,0x0a,"Data currently unavailable"},
- {0x55,0x0b,"Insufficient power for operation"},
- {0x55,0x0c,"Insufficient resources to create rod"},
- {0x55,0x0d,"Insufficient resources to create rod token"},
- {0x55,0x0e,"Insufficient zone resources"},
- {0x55,0x0f,"Insufficient zone resources to complete write"},
- {0x55,0x10,"Maximum number of streams open"},
- {0x55,0x11,"Insufficient resources to bind"},
- {0x57,0x00,"Unable to recover table-of-contents"},
- {0x58,0x00,"Generation does not exist"},
- {0x59,0x00,"Updated block read"},
- {0x5A,0x00,"Operator request or state change input"},
- {0x5A,0x01,"Operator medium removal request"},
- {0x5A,0x02,"Operator selected write protect"},
- {0x5A,0x03,"Operator selected write permit"},
- {0x5B,0x00,"Log exception"},
- {0x5B,0x01,"Threshold condition met"},
- {0x5B,0x02,"Log counter at maximum"},
- {0x5B,0x03,"Log list codes exhausted"},
- {0x5C,0x00,"Rpl status change"},
- {0x5C,0x01,"Spindles synchronized"},
- {0x5C,0x02,"Spindles not synchronized"},
- {0x5D,0x00,"Failure prediction threshold exceeded"},
- {0x5D,0x01,"Media failure prediction threshold exceeded"},
- {0x5D,0x02,"Logical unit failure prediction threshold exceeded"},
- {0x5D,0x03,"spare area exhaustion prediction threshold exceeded"},
- {0x5D,0x10,"Hardware impending failure general hard drive failure"},
- {0x5D,0x11,"Hardware impending failure drive error rate too high" },
- {0x5D,0x12,"Hardware impending failure data error rate too high" },
- {0x5D,0x13,"Hardware impending failure seek error rate too high" },
- {0x5D,0x14,"Hardware impending failure too many block reassigns"},
- {0x5D,0x15,"Hardware impending failure access times too high" },
- {0x5D,0x16,"Hardware impending failure start unit times too high" },
- {0x5D,0x17,"Hardware impending failure channel parametrics"},
- {0x5D,0x18,"Hardware impending failure controller detected"},
- {0x5D,0x19,"Hardware impending failure throughput performance"},
- {0x5D,0x1A,"Hardware impending failure seek time performance"},
- {0x5D,0x1B,"Hardware impending failure spin-up retry count"},
- {0x5D,0x1C,"Hardware impending failure drive calibration retry count"},
- {0x5D,0x1D,"Hardware impending failure power loss protection circuit"},
- {0x5D,0x20,"Controller impending failure general hard drive failure"},
- {0x5D,0x21,"Controller impending failure drive error rate too high" },
- {0x5D,0x22,"Controller impending failure data error rate too high" },
- {0x5D,0x23,"Controller impending failure seek error rate too high" },
- {0x5D,0x24,"Controller impending failure too many block reassigns"},
- {0x5D,0x25,"Controller impending failure access times too high" },
- {0x5D,0x26,"Controller impending failure start unit times too high" },
- {0x5D,0x27,"Controller impending failure channel parametrics"},
- {0x5D,0x28,"Controller impending failure controller detected"},
- {0x5D,0x29,"Controller impending failure throughput performance"},
- {0x5D,0x2A,"Controller impending failure seek time performance"},
- {0x5D,0x2B,"Controller impending failure spin-up retry count"},
- {0x5D,0x2C,"Controller impending failure drive calibration retry count"},
- {0x5D,0x30,"Data channel impending failure general hard drive failure"},
- {0x5D,0x31,"Data channel impending failure drive error rate too high" },
- {0x5D,0x32,"Data channel impending failure data error rate too high" },
- {0x5D,0x33,"Data channel impending failure seek error rate too high" },
- {0x5D,0x34,"Data channel impending failure too many block reassigns"},
- {0x5D,0x35,"Data channel impending failure access times too high" },
- {0x5D,0x36,"Data channel impending failure start unit times too high" },
- {0x5D,0x37,"Data channel impending failure channel parametrics"},
- {0x5D,0x38,"Data channel impending failure controller detected"},
- {0x5D,0x39,"Data channel impending failure throughput performance"},
- {0x5D,0x3A,"Data channel impending failure seek time performance"},
- {0x5D,0x3B,"Data channel impending failure spin-up retry count"},
- {0x5D,0x3C,"Data channel impending failure drive calibration retry count"},
- {0x5D,0x40,"Servo impending failure general hard drive failure"},
- {0x5D,0x41,"Servo impending failure drive error rate too high" },
- {0x5D,0x42,"Servo impending failure data error rate too high" },
- {0x5D,0x43,"Servo impending failure seek error rate too high" },
- {0x5D,0x44,"Servo impending failure too many block reassigns"},
- {0x5D,0x45,"Servo impending failure access times too high" },
- {0x5D,0x46,"Servo impending failure start unit times too high" },
- {0x5D,0x47,"Servo impending failure channel parametrics"},
- {0x5D,0x48,"Servo impending failure controller detected"},
- {0x5D,0x49,"Servo impending failure throughput performance"},
- {0x5D,0x4A,"Servo impending failure seek time performance"},
- {0x5D,0x4B,"Servo impending failure spin-up retry count"},
- {0x5D,0x4C,"Servo impending failure drive calibration retry count"},
- {0x5D,0x50,"Spindle impending failure general hard drive failure"},
- {0x5D,0x51,"Spindle impending failure drive error rate too high" },
- {0x5D,0x52,"Spindle impending failure data error rate too high" },
- {0x5D,0x53,"Spindle impending failure seek error rate too high" },
- {0x5D,0x54,"Spindle impending failure too many block reassigns"},
- {0x5D,0x55,"Spindle impending failure access times too high" },
- {0x5D,0x56,"Spindle impending failure start unit times too high" },
- {0x5D,0x57,"Spindle impending failure channel parametrics"},
- {0x5D,0x58,"Spindle impending failure controller detected"},
- {0x5D,0x59,"Spindle impending failure throughput performance"},
- {0x5D,0x5A,"Spindle impending failure seek time performance"},
- {0x5D,0x5B,"Spindle impending failure spin-up retry count"},
- {0x5D,0x5C,"Spindle impending failure drive calibration retry count"},
- {0x5D,0x60,"Firmware impending failure general hard drive failure"},
- {0x5D,0x61,"Firmware impending failure drive error rate too high" },
- {0x5D,0x62,"Firmware impending failure data error rate too high" },
- {0x5D,0x63,"Firmware impending failure seek error rate too high" },
- {0x5D,0x64,"Firmware impending failure too many block reassigns"},
- {0x5D,0x65,"Firmware impending failure access times too high" },
- {0x5D,0x66,"Firmware impending failure start unit times too high" },
- {0x5D,0x67,"Firmware impending failure channel parametrics"},
- {0x5D,0x68,"Firmware impending failure controller detected"},
- {0x5D,0x69,"Firmware impending failure throughput performance"},
- {0x5D,0x6A,"Firmware impending failure seek time performance"},
- {0x5D,0x6B,"Firmware impending failure spin-up retry count"},
- {0x5D,0x6C,"Firmware impending failure drive calibration retry count"},
- {0x5D,0x73,"Media impending failure endurance limit met"},
- {0x5D,0xFF,"Failure prediction threshold exceeded (false)"},
- {0x5E,0x00,"Low power condition on"},
- {0x5E,0x01,"Idle condition activated by timer"},
- {0x5E,0x02,"Standby condition activated by timer"},
- {0x5E,0x03,"Idle condition activated by command"},
- {0x5E,0x04,"Standby condition activated by command"},
- {0x5E,0x05,"Idle_b condition activated by timer"},
- {0x5E,0x06,"Idle_b condition activated by command"},
- {0x5E,0x07,"Idle_c condition activated by timer"},
- {0x5E,0x08,"Idle_c condition activated by command"},
- {0x5E,0x09,"Standby_y condition activated by timer"},
- {0x5E,0x0a,"Standby_y condition activated by command"},
- {0x5E,0x41,"Power state change to active"},
- {0x5E,0x42,"Power state change to idle"},
- {0x5E,0x43,"Power state change to standby"},
- {0x5E,0x45,"Power state change to sleep"},
- {0x5E,0x47,"Power state change to device control"},
- {0x60,0x00,"Lamp failure"},
- {0x61,0x00,"Video acquisition error"},
- {0x61,0x01,"Unable to acquire video"},
- {0x61,0x02,"Out of focus"},
- {0x62,0x00,"Scan head positioning error"},
- {0x63,0x00,"End of user area encountered on this track"},
- {0x63,0x01,"Packet does not fit in available space"},
- {0x64,0x00,"Illegal mode for this track"},
- {0x64,0x01,"Invalid packet size"},
- {0x65,0x00,"Voltage fault"},
- {0x66,0x00,"Automatic document feeder cover up"},
- {0x66,0x01,"Automatic document feeder lift up"},
- {0x66,0x02,"Document jam in automatic document feeder"},
- {0x66,0x03,"Document miss feed automatic in document feeder"},
- {0x67,0x00,"Configuration failure"},
- {0x67,0x01,"Configuration of incapable logical units failed"},
- {0x67,0x02,"Add logical unit failed"},
- {0x67,0x03,"Modification of logical unit failed"},
- {0x67,0x04,"Exchange of logical unit failed"},
- {0x67,0x05,"Remove of logical unit failed"},
- {0x67,0x06,"Attachment of logical unit failed"},
- {0x67,0x07,"Creation of logical unit failed"},
- {0x67,0x08,"Assign failure occurred"},
- {0x67,0x09,"Multiply assigned logical unit"},
- {0x67,0x0A,"Set target port groups command failed"},
- {0x67,0x0B,"ATA device feature not enabled"},
- {0x67,0x0C,"Command rejected"},
- {0x67,0x0D,"Explicit bind not allowed"},
- {0x68,0x00,"Logical unit not configured"},
- {0x68,0x01,"Subsidiary logical unit not configured"},
- {0x69,0x00,"Data loss on logical unit"},
- {0x69,0x01,"Multiple logical unit failures"},
- {0x69,0x02,"Parity/data mismatch"},
- {0x6A,0x00,"Informational, refer to log"},
- {0x6B,0x00,"State change has occurred"},
- {0x6B,0x01,"Redundancy level got better"},
- {0x6B,0x02,"Redundancy level got worse"},
- {0x6C,0x00,"Rebuild failure occurred"},
- {0x6D,0x00,"Recalculate failure occurred"},
- {0x6E,0x00,"Command to logical unit failed"},
- {0x6F,0x00,"Copy protection key exchange failure - authentication "
- "failure"},
- {0x6F,0x01,"Copy protection key exchange failure - key not present"},
- {0x6F,0x02,"Copy protection key exchange failure - key not established"},
- {0x6F,0x03,"Read of scrambled sector without authentication"},
- {0x6F,0x04,"Media region code is mismatched to logical unit region"},
- {0x6F,0x05,"Drive region must be permanent/region reset count error"},
- {0x6F,0x06,"Insufficient block count for binding nonce recording"},
- {0x6F,0x07,"Conflict in binding nonce recording"},
- {0x6F,0x08,"Insufficient permission"},
- {0x6F,0x09,"Invalid drive-host pairing server"},
- {0x6F,0x0A,"Drive-host pairing suspended"},
- /*
- * ASC 0x70 overridden by an "additional2" array entry
- * so there is no need to have them here.
- */
- /* {0x70,0x00,"Decompression exception short algorithm id of nn"}, */
-
- {0x71,0x00,"Decompression exception long algorithm id"},
- {0x72,0x00,"Session fixation error"},
- {0x72,0x01,"Session fixation error writing lead-in"},
- {0x72,0x02,"Session fixation error writing lead-out"},
- {0x72,0x03,"Session fixation error - incomplete track in session"},
- {0x72,0x04,"Empty or partially written reserved track"},
- {0x72,0x05,"No more track reservations allowed"},
- {0x72,0x06,"RMZ extension is not allowed"},
- {0x72,0x07,"No more test zone extensions are allowed"},
- {0x73,0x00,"CD control error"},
- {0x73,0x01,"Power calibration area almost full"},
- {0x73,0x02,"Power calibration area is full"},
- {0x73,0x03,"Power calibration area error"},
- {0x73,0x04,"Program memory area update failure"},
- {0x73,0x05,"Program memory area is full"},
- {0x73,0x06,"RMA/PMA is almost full"},
- {0x73,0x10,"Current power calibration area almost full"},
- {0x73,0x11,"Current power calibration area is full"},
- {0x73,0x17,"RDZ is full"},
- {0x74,0x00,"Security error"},
- {0x74,0x01,"Unable to decrypt data"},
- {0x74,0x02,"Unencrypted data encountered while decrypting"},
- {0x74,0x03,"Incorrect data encryption key"},
- {0x74,0x04,"Cryptographic integrity validation failed"},
- {0x74,0x05,"Error decrypting data"},
- {0x74,0x06,"Unknown signature verification key"},
- {0x74,0x07,"Encryption parameters not useable"},
- {0x74,0x08,"Digital signature validation failure"},
- {0x74,0x09,"Encryption mode mismatch on read"},
- {0x74,0x0a,"Encrypted block not raw read enabled"},
- {0x74,0x0b,"Incorrect Encryption parameters"},
- {0x74,0x0c,"Unable to decrypt parameter list"},
- {0x74,0x0d,"Encryption algorithm disabled"},
- {0x74,0x10,"SA creation parameter value invalid"},
- {0x74,0x11,"SA creation parameter value rejected"},
- {0x74,0x12,"Invalid SA usage"},
- {0x74,0x21,"Data encryption configuration prevented"},
- {0x74,0x30,"SA creation parameter not supported"},
- {0x74,0x40,"Authentication failed"},
- {0x74,0x61,"External data encryption key manager access error"},
- {0x74,0x62,"External data encryption key manager error"},
- {0x74,0x63,"External data encryption key not found"},
- {0x74,0x64,"External data encryption request not authorized"},
- {0x74,0x6e,"External data encryption control timeout"},
- {0x74,0x6f,"External data encryption control error"},
- {0x74,0x71,"Logical unit access not authorized"},
- {0x74,0x79,"Security conflict in translated device"},
- {0, 0, NULL}
-};
-
-#else /* SG_SCSI_STRINGS */
-
-struct sg_lib_asc_ascq_range_t sg_lib_asc_ascq_range[] =
-{
- {0, 0, 0, NULL}
-};
-
-struct sg_lib_asc_ascq_t sg_lib_asc_ascq[] =
-{
- {0, 0, NULL}
-};
-#endif /* SG_SCSI_STRINGS */
-
-const char * sg_lib_sense_key_desc[] = {
- "No Sense", /* Filemark, ILI and/or EOM; progress
- indication (during FORMAT); power
- condition sensing (REQUEST SENSE) */
- "Recovered Error", /* The last command completed successfully
- but used error correction */
- "Not Ready", /* The addressed target is not ready */
- "Medium Error", /* Data error detected on the medium */
- "Hardware Error", /* Controller or device failure */
- "Illegal Request",
- "Unit Attention", /* Removable medium was changed, or
- the target has been reset */
- "Data Protect", /* Access to the data is blocked */
- "Blank Check", /* Reached unexpected written or unwritten
- region of the medium */
- "Vendor specific(9)", /* Vendor specific */
- "Copy Aborted", /* COPY or COMPARE was aborted */
- "Aborted Command", /* The target aborted the command */
- "Equal", /* SEARCH DATA found data equal (obsolete) */
- "Volume Overflow", /* Medium full with data to be written */
- "Miscompare", /* Source data and data on the medium
- do not agree */
- "Completed" /* may occur for successful cmd (spc4r23) */
-};
-
-const char * sg_lib_pdt_strs[32] = { /* should have 2**5 elements */
- /* 0 */ "disk",
- "tape",
- "printer", /* obsolete, spc5r01 */
- "processor", /* often SAF-TE device, copy manager */
- "write once optical disk", /* obsolete, spc5r01 */
- /* 5 */ "cd/dvd",
- "scanner", /* obsolete */
- "optical memory device",
- "medium changer",
- "communications", /* obsolete */
- /* 0xa */ "graphics [0xa]", /* obsolete */
- "graphics [0xb]", /* obsolete */
- "storage array controller",
- "enclosure services device",
- "simplified direct access device",
- "optical card reader/writer device",
- /* 0x10 */ "bridge controller commands",
- "object based storage",
- "automation/driver interface",
- "security manager device", /* obsolete, spc5r01 */
- "zoned block commands",
- "0x15", "0x16", "0x17", "0x18",
- "0x19", "0x1a", "0x1b", "0x1c", "0x1d",
- "well known logical unit",
- "no physical device on this lu",
-};
-
-const char * sg_lib_transport_proto_strs[] =
-{
- "Fibre Channel Protocol for SCSI (FCP-4)",
- "SCSI Parallel Interface (SPI-5)", /* obsolete in spc5r01 */
- "Serial Storage Architecture SCSI-3 Protocol (SSA-S3P)",
- "Serial Bus Protocol for IEEE 1394 (SBP-3)",
- "SCSI RDMA Protocol (SRP)",
- "Internet SCSI (iSCSI)",
- "Serial Attached SCSI Protocol (SPL-4)",
- "Automation/Drive Interface Transport (ADT-2)",
- "AT Attachment Interface (ACS-2)", /* 0x8 */
- "USB Attached SCSI (UAS-2)",
- "SCSI over PCI Express (SOP)",
- "PCIe", /* added in spc5r02 */
- "Oxc", "Oxd", "Oxe",
- "No specific protocol"
-};
-
-/* SCSI Feature Sets array. code->value, pdt->peri_dev_type (-1 for SPC) */
-struct sg_lib_value_name_t sg_lib_scsi_feature_sets[] =
-{
- {SCSI_FS_SPC_DISCOVERY_2016, -1, "Discovery 2016"},
- {SCSI_FS_SBC_BASE_2010, PDT_DISK, "SBC Base 2010"},
- {SCSI_FS_SBC_BASE_2016, PDT_DISK, "SBC Base 2016"},
- {SCSI_FS_SBC_BASIC_PROV_2016, PDT_DISK, "Basic provisioning 2016"},
- {SCSI_FS_SBC_DRIVE_MAINT_2016, PDT_DISK, "Drive maintenance 2016"},
- {0x0, 0, NULL}, /* 0x0 is reserved sfs; trailing sentinel */
-};
-
-#if (SG_SCSI_STRINGS && HAVE_NVME && (! IGNORE_NVME))
-
-/* .value is completion queue's DW3 as follows: ((DW3 >> 17) & 0x3ff)
- * .peri_dev_type is an index for the sg_lib_scsi_status_sense_arr[]
- * .name is taken from NVMe 1.3a document, section 4.6.1.2.1 with less
- * capitalization.
- * NVMe term bits 31:17 of DW3 in the completion field as the "Status
- * Field" (SF). Bit 31 is "Do not retry" (DNR) and bit 30 is "More" (M).
- * Bits 29:28 are reserved, bit 27:25 are the "Status Code Type" (SCT)
- * and bits 24:17 are the Status Code (SC). This table is in ascending
- * order of its .value field so a binary search could be done on it. */
-struct sg_lib_value_name_t sg_lib_nvme_cmd_status_arr[] =
-{
- /* Generic command status values, Status Code Type (SCT): 0h
- * Lowest 8 bits are the Status Code (SC), in this case:
- * 00h - 7Fh: Applicable to Admin Command Set, or across multiple
- * command sets
- * 80h - BFh: I/O Command Set Specific status codes
- * c0h - FFh: I/O Vendor Specific status codes */
- {0x0, 0, "Successful completion"},
- {0x1, 1, "Invalid command opcode"},
- {0x2, 2, "Invalid field in command"},
- {0x3, 2, "Command id conflict"},
- {0x4, 3, "Data transfer error"},
- {0x5, 4, "Command aborted due to power loss notication"},
- {0x6, 5, "Internal error"},
- {0x7, 6, "Command abort requested"},
- {0x8, 6, "Command aborted due to SQ deletion"},
- {0x9, 6, "Command aborted due to failed fused command"},
- {0xa, 6, "Command aborted due to missing fused command"},
- {0xb, 7, "Invalid namespace or format"},
- {0xc, 5, "Command sequence error"},
- {0xd, 5, "Invalid SGL segment descriptor"},
- {0xe, 5, "Invalid number of SGL descriptors"},
- {0xf, 5, "Data SGL length invalid"},
- {0x10, 5, "Matadata SGL length invalid"},
- {0x11, 5, "SGL descriptor type invalid"},
- {0x12, 5, "Invalid use of controller memory buffer"},
- {0x13, 5, "PRP offset invalid"},
- {0x14, 2, "Atomic write unit exceeded"},
- {0x15, 8, "Operation denied"},
- {0x16, 5, "SGL offset invalid"},
- {0x17, 5, "Reserved [0x17]"},
- {0x18, 5, "Host identifier inconsistent format"},
- {0x19, 5, "Keep alive timeout expired"},
- {0x1a, 5, "Keep alive timeout invalid"},
- {0x1b, 6, "Command aborted due to Preempt and Abort"},
- {0x1c, 10, "Sanitize failed"},
- {0x1d, 11, "Sanitize in progress"},
- {0x1e, 5, "SGL data block granularity invalid"},
- {0x1f, 5, "Command not supported for queue in CMB"},
-
- /* Generic command status values, NVM (I/O) Command Set */
- {0x80, 12, "LBA out of range"},
- {0x81, 3, "Capacity exceeded"},
- {0x82, 13, "Namespace not ready"},
- {0x83, 14, "Reservation conflict"},
- {0x84, 15, "Format in progress"},
- /* 0xc0 - 0xff: vendor specific */
-
- /* Command specific status values, Status Code Type (SCT): 1h */
- {0x100, 5, "Completion queue invalid"},
- {0x101, 5, "Invalid queue identifier"},
- {0x102, 5, "Invalid queue size"},
- {0x103, 5, "Abort command limit exceeded"},
- {0x104, 5, "Reserved [0x104]"},
- {0x105, 5, "Asynchronous event request limit exceeded"},
- {0x106, 5, "Invalid firmware slot"},
- {0x107, 5, "Invalid firmware image"},
- {0x108, 5, "Invalid interrupt vector"},
- {0x109, 5, "Invalid log page"},
- {0x10a,16, "Invalid format"},
- {0x10b, 5, "Firmware activation requires conventional reset"},
- {0x10c, 5, "Invalid queue deletion"},
- {0x10d, 5, "Feature identifier not saveable"},
- {0x10e, 5, "Feature not changeable"},
- {0x10f, 5, "Feature not namespace specific"},
- {0x110, 5, "Firmware activation requires NVM subsystem reset"},
- {0x111, 5, "Firmware activation requires reset"},
- {0x112, 5, "Firmware activation requires maximum time violation"},
- {0x113, 5, "Firmware activation prohibited"},
- {0x114, 5, "Overlapping range"},
- {0x115, 5, "Namespace insufficient capacity"},
- {0x116, 5, "Namespace identifier unavailable"},
- {0x117, 5, "Reserved [0x107]"},
- {0x118, 5, "Namespace already attached"},
- {0x119, 5, "Namespace is private"},
- {0x11a, 5, "Namespace not attached"},
- {0x11b, 3, "Thin provisioning not supported"},
- {0x11c, 3, "Controller list invalid"},
- {0x11d,17, "Device self-test in progress"},
- {0x11e,18, "Boot partition write prohibited"},
- {0x11f, 5, "Invalid controller identifier"},
- {0x120, 5, "Invalid secondary controller state"},
- {0x121, 5, "Invalid number of controller resorces"},
- {0x122, 5, "Invalid resorce identifier"},
-
- /* Command specific status values, Status Code Type (SCT): 1h
- * for NVM (I/O) Command Set */
- {0x180, 2, "Conflicting attributes"},
- {0x181,19, "Invalid protection information"},
- {0x182,18, "Attempted write to read only range"},
- /* 0x1c0 - 0x1ff: vendor specific */
-
- /* Media and Data Integrity error values, Status Code Type (SCT): 2h */
- {0x280,20, "Write fault"},
- {0x281,21, "Unrecovered read error"},
- {0x282,22, "End-to-end guard check error"},
- {0x283,23, "End-to-end application tag check error"},
- {0x284,24, "End-to-end reference tag check error"},
- {0x285,25, "Compare failure"},
- {0x286, 8, "Access denied"},
- {0x287,26, "Deallocated or unwritten logical block"},
- /* 0x2c0 - 0x2ff: vendor specific */
-
- /* Leave this Sentinel value at end of this array */
- {0x3ff, 0, NULL},
-};
-
-/* The sg_lib_nvme_cmd_status_arr[n].peri_dev_type field is an index
- * to this array. It allows an NVMe status (error) value to be mapped
- * to this SCSI tuple: status, sense_key, additional sense code (asc) and
- * asc qualifier (ascq). For brevity SAM_STAT_CHECK_CONDITION is written
- * as 0x2. */
-struct sg_lib_4tuple_u8 sg_lib_scsi_status_sense_arr[] =
-{
- {SAM_STAT_GOOD, SPC_SK_NO_SENSE, 0, 0}, /* it's all good */ /* 0 */
- {SAM_STAT_CHECK_CONDITION, SPC_SK_ILLEGAL_REQUEST, 0x20, 0x0},/* opcode */
- {0x2, SPC_SK_ILLEGAL_REQUEST, 0x24, 0x0}, /* field in cdb */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x0, 0x0},
- {SAM_STAT_TASK_ABORTED, SPC_SK_ABORTED_COMMAND, 0xb, 0x8},
- {0x2, SPC_SK_HARDWARE_ERROR, 0x44, 0x0}, /* internal error */ /* 5 */
- {SAM_STAT_TASK_ABORTED, SPC_SK_ABORTED_COMMAND, 0x0, 0x0},
- {0x2, SPC_SK_ILLEGAL_REQUEST, 0x20, 0x9}, /* invalid LU */
- {0x2, SPC_SK_ILLEGAL_REQUEST, 0x20, 0x2}, /* access denied */
- {0x2, SPC_SK_ILLEGAL_REQUEST, 0x2c, 0x0}, /* cmd sequence error */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x31, 0x3}, /* sanitize failed */ /* 10 */
- {0x2, SPC_SK_NOT_READY, 0x4, 0x1b}, /* sanitize in progress */
- {0x2, SPC_SK_ILLEGAL_REQUEST, 0x21, 0x0}, /* LBA out of range */
- {0x2, SPC_SK_NOT_READY, 0x4, 0x0}, /* not reportable; 0x1: becoming */
- {SAM_STAT_RESERVATION_CONFLICT, 0x0, 0x0, 0x0},
- {0x2, SPC_SK_NOT_READY, 0x4, 0x4}, /* format in progress */ /* 15 */
- {0x2, SPC_SK_ILLEGAL_REQUEST, 0x31, 0x1}, /* format failed */
- {0x2, SPC_SK_NOT_READY, 0x4, 0x9}, /* self-test in progress */
- {0x2, SPC_SK_DATA_PROTECT, 0x27, 0x0}, /* write prohibited */
- {0x2, SPC_SK_ILLEGAL_REQUEST, 0x10, 0x5}, /* protection info */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x3, 0x0}, /* periph dev w fault */ /* 20 */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x11, 0x0}, /* unrecoc rd */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x1}, /* PI guard */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x2}, /* PI app tag */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x2}, /* PI app tag */
- {0x2, SPC_SK_MISCOMPARE, 0x1d, 0x0}, /* during verify */ /* 25 */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x21, 0x6}, /* read invalid data */
-
- /* Leave this Sentinel value at end of this array */
- {0xff, 0xff, 0xff, 0xff},
-};
-
-
-#else /* (SG_SCSI_STRINGS && HAVE_NVME && (! IGNORE_NVME)) */
-struct sg_lib_value_name_t sg_lib_nvme_cmd_status_arr[] =
-{
-
- /* Leave this Sentinel value at end of this array */
- {0x3ff, 0, NULL},
-};
-
-struct sg_lib_4tuple_u8 sg_lib_scsi_status_sense_arr[] =
-{
-
- /* Leave this Sentinel value at end of this array */
- {0xff, 0xff, 0xff, 0xff},
-};
-
-#endif /* (SG_SCSI_STRINGS && HAVE_NVME && (! IGNORE_NVME)) */
diff --git a/tools/sg_write_buffer/sg_pt_common.c b/tools/sg_write_buffer/sg_pt_common.c
deleted file mode 100644
index 85bc191..0000000
--- a/tools/sg_write_buffer/sg_pt_common.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2009-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-#define __STDC_FORMAT_MACROS 1
-#include <inttypes.h>
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sg_lib.h"
-#include "sg_pt.h"
-#include "sg_pt_nvme.h"
-
-
-static const char * scsi_pt_version_str = "3.03 20180115";
-
-static const char * nvme_scsi_vendor_str = "NVMe ";
-
-
-const char *
-scsi_pt_version()
-{
- return scsi_pt_version_str;
-}
-
-/* Given the NVMe Identify controller response and optionally the NVMe
- * Identify namespace response (NULL otherwise), generate the SCSI VPD
- * page 0x83 (device identification) descriptor(s) in dop. Return the
- * number of bytes written which will not exceed max_do_len. Probably use
- * Peripheral Device Type (pdt) of 0 (disk) for don't know. Transport
- * protocol (tproto) should be -1 if not known, else SCSI value.
- * N.B. Does not write total VPD page length into dop[2:3] . */
-int
-sg_make_vpd_devid_for_nvme(const uint8_t * nvme_id_ctl_p,
- const uint8_t * nvme_id_ns_p, int pdt,
- int tproto, uint8_t * dop, int max_do_len)
-{
- bool have_nguid, have_eui64;
- int k, n;
- char b[4];
-
- if ((NULL == nvme_id_ctl_p) || (NULL == dop) || (max_do_len < 56))
- return 0;
-
- memset(dop, 0, max_do_len);
- dop[0] = 0x1f & pdt; /* (PQ=0)<<5 | (PDT=pdt); 0 or 0xd (SES) */
- dop[1] = 0x83; /* Device Identification VPD page number */
- /* Build a T10 Vendor ID based designator (desig_id=1) for controller */
- if (tproto >= 0) {
- dop[4] = ((0xf & tproto) << 4) | 0x2;
- dop[5] = 0xa1; /* PIV=1, ASSOC=2 (target device), desig_id=1 */
- } else {
- dop[4] = 0x2; /* Prococol id=0, code_set=2 (ASCII) */
- dop[5] = 0x21; /* PIV=0, ASSOC=2 (target device), desig_id=1 */
- }
- memcpy(dop + 8, nvme_scsi_vendor_str, 8); /* N.B. this is "NVMe " */
- memcpy(dop + 16, nvme_id_ctl_p + 24, 40); /* MN */
- for (k = 40; k > 0; --k) {
- if (' ' == dop[15 + k])
- dop[15 + k] = '_'; /* convert trailing spaces */
- else
- break;
- }
- if (40 == k)
- --k;
- n = 16 + 1 + k;
- if (max_do_len < (n + 20))
- return 0;
- memcpy(dop + n, nvme_id_ctl_p + 4, 20); /* SN */
- for (k = 20; k > 0; --k) { /* trim trailing spaces */
- if (' ' == dop[n + k - 1])
- dop[n + k - 1] = '\0';
- else
- break;
- }
- n += k;
- if (0 != (n % 4))
- n = ((n / 4) + 1) * 4; /* round up to next modulo 4 */
- dop[7] = n - 8;
- if (NULL == nvme_id_ns_p)
- return n;
-
- /* Look for NGUID (16 byte identifier) or EUI64 (8 byte) fields in
- * NVME Identify for namespace. If found form a EUI and a SCSI string
- * descriptor for non-zero NGUID or EUI64 (prefer NGUID if both). */
- have_nguid = ! sg_all_zeros(nvme_id_ns_p + 104, 16);
- have_eui64 = ! sg_all_zeros(nvme_id_ns_p + 120, 8);
- if ((! have_nguid) && (! have_eui64))
- return n;
- if (have_nguid) {
- if (max_do_len < (n + 20))
- return n;
- dop[n + 0] = 0x1; /* Prococol id=0, code_set=1 (binary) */
- dop[n + 1] = 0x02; /* PIV=0, ASSOC=0 (lu), desig_id=2 (eui) */
- dop[n + 3] = 16;
- memcpy(dop + n + 4, nvme_id_ns_p + 104, 16);
- n += 20;
- if (max_do_len < (n + 40))
- return n;
- dop[n + 0] = 0x3; /* Prococol id=0, code_set=3 (utf8) */
- dop[n + 1] = 0x08; /* PIV=0, ASSOC=0 (lu), desig_id=8 (scsi string) */
- dop[n + 3] = 36;
- memcpy(dop + n + 4, "eui.", 4);
- for (k = 0; k < 16; ++k) {
- snprintf(b, sizeof(b), "%02X", nvme_id_ns_p[104 + k]);
- memcpy(dop + n + 8 + (2 * k), b, 2);
- }
- return n + 40;
- } else { /* have_eui64 is true, 8 byte identifier */
- if (max_do_len < (n + 12))
- return n;
- dop[n + 0] = 0x1; /* Prococol id=0, code_set=1 (binary) */
- dop[n + 1] = 0x02; /* PIV=0, ASSOC=0 (lu), desig_id=2 (eui) */
- dop[n + 3] = 8;
- memcpy(dop + n + 4, nvme_id_ns_p + 120, 8);
- n += 12;
- if (max_do_len < (n + 24))
- return n;
- dop[n + 0] = 0x3; /* Prococol id=0, code_set=3 (utf8) */
- dop[n + 1] = 0x08; /* PIV=0, ASSOC=0 (lu), desig_id=8 (scsi string) */
- dop[n + 3] = 20;
- memcpy(dop + n + 4, "eui.", 4);
- for (k = 0; k < 8; ++k) {
- snprintf(b, sizeof(b), "%02X", nvme_id_ns_p[120 + k]);
- memcpy(dop + n + 8 + (2 * k), b, 2);
- }
- return n + 24;
- }
-}
diff --git a/tools/sg_write_buffer/sg_pt_linux.c b/tools/sg_write_buffer/sg_pt_linux.c
deleted file mode 100644
index 22ea068..0000000
--- a/tools/sg_write_buffer/sg_pt_linux.c
+++ /dev/null
@@ -1,964 +0,0 @@
-/*
- * Copyright (c) 2005-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-/* sg_pt_linux version 1.37 20180126 */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h> /* to define 'major' */
-#ifndef major
-#include <sys/types.h>
-#endif
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <linux/major.h>
-
-#include "sg_pt.h"
-#include "sg_lib.h"
-#include "sg_linux_inc.h"
-#include "sg_pt_linux.h"
-
-
-#ifdef major
-#define SG_DEV_MAJOR major
-#else
-#ifdef HAVE_LINUX_KDEV_T_H
-#include <linux/kdev_t.h>
-#endif
-#define SG_DEV_MAJOR MAJOR /* MAJOR() macro faulty if > 255 minors */
-#endif
-
-#ifndef BLOCK_EXT_MAJOR
-#define BLOCK_EXT_MAJOR 259
-#endif
-
-#define DEF_TIMEOUT 60000 /* 60,000 millisecs (60 seconds) */
-
-static const char * linux_host_bytes[] = {
- "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT",
- "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR",
- "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR",
- "DID_IMM_RETRY", "DID_REQUEUE" /* 0xd */,
- "DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST",
- "DID_TARGET_FAILURE" /* 0x10 */,
- "DID_NEXUS_FAILURE (reservation conflict)",
- "DID_ALLOC_FAILURE",
- "DID_MEDIUM_ERROR",
-};
-
-#define LINUX_HOST_BYTES_SZ \
- (int)(sizeof(linux_host_bytes) / sizeof(linux_host_bytes[0]))
-
-static const char * linux_driver_bytes[] = {
- "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA",
- "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",
- "DRIVER_SENSE"
-};
-
-#define LINUX_DRIVER_BYTES_SZ \
- (int)(sizeof(linux_driver_bytes) / sizeof(linux_driver_bytes[0]))
-
-#if 0
-static const char * linux_driver_suggests[] = {
- "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP",
- "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN",
- "SUGGEST_SENSE"
-};
-
-#define LINUX_DRIVER_SUGGESTS_SZ \
- (int)(sizeof(linux_driver_suggests) / sizeof(linux_driver_suggests[0]))
-#endif
-
-/*
- * These defines are for constants that should be visible in the
- * /usr/include/scsi directory (brought in by sg_linux_inc.h).
- * Redefined and aliased here to decouple this code from
- * sg_io_linux.h N.B. the SUGGEST_* constants are no longer used.
- */
-#ifndef DRIVER_MASK
-#define DRIVER_MASK 0x0f
-#endif
-#ifndef SUGGEST_MASK
-#define SUGGEST_MASK 0xf0
-#endif
-#ifndef DRIVER_SENSE
-#define DRIVER_SENSE 0x08
-#endif
-#define SG_LIB_DRIVER_MASK DRIVER_MASK
-#define SG_LIB_SUGGEST_MASK SUGGEST_MASK
-#define SG_LIB_DRIVER_SENSE DRIVER_SENSE
-
-bool sg_bsg_nvme_char_major_checked = false;
-int sg_bsg_major = 0;
-volatile int sg_nvme_char_major = 0;
-
-long sg_lin_page_size = 4096; /* default, overridden with correct value */
-
-
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
-/* This function only needs to be called once (unless a NVMe controller
- * can be hot-plugged into system in which case it should be called
- * (again) after that event). */
-void
-sg_find_bsg_nvme_char_major(int verbose)
-{
- bool got_one = false;
- int n;
- const char * proc_devices = "/proc/devices";
- char * cp;
- FILE *fp;
- char a[128];
- char b[128];
-
- sg_lin_page_size = sysconf(_SC_PAGESIZE);
- if (NULL == (fp = fopen(proc_devices, "r"))) {
- if (verbose)
- pr2ws("fopen %s failed: %s\n", proc_devices, strerror(errno));
- return;
- }
- while ((cp = fgets(b, sizeof(b), fp))) {
- if ((1 == sscanf(b, "%126s", a)) &&
- (0 == memcmp(a, "Character", 9)))
- break;
- }
- while (cp && (cp = fgets(b, sizeof(b), fp))) {
- if (2 == sscanf(b, "%d %126s", &n, a)) {
- if (0 == strcmp("bsg", a)) {
- sg_bsg_major = n;
- if (got_one)
- break;
- got_one = true;
- } else if (0 == strcmp("nvme", a)) {
- sg_nvme_char_major = n;
- if (got_one)
- break;
- got_one = true;
- }
- } else
- break;
- }
- if (verbose > 3) {
- if (cp) {
- if (sg_bsg_major > 0)
- pr2ws("found sg_bsg_major=%d\n", sg_bsg_major);
- if (sg_nvme_char_major > 0)
- pr2ws("found sg_nvme_char_major=%d\n", sg_nvme_char_major);
- } else
- pr2ws("found no bsg not nvme char device in %s\n", proc_devices);
- }
- fclose(fp);
-}
-
-/* Assumes that sg_find_bsg_nvme_char_major() has already been called. Returns
- * true if dev_fd is a scsi generic pass-through device. If yields
- * *is_nvme_p = true with *nsid_p = 0 then dev_fd is a NVMe char device.
- * If yields *nsid_p > 0 then dev_fd is a NVMe block device. */
-static bool
-check_file_type(int dev_fd, struct stat * dev_statp, bool * is_bsg_p,
- bool * is_nvme_p, uint32_t * nsid_p, int * os_err_p,
- int verbose)
-{
- bool is_nvme = false;
- bool is_sg = false;
- bool is_bsg = false;
- bool is_block = false;
- int os_err = 0;
- int major_num;
- uint32_t nsid = 0; /* invalid NSID */
-
- if (dev_fd >= 0) {
- if (fstat(dev_fd, dev_statp) < 0) {
- os_err = errno;
- if (verbose)
- pr2ws("%s: fstat() failed: %s (errno=%d)\n", __func__,
- safe_strerror(os_err), os_err);
- goto skip_out;
- }
- major_num = (int)SG_DEV_MAJOR(dev_statp->st_rdev);
- if (S_ISCHR(dev_statp->st_mode)) {
- if (SCSI_GENERIC_MAJOR == major_num)
- is_sg = true;
- else if (sg_bsg_major == major_num)
- is_bsg = true;
- else if (sg_nvme_char_major == major_num)
- is_nvme = true;
- } else if (S_ISBLK(dev_statp->st_mode)) {
- is_block = true;
- if (BLOCK_EXT_MAJOR == major_num) {
- is_nvme = true;
- nsid = ioctl(dev_fd, NVME_IOCTL_ID, NULL);
- if (SG_NVME_BROADCAST_NSID == nsid) { /* means ioctl error */
- os_err = errno;
- if (verbose)
- pr2ws("%s: ioctl(NVME_IOCTL_ID) failed: %s "
- "(errno=%d)\n", __func__, safe_strerror(os_err),
- os_err);
- } else
- os_err = 0;
- }
- }
- } else {
- os_err = EBADF;
- if (verbose)
- pr2ws("%s: invalid file descriptor (%d)\n", __func__, dev_fd);
- }
-skip_out:
- if (verbose > 3) {
- pr2ws("%s: file descriptor is ", __func__);
- if (is_sg)
- pr2ws("sg device\n");
- else if (is_bsg)
- pr2ws("bsg device\n");
- else if (is_nvme && (0 == nsid))
- pr2ws("NVMe char device\n");
- else if (is_nvme)
- pr2ws("NVMe block device, nsid=%lld\n",
- ((uint32_t)-1 == nsid) ? -1LL : (long long)nsid);
- else if (is_block)
- pr2ws("block device\n");
- else
- pr2ws("undetermined device, could be regular file\n");
- }
- if (is_bsg_p)
- *is_bsg_p = is_bsg;
- if (is_nvme_p)
- *is_nvme_p = is_nvme;
- if (nsid_p)
- *nsid_p = nsid;
- if (os_err_p)
- *os_err_p = os_err;
- return is_sg;
-}
-
-/* Assumes dev_fd is an "open" file handle associated with device_name. If
- * the implementation (possibly for one OS) cannot determine from dev_fd if
- * a SCSI or NVMe pass-through is referenced, then it might guess based on
- * device_name. Returns 1 if SCSI generic pass-though device, returns 2 if
- * secondary SCSI pass-through device (in Linux a bsg device); returns 3 is
- * char NVMe device (i.e. no NSID); returns 4 if block NVMe device (includes
- * NSID), or 0 if something else (e.g. ATA block device) or dev_fd < 0.
- * If error, returns negated errno (operating system) value. */
-int
-check_pt_file_handle(int dev_fd, const char * device_name, int verbose)
-{
- if (verbose > 4)
- pr2ws("%s: dev_fd=%d, device_name: %s\n", __func__, dev_fd,
- device_name);
- /* Linux doesn't need device_name to determine which pass-through */
- if (! sg_bsg_nvme_char_major_checked) {
- sg_bsg_nvme_char_major_checked = true;
- sg_find_bsg_nvme_char_major(verbose);
- }
- if (dev_fd >= 0) {
- bool is_sg, is_bsg, is_nvme;
- int err;
- uint32_t nsid;
- struct stat a_stat;
-
- is_sg = check_file_type(dev_fd, &a_stat, &is_bsg, &is_nvme, &nsid,
- &err, verbose);
- if (err)
- return -err;
- else if (is_sg)
- return 1;
- else if (is_bsg)
- return 2;
- else if (is_nvme && (0 == nsid))
- return 3;
- else if (is_nvme)
- return 4;
- else
- return 0;
- } else
- return 0;
-}
-
-/*
- * We make a runtime decision whether to use the sg v3 interface or the sg
- * v4 interface (currently exclusively used by the bsg driver). If all the
- * following are true we use sg v4 which is only currently supported on bsg
- * device nodes:
- * a) there is a bsg entry in the /proc/devices file
- * b) the device node given to scsi_pt_open() is a char device
- * c) the char major number of the device node given to scsi_pt_open()
- * matches the char major number of the bsg entry in /proc/devices
- * Otherwise the sg v3 interface is used.
- *
- * Note that in either case we prepare the data in a sg v4 structure. If
- * the runtime tests indicate that the v3 interface is needed then
- * do_scsi_pt_v3() transfers the input data into a v3 structure and
- * then the output data is transferred back into a sg v4 structure.
- * That implementation detail could change in the future.
- *
- * [20120806] Only use MAJOR() macro in kdev_t.h if that header file is
- * available and major() macro [N.B. lower case] is not available.
- */
-
-
-#ifdef major
-#define SG_DEV_MAJOR major
-#else
-#ifdef HAVE_LINUX_KDEV_T_H
-#include <linux/kdev_t.h>
-#endif
-#define SG_DEV_MAJOR MAJOR /* MAJOR() macro faulty if > 255 minors */
-#endif
-
-
-/* Returns >= 0 if successful. If error in Unix returns negated errno. */
-int
-scsi_pt_open_device(const char * device_name, bool read_only, int verbose)
-{
- int oflags = O_NONBLOCK;
-
- oflags |= (read_only ? O_RDONLY : O_RDWR);
- return scsi_pt_open_flags(device_name, oflags, verbose);
-}
-
-/* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed */
-/* together. The 'flags' argument is advisory and may be ignored. */
-/* Returns >= 0 if successful, otherwise returns negated errno. */
-int
-scsi_pt_open_flags(const char * device_name, int flags, int verbose)
-{
- int fd;
-
- if (! sg_bsg_nvme_char_major_checked) {
- sg_bsg_nvme_char_major_checked = true;
- sg_find_bsg_nvme_char_major(verbose);
- }
- if (verbose > 1) {
- pr2ws("open %s with flags=0x%x\n", device_name, flags);
- }
- fd = open(device_name, flags);
- if (fd < 0) {
- fd = -errno;
- if (verbose > 1)
- pr2ws("%s: open(%s, 0x%x) failed: %s\n", __func__, device_name,
- flags, safe_strerror(-fd));
- }
- return fd;
-}
-
-/* Returns 0 if successful. If error in Unix returns negated errno. */
-int
-scsi_pt_close_device(int device_fd)
-{
- int res;
-
- res = close(device_fd);
- if (res < 0)
- res = -errno;
- return res;
-}
-
-
-/* Caller should additionally call get_scsi_pt_os_err() after this call */
-struct sg_pt_base *
-construct_scsi_pt_obj_with_fd(int dev_fd, int verbose)
-{
- int err;
- struct sg_pt_linux_scsi * ptp;
-
- /* The following 2 lines are temporary. It is to avoid a NULL pointer
- * crash when an old utility is used with a newer library built after
- * the sg_warnings_strm cleanup */
- if (NULL == sg_warnings_strm)
- sg_warnings_strm = stderr;
-
- ptp = (struct sg_pt_linux_scsi *)
- calloc(1, sizeof(struct sg_pt_linux_scsi));
- if (ptp) {
- err = set_pt_file_handle((struct sg_pt_base *)ptp, dev_fd, verbose);
- if ((0 == err) && (! ptp->is_nvme)) {
- ptp->io_hdr.guard = 'Q';
-#ifdef BSG_PROTOCOL_SCSI
- ptp->io_hdr.protocol = BSG_PROTOCOL_SCSI;
-#endif
-#ifdef BSG_SUB_PROTOCOL_SCSI_CMD
- ptp->io_hdr.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
-#endif
- }
- } else if (verbose)
- pr2ws("%s: calloc() failed, out of memory?\n", __func__);
-
- return (struct sg_pt_base *)ptp;
-}
-
-struct sg_pt_base *
-construct_scsi_pt_obj()
-{
- return construct_scsi_pt_obj_with_fd(-1 /* dev_fd */, 0 /* verbose */);
-}
-
-void
-destruct_scsi_pt_obj(struct sg_pt_base * vp)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (ptp->free_nvme_id_ctlp) {
- free(ptp->free_nvme_id_ctlp);
- ptp->free_nvme_id_ctlp = NULL;
- ptp->nvme_id_ctlp = NULL;
- }
- if (ptp)
- free(ptp);
-}
-
-/* Remembers previous device file descriptor */
-void
-clear_scsi_pt_obj(struct sg_pt_base * vp)
-{
- bool is_sg, is_bsg, is_nvme;
- int fd;
- uint32_t nvme_nsid;
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (ptp) {
- fd = ptp->dev_fd;
- is_sg = ptp->is_sg;
- is_bsg = ptp->is_bsg;
- is_nvme = ptp->is_nvme;
- nvme_nsid = ptp->nvme_nsid;
- memset(ptp, 0, sizeof(struct sg_pt_linux_scsi));
- ptp->io_hdr.guard = 'Q';
-#ifdef BSG_PROTOCOL_SCSI
- ptp->io_hdr.protocol = BSG_PROTOCOL_SCSI;
-#endif
-#ifdef BSG_SUB_PROTOCOL_SCSI_CMD
- ptp->io_hdr.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
-#endif
- ptp->dev_fd = fd;
- ptp->is_sg = is_sg;
- ptp->is_bsg = is_bsg;
- ptp->is_nvme = is_nvme;
- ptp->nvme_direct = false;
- ptp->nvme_nsid = nvme_nsid;
- }
-}
-
-/* Forget any previous dev_fd and install the one given. May attempt to
- * find file type (e.g. if pass-though) from OS so there could be an error.
- * Returns 0 for success or the same value as get_scsi_pt_os_err()
- * will return. dev_fd should be >= 0 for a valid file handle or -1 . */
-int
-set_pt_file_handle(struct sg_pt_base * vp, int dev_fd, int verbose)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
- struct stat a_stat;
-
- if (! sg_bsg_nvme_char_major_checked) {
- sg_bsg_nvme_char_major_checked = true;
- sg_find_bsg_nvme_char_major(verbose);
- }
- ptp->dev_fd = dev_fd;
- if (dev_fd >= 0)
- ptp->is_sg = check_file_type(dev_fd, &a_stat, &ptp->is_bsg,
- &ptp->is_nvme, &ptp->nvme_nsid,
- &ptp->os_err, verbose);
- else {
- ptp->is_sg = false;
- ptp->is_bsg = false;
- ptp->is_nvme = false;
- ptp->nvme_direct = false;
- ptp->nvme_nsid = 0;
- ptp->os_err = 0;
- }
- return ptp->os_err;
-}
-
-/* Valid file handles (which is the return value) are >= 0 . Returns -1
- * if there is no valid file handle. */
-int
-get_pt_file_handle(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- return ptp->dev_fd;
-}
-
-void
-set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb,
- int cdb_len)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (ptp->io_hdr.request)
- ++ptp->in_err;
- ptp->io_hdr.request = (__u64)(sg_uintptr_t)cdb;
- ptp->io_hdr.request_len = cdb_len;
-}
-
-void
-set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense,
- int max_sense_len)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (ptp->io_hdr.response)
- ++ptp->in_err;
- memset(sense, 0, max_sense_len);
- ptp->io_hdr.response = (__u64)(sg_uintptr_t)sense;
- ptp->io_hdr.max_response_len = max_sense_len;
-}
-
-/* Setup for data transfer from device */
-void
-set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp,
- int dxfer_ilen)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (ptp->io_hdr.din_xferp)
- ++ptp->in_err;
- if (dxfer_ilen > 0) {
- ptp->io_hdr.din_xferp = (__u64)(sg_uintptr_t)dxferp;
- ptp->io_hdr.din_xfer_len = dxfer_ilen;
- }
-}
-
-/* Setup for data transfer toward device */
-void
-set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp,
- int dxfer_olen)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (ptp->io_hdr.dout_xferp)
- ++ptp->in_err;
- if (dxfer_olen > 0) {
- ptp->io_hdr.dout_xferp = (__u64)(sg_uintptr_t)dxferp;
- ptp->io_hdr.dout_xfer_len = dxfer_olen;
- }
-}
-
-void
-set_pt_metadata_xfer(struct sg_pt_base * vp, unsigned char * dxferp,
- uint32_t dxfer_len, bool out_true)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (dxfer_len > 0) {
- ptp->mdxferp = dxferp;
- ptp->mdxfer_len = dxfer_len;
- ptp->mdxfer_out = out_true;
- }
-}
-
-void
-set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- ptp->io_hdr.spare_in = pack_id;
-}
-
-void
-set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- ptp->io_hdr.request_tag = tag;
-}
-
-/* Note that task management function codes are transport specific */
-void
-set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- ptp->io_hdr.subprotocol = 1; /* SCSI task management function */
- ptp->tmf_request[0] = (unsigned char)tmf_code; /* assume it fits */
- ptp->io_hdr.request = (__u64)(sg_uintptr_t)(&(ptp->tmf_request[0]));
- ptp->io_hdr.request_len = 1;
-}
-
-void
-set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- ptp->io_hdr.request_attr = attribute;
- ptp->io_hdr.request_priority = priority;
-}
-
-#ifndef BSG_FLAG_Q_AT_TAIL
-#define BSG_FLAG_Q_AT_TAIL 0x10
-#endif
-#ifndef BSG_FLAG_Q_AT_HEAD
-#define BSG_FLAG_Q_AT_HEAD 0x20
-#endif
-
-/* Need this later if translated to v3 interface */
-#ifndef SG_FLAG_Q_AT_TAIL
-#define SG_FLAG_Q_AT_TAIL 0x10
-#endif
-#ifndef SG_FLAG_Q_AT_HEAD
-#define SG_FLAG_Q_AT_HEAD 0x20
-#endif
-
-void
-set_scsi_pt_flags(struct sg_pt_base * vp, int flags)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- /* default action of bsg driver (sg v4) is QUEUE_AT_HEAD */
- /* default action of block layer SG_IO ioctl is QUEUE_AT_TAIL */
- if (SCSI_PT_FLAGS_QUEUE_AT_HEAD & flags) { /* favour AT_HEAD */
- ptp->io_hdr.flags |= BSG_FLAG_Q_AT_HEAD;
- ptp->io_hdr.flags &= ~BSG_FLAG_Q_AT_TAIL;
- } else if (SCSI_PT_FLAGS_QUEUE_AT_TAIL & flags) {
- ptp->io_hdr.flags |= BSG_FLAG_Q_AT_TAIL;
- ptp->io_hdr.flags &= ~BSG_FLAG_Q_AT_HEAD;
- }
-}
-
-/* N.B. Returns din_resid and ignores dout_resid */
-int
-get_scsi_pt_resid(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (NULL == ptp)
- return 0;
- return ptp->nvme_direct ? 0 : ptp->io_hdr.din_resid;
-}
-
-int
-get_scsi_pt_status_response(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (NULL == ptp)
- return 0;
- return (int)(ptp->nvme_direct ? ptp->nvme_status :
- ptp->io_hdr.device_status);
-}
-
-uint32_t
-get_pt_result(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- if (NULL == ptp)
- return 0;
- return ptp->nvme_direct ? ptp->nvme_result :
- ptp->io_hdr.device_status;
-}
-
-int
-get_scsi_pt_sense_len(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- return ptp->io_hdr.response_len;
-}
-
-int
-get_scsi_pt_duration_ms(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- return ptp->io_hdr.duration;
-}
-
-int
-get_scsi_pt_transport_err(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- return ptp->io_hdr.transport_status;
-}
-
-void
-set_scsi_pt_transport_err(struct sg_pt_base * vp, int err)
-{
- struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- ptp->io_hdr.transport_status = err;
-}
-
-/* Returns b which will contain a null char terminated string (if
- * max_b_len > 0). Combined driver and transport (called "host" in Linux
- * kernel) statuses */
-char *
-get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len,
- char * b)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
- int ds = ptp->io_hdr.driver_status;
- int hs = ptp->io_hdr.transport_status;
- int n, m;
- char * cp = b;
- int driv;
- const char * driv_cp = "invalid";
-
- if (max_b_len < 1)
- return b;
- m = max_b_len;
- n = 0;
- if (hs) {
- if ((hs < 0) || (hs >= LINUX_HOST_BYTES_SZ))
- n = snprintf(cp, m, "Host_status=0x%02x is invalid\n", hs);
- else
- n = snprintf(cp, m, "Host_status=0x%02x [%s]\n", hs,
- linux_host_bytes[hs]);
- }
- m -= n;
- if (m < 1) {
- b[max_b_len - 1] = '\0';
- return b;
- }
- cp += n;
- driv = ds & SG_LIB_DRIVER_MASK;
- if (driv < LINUX_DRIVER_BYTES_SZ)
- driv_cp = linux_driver_bytes[driv];
-#if 0
- sugg = (ds & SG_LIB_SUGGEST_MASK) >> 4;
- if (sugg < LINUX_DRIVER_SUGGESTS_SZ)
- sugg_cp = linux_driver_suggests[sugg];
-#endif
- n = snprintf(cp, m, "Driver_status=0x%02x [%s]\n", ds, driv_cp);
- m -= n;
- if (m < 1)
- b[max_b_len - 1] = '\0';
- return b;
-}
-
-int
-get_scsi_pt_result_category(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
- int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK;
- int scsi_st = ptp->io_hdr.device_status & 0x7e;
-
- if (ptp->os_err)
- return SCSI_PT_RESULT_OS_ERR;
- else if (ptp->io_hdr.transport_status)
- return SCSI_PT_RESULT_TRANSPORT_ERR;
- else if (dr_st && (SG_LIB_DRIVER_SENSE != dr_st))
- return SCSI_PT_RESULT_TRANSPORT_ERR;
- else if ((SG_LIB_DRIVER_SENSE == dr_st) ||
- (SAM_STAT_CHECK_CONDITION == scsi_st) ||
- (SAM_STAT_COMMAND_TERMINATED == scsi_st))
- return SCSI_PT_RESULT_SENSE;
- else if (scsi_st)
- return SCSI_PT_RESULT_STATUS;
- else
- return SCSI_PT_RESULT_GOOD;
-}
-
-int
-get_scsi_pt_os_err(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- return ptp->os_err;
-}
-
-char *
-get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
- const char * cp;
-
- cp = safe_strerror(ptp->os_err);
- strncpy(b, cp, max_b_len);
- if ((int)strlen(cp) >= max_b_len)
- b[max_b_len - 1] = '\0';
- return b;
-}
-
-bool
-pt_device_is_nvme(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- return ptp->is_nvme;
-}
-
-/* If a NVMe block device (which includes the NSID) handle is associated
- * with 'vp', then its NSID is returned (values range from 0x1 to
- * 0xffffffe). Otherwise 0 is returned. */
-uint32_t
-get_pt_nvme_nsid(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- return ptp->nvme_nsid;
-}
-
-/* Executes SCSI command using sg v3 interface */
-static int
-do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp, int fd, int time_secs,
- int verbose)
-{
- struct sg_io_hdr v3_hdr;
-
- memset(&v3_hdr, 0, sizeof(v3_hdr));
- /* convert v4 to v3 header */
- v3_hdr.interface_id = 'S';
- v3_hdr.dxfer_direction = SG_DXFER_NONE;
- v3_hdr.cmdp = (unsigned char *)(long)ptp->io_hdr.request;
- v3_hdr.cmd_len = (unsigned char)ptp->io_hdr.request_len;
- if (ptp->io_hdr.din_xfer_len > 0) {
- if (ptp->io_hdr.dout_xfer_len > 0) {
- if (verbose)
- pr2ws("sgv3 doesn't support bidi\n");
- return SCSI_PT_DO_BAD_PARAMS;
- }
- v3_hdr.dxferp = (void *)(long)ptp->io_hdr.din_xferp;
- v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.din_xfer_len;
- v3_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- } else if (ptp->io_hdr.dout_xfer_len > 0) {
- v3_hdr.dxferp = (void *)(long)ptp->io_hdr.dout_xferp;
- v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.dout_xfer_len;
- v3_hdr.dxfer_direction = SG_DXFER_TO_DEV;
- }
- if (ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 0)) {
- v3_hdr.sbp = (unsigned char *)(long)ptp->io_hdr.response;
- v3_hdr.mx_sb_len = (unsigned char)ptp->io_hdr.max_response_len;
- }
- v3_hdr.pack_id = (int)ptp->io_hdr.spare_in;
- if (BSG_FLAG_Q_AT_HEAD & ptp->io_hdr.flags)
- v3_hdr.flags |= SG_FLAG_Q_AT_HEAD; /* favour AT_HEAD */
- else if (BSG_FLAG_Q_AT_TAIL & ptp->io_hdr.flags)
- v3_hdr.flags |= SG_FLAG_Q_AT_TAIL;
-
- if (NULL == v3_hdr.cmdp) {
- if (verbose)
- pr2ws("No SCSI command (cdb) given\n");
- return SCSI_PT_DO_BAD_PARAMS;
- }
- /* io_hdr.timeout is in milliseconds, if greater than zero */
- v3_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT);
- /* Finally do the v3 SG_IO ioctl */
- if (ioctl(fd, SG_IO, &v3_hdr) < 0) {
- ptp->os_err = errno;
- if (verbose > 1)
- pr2ws("ioctl(SG_IO v3) failed: %s (errno=%d)\n",
- safe_strerror(ptp->os_err), ptp->os_err);
- return -ptp->os_err;
- }
- ptp->io_hdr.device_status = (__u32)v3_hdr.status;
- ptp->io_hdr.driver_status = (__u32)v3_hdr.driver_status;
- ptp->io_hdr.transport_status = (__u32)v3_hdr.host_status;
- ptp->io_hdr.response_len = (__u32)v3_hdr.sb_len_wr;
- ptp->io_hdr.duration = (__u32)v3_hdr.duration;
- ptp->io_hdr.din_resid = (__s32)v3_hdr.resid;
- /* v3_hdr.info not passed back since no mapping defined (yet) */
- return 0;
-}
-
-/* Executes SCSI command (or at least forwards it to lower layers).
- * Returns 0 for success, negative numbers are negated 'errno' values from
- * OS system calls. Positive return values are errors from this package. */
-int
-do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose)
-{
- int err;
- struct sg_pt_linux_scsi * ptp = &vp->impl;
- bool have_checked_for_type = (ptp->dev_fd >= 0);
-
- if (! sg_bsg_nvme_char_major_checked) {
- sg_bsg_nvme_char_major_checked = true;
- sg_find_bsg_nvme_char_major(verbose);
- }
- if (ptp->in_err) {
- if (verbose)
- pr2ws("Replicated or unused set_scsi_pt... functions\n");
- return SCSI_PT_DO_BAD_PARAMS;
- }
- if (fd >= 0) {
- if ((ptp->dev_fd >= 0) && (fd != ptp->dev_fd)) {
- if (verbose)
- pr2ws("%s: file descriptor given to create() and here "
- "differ\n", __func__);
- return SCSI_PT_DO_BAD_PARAMS;
- }
- ptp->dev_fd = fd;
- } else if (ptp->dev_fd < 0) {
- if (verbose)
- pr2ws("%s: invalid file descriptors\n", __func__);
- return SCSI_PT_DO_BAD_PARAMS;
- } else
- fd = ptp->dev_fd;
- if (! have_checked_for_type) {
- err = set_pt_file_handle(vp, ptp->dev_fd, verbose);
- if (err)
- return -ptp->os_err;
- }
- if (ptp->os_err)
- return -ptp->os_err;
- if (ptp->is_nvme)
- return sg_do_nvme_pt(vp, -1, time_secs, verbose);
- else if (sg_bsg_major <= 0)
- return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
- else if (ptp->is_bsg)
- ; /* drop through to sg v4 implementation */
- else
- return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
-
- if (! ptp->io_hdr.request) {
- if (verbose)
- pr2ws("No SCSI command (cdb) given (v4)\n");
- return SCSI_PT_DO_BAD_PARAMS;
- }
- /* io_hdr.timeout is in milliseconds */
- ptp->io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) :
- DEF_TIMEOUT);
-#if 0
- /* sense buffer already zeroed */
- if (ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 0)) {
- void * p;
-
- p = (void *)(long)ptp->io_hdr.response;
- memset(p, 0, ptp->io_hdr.max_response_len);
- }
-#endif
- if (ioctl(fd, SG_IO, &ptp->io_hdr) < 0) {
- ptp->os_err = errno;
- if (verbose > 1)
- pr2ws("ioctl(SG_IO v4) failed: %s (errno=%d)\n",
- safe_strerror(ptp->os_err), ptp->os_err);
- return -ptp->os_err;
- }
- return 0;
-}
diff --git a/tools/sg_write_buffer/sg_pt_linux_nvme.c b/tools/sg_write_buffer/sg_pt_linux_nvme.c
deleted file mode 100644
index 5b08f6d..0000000
--- a/tools/sg_write_buffer/sg_pt_linux_nvme.c
+++ /dev/null
@@ -1,1185 +0,0 @@
-/*
- * Copyright (c) 2017-2018 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- *
- * The code to use the NVMe Management Interface (MI) SES pass-through
- * was provided by WDC in November 2017.
- */
-
-/*
- * Copyright 2017, Western Digital Corporation
- *
- * Written by Berck Nash
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- *
- * Based on the NVM-Express command line utility, which bore the following
- * notice:
- *
- * Copyright (c) 2014-2015, Intel Corporation.
- *
- * Written by Keith Busch <keith.busch@intel.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
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-/* sg_pt_linux_nvme version 1.04 20180115 */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#define __STDC_FORMAT_MACROS 1
-#include <inttypes.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h> /* to define 'major' */
-#ifndef major
-#include <sys/types.h>
-#endif
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <linux/major.h>
-
-#include "sg_pt.h"
-#include "sg_lib.h"
-#include "sg_linux_inc.h"
-#include "sg_pt_linux.h"
-#include "sg_unaligned.h"
-
-#define SCSI_INQUIRY_OPC 0x12
-#define SCSI_REPORT_LUNS_OPC 0xa0
-#define SCSI_TEST_UNIT_READY_OPC 0x0
-#define SCSI_REQUEST_SENSE_OPC 0x3
-#define SCSI_SEND_DIAGNOSTIC_OPC 0x1d
-#define SCSI_RECEIVE_DIAGNOSTIC_OPC 0x1c
-#define SCSI_MAINT_IN_OPC 0xa3
-#define SCSI_REP_SUP_OPCS_OPC 0xc
-#define SCSI_REP_SUP_TMFS_OPC 0xd
-
-/* Additional Sense Code (ASC) */
-#define NO_ADDITIONAL_SENSE 0x0
-#define LOGICAL_UNIT_NOT_READY 0x4
-#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
-#define UNRECOVERED_READ_ERR 0x11
-#define PARAMETER_LIST_LENGTH_ERR 0x1a
-#define INVALID_OPCODE 0x20
-#define LBA_OUT_OF_RANGE 0x21
-#define INVALID_FIELD_IN_CDB 0x24
-#define INVALID_FIELD_IN_PARAM_LIST 0x26
-#define UA_RESET_ASC 0x29
-#define UA_CHANGED_ASC 0x2a
-#define TARGET_CHANGED_ASC 0x3f
-#define LUNS_CHANGED_ASCQ 0x0e
-#define INSUFF_RES_ASC 0x55
-#define INSUFF_RES_ASCQ 0x3
-#define LOW_POWER_COND_ON_ASC 0x5e /* ASCQ=0 */
-#define POWER_ON_RESET_ASCQ 0x0
-#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
-#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
-#define CAPACITY_CHANGED_ASCQ 0x9
-#define SAVING_PARAMS_UNSUP 0x39
-#define TRANSPORT_PROBLEM 0x4b
-#define THRESHOLD_EXCEEDED 0x5d
-#define LOW_POWER_COND_ON 0x5e
-#define MISCOMPARE_VERIFY_ASC 0x1d
-#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
-#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
-
-
-static inline bool is_aligned(const void * pointer, size_t byte_count)
-{
- return ((sg_uintptr_t)pointer % byte_count) == 0;
-}
-
-
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
-#if (HAVE_NVME && (! IGNORE_NVME))
-
-/* This trims given NVMe block device name in Linux (e.g. /dev/nvme0n1p5)
- * to the name of its associated char device (e.g. /dev/nvme0). If this
- * occurs true is returned and the char device name is placed in 'b' (as
- * long as b_len is sufficient). Otherwise false is returned. */
-bool
-sg_get_nvme_char_devname(const char * nvme_block_devname, uint32_t b_len,
- char * b)
-{
- uint32_t n, tlen;
- const char * cp;
- char buff[8];
-
- if ((NULL == b) || (b_len < 5))
- return false; /* degenerate cases */
- cp = strstr(nvme_block_devname, "nvme");
- if (NULL == cp)
- return false; /* expected to find "nvme" in given name */
- if (1 != sscanf(cp, "nvme%u", &n))
- return false; /* didn't find valid "nvme<number>" */
- snprintf(buff, sizeof(buff), "%u", n);
- tlen = (cp - nvme_block_devname) + 4 + strlen(buff);
- if ((tlen + 1) > b_len)
- return false; /* b isn't long enough to fit output */
- memcpy(b, nvme_block_devname, tlen);
- b[tlen] = '\0';
- return true;
-}
-
-static void
-build_sense_buffer(bool desc, uint8_t *buf, uint8_t skey, uint8_t asc,
- uint8_t ascq)
-{
- if (desc) {
- buf[0] = 0x72; /* descriptor, current */
- buf[1] = skey;
- buf[2] = asc;
- buf[3] = ascq;
- buf[7] = 0;
- } else {
- buf[0] = 0x70; /* fixed, current */
- buf[2] = skey;
- buf[7] = 0xa; /* Assumes length is 18 bytes */
- buf[12] = asc;
- buf[13] = ascq;
- }
-}
-
-/* Set in_bit to -1 to indicate no bit position of invalid field */
-static void
-mk_sense_asc_ascq(struct sg_pt_linux_scsi * ptp, int sk, int asc, int ascq,
- int vb)
-{
- bool dsense = ptp->scsi_dsense;
- int n;
- uint8_t * sbp = (uint8_t *)ptp->io_hdr.response;
-
- ptp->io_hdr.device_status = SAM_STAT_CHECK_CONDITION;
- n = ptp->io_hdr.max_response_len;
- if ((n < 8) || ((! dsense) && (n < 14))) {
- if (vb)
- pr2ws("%s: max_response_len=%d too short, want 14 or more\n",
- __func__, n);
- return;
- } else
- ptp->io_hdr.response_len = dsense ? 8 : ((n < 18) ? n : 18);
- memset(sbp, 0, n);
- build_sense_buffer(dsense, sbp, sk, asc, ascq);
- if (vb > 3)
- pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__, sk,
- asc, ascq);
-}
-
-static void
-mk_sense_from_nvme_status(struct sg_pt_linux_scsi * ptp, int vb)
-{
- bool ok;
- bool dsense = ptp->scsi_dsense;
- int n;
- uint8_t sstatus, sk, asc, ascq;
- uint8_t * sbp = (uint8_t *)ptp->io_hdr.response;
-
- ok = sg_nvme_status2scsi(ptp->nvme_status, &sstatus, &sk, &asc, &ascq);
- if (! ok) { /* can't find a mapping to a SCSI error, so ... */
- sstatus = SAM_STAT_CHECK_CONDITION;
- sk = SPC_SK_ILLEGAL_REQUEST;
- asc = 0xb;
- ascq = 0x0; /* asc: "WARNING" purposely vague */
- }
-
- ptp->io_hdr.device_status = sstatus;
- n = ptp->io_hdr.max_response_len;
- if ((n < 8) || ((! dsense) && (n < 14))) {
- pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__, n);
- return;
- } else
- ptp->io_hdr.response_len = (dsense ? 8 : ((n < 18) ? n : 18));
- memset(sbp, 0, n);
- build_sense_buffer(dsense, sbp, sk, asc, ascq);
- if (vb > 3)
- pr2ws("%s: [status, sense_key,asc,ascq]: [0x%x, 0x%x,0x%x,0x%x]\n",
- __func__, sstatus, sk, asc, ascq);
-}
-
-/* Set in_bit to -1 to indicate no bit position of invalid field */
-static void
-mk_sense_invalid_fld(struct sg_pt_linux_scsi * ptp, bool in_cdb, int in_byte,
- int in_bit, int vb)
-{
- bool dsense = ptp->scsi_dsense;
- int sl, asc, n;
- uint8_t * sbp = (uint8_t *)ptp->io_hdr.response;
- uint8_t sks[4];
-
- ptp->io_hdr.device_status = SAM_STAT_CHECK_CONDITION;
- asc = in_cdb ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
- n = ptp->io_hdr.max_response_len;
- if ((n < 8) || ((! dsense) && (n < 14))) {
- if (vb)
- pr2ws("%s: max_response_len=%d too short, want 14 or more\n",
- __func__, n);
- return;
- } else
- ptp->io_hdr.response_len = dsense ? 8 : ((n < 18) ? n : 18);
- memset(sbp, 0, n);
- build_sense_buffer(dsense, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
- memset(sks, 0, sizeof(sks));
- sks[0] = 0x80;
- if (in_cdb)
- sks[0] |= 0x40;
- if (in_bit >= 0) {
- sks[0] |= 0x8;
- sks[0] |= (0x7 & in_bit);
- }
- sg_put_unaligned_be16(in_byte, sks + 1);
- if (dsense) {
- sl = sbp[7] + 8;
- sbp[7] = sl;
- sbp[sl] = 0x2;
- sbp[sl + 1] = 0x6;
- memcpy(sbp + sl + 4, sks, 3);
- } else
- memcpy(sbp + 15, sks, 3);
- if (vb > 3)
- pr2ws("%s: [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
- __func__, asc, in_cdb ? 'C' : 'D', in_byte, in_bit);
-}
-
-/* Returns 0 for success. Returns SG_LIB_NVME_STATUS if there is non-zero
- * NVMe status (from the completion queue) with the value placed in
- * ptp->nvme_status. If Unix error from ioctl then return negated value
- * (equivalent -errno from basic Unix system functions like open()).
- * CDW0 from the completion queue is placed in ptp->nvme_result in the
- * absence of a Unix error. If time_secs is negative it is treated as
- * a timeout in milliseconds (of abs(time_secs) ). */
-static int
-do_nvme_admin_cmd(struct sg_pt_linux_scsi * ptp,
- struct sg_nvme_passthru_cmd *cmdp, void * dp, bool is_read,
- int time_secs, int vb)
-{
- const uint32_t cmd_len = sizeof(struct sg_nvme_passthru_cmd);
- int res;
- uint32_t n;
- uint16_t sct_sc;
- const uint8_t * up = ((const uint8_t *)cmdp) + SG_NVME_PT_OPCODE;
-
- cmdp->timeout_ms = (time_secs < 0) ? (-time_secs) : (1000 * time_secs);
- ptp->os_err = 0;
- if (vb > 2) {
- pr2ws("NVMe command:\n");
- hex2stderr((const uint8_t *)cmdp, cmd_len, 1);
- if ((vb > 3) && (! is_read) && dp) {
- uint32_t len = sg_get_unaligned_le32(up + SG_NVME_PT_DATA_LEN);
-
- if (len > 0) {
- n = len;
- if ((len < 512) || (vb > 5))
- pr2ws("\nData-out buffer (%u bytes):\n", n);
- else {
- pr2ws("\nData-out buffer (first 512 of %u bytes):\n", n);
- n = 512;
- }
- hex2stderr((const uint8_t *)dp, n, 0);
- }
- }
- }
- res = ioctl(ptp->dev_fd, NVME_IOCTL_ADMIN_CMD, cmdp);
- if (res < 0) { /* OS error (errno negated) */
- ptp->os_err = -res;
- if (vb > 1) {
- pr2ws("%s: ioctl opcode=0x%x failed: %s "
- "(errno=%d)\n", __func__, *up, strerror(-res), -res);
- }
- return res;
- }
-
- /* Now res contains NVMe completion queue CDW3 31:17 (15 bits) */
- ptp->nvme_result = cmdp->result;
- if (ptp->nvme_direct && ptp->io_hdr.response &&
- (ptp->io_hdr.max_response_len > 3)) {
- /* build 16 byte "sense" buffer */
- uint8_t * sbp = (uint8_t *)ptp->io_hdr.response;
- uint16_t st = (uint16_t)res;
-
- n = ptp->io_hdr.max_response_len;
- n = (n < 16) ? n : 16;
- memset(sbp, 0 , n);
- ptp->io_hdr.response_len = n;
- sg_put_unaligned_le32(cmdp->result,
- sbp + SG_NVME_PT_CQ_RESULT);
- if (n > 15) /* LSBit will be 0 (Phase bit) after (st << 1) */
- sg_put_unaligned_le16(st << 1, sbp + SG_NVME_PT_CQ_STATUS_P);
- }
- /* clear upper bits (DNR and More) leaving ((SCT << 8) | SC) */
- sct_sc = 0x3ff & res;
- ptp->nvme_status = sct_sc;
- if (sct_sc) { /* when non-zero, treat as command error */
- if (vb > 1) {
- char b[80];
-
- pr2ws("%s: ioctl opcode=0x%x failed: NVMe status: %s [0x%x]\n",
- __func__, *up,
- sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b), sct_sc);
- }
- return SG_LIB_NVME_STATUS; /* == SCSI_PT_DO_NVME_STATUS */
- }
- if ((vb > 3) && is_read && dp) {
- uint32_t len = sg_get_unaligned_le32(up + SG_NVME_PT_DATA_LEN);
-
- if (len > 0) {
- n = len;
- if ((len < 1024) || (vb > 5))
- pr2ws("\nData-in buffer (%u bytes):\n", n);
- else {
- pr2ws("\nData-in buffer (first 1024 of %u bytes):\n", n);
- n = 1024;
- }
- hex2stderr((const uint8_t *)dp, n, 0);
- }
- }
- return 0;
-}
-
-/* Returns 0 on success; otherwise a positive value is returned */
-static int
-sntl_cache_identity(struct sg_pt_linux_scsi * ptp, int time_secs, int vb)
-{
- struct sg_nvme_passthru_cmd cmd;
- uint32_t pg_sz = sg_get_page_size();
- uint8_t * up;
-
- up = sg_memalign(pg_sz, pg_sz, &ptp->free_nvme_id_ctlp, vb > 3);
- ptp->nvme_id_ctlp = up;
- if (NULL == up) {
- pr2ws("%s: sg_memalign() failed to get memory\n", __func__);
- return -ENOMEM;
- }
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = 0x6; /* Identify */
- cmd.cdw10 = 0x1; /* CNS=0x1 Identify controller */
- cmd.addr = (uint64_t)(sg_uintptr_t)ptp->nvme_id_ctlp;
- cmd.data_len = pg_sz;
- return do_nvme_admin_cmd(ptp, &cmd, up, true, time_secs, vb);
-}
-
-static const char * nvme_scsi_vendor_str = "NVMe ";
-static const uint16_t inq_resp_len = 36;
-
-static int
-sntl_inq(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs,
- int vb)
-{
- bool evpd;
- bool cp_id_ctl = false;
- int res;
- uint16_t n, alloc_len, pg_cd;
- uint32_t pg_sz = sg_get_page_size();
- uint8_t * nvme_id_ns = NULL;
- uint8_t * free_nvme_id_ns = NULL;
- uint8_t inq_dout[256];
-
- if (vb > 3)
- pr2ws("%s: time_secs=%d\n", __func__, time_secs);
-
- if (0x2 & cdbp[1]) { /* Reject CmdDt=1 */
- mk_sense_invalid_fld(ptp, true, 1, 1, vb);
- return 0;
- }
- if (NULL == ptp->nvme_id_ctlp) {
- res = sntl_cache_identity(ptp, time_secs, vb);
- if (SG_LIB_NVME_STATUS == res) {
- mk_sense_from_nvme_status(ptp, vb);
- return 0;
- } else if (res) /* should be negative errno */
- return res;
- }
- memset(inq_dout, 0, sizeof(inq_dout));
- alloc_len = sg_get_unaligned_be16(cdbp + 3);
- evpd = !!(0x1 & cdbp[1]);
- pg_cd = cdbp[2];
- if (evpd) { /* VPD page responses */
- switch (pg_cd) {
- case 0:
- /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
- inq_dout[1] = pg_cd;
- n = 8;
- sg_put_unaligned_be16(n - 4, inq_dout + 2);
- inq_dout[4] = 0x0;
- inq_dout[5] = 0x80;
- inq_dout[6] = 0x83;
- inq_dout[n - 1] = 0xde; /* last VPD number */
- break;
- case 0x80:
- /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
- inq_dout[1] = pg_cd;
- sg_put_unaligned_be16(20, inq_dout + 2);
- memcpy(inq_dout + 4, ptp->nvme_id_ctlp + 4, 20); /* SN */
- n = 24;
- break;
- case 0x83:
- if ((ptp->nvme_nsid > 0) &&
- (ptp->nvme_nsid < SG_NVME_BROADCAST_NSID)) {
- nvme_id_ns = sg_memalign(pg_sz, pg_sz, &free_nvme_id_ns,
- vb > 3);
- if (nvme_id_ns) {
- struct sg_nvme_passthru_cmd cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = 0x6; /* Identify */
- cmd.nsid = ptp->nvme_nsid;
- cmd.cdw10 = 0x0; /* CNS=0x0 Identify namespace */
- cmd.addr = (uint64_t)(sg_uintptr_t)nvme_id_ns;
- cmd.data_len = pg_sz;
- res = do_nvme_admin_cmd(ptp, &cmd, nvme_id_ns, true,
- time_secs, vb > 3);
- if (res) {
- free(free_nvme_id_ns);
- free_nvme_id_ns = NULL;
- nvme_id_ns = NULL;
- }
- }
- }
- n = sg_make_vpd_devid_for_nvme(ptp->nvme_id_ctlp, nvme_id_ns,
- 0 /* pdt */, -1 /*tproto */,
- inq_dout, sizeof(inq_dout));
- if (n > 3)
- sg_put_unaligned_be16(n - 4, inq_dout + 2);
- if (free_nvme_id_ns) {
- free(free_nvme_id_ns);
- free_nvme_id_ns = NULL;
- nvme_id_ns = NULL;
- }
- break;
- case 0xde:
- inq_dout[1] = pg_cd;
- sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2);
- n = 16 + 4096;
- cp_id_ctl = true;
- break;
- default: /* Point to page_code field in cdb */
- mk_sense_invalid_fld(ptp, true, 2, 7, vb);
- return 0;
- }
- if (alloc_len > 0) {
- n = (alloc_len < n) ? alloc_len : n;
- n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len;
- ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n;
- if (n > 0) {
- if (cp_id_ctl) {
- memcpy((uint8_t *)ptp->io_hdr.din_xferp, inq_dout,
- (n < 16 ? n : 16));
- if (n > 16)
- memcpy((uint8_t *)ptp->io_hdr.din_xferp + 16,
- ptp->nvme_id_ctlp, n - 16);
- } else
- memcpy((uint8_t *)ptp->io_hdr.din_xferp, inq_dout, n);
- }
- }
- } else { /* Standard INQUIRY response */
- /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); pdt=0 --> SBC; 0xd --> SES */
- inq_dout[2] = 6; /* version: SPC-4 */
- inq_dout[3] = 2; /* NORMACA=0, HISUP=0, response data format: 2 */
- inq_dout[4] = 31; /* so response length is (or could be) 36 bytes */
- inq_dout[6] = 0x40; /* ENCSERV=1 */
- inq_dout[7] = 0x2; /* CMDQUE=1 */
- memcpy(inq_dout + 8, nvme_scsi_vendor_str, 8); /* NVMe not Intel */
- memcpy(inq_dout + 16, ptp->nvme_id_ctlp + 24, 16); /* Prod <-- MN */
- memcpy(inq_dout + 32, ptp->nvme_id_ctlp + 64, 4); /* Rev <-- FR */
- if (alloc_len > 0) {
- n = (alloc_len < inq_resp_len) ? alloc_len : inq_resp_len;
- n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len;
- ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n;
- if (n > 0)
- memcpy((uint8_t *)ptp->io_hdr.din_xferp, inq_dout, n);
- }
- }
- return 0;
-}
-
-static int
-sntl_rluns(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs,
- int vb)
-{
- int res;
- uint16_t sel_report;
- uint32_t alloc_len, k, n, num, max_nsid;
- uint8_t * rl_doutp;
- uint8_t * up;
-
- if (vb > 3)
- pr2ws("%s: time_secs=%d\n", __func__, time_secs);
-
- sel_report = cdbp[2];
- alloc_len = sg_get_unaligned_be32(cdbp + 6);
- if (NULL == ptp->nvme_id_ctlp) {
- res = sntl_cache_identity(ptp, time_secs, vb);
- if (SG_LIB_NVME_STATUS == res) {
- mk_sense_from_nvme_status(ptp, vb);
- return 0;
- } else if (res)
- return res;
- }
- max_nsid = sg_get_unaligned_le32(ptp->nvme_id_ctlp + 516);
- switch (sel_report) {
- case 0:
- case 2:
- num = max_nsid;
- break;
- case 1:
- case 0x10:
- case 0x12:
- num = 0;
- break;
- case 0x11:
- num = (1 == ptp->nvme_nsid) ? max_nsid : 0;
- break;
- default:
- if (vb > 1)
- pr2ws("%s: bad select_report value: 0x%x\n", __func__,
- sel_report);
- mk_sense_invalid_fld(ptp, true, 2, 7, vb);
- return 0;
- }
- rl_doutp = (uint8_t *)calloc(num + 1, 8);
- if (NULL == rl_doutp) {
- pr2ws("%s: calloc() failed to get memory\n", __func__);
- return -ENOMEM;
- }
- for (k = 0, up = rl_doutp + 8; k < num; ++k, up += 8)
- sg_put_unaligned_be16(k, up);
- n = num * 8;
- sg_put_unaligned_be32(n, rl_doutp);
- n+= 8;
- if (alloc_len > 0) {
- n = (alloc_len < n) ? alloc_len : n;
- n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len;
- ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n;
- if (n > 0)
- memcpy((uint8_t *)ptp->io_hdr.din_xferp, rl_doutp, n);
- }
- res = 0;
- free(rl_doutp);
- return res;
-}
-
-static int
-sntl_tur(struct sg_pt_linux_scsi * ptp, int time_secs, int vb)
-{
- int res;
- uint32_t pow_state;
- struct sg_nvme_passthru_cmd cmd;
-
- if (vb > 4)
- pr2ws("%s: time_secs=%d\n", __func__, time_secs);
- if (NULL == ptp->nvme_id_ctlp) {
- res = sntl_cache_identity(ptp, time_secs, vb);
- if (SG_LIB_NVME_STATUS == res) {
- mk_sense_from_nvme_status(ptp, vb);
- return 0;
- } else if (res)
- return res;
- }
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = 0xa; /* Get feature */
- cmd.nsid = SG_NVME_BROADCAST_NSID;
- cmd.cdw10 = 0x2; /* SEL=0 (current), Feature=2 Power Management */
- cmd.timeout_ms = (time_secs < 0) ? 0 : (1000 * time_secs);
- res = do_nvme_admin_cmd(ptp, &cmd, NULL, false, time_secs, vb);
- if (0 != res) {
- if (SG_LIB_NVME_STATUS == res) {
- mk_sense_from_nvme_status(ptp, vb);
- return 0;
- } else
- return res;
- } else {
- ptp->os_err = 0;
- ptp->nvme_status = 0;
- }
- pow_state = (0x1f & ptp->nvme_result);
- if (vb > 3)
- pr2ws("%s: pow_state=%u\n", __func__, pow_state);
-#if 0 /* pow_state bounces around too much on laptop */
- if (pow_state)
- mk_sense_asc_ascq(ptp, SPC_SK_NOT_READY, LOW_POWER_COND_ON_ASC, 0,
- vb);
-#endif
- return 0;
-}
-
-static int
-sntl_req_sense(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
- int time_secs, int vb)
-{
- bool desc;
- int res;
- uint32_t pow_state, alloc_len, n;
- struct sg_nvme_passthru_cmd cmd;
- uint8_t rs_dout[64];
-
- if (vb > 3)
- pr2ws("%s: time_secs=%d\n", __func__, time_secs);
- if (NULL == ptp->nvme_id_ctlp) {
- res = sntl_cache_identity(ptp, time_secs, vb);
- if (SG_LIB_NVME_STATUS == res) {
- mk_sense_from_nvme_status(ptp, vb);
- return 0;
- } else if (res)
- return res;
- }
- desc = !!(0x1 & cdbp[1]);
- alloc_len = cdbp[4];
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = 0xa; /* Get feature */
- cmd.nsid = SG_NVME_BROADCAST_NSID;
- cmd.cdw10 = 0x2; /* SEL=0 (current), Feature=2 Power Management */
- cmd.timeout_ms = (time_secs < 0) ? 0 : (1000 * time_secs);
- res = do_nvme_admin_cmd(ptp, &cmd, NULL, false, time_secs, vb);
- if (0 != res) {
- if (SG_LIB_NVME_STATUS == res) {
- mk_sense_from_nvme_status(ptp, vb);
- return 0;
- } else
- return res;
- } else {
- ptp->os_err = 0;
- ptp->nvme_status = 0;
- }
- ptp->io_hdr.response_len = 0;
- pow_state = (0x1f & ptp->nvme_result);
- if (vb > 3)
- pr2ws("%s: pow_state=%u\n", __func__, pow_state);
- memset(rs_dout, 0, sizeof(rs_dout));
- if (pow_state)
- build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
- LOW_POWER_COND_ON_ASC, 0);
- else
- build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
- NO_ADDITIONAL_SENSE, 0);
- n = desc ? 8 : 18;
- n = (n < alloc_len) ? n : alloc_len;
- n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len;
- ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n;
- if (n > 0)
- memcpy((uint8_t *)ptp->io_hdr.din_xferp, rs_dout, n);
- return 0;
-}
-
-/* This is not really a SNTL. For SCSI SEND DIAGNOSTIC(PF=1) NVMe-MI
- * has a special command (SES Send) to tunnel through pages to an
- * enclosure. The NVMe enclosure is meant to understand the SES
- * (SCSI Enclosure Services) use of diagnostics pages that are
- * related to SES. */
-static int
-sntl_senddiag(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
- int time_secs, int vb)
-{
- bool pf, self_test;
- int res;
- uint8_t st_cd, dpg_cd;
- uint32_t alloc_len, n, dout_len, dpg_len, nvme_dst;
- uint32_t pg_sz = sg_get_page_size();
- uint8_t * dop;
- struct sg_nvme_passthru_cmd cmd;
- uint8_t * cmd_up = (uint8_t *)&cmd;
-
- st_cd = 0x7 & (cdbp[1] >> 5);
- self_test = !! (0x4 & cdbp[1]);
- pf = !! (0x10 & cdbp[1]);
- if (vb > 3)
- pr2ws("%s: pf=%d, self_test=%d (st_code=%d)\n", __func__, (int)pf,
- (int)self_test, (int)st_cd);
- if (self_test || st_cd) {
- memset(cmd_up, 0, sizeof(cmd));
- cmd_up[SG_NVME_PT_OPCODE] = 0x14; /* Device self-test */
- /* just this namespace (if there is one) and controller */
- sg_put_unaligned_le32(ptp->nvme_nsid, cmd_up + SG_NVME_PT_NSID);
- switch (st_cd) {
- case 0: /* Here if self_test is set, do short self-test */
- case 1: /* Background short */
- case 5: /* Foreground short */
- nvme_dst = 1;
- break;
- case 2: /* Background extended */
- case 6: /* Foreground extended */
- nvme_dst = 2;
- break;
- case 4: /* Abort self-test */
- nvme_dst = 0xf;
- break;
- default:
- pr2ws("%s: bad self-test code [0x%x]\n", __func__, st_cd);
- mk_sense_invalid_fld(ptp, true, 1, 7, vb);
- return 0;
- }
- sg_put_unaligned_le32(nvme_dst, cmd_up + SG_NVME_PT_CDW10);
- res = do_nvme_admin_cmd(ptp, &cmd, NULL, false, time_secs, vb);
- if (0 != res) {
- if (SG_LIB_NVME_STATUS == res) {
- mk_sense_from_nvme_status(ptp, vb);
- return 0;
- } else
- return res;
- }
- }
- alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */
- dout_len = ptp->io_hdr.dout_xfer_len;
- if (pf) {
- if (0 == alloc_len) {
- mk_sense_invalid_fld(ptp, true, 3, 7, vb);
- if (vb)
- pr2ws("%s: PF bit set bit param_list_len=0\n", __func__);
- return 0;
- }
- } else { /* PF bit clear */
- if (alloc_len) {
- mk_sense_invalid_fld(ptp, true, 3, 7, vb);
- if (vb)
- pr2ws("%s: param_list_len>0 but PF clear\n", __func__);
- return 0;
- } else
- return 0; /* nothing to do */
- if (dout_len > 0) {
- if (vb)
- pr2ws("%s: dout given but PF clear\n", __func__);
- return SCSI_PT_DO_BAD_PARAMS;
- }
- }
- if (dout_len < 4) {
- if (vb)
- pr2ws("%s: dout length (%u bytes) too short\n", __func__,
- dout_len);
- return SCSI_PT_DO_BAD_PARAMS;
- }
- n = dout_len;
- n = (n < alloc_len) ? n : alloc_len;
- dop = (uint8_t *)ptp->io_hdr.dout_xferp;
- if (! is_aligned(dop, pg_sz)) { /* caller best use sg_memalign(,pg_sz) */
- if (vb)
- pr2ws("%s: dout [0x%" PRIx64 "] not page aligned\n", __func__,
- (uint64_t)ptp->io_hdr.dout_xferp);
- return SCSI_PT_DO_BAD_PARAMS;
- }
- dpg_cd = dop[0];
- dpg_len = sg_get_unaligned_be16(dop + 2) + 4;
- /* should we allow for more than one D_PG is dout ?? */
- n = (n < dpg_len) ? n : dpg_len; /* not yet ... */
-
- if (vb)
- pr2ws("%s: passing through d_pg=0x%x, len=%u to NVME_MI SES send\n",
- __func__, dpg_cd, dpg_len);
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = 0x1d; /* MI send; hmmm same opcode as SEND DIAG */
- cmd.addr = (uint64_t)(sg_uintptr_t)dop;
- cmd.data_len = 0x1000; /* NVMe 4k page size. Maybe determine this? */
- /* dout_len > 0x1000, is this a problem?? */
- cmd.cdw10 = 0x0804; /* NVMe Message Header */
- cmd.cdw11 = 0x9; /* nvme_mi_ses_send; (0x8 -> mi_ses_recv) */
- cmd.cdw13 = n;
- res = do_nvme_admin_cmd(ptp, &cmd, dop, false, time_secs, vb);
- if (0 != res) {
- if (SG_LIB_NVME_STATUS == res) {
- mk_sense_from_nvme_status(ptp, vb);
- return 0;
- }
- }
- return res;
-}
-
-/* This is not really a SNTL. For SCSI RECEIVE DIAGNOSTIC RESULTS(PCV=1)
- * NVMe-MI has a special command (SES Receive) to read pages through a
- * tunnel from an enclosure. The NVMe enclosure is meant to understand the
- * SES (SCSI Enclosure Services) use of diagnostics pages that are
- * related to SES. */
-static int
-sntl_recvdiag(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
- int time_secs, int vb)
-{
- bool pcv;
- int res;
- uint8_t dpg_cd;
- uint32_t alloc_len, n, din_len;
- uint32_t pg_sz = sg_get_page_size();
- uint8_t * dip;
- struct sg_nvme_passthru_cmd cmd;
-
- pcv = !! (0x1 & cdbp[1]);
- dpg_cd = cdbp[2];
- alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */
- if (vb > 3)
- pr2ws("%s: dpg_cd=0x%x, pcv=%d, alloc_len=0x%x\n", __func__,
- dpg_cd, (int)pcv, alloc_len);
- din_len = ptp->io_hdr.din_xfer_len;
- n = din_len;
- n = (n < alloc_len) ? n : alloc_len;
- dip = (uint8_t *)ptp->io_hdr.din_xferp;
- if (! is_aligned(dip, pg_sz)) { /* caller best use sg_memalign(,pg_sz) */
- if (vb)
- pr2ws("%s: din [0x%" PRIx64 "] not page aligned\n", __func__,
- (uint64_t)ptp->io_hdr.din_xferp);
- return SCSI_PT_DO_BAD_PARAMS;
- }
-
- if (vb)
- pr2ws("%s: expecting d_pg=0x%x from NVME_MI SES receive\n", __func__,
- dpg_cd);
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = 0x1e; /* MI receive */
- cmd.addr = (uint64_t)(sg_uintptr_t)dip;
- cmd.data_len = 0x1000; /* NVMe 4k page size. Maybe determine this? */
- /* din_len > 0x1000, is this a problem?? */
- cmd.cdw10 = 0x0804; /* NVMe Message Header */
- cmd.cdw11 = 0x8; /* nvme_mi_ses_receive */
- cmd.cdw12 = dpg_cd;
- cmd.cdw13 = n;
- res = do_nvme_admin_cmd(ptp, &cmd, dip, true, time_secs, vb);
- if (0 != res) {
- if (SG_LIB_NVME_STATUS == res) {
- mk_sense_from_nvme_status(ptp, vb);
- return 0;
- } else
- return res;
- }
- ptp->io_hdr.din_resid = din_len - n;
- return res;
-}
-
-#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
-#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
-#define FF_SA (F_SA_HIGH | F_SA_LOW)
-#define F_INV_OP 0x200
-
-static struct opcode_info_t {
- uint8_t opcode;
- uint16_t sa; /* service action, 0 for none */
- uint32_t flags; /* OR-ed set of F_* flags */
- uint8_t len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */
- /* ignore cdb bytes after position 15 */
- } opcode_info_arr[] = {
- {0x0, 0, 0, {6, /* TEST UNIT READY */
- 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
- {0x3, 0, 0, {6, /* REQUEST SENSE */
- 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
- {0x12, 0, 0, {6, /* INQUIRY */
- 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
- {0x1c, 0, 0, {6, /* RECEIVE DIAGNOSTIC RESULTS */
- 0x1, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
- {0x1d, 0, 0, {6, /* SEND DIAGNOSTIC */
- 0xf7, 0x0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
- {0xa0, 0, 0, {12, /* REPORT LUNS */
- 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} },
- {0xa3, 0xc, F_SA_LOW, {12, /* REPORT SUPPORTED OPERATION CODES */
- 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
- 0} },
- {0xa3, 0xd, F_SA_LOW, {12, /* REPORT SUPPORTED TASK MAN. FUNCTIONS */
- 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} },
-
- {0xff, 0xffff, 0xffff, {0, /* Sentinel, keep as last element */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-};
-
-static int
-sntl_rep_opcodes(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
- int time_secs, int vb)
-{
- bool rctd;
- uint8_t reporting_opts, req_opcode, supp;
- uint16_t req_sa, u;
- uint32_t alloc_len, offset, a_len;
- uint32_t pg_sz = sg_get_page_size();
- int k, len, count, bump;
- const struct opcode_info_t *oip;
- uint8_t *arr;
- uint8_t *free_arr;
-
- if (vb > 3)
- pr2ws("%s: time_secs=%d\n", __func__, time_secs);
- rctd = !!(cdbp[2] & 0x80); /* report command timeout desc. */
- reporting_opts = cdbp[2] & 0x7;
- req_opcode = cdbp[3];
- req_sa = sg_get_unaligned_be16(cdbp + 4);
- alloc_len = sg_get_unaligned_be32(cdbp + 6);
- if (alloc_len < 4 || alloc_len > 0xffff) {
- mk_sense_invalid_fld(ptp, true, 6, -1, vb);
- return 0;
- }
- a_len = pg_sz - 72;
- arr = sg_memalign(pg_sz, pg_sz, &free_arr, vb > 3);
- if (NULL == arr) {
- pr2ws("%s: calloc() failed to get memory\n", __func__);
- return -ENOMEM;
- }
- switch (reporting_opts) {
- case 0: /* all commands */
- count = 0;
- bump = rctd ? 20 : 8;
- for (offset = 4, oip = opcode_info_arr;
- (oip->flags != 0xffff) && (offset < a_len); ++oip) {
- if (F_INV_OP & oip->flags)
- continue;
- ++count;
- arr[offset] = oip->opcode;
- sg_put_unaligned_be16(oip->sa, arr + offset + 2);
- if (rctd)
- arr[offset + 5] |= 0x2;
- if (FF_SA & oip->flags)
- arr[offset + 5] |= 0x1;
- sg_put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
- if (rctd)
- sg_put_unaligned_be16(0xa, arr + offset + 8);
- offset += bump;
- }
- sg_put_unaligned_be32(count * bump, arr + 0);
- break;
- case 1: /* one command: opcode only */
- case 2: /* one command: opcode plus service action */
- case 3: /* one command: if sa==0 then opcode only else opcode+sa */
- for (oip = opcode_info_arr; oip->flags != 0xffff; ++oip) {
- if ((req_opcode == oip->opcode) && (req_sa == oip->sa))
- break;
- }
- if ((0xffff == oip->flags) || (F_INV_OP & oip->flags)) {
- supp = 1;
- offset = 4;
- } else {
- if (1 == reporting_opts) {
- if (FF_SA & oip->flags) {
- mk_sense_invalid_fld(ptp, true, 2, 2, vb);
- free(free_arr);
- return 0;
- }
- req_sa = 0;
- } else if ((2 == reporting_opts) && 0 == (FF_SA & oip->flags)) {
- mk_sense_invalid_fld(ptp, true, 4, -1, vb);
- free(free_arr);
- return 0;
- }
- if ((0 == (FF_SA & oip->flags)) && (req_opcode == oip->opcode))
- supp = 3;
- else if (0 == (FF_SA & oip->flags))
- supp = 1;
- else if (req_sa != oip->sa)
- supp = 1;
- else
- supp = 3;
- if (3 == supp) {
- u = oip->len_mask[0];
- sg_put_unaligned_be16(u, arr + 2);
- arr[4] = oip->opcode;
- for (k = 1; k < u; ++k)
- arr[4 + k] = (k < 16) ?
- oip->len_mask[k] : 0xff;
- offset = 4 + u;
- } else
- offset = 4;
- }
- arr[1] = (rctd ? 0x80 : 0) | supp;
- if (rctd) {
- sg_put_unaligned_be16(0xa, arr + offset);
- offset += 12;
- }
- break;
- default:
- mk_sense_invalid_fld(ptp, true, 2, 2, vb);
- free(free_arr);
- return 0;
- }
- offset = (offset < a_len) ? offset : a_len;
- len = (offset < alloc_len) ? offset : alloc_len;
- ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - len;
- if (len > 0)
- memcpy((uint8_t *)ptp->io_hdr.din_xferp, arr, len);
- free(free_arr);
- return 0;
-}
-
-static int
-sntl_rep_tmfs(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
- int time_secs, int vb)
-{
- bool repd;
- uint32_t alloc_len, len;
- uint8_t arr[16];
-
- if (vb > 3)
- pr2ws("%s: time_secs=%d\n", __func__, time_secs);
- memset(arr, 0, sizeof(arr));
- repd = !!(cdbp[2] & 0x80);
- alloc_len = sg_get_unaligned_be32(cdbp + 6);
- if (alloc_len < 4) {
- mk_sense_invalid_fld(ptp, true, 6, -1, vb);
- return 0;
- }
- arr[0] = 0xc8; /* ATS | ATSS | LURS */
- arr[1] = 0x1; /* ITNRS */
- if (repd) {
- arr[3] = 0xc;
- len = 16;
- } else
- len = 4;
-
- len = (len < alloc_len) ? len : alloc_len;
- ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - len;
- if (len > 0)
- memcpy((uint8_t *)ptp->io_hdr.din_xferp, arr, len);
- return 0;
-}
-
-/* Executes NVMe Admin command (or at least forwards it to lower layers).
- * Returns 0 for success, negative numbers are negated 'errno' values from
- * OS system calls. Positive return values are errors from this package.
- * When time_secs is 0 the Linux NVMe Admin command default of 60 seconds
- * is used. */
-int
-sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb)
-{
- bool scsi_cdb;
- bool is_read = false;
- int n, len;
- uint16_t sa;
- struct sg_pt_linux_scsi * ptp = &vp->impl;
- struct sg_nvme_passthru_cmd cmd;
- const uint8_t * cdbp;
- void * dp = NULL;
-
- if (! ptp->io_hdr.request) {
- if (vb)
- pr2ws("No NVMe command given (set_scsi_pt_cdb())\n");
- return SCSI_PT_DO_BAD_PARAMS;
- }
- if (fd >= 0) {
- if ((ptp->dev_fd >= 0) && (fd != ptp->dev_fd)) {
- if (vb)
- pr2ws("%s: file descriptor given to create() and here "
- "differ\n", __func__);
- return SCSI_PT_DO_BAD_PARAMS;
- }
- ptp->dev_fd = fd;
- } else if (ptp->dev_fd < 0) {
- if (vb)
- pr2ws("%s: invalid file descriptors\n", __func__);
- return SCSI_PT_DO_BAD_PARAMS;
- }
- n = ptp->io_hdr.request_len;
- cdbp = (const uint8_t *)ptp->io_hdr.request;
- if (vb > 3)
- pr2ws("%s: opcode=0x%x, fd=%d, time_secs=%d\n", __func__, cdbp[0],
- fd, time_secs);
- scsi_cdb = sg_is_scsi_cdb(cdbp, n);
- /* direct NVMe command (i.e. 64 bytes long) or SNTL */
- ptp->nvme_direct = ! scsi_cdb;
- if (scsi_cdb) {
- switch (cdbp[0]) {
- case SCSI_INQUIRY_OPC:
- return sntl_inq(ptp, cdbp, time_secs, vb);
- case SCSI_REPORT_LUNS_OPC:
- return sntl_rluns(ptp, cdbp, time_secs, vb);
- case SCSI_TEST_UNIT_READY_OPC:
- return sntl_tur(ptp, time_secs, vb);
- case SCSI_REQUEST_SENSE_OPC:
- return sntl_req_sense(ptp, cdbp, time_secs, vb);
- case SCSI_SEND_DIAGNOSTIC_OPC:
- return sntl_senddiag(ptp, cdbp, time_secs, vb);
- case SCSI_RECEIVE_DIAGNOSTIC_OPC:
- return sntl_recvdiag(ptp, cdbp, time_secs, vb);
- case SCSI_MAINT_IN_OPC:
- sa = 0x1f & cdbp[1]; /* service action */
- if (SCSI_REP_SUP_OPCS_OPC == sa)
- return sntl_rep_opcodes(ptp, cdbp, time_secs, vb);
- else if (SCSI_REP_SUP_TMFS_OPC == sa)
- return sntl_rep_tmfs(ptp, cdbp, time_secs, vb);
- /* fall through */
- default:
- if (vb > 2) {
- char b[64];
-
- sg_get_command_name(cdbp, -1, sizeof(b), b);
- pr2ws("%s: no translation to NVMe for SCSI %s command\n",
- __func__, b);
- }
- mk_sense_asc_ascq(ptp, SPC_SK_ILLEGAL_REQUEST, INVALID_OPCODE,
- 0, vb);
- return 0;
- }
- }
- len = (int)sizeof(cmd);
- n = (n < len) ? n : len;
- if (n < 64) {
- if (vb)
- pr2ws("%s: command length of %d bytes is too short\n", __func__,
- n);
- return SCSI_PT_DO_BAD_PARAMS;
- }
- memcpy(&cmd, (const uint8_t *)ptp->io_hdr.request, n);
- if (n < len) /* zero out rest of 'cmd' */
- memset((unsigned char *)&cmd + n, 0, len - n);
- if (ptp->io_hdr.din_xfer_len > 0) {
- cmd.data_len = ptp->io_hdr.din_xfer_len;
- dp = (void *)ptp->io_hdr.din_xferp;
- cmd.addr = (uint64_t)(sg_uintptr_t)ptp->io_hdr.din_xferp;
- is_read = true;
- } else if (ptp->io_hdr.dout_xfer_len > 0) {
- cmd.data_len = ptp->io_hdr.dout_xfer_len;
- dp = (void *)ptp->io_hdr.dout_xferp;
- cmd.addr = (uint64_t)(sg_uintptr_t)ptp->io_hdr.dout_xferp;
- is_read = false;
- }
- return do_nvme_admin_cmd(ptp, &cmd, dp, is_read, time_secs, vb);
-}
-
-#else /* (HAVE_NVME && (! IGNORE_NVME)) */
-
-int
-sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb)
-{
- if (vb)
- pr2ws("%s: not supported\n", __func__);
- if (vp) { ; } /* suppress warning */
- if (fd) { ; } /* suppress warning */
- if (time_secs) { ; } /* suppress warning */
- return -ENOTTY; /* inappropriate ioctl error */
-}
-
-#endif /* (HAVE_NVME && (! IGNORE_NVME)) */
diff --git a/tools/sg_write_buffer/sg_write_buffer.c b/tools/sg_write_buffer/sg_write_buffer.c
deleted file mode 100644
index 18d8f6f..0000000
--- a/tools/sg_write_buffer/sg_write_buffer.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright (c) 2006-2018 Luben Tuikov and Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <ctype.h>
-#include <string.h>
-#include <getopt.h>
-#define __STDC_FORMAT_MACROS 1
-#include <inttypes.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "sg_lib.h"
-#include "sg_cmds_basic.h"
-#include "sg_cmds_extra.h"
-#include "sg_unaligned.h"
-#include "sg_pr2serr.h"
-
-#ifdef SG_LIB_WIN32
-#ifdef SG_LIB_WIN32_DIRECT
-#include "sg_pt.h" /* needed for scsi_pt_win32_direct() */
-#endif
-#endif
-
-/*
- * This utility issues the SCSI WRITE BUFFER command to the given device.
- */
-
-static const char * version_str = "1.24 20180111"; /* spc5r18 */
-
-#define ME "sg_write_buffer: "
-#define DEF_XFER_LEN (8 * 1024 * 1024)
-#define EBUFF_SZ 256
-
-#define WRITE_BUFFER_CMD 0x3b
-#define WRITE_BUFFER_CMDLEN 10
-#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
-#define DEF_PT_TIMEOUT 300 /* 300 seconds, 5 minutes */
-
-static struct option long_options[] = {
- {"bpw", required_argument, 0, 'b'},
- {"dry-run", no_argument, 0, 'd'},
- {"dry_run", no_argument, 0, 'd'},
- {"help", no_argument, 0, 'h'},
- {"id", required_argument, 0, 'i'},
- {"in", required_argument, 0, 'I'},
- {"length", required_argument, 0, 'l'},
- {"mode", required_argument, 0, 'm'},
- {"offset", required_argument, 0, 'o'},
- {"read-stdin", no_argument, 0, 'r'},
- {"read_stdin", no_argument, 0, 'r'},
- {"raw", no_argument, 0, 'r'},
- {"skip", required_argument, 0, 's'},
- {"specific", required_argument, 0, 'S'},
- {"timeout", required_argument, 0, 't' },
- {"verbose", no_argument, 0, 'v'},
- {"version", no_argument, 0, 'V'},
- {0, 0, 0, 0},
-};
-
-
-static void
-usage()
-{
- pr2serr("Usage: "
- "sg_write_buffer [--bpw=CS] [--dry-run] [--help] [--id=ID] "
- "[--in=FILE]\n"
- " [--length=LEN] [--mode=MO] "
- "[--offset=OFF]\n"
- " [--read-stdin] [--skip=SKIP] "
- "[--specific=MS]\n"
- " [--timeout=TO] [--verbose] [--version] "
- "DEVICE\n"
- " where:\n"
- " --bpw=CS|-b CS CS is chunk size: bytes per write "
- "buffer\n"
- " command (def: 0 -> as many as "
- "possible)\n"
- " --dry-run|-d skip WRITE BUFFER commands, do "
- "everything else\n"
- " --help|-h print out usage message then exit\n"
- " --id=ID|-i ID buffer identifier (0 (default) to "
- "255)\n"
- " --in=FILE|-I FILE read from FILE ('-I -' read "
- "from stdin)\n"
- " --length=LEN|-l LEN length in bytes to write; may be "
- "deduced from\n"
- " FILE\n"
- " --mode=MO|-m MO write buffer mode, MO is number or "
- "acronym\n"
- " (def: 0 -> 'combined header and "
- "data' (obs))\n"
- " --offset=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n"
- " --read-stdin|-r read from stdin (same as '-I -')\n"
- " --skip=SKIP|-s SKIP bytes in file FILE to skip before "
- "reading\n"
- " --specific=MS|-S MS mode specific value; 3 bit field "
- "(0 to 7)\n"
- " --timeout=TO|-t TO command timeout in seconds (def: "
- "300)\n"
- " --verbose|-v increase verbosity\n"
- " --version|-V print version string and exit\n\n"
- "Performs one or more SCSI WRITE BUFFER commands. Use '-m xxx' "
- "to list\navailable modes. A chunk size of 4 KB ('--bpw=4k') "
- "seems to work well.\nExample: sg_write_buffer -b 4k -I xxx.lod "
- "-m 7 /dev/sg3\n"
- );
-
-}
-
-#define MODE_HEADER_DATA 0
-#define MODE_VENDOR 1
-#define MODE_DATA 2
-#define MODE_DNLD_MC 4
-#define MODE_DNLD_MC_SAVE 5
-#define MODE_DNLD_MC_OFFS 6
-#define MODE_DNLD_MC_OFFS_SAVE 7
-#define MODE_ECHO_BUFFER 0x0A
-#define MODE_DNLD_MC_EV_OFFS_DEFER 0x0D
-#define MODE_DNLD_MC_OFFS_DEFER 0x0E
-#define MODE_ACTIVATE_MC 0x0F
-#define MODE_EN_EX_ECHO 0x1A
-#define MODE_DIS_EX 0x1B
-#define MODE_DNLD_ERR_HISTORY 0x1C
-
-
-struct mode_s {
- const char *mode_string;
- int mode;
- const char *comment;
-};
-
-static struct mode_s mode_arr[] = {
- {"hd", MODE_HEADER_DATA, "combined header and data "
- "(obsolete)"},
- {"vendor", MODE_VENDOR, "vendor specific"},
- {"data", MODE_DATA, "data"},
- {"dmc", MODE_DNLD_MC, "download microcode and activate"},
- {"dmc_save", MODE_DNLD_MC_SAVE, "download microcode, save and "
- "activate"},
- {"dmc_offs", MODE_DNLD_MC_OFFS, "download microcode with offsets "
- "and activate"},
- {"dmc_offs_save", MODE_DNLD_MC_OFFS_SAVE, "download microcode with "
- "offsets, save and\n\t\t\t\tactivate"},
- {"echo", MODE_ECHO_BUFFER, "write data to echo buffer"},
- {"dmc_offs_ev_defer", MODE_DNLD_MC_EV_OFFS_DEFER, "download "
- "microcode with offsets, select\n\t\t\t\tactivation event, "
- "save and defer activation"},
- {"dmc_offs_defer", MODE_DNLD_MC_OFFS_DEFER, "download microcode "
- "with offsets, save and\n\t\t\t\tdefer activation"},
- {"activate_mc", MODE_ACTIVATE_MC, "activate deferred microcode"},
- {"en_ex", MODE_EN_EX_ECHO, "enable expander communications "
- "protocol and\n\t\t\t\techo buffer (obsolete)"},
- {"dis_ex", MODE_DIS_EX, "disable expander communications "
- "protocol\n\t\t\t\t(obsolete)"},
- {"deh", MODE_DNLD_ERR_HISTORY, "download application client "
- "error history "},
- {NULL, 0, NULL},
-};
-
-static void
-print_modes(void)
-{
- const struct mode_s * mp;
-
- pr2serr("The modes parameter argument can be numeric (hex or decimal)\n"
- "or symbolic:\n");
- for (mp = mode_arr; mp->mode_string; ++mp) {
- pr2serr(" %2d (0x%02x) %-18s%s\n", mp->mode, mp->mode,
- mp->mode_string, mp->comment);
- }
- pr2serr("\nAdditionally '--bpw=<val>,act' does a activate deferred "
- "microcode after\nsuccessful dmc_offs_defer and "
- "dmc_offs_ev_defer mode downloads.\n");
-}
-
-
-int
-main(int argc, char * argv[])
-{
- bool bpw_then_activate = false;
- bool dry_run = false;
- bool got_stdin = false;
- bool wb_len_given = false;
- int sg_fd, infd, res, c, len, k, n;
- int bpw = 0;
- int do_help = 0;
- int ret = 0;
- int verbose = 0;
- int wb_id = 0;
- int wb_len = 0;
- int wb_mode = 0;
- int wb_offset = 0;
- int wb_skip = 0;
- int wb_timeout = DEF_PT_TIMEOUT;
- int wb_mspec = 0;
- const char * device_name = NULL;
- const char * file_name = NULL;
- unsigned char * dop = NULL;
- char * cp;
- const struct mode_s * mp;
- char ebuff[EBUFF_SZ];
-
- while (1) {
- int option_index = 0;
-
- c = getopt_long(argc, argv, "b:dhi:I:l:m:o:rs:S:t:vV", long_options,
- &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'b':
- bpw = sg_get_num(optarg);
- if (bpw < 0) {
- pr2serr("argument to '--bpw' should be in a positive "
- "number\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- if ((cp = strchr(optarg, ','))) {
- if (0 == strncmp("act", cp + 1, 3))
- bpw_then_activate = true;
- }
- break;
- case 'd':
- dry_run = true;
- break;
- case 'h':
- case '?':
- ++do_help;
- break;
- case 'i':
- wb_id = sg_get_num(optarg);
- if ((wb_id < 0) || (wb_id > 255)) {
- pr2serr("argument to '--id' should be in the range 0 to "
- "255\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- break;
- case 'I':
- file_name = optarg;
- break;
- case 'l':
- wb_len = sg_get_num(optarg);
- if (wb_len < 0) {
- pr2serr("bad argument to '--length'\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- wb_len_given = true;
- break;
- case 'm':
- if (isdigit(*optarg)) {
- wb_mode = sg_get_num(optarg);
- if ((wb_mode < 0) || (wb_mode > 31)) {
- pr2serr("argument to '--mode' should be in the range 0 "
- "to 31\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- } else {
- len = strlen(optarg);
- for (mp = mode_arr; mp->mode_string; ++mp) {
- if (0 == strncmp(mp->mode_string, optarg, len)) {
- wb_mode = mp->mode;
- break;
- }
- }
- if (! mp->mode_string) {
- print_modes();
- return SG_LIB_SYNTAX_ERROR;
- }
- }
- break;
- case 'o':
- wb_offset = sg_get_num(optarg);
- if (wb_offset < 0) {
- pr2serr("bad argument to '--offset'\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- break;
- case 'r': /* --read-stdin and --raw (previous name) */
- file_name = "-";
- break;
- case 's':
- wb_skip = sg_get_num(optarg);
- if (wb_skip < 0) {
- pr2serr("bad argument to '--skip'\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- break;
- case 'S':
- wb_mspec = sg_get_num(optarg);
- if ((wb_mspec < 0) || (wb_mspec > 7)) {
- pr2serr("expected argument to '--specific' to be 0 to 7\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- break;
- case 't':
- wb_timeout = sg_get_num(optarg);
- if (wb_timeout < 0) {
- pr2serr("Invalid argument to '--timeout'\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- break;
- case 'v':
- ++verbose;
- break;
- case 'V':
- pr2serr(ME "version: %s\n", version_str);
- return 0;
- default:
- pr2serr("unrecognised option code 0x%x ??\n", c);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- }
- if (do_help) {
- if (do_help > 1) {
- usage();
- pr2serr("\n");
- print_modes();
- } else
- usage();
- return 0;
- }
- if (optind < argc) {
- if (NULL == device_name) {
- device_name = argv[optind];
- ++optind;
- }
- if (optind < argc) {
- for (; optind < argc; ++optind)
- pr2serr("Unexpected extra argument: %s\n", argv[optind]);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- }
-
- if (NULL == device_name) {
- pr2serr("missing device name!\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
-
- if ((wb_len > 0) && (bpw > wb_len)) {
- pr2serr("trim chunk size (CS) to be the same as LEN\n");
- bpw = wb_len;
- }
-
-#ifdef SG_LIB_WIN32
-#ifdef SG_LIB_WIN32_DIRECT
- if (verbose > 4)
- pr2serr("Initial win32 SPT interface state: %s\n",
- scsi_pt_win32_spt_state() ? "direct" : "indirect");
- scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
-#endif
-#endif
-
- sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose);
- if (sg_fd < 0) {
- pr2serr(ME "open error: %s: %s\n", device_name,
- safe_strerror(-sg_fd));
- return SG_LIB_FILE_ERROR;
- }
- if (file_name || (wb_len > 0)) {
- if (0 == wb_len)
- wb_len = DEF_XFER_LEN;
- if (NULL == (dop = (unsigned char *)malloc(wb_len))) {
- pr2serr(ME "out of memory\n");
- ret = SG_LIB_SYNTAX_ERROR;
- goto err_out;
- }
- memset(dop, 0xff, wb_len);
- if (file_name) {
- got_stdin = (0 == strcmp(file_name, "-"));
- if (got_stdin) {
- if (wb_skip > 0) {
- pr2serr("Can't skip on stdin\n");
- ret = SG_LIB_FILE_ERROR;
- goto err_out;
- }
- infd = STDIN_FILENO;
- } else {
- if ((infd = open(file_name, O_RDONLY)) < 0) {
- snprintf(ebuff, EBUFF_SZ,
- ME "could not open %s for reading", file_name);
- perror(ebuff);
- ret = SG_LIB_FILE_ERROR;
- goto err_out;
- } else if (sg_set_binary_mode(infd) < 0)
- perror("sg_set_binary_mode");
- if (wb_skip > 0) {
- if (lseek(infd, wb_skip, SEEK_SET) < 0) {
- snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to "
- "required position on %s", file_name);
- perror(ebuff);
- close(infd);
- ret = SG_LIB_FILE_ERROR;
- goto err_out;
- }
- }
- }
- res = read(infd, dop, wb_len);
- if (res < 0) {
- snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
- file_name);
- perror(ebuff);
- if (! got_stdin)
- close(infd);
- ret = SG_LIB_FILE_ERROR;
- goto err_out;
- }
- if (res < wb_len) {
- if (wb_len_given) {
- pr2serr("tried to read %d bytes from %s, got %d bytes\n",
- wb_len, file_name, res);
- pr2serr("pad with 0xff bytes and continue\n");
- } else {
- if (verbose) {
- pr2serr("tried to read %d bytes from %s, got %d "
- "bytes\n", wb_len, file_name, res);
- pr2serr("will write %d bytes", res);
- if ((bpw > 0) && (bpw < wb_len))
- pr2serr(", %d bytes per WRITE BUFFER command\n",
- bpw);
- else
- pr2serr("\n");
- }
- wb_len = res;
- }
- }
- if (! got_stdin)
- close(infd);
- }
- }
-
- res = 0;
- if (bpw > 0) {
- for (k = 0; k < wb_len; k += n) {
- n = wb_len - k;
- if (n > bpw)
- n = bpw;
- if (verbose)
- pr2serr("sending write buffer, mode=0x%x, mspec=%d, id=%d, "
- " offset=%d, len=%d\n", wb_mode, wb_mspec, wb_id,
- wb_offset + k, n);
- if (dry_run) {
- if (verbose)
- pr2serr("skipping WRITE BUFFER command due to "
- "--dry-run\n");
- res = 0;
- } else
- res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id,
- wb_offset + k, dop + k, n,
- wb_timeout, true, verbose);
- if (res)
- break;
- }
- if (bpw_then_activate) {
- if (verbose)
- pr2serr("sending Activate deferred microcode [0xf]\n");
- if (dry_run) {
- if (verbose)
- pr2serr("skipping WRITE BUFFER(ACTIVATE) command due to "
- "--dry-run\n");
- res = 0;
- } else
- res = sg_ll_write_buffer_v2(sg_fd, MODE_ACTIVATE_MC,
- 0 /* buffer_id */,
- 0 /* buffer_offset */, 0,
- NULL, 0, wb_timeout, true,
- verbose);
- }
- } else {
- if (verbose)
- pr2serr("sending single write buffer, mode=0x%x, mpsec=%d, "
- "id=%d, offset=%d, len=%d\n", wb_mode, wb_mspec, wb_id,
- wb_offset, wb_len);
- if (dry_run) {
- if (verbose)
- pr2serr("skipping WRITE BUFFER(all in one) command due to "
- "--dry-run\n");
- res = 0;
- } else
- res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id,
- wb_offset, dop, wb_len, wb_timeout,
- true, verbose);
- }
- if (0 != res) {
- char b[80];
-
- ret = res;
- sg_get_category_sense_str(res, sizeof(b), b, verbose);
- pr2serr("Write buffer failed: %s\n", b);
- }
-
-err_out:
- if (dop)
- free(dop);
- res = sg_cmds_close_device(sg_fd);
- if (res < 0) {
- pr2serr("close error: %s\n", safe_strerror(-res));
- if (0 == ret)
- return SG_LIB_FILE_ERROR;
- }
- return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
-}