📄 scsicmds.cpp
字号:
io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); /* 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; 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 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.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = RECEIVE_DIAGNOSTIC; cdb[1] = pcv; cdb[2] = pagenum; cdb[3] = (bufLen >> 8) & 0xff; cdb[4] = 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; status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); if (0 != status) return status; 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){ 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.dxfer_dir = DXFER_NONE; io_hdr.dxfer_len = 0; io_hdr.dxferp = NULL; cdb[0] = TEST_UNIT_READY; 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; status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); if (0 != status) return status; 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){ struct scsi_sense_disect sinfo; int status; status = _testunitready(device, &sinfo); if (0 != status) return status; status = scsiSimpleSenseFilter(&sinfo); if (SIMPLE_ERR_TRY_AGAIN == status) { /* power on reset, media changed, ok ... try again */ status = _testunitready(device, &sinfo); if (0 != status) return status; status = scsiSimpleSenseFilter(&sinfo); } return 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, 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.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = READ_DEFECT_10; cdb[2] = (unsigned char)(((req_plist << 4) & 0x10) | ((req_glist << 3) & 0x8) | (dl_format & 0x7)); 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; status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); if (0 != status) return status; scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo);}/* Offset into mode sense (6 or 10 byte) response that actual mode page * starts at (relative to resp[0]). Returns -1 if problem */int scsiModePageOffset(const UINT8 * resp, int len, int modese_len){ int resp_len, bd_len; int offset = -1; if (resp) { if (10 == modese_len) { resp_len = (resp[0] << 8) + resp[1] + 2; bd_len = (resp[6] << 8) + resp[7]; offset = bd_len + 8; } else { resp_len = resp[0] + 1; bd_len = resp[3]; offset = bd_len + 4; } if ((offset + 2) > len) { pout("scsiModePageOffset: raw_curr too small, offset=%d " "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len); offset = -1; } else if ((offset + 2) > resp_len) { if ((resp_len > 2) || con->reportscsiioctl) pout("scsiModePageOffset: response length too short, " "resp_len=%d offset=%d bd_len=%d\n", resp_len, offset, bd_len); offset = -1; } } return offset;}/* IEC mode page byte 2 bit masks */#define DEXCPT_ENABLE 0x08#define EWASC_ENABLE 0x10#define DEXCPT_DISABLE 0xf7#define EWASC_DISABLE 0xef#define TEST_DISABLE 0xfb/* Fetches the Informational Exceptions Control mode page. First tries * the 6 byte MODE SENSE command and if that fails with an illegal opcode * 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 err = 0; memset(iecp, 0, sizeof(*iecp)); iecp->modese_len = modese_len; iecp->requestedCurrent = 1; if (iecp->modese_len <= 6) { if ((err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, 0, MPAGE_CONTROL_CURRENT, iecp->raw_curr, sizeof(iecp->raw_curr)))) { if (SIMPLE_ERR_BAD_OPCODE == err) iecp->modese_len = 10; else { iecp->modese_len = 0; return err; } } else if (0 == iecp->modese_len) iecp->modese_len = 6; } if (10 == iecp->modese_len) { err = scsiModeSense10(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, 0, MPAGE_CONTROL_CURRENT, iecp->raw_curr, sizeof(iecp->raw_curr)); if (err) { iecp->modese_len = 0; return err; } } iecp->gotCurrent = 1; iecp->requestedChangeable = 1; if (10 == iecp->modese_len) err = scsiModeSense10(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, 0, MPAGE_CONTROL_CHANGEABLE, iecp->raw_chg, sizeof(iecp->raw_chg)); else if (6 == iecp->modese_len) err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, 0, MPAGE_CONTROL_CHANGEABLE, iecp->raw_chg, sizeof(iecp->raw_chg)); if (err) return err; iecp->gotChangeable = 1; return 0;}int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp){ int offset; if (iecp && iecp->gotCurrent) { offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr), iecp->modese_len); if (offset >= 0) return (iecp->raw_curr[offset + 2] & DEXCPT_ENABLE) ? 0 : 1; else return 0; } else return 0;}int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp){ int offset; if (iecp && iecp->gotCurrent) { offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr), iecp->modese_len); if (offset >= 0) return (iecp->raw_curr[offset + 2] & EWASC_ENABLE) ? 1 : 0; else return 0; } else return 0;}/* set EWASC and clear PERF, EBF, DEXCPT TEST and LOGERR */#define SCSI_IEC_MP_BYTE2_ENABLED 0x10 #define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4/* exception/warning via an unrequested REQUEST SENSE command */#define SCSI_IEC_MP_MRIE 6 #define SCSI_IEC_MP_INTERVAL_T 0#define SCSI_IEC_MP_REPORT_COUNT 1/* Try to set (or clear) both Exception Control and Warning in the IE * mode page subject to the "changeable" mask. The object pointed to * by iecp is (possibly) inaccurate after this call, therefore * scsiFetchIECmpage() should be called again if the IEC mode page * 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, const struct scsi_iec_mode_page *iecp){ int k, offset, resp_len; int err = 0; UINT8 rout[SCSI_IECMP_RAW_LEN]; int sp, eCEnabled, wEnabled; if ((! iecp) || (! iecp->gotCurrent)) return -EINVAL; offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr), iecp->modese_len); if (offset < 0) return -EINVAL; memcpy(rout, iecp->raw_curr, SCSI_IECMP_RAW_LEN); if (10 == iecp->modese_len) { resp_len = (rout[0] << 8) + rout[1] + 2; rout[3] &= 0xef; /* for disks mask out DPOFUA bit */ } else { resp_len = rout[0] + 1; rout[2] &= 0xef; /* for disks mask out DPOFUA bit */ } sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */ if (enabled) { rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED; if (con->reportscsiioctl > 2) rout[offset + 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK; rout[offset + 3] = SCSI_IEC_MP_MRIE; rout[offset + 4] = (SCSI_IEC_MP_INTERVAL_T >> 24) & 0xff; rout[offset + 5] = (SCSI_IEC_MP_INTERVAL_T >> 16) & 0xff; rout[offset + 6] = (SCSI_IEC_MP_INTERVAL_T >> 8) & 0xff; rout[offset + 7] = SCSI_IEC_MP_INTERVAL_T & 0xff; rout[offset + 8] = (SCSI_IEC_MP_REPORT_COUNT >> 24) & 0xff; rout[offset + 9] = (SCSI_IEC_MP_REPORT_COUNT >> 16) & 0xff; rout[offset + 10] = (SCSI_IEC_MP_REPORT_COUNT >> 8) & 0xff; rout[offset + 11] = SCSI_IEC_MP_REPORT_COUNT & 0xff; if (iecp->gotChangeable) { UINT8 chg2 = iecp->raw_chg[offset + 2]; rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) : iecp->raw_curr[offset + 2]; for (k = 3; k < 12; ++k) { if (0 == iecp->raw_chg[offset + k]) rout[offset + k] = iecp->raw_curr[offset + k]; } } if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) { if (con->reportscsiioctl > 0) pout("scsiSetExceptionControlAndWarning: already enabled\n"); return 0; } } else { /* disabling Exception Control and (temperature) Warnings */ eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1; wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0; if ((! eCEnabled) && (! wEnabled)) { if (con->reportscsiioctl > 0) pout("scsiSetExceptionControlAndWarning: already disabled\n"); return 0; /* nothing to do, leave other setting alone */ } if (wEnabled) rout[offset + 2] &= EWASC_DISABLE; if (eCEnabled) { if (iecp->gotChangeable && (iecp->raw_chg[offset + 2] & DEXCPT_ENABLE)) rout[offset + 2] |= DEXCPT_ENABLE; rout[offset + 2] &= TEST_DISABLE;/* clear TEST bit for spec */ } } if (10 == iecp->modese_len) err = scsiModeSelect10(device, sp, rout, resp_len); else if (6 == iecp->modese_len) err = scsiModeSelect(device, sp, rout, resp_len); return err;}int scsiGetTemp(int device, UINT8 *currenttemp, UINT8 *triptemp){ UINT8 tBuf[252]; int err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -