sg_cmds_extra.c (sdparm-1.11.tgz) | : | sg_cmds_extra.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 | |||
*/ | */ | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <stdarg.h> | #include <stdarg.h> | |||
skipping to change at line 448 | skipping to change at line 448 | |||
destruct_scsi_pt_obj(ptvp); | destruct_scsi_pt_obj(ptvp); | |||
return ret; | return ret; | |||
} | } | |||
/* Invokes a SCSI SEND DIAGNOSTIC command. Foreground, extended self tests can | /* 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 | * 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 | * 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, | * value is taken as the timeout value in seconds. Return of 0 -> success, | |||
* various SG_LIB_CAT_* positive values or -1 -> other errors */ | * various SG_LIB_CAT_* positive values or -1 -> other errors */ | |||
int | int | |||
sg_ll_send_diag_pt(struct sg_pt_base * ptvp, int st_code, bool pf_bit, | sg_ll_send_diag_com(struct sg_pt_base * ptvp, int sg_fd, int st_code, | |||
bool st_bit, bool devofl_bit, bool unitofl_bit, | bool pf_bit, bool st_bit, bool devofl_bit, | |||
int long_duration, void * paramp, int param_len, | bool unitofl_bit, int long_duration, void * paramp, | |||
bool noisy, int vb) | int param_len, bool noisy, int vb) | |||
{ | { | |||
static const char * const cdb_s = "Send diagnostic"; | static const char * const cdb_s = "Send diagnostic"; | |||
bool ptvp_given = false; | ||||
bool local_sense = true; | ||||
bool local_cdb = true; | ||||
int res, ret, s_cat, tmout; | int res, ret, s_cat, tmout; | |||
uint8_t senddiag_cdb[SEND_DIAGNOSTIC_CMDLEN] = | uint8_t senddiag_cdb[SEND_DIAGNOSTIC_CMDLEN] = | |||
{SEND_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0}; | {SEND_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0}; | |||
uint8_t sense_b[SENSE_BUFF_LEN]; | uint8_t sense_b[SENSE_BUFF_LEN]; | |||
senddiag_cdb[1] = (uint8_t)(st_code << 5); | senddiag_cdb[1] = (uint8_t)(st_code << 5); | |||
if (pf_bit) | if (pf_bit) | |||
senddiag_cdb[1] |= 0x10; | senddiag_cdb[1] |= 0x10; | |||
if (st_bit) | if (st_bit) | |||
senddiag_cdb[1] |= 0x4; | senddiag_cdb[1] |= 0x4; | |||
skipping to change at line 488 | skipping to change at line 491 | |||
sg_get_command_str(senddiag_cdb, SEND_DIAGNOSTIC_CMDLEN, | sg_get_command_str(senddiag_cdb, SEND_DIAGNOSTIC_CMDLEN, | |||
false, sizeof(b), b)); | false, sizeof(b), b)); | |||
if (vb > 1) { | if (vb > 1) { | |||
if (paramp && param_len) { | if (paramp && param_len) { | |||
pr2ws(" %s parameter list:\n", cdb_s); | pr2ws(" %s parameter list:\n", cdb_s); | |||
hex2stderr((const uint8_t *)paramp, param_len, -1); | hex2stderr((const uint8_t *)paramp, param_len, -1); | |||
} | } | |||
pr2ws(" %s timeout: %d seconds\n", cdb_s, tmout); | pr2ws(" %s timeout: %d seconds\n", cdb_s, tmout); | |||
} | } | |||
} | } | |||
if (ptvp) { | ||||
set_scsi_pt_cdb(ptvp, senddiag_cdb, sizeof(senddiag_cdb)); | ptvp_given = true; | |||
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); | 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, senddiag_cdb, sizeof(senddiag_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, vb); | ||||
if (NULL == ptvp) | ||||
return sg_convert_errno(ENOMEM); | ||||
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, (uint8_t *)paramp, param_len); | set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); | |||
res = do_scsi_pt(ptvp, -1, tmout, vb); | res = do_scsi_pt(ptvp, -1, tmout, vb); | |||
ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); | ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_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 (s_cat) { | switch (s_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 = s_cat; | ret = s_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_send_diag_pt(struct sg_pt_base * ptvp, 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 vb) | ||||
{ | ||||
return sg_ll_send_diag_com(ptvp, -1, st_code, pf_bit, st_bit, devofl_bit, | ||||
unitofl_bit, long_duration, paramp, | ||||
param_len, noisy, vb); | ||||
} | ||||
int | ||||
sg_ll_send_diag(int sg_fd, int st_code, bool pf_bit, bool st_bit, | 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, | bool devofl_bit, bool unitofl_bit, int long_duration, | |||
void * paramp, int param_len, bool noisy, int vb) | void * paramp, int param_len, bool noisy, int vb) | |||
{ | { | |||
int ret; | return sg_ll_send_diag_com(NULL, sg_fd, st_code, pf_bit, st_bit, | |||
struct sg_pt_base * ptvp; | devofl_bit, unitofl_bit, long_duration, paramp, | |||
param_len, noisy, vb); | ||||
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb); | ||||
if (NULL == ptvp) | ||||
return sg_convert_errno(ENOMEM); | ||||
ret = sg_ll_send_diag_pt(ptvp, st_code, pf_bit, st_bit, devofl_bit, | ||||
unitofl_bit, long_duration, paramp, param_len, | ||||
noisy, vb); | ||||
destruct_scsi_pt_obj(ptvp); | ||||
return ret; | ||||
} | } | |||
/* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success, | /* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS 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 */ | |||
int | static int | |||
sg_ll_receive_diag_pt(struct sg_pt_base * ptvp, bool pcv, int pg_code, | sg_ll_receive_diag_com(struct sg_pt_base * ptvp, int sg_fd, bool pcv, | |||
void * resp, int mx_resp_len, int timeout_secs, | int pg_code, void * resp, int mx_resp_len, | |||
int * residp, bool noisy, int vb) | int timeout_secs, int * residp, bool noisy, int vb) | |||
{ | { | |||
bool ptvp_given = false; | ||||
bool local_sense = true; | ||||
bool local_cdb = true; | ||||
int resid = 0; | int resid = 0; | |||
int res, ret, s_cat; | int res, ret, s_cat; | |||
static const char * const cdb_s = "Receive diagnostic results"; | static const char * const cdb_s = "Receive diagnostic results"; | |||
uint8_t rcvdiag_cdb[RECEIVE_DIAGNOSTICS_CMDLEN] = | uint8_t rcvdiag_cdb[RECEIVE_DIAGNOSTICS_CMDLEN] = | |||
{RECEIVE_DIAGNOSTICS_CMD, 0, 0, 0, 0, 0}; | {RECEIVE_DIAGNOSTICS_CMD, 0, 0, 0, 0, 0}; | |||
uint8_t sense_b[SENSE_BUFF_LEN]; | uint8_t sense_b[SENSE_BUFF_LEN]; | |||
if (pcv) | if (pcv) | |||
rcvdiag_cdb[1] = 0x1; | rcvdiag_cdb[1] = 0x1; | |||
rcvdiag_cdb[2] = (uint8_t)(pg_code); | rcvdiag_cdb[2] = (uint8_t)(pg_code); | |||
skipping to change at line 559 | skipping to change at line 592 | |||
if (vb) { | if (vb) { | |||
char b[128]; | char b[128]; | |||
pr2ws(" %s cdb: %s\n", cdb_s, | pr2ws(" %s cdb: %s\n", cdb_s, | |||
sg_get_command_str(rcvdiag_cdb, RECEIVE_DIAGNOSTICS_CMDLEN, | sg_get_command_str(rcvdiag_cdb, RECEIVE_DIAGNOSTICS_CMDLEN, | |||
false, sizeof(b), b)); | false, sizeof(b), b)); | |||
} | } | |||
if (timeout_secs <= 0) | if (timeout_secs <= 0) | |||
timeout_secs = DEF_PT_TIMEOUT; | timeout_secs = DEF_PT_TIMEOUT; | |||
set_scsi_pt_cdb(ptvp, rcvdiag_cdb, sizeof(rcvdiag_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, rcvdiag_cdb, sizeof(rcvdiag_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, vb); | ||||
if (NULL == ptvp) | ||||
return sg_convert_errno(ENOMEM); | ||||
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, (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, vb); | res = do_scsi_pt(ptvp, -1, timeout_secs, vb); | |||
ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); | ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_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) { | |||
switch (s_cat) { | switch (s_cat) { | |||
skipping to change at line 593 | skipping to change at line 642 | |||
pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); | pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); | |||
hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), | hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), | |||
-1); | -1); | |||
} else { | } else { | |||
pr2ws(":\n"); | pr2ws(":\n"); | |||
hex2stderr((const uint8_t *)resp, ret, 0); | hex2stderr((const uint8_t *)resp, ret, 0); | |||
} | } | |||
} | } | |||
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 | ||||
sg_ll_receive_diag_pt(struct sg_pt_base * ptvp, bool pcv, int pg_code, | ||||
void * resp, int mx_resp_len, int timeout_secs, | ||||
int * residp, bool noisy, int vb) | ||||
{ | ||||
return sg_ll_receive_diag_com(ptvp, -1, pcv, pg_code, resp, mx_resp_len, | ||||
timeout_secs, residp, noisy, vb); | ||||
} | ||||
/* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success, | /* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS 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 */ | |||
int | int | |||
sg_ll_receive_diag(int sg_fd, bool pcv, int pg_code, void * resp, | sg_ll_receive_diag(int sg_fd, bool pcv, int pg_code, void * resp, | |||
int mx_resp_len, bool noisy, int vb) | int mx_resp_len, bool noisy, int vb) | |||
{ | { | |||
int ret; | return sg_ll_receive_diag_com(NULL, sg_fd, pcv, pg_code, resp, | |||
struct sg_pt_base * ptvp; | mx_resp_len, 0, NULL, noisy, vb); | |||
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb); | ||||
if (NULL == ptvp) | ||||
return sg_convert_errno(ENOMEM); | ||||
ret = sg_ll_receive_diag_pt(ptvp, pcv, pg_code, resp, mx_resp_len, 0, | ||||
NULL, noisy, vb); | ||||
destruct_scsi_pt_obj(ptvp); | ||||
return ret; | ||||
} | } | |||
int | int | |||
sg_ll_receive_diag_v2(int sg_fd, bool pcv, int pg_code, void * resp, | sg_ll_receive_diag_v2(int sg_fd, bool pcv, int pg_code, void * resp, | |||
int mx_resp_len, int timeout_secs, int * residp, | int mx_resp_len, int timeout_secs, int * residp, | |||
bool noisy, int vb) | bool noisy, int vb) | |||
{ | { | |||
int ret; | return sg_ll_receive_diag_com(NULL, sg_fd, pcv, pg_code, resp, | |||
struct sg_pt_base * ptvp; | mx_resp_len, timeout_secs, residp, noisy, | |||
vb); | ||||
ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb); | ||||
if (NULL == ptvp) | ||||
return sg_convert_errno(ENOMEM); | ||||
ret = sg_ll_receive_diag_pt(ptvp, pcv, pg_code, resp, mx_resp_len, | ||||
timeout_secs, residp, noisy, vb); | ||||
destruct_scsi_pt_obj(ptvp); | ||||
return ret; | ||||
} | } | |||
/* Invokes a SCSI READ DEFECT DATA (10) command (SBC). Return of 0 -> success | /* Invokes a SCSI READ DEFECT DATA (10) command (SBC). Return of 0 -> success | |||
* various SG_LIB_CAT_* positive values or -1 -> other errors */ | * various SG_LIB_CAT_* positive values or -1 -> other errors */ | |||
int | int | |||
sg_ll_read_defect10(int sg_fd, bool req_plist, bool req_glist, int dl_format, | 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 vb) | void * resp, int mx_resp_len, bool noisy, int vb) | |||
{ | { | |||
static const char * const cdb_s = "Read defect(10)"; | static const char * const cdb_s = "Read defect(10)"; | |||
int res, ret, s_cat; | int res, ret, s_cat; | |||
End of changes. 13 change blocks. | ||||
46 lines changed or deleted | 99 lines changed or added |