#include "int64.h"
#include "extern.h"
#include "scsicmds.h"
+#include "atacmds.h" // FIXME: for smart_command_set only
+#include "dev_interface.h"
#include "utility.h"
-const char *scsicmds_c_cvsid="$Id: scsicmds.cpp,v 1.96 2008/03/04 22:09:47 ballen4705 Exp $"
+const char *scsicmds_c_cvsid="$Id: scsicmds.cpp,v 1.98 2009/06/24 04:10:10 dpgilbert Exp $"
CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
/* for passing global control variables */
{RECEIVE_DIAGNOSTIC, "receive diagnostic"}, /* 0x1c */
{SEND_DIAGNOSTIC, "send diagnostic"}, /* 0x1d */
{READ_DEFECT_10, "read defect list(10)"}, /* 0x37 */
+ {LOG_SELECT, "log select"}, /* 0x4c */
{LOG_SENSE, "log sense"}, /* 0x4d */
{MODE_SELECT_10, "mode select(10)"}, /* 0x55 */
{MODE_SENSE_10, "mode sense(10)"}, /* 0x5a */
requesting the deduced response length. This protects certain fragile
HBAs. The twin fetch technique should not be used with the TapeAlert
log page since it clears its state flags after each fetch. */
-int scsiLogSense(int device, int pagenum, int subpagenum, UINT8 *pBuf,
+int scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf,
int bufLen, int known_resp_len)
{
struct scsi_cmnd_io io_hdr;
io_hdr.sensep = sense;
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
-
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
if ((res = scsiSimpleSenseFilter(&sinfo)))
return res;
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
status = scsiSimpleSenseFilter(&sinfo);
if (0 != status)
return 0;
}
+/* Sends a LOG SELECT command. Can be used to set log page values
+ * or reset one log page (or all of them) to its defaults (typically zero).
+ * Returns 0 if ok, 1 if NOT READY, 2 if command not supported, * 3 if
+ * field in command not supported, * 4 if bad parameter to command or
+ * returns negated errno. SPC-4 sections 6.5 and 7.2 (rev 20) */
+int scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum,
+ int subpagenum, UINT8 *pBuf, int bufLen)
+{
+ struct scsi_cmnd_io io_hdr;
+ struct scsi_sense_disect sinfo;
+ UINT8 cdb[10];
+ UINT8 sense[32];
+
+ memset(&io_hdr, 0, sizeof(io_hdr));
+ memset(cdb, 0, sizeof(cdb));
+ io_hdr.dxfer_dir = DXFER_TO_DEVICE;
+ io_hdr.dxfer_len = bufLen;
+ io_hdr.dxferp = pBuf;
+ cdb[0] = LOG_SELECT;
+ cdb[1] = (pcr ? 2 : 0) | (sp ? 1 : 0);
+ cdb[2] = ((pc << 6) & 0xc0) | (pagenum & 0x3f);
+ cdb[3] = (subpagenum & 0xff);
+ cdb[7] = ((bufLen >> 8) & 0xff);
+ cdb[8] = (bufLen & 0xff);
+ io_hdr.cmnd = cdb;
+ io_hdr.cmnd_len = sizeof(cdb);
+ io_hdr.sensep = sense;
+ io_hdr.max_sense_len = sizeof(sense);
+ io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
+
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
+ scsi_do_sense_disect(&io_hdr, &sinfo);
+ return scsiSimpleSenseFilter(&sinfo);
+}
+
/* Send MODE SENSE (6 byte) command. Returns 0 if ok, 1 if NOT READY,
* 2 if command not supported (then MODE SENSE(10) should be supported),
* 3 if field in command not supported or returns negated errno.
* SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */
-int scsiModeSense(int device, int pagenum, int subpagenum, int pc,
+int scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
UINT8 *pBuf, int bufLen)
{
struct scsi_cmnd_io io_hdr;
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
status = scsiSimpleSenseFilter(&sinfo);
if (SIMPLE_ERR_TRY_AGAIN == status) {
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
status = scsiSimpleSenseFilter(&sinfo);
}
* 2 if command not supported (then MODE SELECT(10) may be supported),
* 3 if field in command not supported, 4 if bad parameter to command
* or returns negated errno. SPC-3 sections 6.7 and 7.4 (rev 22a) */
-int scsiModeSelect(int device, int sp, UINT8 *pBuf, int bufLen)
+int scsiModeSelect(scsi_device * device, int sp, UINT8 *pBuf, int bufLen)
{
struct scsi_cmnd_io io_hdr;
struct scsi_sense_disect sinfo;
UINT8 cdb[6];
UINT8 sense[32];
- int status, pg_offset, pg_len, hdr_plus_1_pg;
+ int pg_offset, pg_len, hdr_plus_1_pg;
pg_offset = 4 + pBuf[3];
if (pg_offset + 2 >= bufLen)
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
return scsiSimpleSenseFilter(&sinfo);
}
* not supported (then MODE SENSE(6) might be supported), 3 if field in
* command not supported or returns negated errno.
* SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */
-int scsiModeSense10(int device, int pagenum, int subpagenum, int pc,
+int scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
UINT8 *pBuf, int bufLen)
{
struct scsi_cmnd_io io_hdr;
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
status = scsiSimpleSenseFilter(&sinfo);
if (SIMPLE_ERR_TRY_AGAIN == status) {
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
status = scsiSimpleSenseFilter(&sinfo);
}
* command not supported (then MODE SELECT(6) may be supported), 3 if field
* in command not supported, 4 if bad parameter to command or returns
* negated errno. SPC-3 sections 6.8 and 7.4 (rev 22a) */
-int scsiModeSelect10(int device, int sp, UINT8 *pBuf, int bufLen)
+int scsiModeSelect10(scsi_device * device, int sp, UINT8 *pBuf, int bufLen)
{
struct scsi_cmnd_io io_hdr;
struct scsi_sense_disect sinfo;
UINT8 cdb[10];
UINT8 sense[32];
- int status, pg_offset, pg_len, hdr_plus_1_pg;
+ int pg_offset, pg_len, hdr_plus_1_pg;
pg_offset = 8 + (pBuf[6] << 8) + pBuf[7];
if (pg_offset + 2 >= bufLen)
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
return scsiSimpleSenseFilter(&sinfo);
}
/* Standard INQUIRY returns 0 for ok, anything else is a major problem.
* bufLen should be 36 for unsafe devices (like USB mass storage stuff)
* otherwise they can lock up! SPC-3 sections 6.4 and 7.6 (rev 22a) */
-int scsiStdInquiry(int device, UINT8 *pBuf, int bufLen)
+int scsiStdInquiry(scsi_device * device, UINT8 *pBuf, int bufLen)
{
struct scsi_sense_disect sinfo;
struct scsi_cmnd_io io_hdr;
UINT8 cdb[6];
UINT8 sense[32];
- int status;
if ((bufLen < 0) || (bufLen > 255))
return -EINVAL;
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
return scsiSimpleSenseFilter(&sinfo);
}
* (unlikely), 2 if command not supported, 3 if field in command not
* supported, 5 if response indicates that EVPD bit ignored or returns
* negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */
-int scsiInquiryVpd(int device, int vpd_page, UINT8 *pBuf, int bufLen)
+int scsiInquiryVpd(scsi_device * device, int vpd_page, UINT8 *pBuf, int bufLen)
{
struct scsi_cmnd_io io_hdr;
struct scsi_sense_disect sinfo;
UINT8 cdb[6];
UINT8 sense[32];
- int status, res;
+ int res;
if ((bufLen < 0) || (bufLen > 255))
return -EINVAL;
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
if ((res = scsiSimpleSenseFilter(&sinfo)))
return res;
/* REQUEST SENSE command. Returns 0 if ok, anything else major problem.
* SPC-3 section 6.27 (rev 22a) */
-int scsiRequestSense(int device, struct scsi_sense_disect * sense_info)
+int scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info)
{
struct scsi_cmnd_io io_hdr;
UINT8 cdb[6];
UINT8 sense[32];
UINT8 buff[18];
- int status, len;
+ int len;
UINT8 ecode;
memset(&io_hdr, 0, sizeof(io_hdr));
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if ((0 == status) && (sense_info)) {
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
+ if (sense_info) {
ecode = buff[0] & 0x7f;
sense_info->error_code = ecode;
sense_info->sense_key = buff[2] & 0xf;
}
}
}
- return status;
+ return 0;
}
/* SEND DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if command
* not supported, 3 if field in command not supported or returns negated
* errno. SPC-3 section 6.28 (rev 22a) */
-int scsiSendDiagnostic(int device, int functioncode, UINT8 *pBuf, int bufLen)
+int scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf, int bufLen)
{
struct scsi_cmnd_io io_hdr;
struct scsi_sense_disect sinfo;
UINT8 cdb[6];
UINT8 sense[32];
- int status;
memset(&io_hdr, 0, sizeof(io_hdr));
memset(cdb, 0, sizeof(cdb));
/* worst case is an extended foreground self test on a big disk */
io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
return scsiSimpleSenseFilter(&sinfo);
}
/* RECEIVE DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if
* command not supported, 3 if field in command not supported or returns
* negated errno. SPC-3 section 6.18 (rev 22a) */
-int scsiReceiveDiagnostic(int device, int pcv, int pagenum, UINT8 *pBuf,
+int scsiReceiveDiagnostic(scsi_device * device, int pcv, int pagenum, UINT8 *pBuf,
int bufLen)
{
struct scsi_cmnd_io io_hdr;
struct scsi_sense_disect sinfo;
UINT8 cdb[6];
UINT8 sense[32];
- int status;
memset(&io_hdr, 0, sizeof(io_hdr));
memset(cdb, 0, sizeof(cdb));
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
return scsiSimpleSenseFilter(&sinfo);
}
/* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */
-static int _testunitready(int device, struct scsi_sense_disect * sinfo)
+static int _testunitready(scsi_device * device, struct scsi_sense_disect * sinfo)
{
struct scsi_cmnd_io io_hdr;
UINT8 cdb[6];
UINT8 sense[32];
- int status;
memset(&io_hdr, 0, sizeof(io_hdr));
memset(cdb, 0, sizeof(cdb));
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, sinfo);
return 0;
}
/* Returns 0 for device responds and media ready, 1 for device responds and
media not ready, or returns a negated errno value */
-int scsiTestUnitReady(int device)
+int scsiTestUnitReady(scsi_device * device)
{
struct scsi_sense_disect sinfo;
int status;
/* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
* command not supported, 3 if field in command not supported or returns
* negated errno. SBC-2 section 5.12 (rev 16) */
-int scsiReadDefect10(int device, int req_plist, int req_glist, int dl_format,
+int scsiReadDefect10(scsi_device * device, int req_plist, int req_glist, int dl_format,
UINT8 *pBuf, int bufLen)
{
struct scsi_cmnd_io io_hdr;
struct scsi_sense_disect sinfo;
UINT8 cdb[10];
UINT8 sense[32];
- int status;
memset(&io_hdr, 0, sizeof(io_hdr));
memset(cdb, 0, sizeof(cdb));
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
- status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);
- if (0 != status)
- return status;
+ if (!device->scsi_pass_through(&io_hdr))
+ return -device->get_errno();
scsi_do_sense_disect(&io_hdr, &sinfo);
return scsiSimpleSenseFilter(&sinfo);
}
* tries a 10 byte MODE SENSE command. Returns 0 if successful, a positive
* number if a known error (see SIMPLE_ERR_ ...) or a negative errno
* value. */
-int scsiFetchIECmpage(int device, struct scsi_iec_mode_page *iecp, int modese_len)
+int scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp, int modese_len)
{
int err = 0;
* is to be re-examined.
* When -r ioctl is invoked 3 or more time on 'smartctl -s on ...'
* then set the TEST bit (causes asc,ascq pair of 0x5d,0xff). */
-int scsiSetExceptionControlAndWarning(int device, int enabled,
+int scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
const struct scsi_iec_mode_page *iecp)
{
int k, offset, resp_len;
return err;
}
-int scsiGetTemp(int device, UINT8 *currenttemp, UINT8 *triptemp)
+int scsiGetTemp(scsi_device * device, UINT8 *currenttemp, UINT8 *triptemp)
{
UINT8 tBuf[252];
int err;
* Fetching asc/ascq code potentially flagging an exception or warning.
* Returns 0 if ok, else error number. A current temperature of 255
* (Celsius) implies that the temperature not available. */
-int scsiCheckIE(int device, int hasIELogPage, int hasTempLogPage,
+int scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
UINT8 *asc, UINT8 *ascq, UINT8 *currenttemp,
UINT8 *triptemp)
{
/* This is not documented in t10.org, page 0x80 is vendor specific */
/* Some IBM disks do an offline read-scan when they get this command. */
-int scsiSmartIBMOfflineTest(int device)
+int scsiSmartIBMOfflineTest(scsi_device * device)
{
UINT8 tBuf[256];
int res;
return res;
}
-int scsiSmartDefaultSelfTest(int device)
+int scsiSmartDefaultSelfTest(scsi_device * device)
{
int res;
return res;
}
-int scsiSmartShortSelfTest(int device)
+int scsiSmartShortSelfTest(scsi_device * device)
{
int res;
return res;
}
-int scsiSmartExtendSelfTest(int device)
+int scsiSmartExtendSelfTest(scsi_device * device)
{
int res;
return res;
}
-int scsiSmartShortCapSelfTest(int device)
+int scsiSmartShortCapSelfTest(scsi_device * device)
{
int res;
return res;
}
-int scsiSmartExtendCapSelfTest(int device)
+int scsiSmartExtendCapSelfTest(scsi_device * device)
{
int res;
return res;
}
-int scsiSmartSelfTestAbort(int device)
+int scsiSmartSelfTestAbort(scsi_device * device)
{
int res;
/* Returns 0 and the expected duration of an extended self test (in seconds)
if successful; any other return value indicates a failure. */
-int scsiFetchExtendedSelfTestTime(int device, int * durationSec, int modese_len)
+int scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec, int modese_len)
{
int err, offset, res;
UINT8 buff[64];
tests (typically by the user) and self tests in progress are not
considered failures. See Working Draft SCSI Primary Commands - 3
(SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
-int scsiCountFailedSelfTests(int fd, int noisy)
+int scsiCountFailedSelfTests(scsi_device * fd, int noisy)
{
int num, k, n, err, res, fails, fail_hour;
UINT8 * ucp;
/* Returns 0 if able to read self test log page; then outputs 1 into
*inProgress if self test still in progress, else outputs 0. */
-int scsiSelfTestInProgress(int fd, int * inProgress)
+int scsiSelfTestInProgress(scsi_device * fd, int * inProgress)
{
int num;
UINT8 * ucp;
malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD
bit is set. Examines default mode page when current==0 else examines
current mode page. */
-int scsiFetchControlGLTSD(int device, int modese_len, int current)
+int scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current)
{
int err, offset;
UINT8 buff[64];
0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if
successful, negative if low level error, > 0 if higher level error (e.g.
SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */
-int scsiSetControlGLTSD(int device, int enabled, int modese_len)
+int scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len)
{
int err, offset, resp_len, sp;
UINT8 buff[64];
/* Returns a negative value if failed to fetch Protocol specific port mode
page or it was malformed. Returns transport protocol identifier when
value >= 0 . */
-int scsiFetchTransportProtocol(int device, int modese_len)
+int scsiFetchTransportProtocol(scsi_device * device, int modese_len)
{
int err, offset;
UINT8 buff[64];