"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/sg_cmds_basic.c" between
sdparm-1.11.tgz and sdparm-1.12.tgz

About: sdparm let you access SCSI modes pages, read VPD pages, send simple SCSI commands (similar functionality for SCSI disks like "hdparm" for ATA disks).

sg_cmds_basic.c  (sdparm-1.11.tgz):sg_cmds_basic.c  (sdparm-1.12.tgz)
/* /*
* Copyright (c) 1999-2019 Douglas Gilbert. * Copyright (c) 1999-2020 Douglas Gilbert.
* All rights reserved. * All rights reserved.
* Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
* license that can be found in the BSD_LICENSE file. * license that can be found in the BSD_LICENSE file.
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
/* /*
* CONTENTS * CONTENTS
* Some SCSI commands are executed in many contexts and hence began * Some SCSI commands are executed in many contexts and hence began
skipping to change at line 44 skipping to change at line 44
#include "sg_cmds_basic.h" #include "sg_cmds_basic.h"
#include "sg_pt.h" #include "sg_pt.h"
#include "sg_unaligned.h" #include "sg_unaligned.h"
#include "sg_pr2serr.h" #include "sg_pr2serr.h"
/* Needs to be after config.h */ /* Needs to be after config.h */
#ifdef SG_LIB_LINUX #ifdef SG_LIB_LINUX
#include <errno.h> #include <errno.h>
#endif #endif
static const char * const version_str = "1.95 20191219"; static const char * const version_str = "1.97 20200722";
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
#define EBUFF_SZ 256 #define EBUFF_SZ 256
#define DEF_PT_TIMEOUT 60 /* 60 seconds */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */
#define START_PT_TIMEOUT 120 /* 120 seconds == 2 minutes */ #define START_PT_TIMEOUT 120 /* 120 seconds == 2 minutes */
#define LONG_PT_TIMEOUT 7200 /* 7,200 seconds == 120 minutes */ #define LONG_PT_TIMEOUT 7200 /* 7,200 seconds == 120 minutes */
#define INQUIRY_CMD 0x12 #define INQUIRY_CMD 0x12
#define INQUIRY_CMDLEN 6 #define INQUIRY_CMDLEN 6
skipping to change at line 182 skipping to change at line 182
} }
if (o_sense_cat) if (o_sense_cat)
*o_sense_cat = scat; *o_sense_cat = scat;
return -2; return -2;
} }
/* This is a helper function used by sg_cmds_* implementations after the /* 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 * 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: * 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 * stderr); depending on the 'noisy' and 'verbose' settings. Returns -2 for
* "sense" category (may not be fatal), -1 for failed, 0, or a positive * o_sense_cat (sense category) written which may not be fatal. Returns
* number. If din type command (or bidi) returns actual number of bytes read * -1 for other types of failure. Returns 0, or a positive number. If data-in
* (din_len - resid); otherwise returns 0. If -2 returned then sense category * type command (or bidi) then returns actual number of bytes read
* output via 'o_sense_cat' pointer (if not NULL). Note that several sense * (din_len - resid); otherwise returns 0. Note that several sense categories
* categories also have data in bytes received; -2 is still returned. */ * also have data in bytes received; -2 is still returned. */
int int
sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin, sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin,
int pt_res, bool noisy, int verbose, int * o_sense_cat) int pt_res, bool noisy, int verbose, int * o_sense_cat)
{ {
bool transport_sense; bool favour_sense;
int cat, slen, resp_code, sstat, req_din_x, req_dout_x; int cat, slen, resp_code, sstat, req_din_x, req_dout_x;
int act_din_x, act_dout_x; int act_din_x, act_dout_x;
const uint8_t * sbp; const uint8_t * sbp;
char b[1024]; char b[1024];
if (NULL == leadin) if (NULL == leadin)
leadin = ""; leadin = "";
if (pt_res < 0) { if (pt_res < 0) {
#ifdef SG_LIB_LINUX #ifdef SG_LIB_LINUX
if (verbose) if (verbose)
skipping to change at line 321 skipping to change at line 321
return -1; return -1;
case SCSI_PT_RESULT_SENSE: case SCSI_PT_RESULT_SENSE:
return sg_cmds_process_helper(leadin, req_din_x, act_din_x, return sg_cmds_process_helper(leadin, req_din_x, act_din_x,
req_dout_x, act_dout_x, sbp, slen, req_dout_x, act_dout_x, sbp, slen,
noisy, verbose, o_sense_cat); noisy, verbose, o_sense_cat);
case SCSI_PT_RESULT_TRANSPORT_ERR: case SCSI_PT_RESULT_TRANSPORT_ERR:
if (verbose || noisy) { if (verbose || noisy) {
get_scsi_pt_transport_err_str(ptvp, sizeof(b), b); get_scsi_pt_transport_err_str(ptvp, sizeof(b), b);
pr2ws("%s: transport: %s\n", leadin, b); pr2ws("%s: transport: %s\n", leadin, b);
} }
/* Shall we favour sense data over a transport error (given both) */
#ifdef SG_LIB_LINUX #ifdef SG_LIB_LINUX
transport_sense = (slen > 0); favour_sense = false; /* DRIVER_SENSE is not passed through */
#else #else
transport_sense = ((SAM_STAT_CHECK_CONDITION == favour_sense = ((SAM_STAT_CHECK_CONDITION ==
get_scsi_pt_status_response(ptvp)) && (slen > 0)); get_scsi_pt_status_response(ptvp)) && (slen > 0));
#endif #endif
if (transport_sense) if (favour_sense)
return sg_cmds_process_helper(leadin, req_din_x, act_din_x, return sg_cmds_process_helper(leadin, req_din_x, act_din_x,
req_dout_x, act_dout_x, sbp, slen, req_dout_x, act_dout_x, sbp, slen,
noisy, verbose, o_sense_cat); noisy, verbose, o_sense_cat);
else else
return -1; return -1;
case SCSI_PT_RESULT_OS_ERR: case SCSI_PT_RESULT_OS_ERR:
if (verbose || noisy) { if (verbose || noisy) {
get_scsi_pt_os_err_str(ptvp, sizeof(b), b); get_scsi_pt_os_err_str(ptvp, sizeof(b), b);
pr2ws("%s: os: %s\n", leadin, b); pr2ws("%s: os: %s\n", leadin, b);
} }
skipping to change at line 366 skipping to change at line 367
if (NULL == ptvp) if (NULL == ptvp)
pr2ws("%s: out of memory\n", cname); pr2ws("%s: out of memory\n", cname);
return ptvp; return ptvp;
} }
static const char * const inquiry_s = "inquiry"; static const char * const inquiry_s = "inquiry";
/* Returns 0 on success, while positive values are SG_LIB_CAT_* errors /* Returns 0 on success, while positive values are SG_LIB_CAT_* errors
* (e.g. SG_LIB_CAT_MALFORMED). If OS error, returns negated errno or -1. */ * (e.g. SG_LIB_CAT_MALFORMED). If OS error, returns negated errno or -1. */
static int static int
sg_ll_inquiry_com(struct sg_pt_base * ptvp, bool cmddt, bool evpd, int pg_op, sg_ll_inquiry_com(struct sg_pt_base * ptvp, int sg_fd, bool cmddt, bool evpd,
void * resp, int mx_resp_len, int timeout_secs, int pg_op, void * resp, int mx_resp_len, int timeout_secs,
int * residp, bool noisy, int verbose) int * residp, bool noisy, int verbose)
{ {
bool ptvp_given = false;
bool local_sense = true;
bool local_cdb = true;
int res, ret, sense_cat, resid; int res, ret, sense_cat, resid;
uint8_t inq_cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0}; uint8_t inq_cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN]; uint8_t sense_b[SENSE_BUFF_LEN];
uint8_t * up; uint8_t * up;
if (resp == NULL) { if (resp == NULL) {
if (verbose) if (verbose)
pr2ws("Got NULL `resp` pointer"); pr2ws("Got NULL `resp` pointer");
return SG_LIB_CAT_MALFORMED; return SG_LIB_CAT_MALFORMED;
} }
skipping to change at line 402 skipping to change at line 406
b)); b));
} }
if (resp && (mx_resp_len > 0)) { if (resp && (mx_resp_len > 0)) {
up = (uint8_t *)resp; up = (uint8_t *)resp;
up[0] = 0x7f; /* defensive prefill */ up[0] = 0x7f; /* defensive prefill */
if (mx_resp_len > 4) if (mx_resp_len > 4)
up[4] = 0; up[4] = 0;
} }
if (timeout_secs <= 0) if (timeout_secs <= 0)
timeout_secs = DEF_PT_TIMEOUT; timeout_secs = DEF_PT_TIMEOUT;
set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb)); if (ptvp) {
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); ptvp_given = true;
partial_clear_scsi_pt_obj(ptvp);
if (get_scsi_pt_cdb_buf(ptvp))
local_cdb = false; /* N.B. Ignores locally built cdb */
else
set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb));
if (get_scsi_pt_sense_buf(ptvp))
local_sense = false;
else
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
} else {
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
if (NULL == ptvp)
return sg_convert_errno(ENOMEM);
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, (uint8_t *)resp, mx_resp_len); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, -1, timeout_secs, verbose); res = do_scsi_pt(ptvp, -1, timeout_secs, verbose);
ret = sg_cmds_process_resp(ptvp, inquiry_s, res, noisy, verbose, ret = sg_cmds_process_resp(ptvp, inquiry_s, res, noisy, verbose,
&sense_cat); &sense_cat);
resid = get_scsi_pt_resid(ptvp); resid = get_scsi_pt_resid(ptvp);
if (residp) if (residp)
*residp = resid; *residp = resid;
if (-1 == ret) if (-1 == ret)
ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
else if (-2 == ret) { else if (-2 == ret) {
skipping to change at line 434 skipping to change at line 454
if (verbose) if (verbose)
pr2ws("%s: got too few bytes (%d)\n", __func__, ret); pr2ws("%s: got too few bytes (%d)\n", __func__, ret);
ret = SG_LIB_CAT_MALFORMED; ret = SG_LIB_CAT_MALFORMED;
} else } else
ret = 0; ret = 0;
if (resid > 0) { if (resid > 0) {
if (resid > mx_resp_len) { if (resid > mx_resp_len) {
pr2ws("%s resid (%d) should never exceed requested " pr2ws("%s resid (%d) should never exceed requested "
"len=%d\n", inquiry_s, resid, mx_resp_len); "len=%d\n", inquiry_s, resid, mx_resp_len);
return ret ? ret : SG_LIB_CAT_MALFORMED; if (0 == ret)
ret = SG_LIB_CAT_MALFORMED;
goto fini;
} }
/* zero unfilled section of response buffer, based on resid */ /* zero unfilled section of response buffer, based on resid */
memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid); memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid);
} }
fini:
if (ptvp_given) {
if (local_sense) /* stop caller trying to access local sense */
set_scsi_pt_sense(ptvp, NULL, 0);
if (local_cdb)
set_scsi_pt_cdb(ptvp, NULL, 0);
} else {
if (ptvp)
destruct_scsi_pt_obj(ptvp);
}
return ret; return ret;
} }
/* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when /* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when
* successful, various SG_LIB_CAT_* positive values, negated errno or * successful, various SG_LIB_CAT_* positive values, negated errno or
* -1 -> other errors. The CMDDT field is obsolete in the INQUIRY cdb. */ * -1 -> other errors. The CMDDT field is obsolete in the INQUIRY cdb. */
int int
sg_ll_inquiry(int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp, sg_ll_inquiry(int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp,
int mx_resp_len, bool noisy, int verbose) int mx_resp_len, bool noisy, int verbose)
{ {
int ret; return sg_ll_inquiry_com(NULL, sg_fd, cmddt, evpd, pg_op, resp,
struct sg_pt_base * ptvp; mx_resp_len, 0 /* timeout_sec */, NULL, noisy,
verbose);
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
if (NULL == ptvp)
return sg_convert_errno(ENOMEM);
ret = sg_ll_inquiry_com(ptvp, cmddt, evpd, pg_op, resp, mx_resp_len,
0 /* timeout_sec */, NULL, noisy, verbose);
destruct_scsi_pt_obj(ptvp);
return ret;
} }
/* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when /* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when
* successful, various SG_LIB_CAT_* positive values or -1 -> other errors. * 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 * 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 * 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 * 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 * and the ability to report the residual count. If timeout_secs is zero
* or less the default command abort timeout (60 seconds) is used. * or less the default command abort timeout (60 seconds) is used.
* If residp is non-NULL then the residual value is written where residp * 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 * 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 * where resp points. If the residual value equals mx_resp_len then no
* bytes have been written. */ * bytes have been written. */
int int
sg_ll_inquiry_v2(int sg_fd, bool evpd, int pg_op, void * resp, sg_ll_inquiry_v2(int sg_fd, bool evpd, int pg_op, void * resp,
int mx_resp_len, int timeout_secs, int * residp, int mx_resp_len, int timeout_secs, int * residp,
bool noisy, int verbose) bool noisy, int verbose)
{ {
int ret; return sg_ll_inquiry_com(NULL, sg_fd, false, evpd, pg_op, resp,
struct sg_pt_base * ptvp; mx_resp_len, timeout_secs, residp, noisy,
verbose);
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
if (NULL == ptvp)
return sg_convert_errno(ENOMEM);
ret = sg_ll_inquiry_com(ptvp, false, evpd, pg_op, resp, mx_resp_len,
timeout_secs, residp, noisy, verbose);
destruct_scsi_pt_obj(ptvp);
return ret;
} }
/* Similar to _v2 but takes a pointer to an object (derived from) sg_pt_base. /* Similar to _v2 but takes a pointer to an object (derived from) sg_pt_base.
* That object is assumed to be constructed and have a device file descriptor * That object is assumed to be constructed and have a device file descriptor
* associated with it. Caller is responsible for lifetime of ptp. */ * associated with it. Caller is responsible for lifetime of ptp. */
int int
sg_ll_inquiry_pt(struct sg_pt_base * ptvp, bool evpd, int pg_op, void * resp, sg_ll_inquiry_pt(struct sg_pt_base * ptvp, bool evpd, int pg_op, void * resp,
int mx_resp_len, int timeout_secs, int * residp, bool noisy, int mx_resp_len, int timeout_secs, int * residp, bool noisy,
int verbose) int verbose)
{ {
clear_scsi_pt_obj(ptvp); return sg_ll_inquiry_com(ptvp, -1, false, evpd, pg_op, resp, mx_resp_len,
return sg_ll_inquiry_com(ptvp, false, evpd, pg_op, resp, mx_resp_len,
timeout_secs, residp, noisy, verbose); timeout_secs, residp, noisy, verbose);
} }
/* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response. /* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response.
* Returns 0 when successful, various SG_LIB_CAT_* positive values, negated * Returns 0 when successful, various SG_LIB_CAT_* positive values, negated
* errno or -1 -> other errors */ * errno or -1 -> other errors */
int int
sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data, sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
bool noisy, int verbose) bool noisy, int verbose)
{ {
int ret; int ret;
skipping to change at line 524 skipping to change at line 540
if (inq_data) { if (inq_data) {
memset(inq_data, 0, sizeof(* inq_data)); memset(inq_data, 0, sizeof(* inq_data));
inq_data->peripheral_qualifier = 0x3; inq_data->peripheral_qualifier = 0x3;
inq_data->peripheral_type = 0x1f; inq_data->peripheral_type = 0x1f;
} }
inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false); inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false);
if (NULL == inq_resp) { if (NULL == inq_resp) {
pr2ws("%s: out of memory\n", __func__); pr2ws("%s: out of memory\n", __func__);
return sg_convert_errno(ENOMEM); return sg_convert_errno(ENOMEM);
} }
ret = sg_ll_inquiry_v2(sg_fd, false, 0, inq_resp, SAFE_STD_INQ_RESP_LEN, ret = sg_ll_inquiry_com(NULL, sg_fd, false, false, 0, inq_resp,
0, NULL, noisy, verbose); SAFE_STD_INQ_RESP_LEN, 0, NULL, noisy, verbose);
if (inq_data && (0 == ret)) { if (inq_data && (0 == ret)) {
inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7; inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7;
inq_data->peripheral_type = inq_resp[0] & 0x1f; inq_data->peripheral_type = inq_resp[0] & 0x1f;
inq_data->byte_1 = inq_resp[1]; inq_data->byte_1 = inq_resp[1];
inq_data->version = inq_resp[2]; inq_data->version = inq_resp[2];
inq_data->byte_3 = inq_resp[3]; inq_data->byte_3 = inq_resp[3];
inq_data->byte_5 = inq_resp[5]; inq_data->byte_5 = inq_resp[5];
inq_data->byte_6 = inq_resp[6]; inq_data->byte_6 = inq_resp[6];
inq_data->byte_7 = inq_resp[7]; inq_data->byte_7 = inq_resp[7];
skipping to change at line 566 skipping to change at line 582
if (inq_data) { if (inq_data) {
memset(inq_data, 0, sizeof(* inq_data)); memset(inq_data, 0, sizeof(* inq_data));
inq_data->peripheral_qualifier = 0x3; inq_data->peripheral_qualifier = 0x3;
inq_data->peripheral_type = 0x1f; inq_data->peripheral_type = 0x1f;
} }
inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false); inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false);
if (NULL == inq_resp) { if (NULL == inq_resp) {
pr2ws("%s: out of memory\n", __func__); pr2ws("%s: out of memory\n", __func__);
return sg_convert_errno(ENOMEM); return sg_convert_errno(ENOMEM);
} }
ret = sg_ll_inquiry_pt(ptvp, false, 0, inq_resp, SAFE_STD_INQ_RESP_LEN, ret = sg_ll_inquiry_com(ptvp, -1, false, false, 0, inq_resp,
0, NULL, noisy, verbose); SAFE_STD_INQ_RESP_LEN, 0, NULL, noisy, verbose);
if (inq_data && (0 == ret)) { if (inq_data && (0 == ret)) {
inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7; inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7;
inq_data->peripheral_type = inq_resp[0] & 0x1f; inq_data->peripheral_type = inq_resp[0] & 0x1f;
inq_data->byte_1 = inq_resp[1]; inq_data->byte_1 = inq_resp[1];
inq_data->version = inq_resp[2]; inq_data->version = inq_resp[2];
inq_data->byte_3 = inq_resp[3]; inq_data->byte_3 = inq_resp[3];
inq_data->byte_5 = inq_resp[5]; inq_data->byte_5 = inq_resp[5];
inq_data->byte_6 = inq_resp[6]; inq_data->byte_6 = inq_resp[6];
inq_data->byte_7 = inq_resp[7]; inq_data->byte_7 = inq_resp[7];
memcpy(inq_data->vendor, inq_resp + 8, 8); memcpy(inq_data->vendor, inq_resp + 8, 8);
memcpy(inq_data->product, inq_resp + 16, 16); memcpy(inq_data->product, inq_resp + 16, 16);
memcpy(inq_data->revision, inq_resp + 32, 4); memcpy(inq_data->revision, inq_resp + 32, 4);
} }
if (free_irp) if (free_irp)
free(free_irp); free(free_irp);
return ret; return ret;
} }
/* Invokes a SCSI TEST UNIT READY command. /* Invokes a SCSI TEST UNIT READY command.
* N.B. To access the sense buffer outside this routine then one be
* provided by the caller.
* 'pack_id' is just for diagnostics, safe to set to 0. * 'pack_id' is just for diagnostics, safe to set to 0.
* Looks for progress indicator if 'progress' non-NULL; * Looks for progress indicator if 'progress' non-NULL;
* if found writes value [0..65535] else write -1. * if found writes value [0..65535] else write -1.
* Returns 0 when successful, various SG_LIB_CAT_* positive values or * Returns 0 when successful, various SG_LIB_CAT_* positive values or
* -1 -> other errors */ * -1 -> other errors */
int static int
sg_ll_test_unit_ready_progress_pt(struct sg_pt_base * ptvp, int pack_id, sg_ll_test_unit_ready_com(struct sg_pt_base * ptvp, int sg_fd, int pack_id,
int * progress, bool noisy, int verbose) int * progress, bool noisy, int verbose)
{ {
static const char * const tur_s = "test unit ready"; static const char * const tur_s = "test unit ready";
bool ptvp_given = false;
bool local_sense = true;
bool local_cdb = true;
int res, ret, sense_cat; int res, ret, sense_cat;
uint8_t tur_cdb[TUR_CMDLEN] = {TUR_CMD, 0, 0, 0, 0, 0}; uint8_t tur_cdb[TUR_CMDLEN] = {TUR_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN]; uint8_t sense_b[SENSE_BUFF_LEN];
if (verbose) { if (verbose) {
char b[128]; char b[128];
pr2ws(" %s cdb: %s\n", tur_s, pr2ws(" %s cdb: %s\n", tur_s,
sg_get_command_str(tur_cdb, TUR_CMDLEN, false, sizeof(b), b)); sg_get_command_str(tur_cdb, TUR_CMDLEN, false, sizeof(b), b));
} }
if (ptvp) {
clear_scsi_pt_obj(ptvp); ptvp_given = true;
set_scsi_pt_cdb(ptvp, tur_cdb, sizeof(tur_cdb)); partial_clear_scsi_pt_obj(ptvp);
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); if (get_scsi_pt_cdb_buf(ptvp))
local_cdb = false; /* N.B. Ignores locally built cdb */
else
set_scsi_pt_cdb(ptvp, tur_cdb, sizeof(tur_cdb));
if (get_scsi_pt_sense_buf(ptvp))
local_sense = false;
else
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
} else {
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
if (NULL == ptvp)
return sg_convert_errno(ENOMEM);
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); set_scsi_pt_packet_id(ptvp, pack_id);
res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose); res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, tur_s, res, noisy, verbose, &sense_cat); ret = sg_cmds_process_resp(ptvp, tur_s, res, noisy, verbose, &sense_cat);
if (-1 == ret) if (-1 == ret)
ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
else if (-2 == ret) { else if (-2 == ret) {
if (progress) { if (progress) {
int slen = get_scsi_pt_sense_len(ptvp); int slen = get_scsi_pt_sense_len(ptvp);
if (! sg_get_sense_progress_fld(sense_b, slen, progress)) if (! sg_get_sense_progress_fld(sense_b, slen, progress))
skipping to change at line 635 skipping to change at line 670
case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_RECOVERED:
case SG_LIB_CAT_NO_SENSE: case SG_LIB_CAT_NO_SENSE:
ret = 0; ret = 0;
break; break;
default: default:
ret = sense_cat; ret = sense_cat;
break; break;
} }
} else } else
ret = 0; ret = 0;
if (ptvp_given) {
if (local_sense) /* stop caller trying to access local sense */
set_scsi_pt_sense(ptvp, NULL, 0);
if (local_cdb)
set_scsi_pt_cdb(ptvp, NULL, 0);
} else {
if (ptvp)
destruct_scsi_pt_obj(ptvp);
}
return ret; return ret;
} }
int int
sg_ll_test_unit_ready_progress_pt(struct sg_pt_base * ptvp, int pack_id,
int * progress, bool noisy, int verbose)
{
return sg_ll_test_unit_ready_com(ptvp, -1, pack_id, progress, noisy,
verbose);
}
int
sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress, sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress,
bool noisy, int verbose) bool noisy, int verbose)
{ {
int ret; return sg_ll_test_unit_ready_com(NULL, sg_fd, pack_id, progress, noisy,
struct sg_pt_base * ptvp; verbose);
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
if (NULL == ptvp)
return sg_convert_errno(ENOMEM);
ret = sg_ll_test_unit_ready_progress_pt(ptvp, pack_id, progress, noisy,
verbose);
destruct_scsi_pt_obj(ptvp);
return ret;
} }
/* Invokes a SCSI TEST UNIT READY command. /* Invokes a SCSI TEST UNIT READY command.
* 'pack_id' is just for diagnostics, safe to set to 0. * 'pack_id' is just for diagnostics, safe to set to 0.
* Returns 0 when successful, various SG_LIB_CAT_* positive values or * Returns 0 when successful, various SG_LIB_CAT_* positive values or
* -1 -> other errors */ * -1 -> other errors */
int int
sg_ll_test_unit_ready(int sg_fd, int pack_id, bool noisy, int verbose) sg_ll_test_unit_ready(int sg_fd, int pack_id, bool noisy, int verbose)
{ {
int ret; return sg_ll_test_unit_ready_com(NULL, sg_fd, pack_id, NULL, noisy,
struct sg_pt_base * ptvp; verbose);
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
if (NULL == ptvp)
return sg_convert_errno(ENOMEM);
ret = sg_ll_test_unit_ready_progress_pt(ptvp, pack_id, NULL, noisy,
verbose);
destruct_scsi_pt_obj(ptvp);
return ret;
} }
int int
sg_ll_test_unit_ready_pt(struct sg_pt_base * ptvp, int pack_id, bool noisy, sg_ll_test_unit_ready_pt(struct sg_pt_base * ptvp, int pack_id, bool noisy,
int verbose) int verbose)
{ {
return sg_ll_test_unit_ready_progress_pt(ptvp, pack_id, NULL, noisy, return sg_ll_test_unit_ready_com(ptvp, -1, pack_id, NULL, noisy, verbose);
verbose);
} }
/* Invokes a SCSI REQUEST SENSE command. Returns 0 when successful, various /* Invokes a SCSI REQUEST SENSE command. Returns 0 when successful, various
* SG_LIB_CAT_* positive values or -1 -> other errors */ * SG_LIB_CAT_* positive values or -1 -> other errors */
static int static int
sg_ll_request_sense_com(struct sg_pt_base * ptvp, int sg_fd, bool desc, sg_ll_request_sense_com(struct sg_pt_base * ptvp, int sg_fd, bool desc,
void * resp, int mx_resp_len, bool noisy, int verbose) void * resp, int mx_resp_len, bool noisy, int verbose)
{ {
bool ptvp_given = false; bool ptvp_given = false;
bool local_cdb = true;
bool local_sense = true;
int ret, res, sense_cat; int ret, res, sense_cat;
static const char * const rq_s = "request sense"; static const char * const rq_s = "request sense";
uint8_t rs_cdb[REQUEST_SENSE_CMDLEN] = uint8_t rs_cdb[REQUEST_SENSE_CMDLEN] =
{REQUEST_SENSE_CMD, 0, 0, 0, 0, 0}; {REQUEST_SENSE_CMD, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN]; uint8_t sense_b[SENSE_BUFF_LEN];
if (desc) if (desc)
rs_cdb[1] |= 0x1; rs_cdb[1] |= 0x1;
if (mx_resp_len > 0xff) { if (mx_resp_len > 0xff) {
pr2ws("mx_resp_len cannot exceed 255\n"); pr2ws("mx_resp_len cannot exceed 255\n");
return -1; return -1;
} }
rs_cdb[4] = mx_resp_len & 0xff; rs_cdb[4] = mx_resp_len & 0xff;
if (verbose) { if (verbose) {
char b[128]; char b[128];
pr2ws(" %s cdb: %s\n", rq_s, pr2ws(" %s cdb: %s\n", rq_s,
sg_get_command_str(rs_cdb, REQUEST_SENSE_CMDLEN, false, sg_get_command_str(rs_cdb, REQUEST_SENSE_CMDLEN, false,
sizeof(b), b)); sizeof(b), b));
} }
if (ptvp) if (ptvp) {
ptvp_given = true; ptvp_given = true;
else { if (get_scsi_pt_sense_buf(ptvp))
local_cdb = false;
else
set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb));
if (get_scsi_pt_sense_buf(ptvp))
local_sense = false;
else
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
} else {
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose); ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
if (NULL == ptvp) if (NULL == ptvp)
return sg_convert_errno(ENOMEM); return sg_convert_errno(ENOMEM);
set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
} }
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, (uint8_t *)resp, mx_resp_len); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose); res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, rq_s, res, noisy, verbose, &sense_cat); ret = sg_cmds_process_resp(ptvp, rq_s, res, noisy, verbose, &sense_cat);
if (-1 == ret) if (-1 == ret)
ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
else if (-2 == ret) { else if (-2 == ret) {
switch (sense_cat) { switch (sense_cat) {
case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_RECOVERED:
case SG_LIB_CAT_NO_SENSE: case SG_LIB_CAT_NO_SENSE:
ret = 0; ret = 0;
skipping to change at line 741 skipping to change at line 786
} }
} else { } else {
if ((mx_resp_len >= 8) && (ret < 8)) { if ((mx_resp_len >= 8) && (ret < 8)) {
if (verbose) if (verbose)
pr2ws(" %s: got %d bytes in response, too short\n", rq_s, pr2ws(" %s: got %d bytes in response, too short\n", rq_s,
ret); ret);
ret = -1; ret = -1;
} else } else
ret = 0; ret = 0;
} }
if ((! ptvp_given) && ptvp) if (ptvp_given) {
if (local_sense) /* stop caller accessing local sense */
set_scsi_pt_sense(ptvp, NULL, 0);
if (local_cdb) /* stop caller accessing local sense */
set_scsi_pt_cdb(ptvp, NULL, 0);
} else if (ptvp)
destruct_scsi_pt_obj(ptvp); destruct_scsi_pt_obj(ptvp);
return ret; return ret;
} }
int int
sg_ll_request_sense(int sg_fd, bool desc, void * resp, int mx_resp_len, sg_ll_request_sense(int sg_fd, bool desc, void * resp, int mx_resp_len,
bool noisy, int verbose) bool noisy, int verbose)
{ {
return sg_ll_request_sense_com(NULL, sg_fd, desc, resp, mx_resp_len, return sg_ll_request_sense_com(NULL, sg_fd, desc, resp, mx_resp_len,
noisy, verbose); noisy, verbose);
} }
int int
sg_ll_request_sense_pt(struct sg_pt_base * ptvp, bool desc, void * resp, sg_ll_request_sense_pt(struct sg_pt_base * ptvp, bool desc, void * resp,
int mx_resp_len, bool noisy, int verbose) int mx_resp_len, bool noisy, int verbose)
{ {
clear_scsi_pt_obj(ptvp);
return sg_ll_request_sense_com(ptvp, -1, desc, resp, mx_resp_len, return sg_ll_request_sense_com(ptvp, -1, desc, resp, mx_resp_len,
noisy, verbose); noisy, verbose);
} }
/* Invokes a SCSI REPORT LUNS command. Return of 0 -> success, /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
* various SG_LIB_CAT_* positive values or -1 -> other errors */ * various SG_LIB_CAT_* positive values or -1 -> other errors */
static int static int
sg_ll_report_luns_com(struct sg_pt_base * ptvp, int sg_fd, int select_report, sg_ll_report_luns_com(struct sg_pt_base * ptvp, int sg_fd, int select_report,
void * resp, int mx_resp_len, bool noisy, int verbose) void * resp, int mx_resp_len, bool noisy, int verbose)
{ {
static const char * const report_luns_s = "report luns"; static const char * const report_luns_s = "report luns";
bool ptvp_given = false; bool ptvp_given = false;
bool local_cdb = true;
bool local_sense = true;
int ret, res, sense_cat; int ret, res, sense_cat;
uint8_t rl_cdb[REPORT_LUNS_CMDLEN] = uint8_t rl_cdb[REPORT_LUNS_CMDLEN] =
{REPORT_LUNS_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; {REPORT_LUNS_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t sense_b[SENSE_BUFF_LEN]; uint8_t sense_b[SENSE_BUFF_LEN];
rl_cdb[2] = select_report & 0xff; rl_cdb[2] = select_report & 0xff;
sg_put_unaligned_be32((uint32_t)mx_resp_len, rl_cdb + 6); sg_put_unaligned_be32((uint32_t)mx_resp_len, rl_cdb + 6);
if (verbose) { if (verbose) {
char b[128]; char b[128];
pr2ws(" %s cdb: %s\n", report_luns_s, pr2ws(" %s cdb: %s\n", report_luns_s,
sg_get_command_str(rl_cdb, REPORT_LUNS_CMDLEN, false, sg_get_command_str(rl_cdb, REPORT_LUNS_CMDLEN, false,
sizeof(b), b)); sizeof(b), b));
} }
if (ptvp) if (ptvp) {
ptvp_given = true; ptvp_given = true;
else if (NULL == ((ptvp = create_pt_obj(report_luns_s)))) partial_clear_scsi_pt_obj(ptvp);
return sg_convert_errno(ENOMEM); if (get_scsi_pt_cdb_buf(ptvp))
set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb)); local_cdb = false;
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); else
set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb));
if (get_scsi_pt_sense_buf(ptvp))
local_sense = false;
else
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
} else {
if (NULL == ((ptvp = create_pt_obj(report_luns_s))))
return sg_convert_errno(ENOMEM);
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, (uint8_t *)resp, mx_resp_len); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, report_luns_s, res, noisy, verbose, ret = sg_cmds_process_resp(ptvp, report_luns_s, res, noisy, verbose,
&sense_cat); &sense_cat);
if (-1 == ret) if (-1 == ret)
ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
else if (-2 == ret) { else if (-2 == ret) {
switch (sense_cat) { switch (sense_cat) {
case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_RECOVERED:
case SG_LIB_CAT_NO_SENSE: case SG_LIB_CAT_NO_SENSE:
ret = 0; ret = 0;
break; break;
default: default:
ret = sense_cat; ret = sense_cat;
break; break;
} }
} else } else
ret = 0; ret = 0;
if ((! ptvp_given) && ptvp) if (ptvp_given) {
destruct_scsi_pt_obj(ptvp); if (local_sense) /* stop caller accessing local sense */
set_scsi_pt_sense(ptvp, NULL, 0);
if (local_cdb)
set_scsi_pt_cdb(ptvp, NULL, 0);
} else {
if (ptvp)
destruct_scsi_pt_obj(ptvp);
}
return ret; return ret;
} }
/* Invokes a SCSI REPORT LUNS command. Return of 0 -> success, /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
* various SG_LIB_CAT_* positive values or -1 -> other errors, * various SG_LIB_CAT_* positive values or -1 -> other errors,
* Expects sg_fd to be >= 0 representing an open device fd. */ * Expects sg_fd to be >= 0 representing an open device fd. */
int int
sg_ll_report_luns(int sg_fd, int select_report, void * resp, int mx_resp_len, sg_ll_report_luns(int sg_fd, int select_report, void * resp, int mx_resp_len,
bool noisy, int verbose) bool noisy, int verbose)
{ {
skipping to change at line 832 skipping to change at line 901
mx_resp_len, noisy, verbose); mx_resp_len, noisy, verbose);
} }
/* Invokes a SCSI REPORT LUNS command. Return of 0 -> success, /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
* various SG_LIB_CAT_* positive values or -1 -> other errors. * various SG_LIB_CAT_* positive values or -1 -> other errors.
* Expects a non-NULL ptvp containing an open device fd. */ * Expects a non-NULL ptvp containing an open device fd. */
int int
sg_ll_report_luns_pt(struct sg_pt_base * ptvp, int select_report, sg_ll_report_luns_pt(struct sg_pt_base * ptvp, int select_report,
void * resp, int mx_resp_len, bool noisy, int verbose) void * resp, int mx_resp_len, bool noisy, int verbose)
{ {
clear_scsi_pt_obj(ptvp);
return sg_ll_report_luns_com(ptvp, -1, select_report, resp, return sg_ll_report_luns_com(ptvp, -1, select_report, resp,
mx_resp_len, noisy, verbose); mx_resp_len, noisy, verbose);
} }
 End of changes. 40 change blocks. 
86 lines changed or deleted 154 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)