Public Member Functions | Protected Member Functions | Protected Attributes | Private Member Functions | Private Attributes

scsi_IO Class Reference
[SCSI Library]

Interface class to access SCSI devices. More...

#include <scsi_io.h>

Inheritance diagram for scsi_IO:
Inheritance graph
[legend]
Collaboration diagram for scsi_IO:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 scsi_IO (const string &a_deviceID)
 Device identification is passed in constructor:
virtual ~scsi_IO ()
void Open ()
 Open SCSI device.
void SkipAttAndDeferred ()
void WaitToBecomeReady ()
virtual bool IsOpen ()=0
virtual void Close ()=0
virtual scsi_Status_e GetCDBStatus ()=0
virtual bool IsSenseValid ()=0
virtual void IOCtl (const scsi_CDB &a_cdb, UInt32_t a_timeout=scsi_TIMEOUT_NORMAL_d)
void SetDeviceID (string a_deviceID)
UInt32_t GetPort () const
UInt32_t GetChannel () const
UInt32_t GetID () const
UInt32_t GetLUN () const
string GetSCSIID () const
const string & GetDeviceName () const
scsi_DeviceType_e GetDeviceType () const
const string & GetVendorID () const
const string & GetProductID () const
const string & GetProductRevision () const
const string & GetProductSerialNumber () const
UInt8_t GetStandard () const
bool GetPossibleMediumChange () const
const data_Sense_tGetSense () const
UInt32_t GetSenseSize () const
UInt32_t GetReadDifference () const
 The difference between the requested and read data if SILI bit is set.

Protected Member Functions

void TestUnitReady ()
virtual void OpenByDeviceName ()=0
 Open SCSI device by its (platform specific!) name.
virtual void OpenBySCSIID ()=0
 Open SCSI device by its (current) SCSI ID.
virtual void OpenBySerialNumber ()=0
 Open SCSI device by its unique identification.
virtual void InqSCSIID ()=0
 Get SCSI ID of the currently opened device.
void InqStandard ()
 Do standard inquiry.
void InqSerialNumber ()
 Do inquiries necessary to get the serial number of the device.
virtual int DoIOCtl (const scsi_CDB &a_cdb, UInt32_t a_timeout)=0
 Function to actually execute CDB commands.
virtual void CheckDriverStatus (UInt8_t a_cdbCode)
 Checks the status of the driver after the execution of CDB.
virtual void CheckHostStatus (UInt8_t a_cdbCode)
 Checks the status of the host (if available) after the execution of CDB.
void CheckStatusAndSense (const scsi_CDB &a_cdb)
 Checks the execution status and sense structure.
void Inquiry ()

Protected Attributes

string m_deviceID
 Unique device identification, passed in constructor or SetDeviceID.
string m_deviceName
 Device name.
UInt32_t m_port
 Also known as bus or host.
UInt32_t m_channel
UInt32_t m_id
UInt32_t m_lun
string m_strSCSIID
string m_vendorID
string m_productID
string m_productSerialNumber
const scsi_SenseVndm_vndSenseText
string m_productRevision
scsi_DeviceType_e m_deviceType
vector< data_Inquiry::inq_Page_tm_supportedPages
UInt8_t m_standard
bool m_possibleMediumChange
data_Sense_t m_sense
bool m_pdDirectMode
 Direct passthrough mode can be disabled via env variable.
UInt32_t m_timeoutOverride
 Default timeouts can be overridden with env.
UInt32_t m_testHWErrProbability
UInt32_t m_testMedErrProbability

Private Member Functions

bool IsPageSupported (data_Inquiry::inq_Page_t a_page)

Private Attributes

 log_CLASSID_m

Detailed Description

Interface class to access SCSI devices.

Successors of this class implement actual communication.

Definition at line 55 of file scsi_io.h.


Constructor & Destructor Documentation

scsi_IO::scsi_IO ( const string &  a_deviceID  ) 

Device identification is passed in constructor:

  • sn:VENDOR_ID:DEVICE_ID:SERIAL_NUMBER .. open by serial number
  • id:PORT:CHANNEL:ID:LUN .. open by SCSI ID
  • else open by device name (e.g. /dev/sgX)

Definition at line 78 of file scsi_io.cpp.

References cmn_GetEnvVariable(), dbg_LOW, log_DBG_m, log_FUNC_A_m, m_pdDirectMode, m_testHWErrProbability, m_testMedErrProbability, m_timeoutOverride, NULL, scsi_ptDirect_c(), scsi_testHWerror_c(), scsi_testMederror_c(), scsi_testProbUnit(), and scsi_timeout_c().

    : m_deviceID(a_deviceID),
      m_deviceName(""),
      m_port(0xFF),
      m_channel(0xFF),
      m_id(0xFF),
      m_lun(0xFF),
      m_vendorID(""),
      m_productID(""),
      m_productSerialNumber(""),
      m_vndSenseText(NULL),
      m_productRevision(""),
      m_deviceType(dt_NO_LUN),
      m_standard(0),
      m_possibleMediumChange(false),
      m_pdDirectMode(true),
      m_timeoutOverride(0),
      m_testHWErrProbability(0),
      m_testMedErrProbability(0) {

    log_FUNC_A_m(scsi_IO, "device: " << a_deviceID);

    string ptDirect = cmn_GetEnvVariable(scsi_ptDirect_c);
    if (ptDirect == "no" || ptDirect == "false") {
        log_DBG_m(dbg_LOW,
            scsi_ptDirect_c << " = " << ptDirect <<
            ". SCSI passthrough direct mode disabled.");

        m_pdDirectMode = false;
    }

    string timeout = cmn_GetEnvVariable(scsi_timeout_c);
    if (timeout.length() > 0) {
        log_DBG_m(dbg_LOW, scsi_timeout_c << " = " << timeout << " sec.");

        m_timeoutOverride = atol(timeout.c_str()) * 1000;
        log_DBG_m(dbg_LOW, "SCSI timeout overridden value (ms): " << m_timeoutOverride);
    }

#ifdef scsi_SIMULATE_ERRORS_d
    // Reading env variables for simulating hardware/medium errors.
    string hwErr = cmn_GetEnvVariable(scsi_testHWerror_c);
    if (hwErr.length() > 0) {
        log_DBG_m(dbg_LOW,
            scsi_testHWerror_c << " = " << hwErr <<
            " (1/" << scsi_testProbUnit << ").");
        m_testHWErrProbability = atol(hwErr.c_str());
    }

    string medErr = cmn_GetEnvVariable(scsi_testMederror_c);
    if (medErr.length() > 0) {
        log_DBG_m(dbg_LOW,
            scsi_testMederror_c << " = " << medErr <<
            " (1/" << scsi_testProbUnit << ").");
        m_testMedErrProbability = atol(medErr.c_str());
    }

    // Set seed for better random
    if (m_testHWErrProbability > 0 || m_testMedErrProbability > 0) {
        time_t now = time(NULL);
        srand(now);
    }
#endif

}

Here is the call graph for this function:

scsi_IO::~scsi_IO (  )  [virtual]

Definition at line 144 of file scsi_io.cpp.

References log_FUNC_m.


Member Function Documentation

virtual void scsi_IO::CheckDriverStatus ( UInt8_t  a_cdbCode  )  [inline, protected, virtual]

Checks the status of the driver after the execution of CDB.

Reimplemented in scsi_LnxSG, and scsi_WinSG.

Definition at line 151 of file scsi_io.h.

Referenced by IOCtl().

                                                      {
        // No driver checking by default
    }

Here is the caller graph for this function:

virtual void scsi_IO::CheckHostStatus ( UInt8_t  a_cdbCode  )  [inline, protected, virtual]

Checks the status of the host (if available) after the execution of CDB.

Reimplemented in scsi_LnxSG, and scsi_WinSG.

Definition at line 158 of file scsi_io.h.

Referenced by IOCtl().

                                                    {
        // No host checking by default
    }

Here is the caller graph for this function:

void scsi_IO::CheckStatusAndSense ( const scsi_CDB a_cdb  )  [protected]

Checks the execution status and sense structure.

Analysing the SCSI sense buffer.

Platform independent check.

Exceptions:
ivd_Error Throws different exceptions for each of the statuses.

Definition at line 554 of file scsi_io.cpp.

References data_Sense_t::additionalLen, data_Sense_t::ait, data_Sense_t::asc, data_Sense_t::ascq, data_AIT_Sense_t::clean, cmn_HexDump(), dbg_DETAIL, dt_TAPE, data_Sense_t::eom, evt_CRITICAL, evt_ERROR, evt_WARNING, data_Sense_t::fileMark, scsi_CDB::GetBufferPointer(), scsi_CDB::GetBufferSize(), GetCDBStatus(), scsi_CDB::GetCmdPointer(), scsi_CDB::GetCmdSize(), ie_SCSI_BLANK, ie_SCSI_DESTFULL, ie_SCSI_EOD, ie_SCSI_EOM, ie_SCSI_FILEMARK, ie_SCSI_HWERR, ie_SCSI_ILENGTH, ie_SCSI_ILREQ, ie_SCSI_MEDERR, ie_SCSI_NO_MEDIUM, ie_SCSI_NOT_READY, ie_SCSI_OVERFLOW, ie_SCSI_PROTECTED, ie_SCSI_RETRY, ie_SCSI_SENSE, ie_SCSI_SRCEMPTY, ie_SCSI_STATUS, ie_SCSI_UNIT_ATT, data_Sense_t::incorrectLength, IsSenseValid(), ivd_Error, log_DBG_m, log_FUNC_m, log_WriteEvent(), log_WRN_m, m_deviceType, m_possibleMediumChange, m_productID, m_productRevision, m_productSerialNumber, m_sense, m_strSCSIID, m_vendorID, m_vndSenseText, data_AIT_Sense_t::mew, scsi_GetASCText(), scsi_GetOpcodeText(), scsi_GetSenseKeyText(), scsi_GetSenseText(), scsi_GetStatusText(), data_Sense_t::senseKey, sk_ABORTED_COMMAND, sk_BLANK_CHECK, sk_COPY_ABORTED, sk_DATA_PROTECT, sk_HARDWARE_ERROR, sk_ILLEGAL_REQUEST, sk_MEDIUM_ERROR, sk_MISCOMPARE, sk_NO_SENSE, sk_NOT_READY, sk_OBSOLETE, sk_RECOVERED_ERROR, sk_RESERVED, sk_UNIT_ATTENTION, sk_VENDOR_SPECIFIC, sk_VOLUME_OVERFLOW, st_ACA_ACTIVE, st_BUSY, st_CHECK_CONDITION, st_COMMAND_TERMINATED, st_CONDITION_GOOD, st_GOOD, st_INTERMEDIATE_C_GOOD, st_INTERMEDIATE_GOOD, st_QUEUE_FULL, and st_RESERVATION_CONFLICT.

Referenced by IOCtl().

                                                       {

    if (!IsSenseValid()) {
        return;
    }

    log_FUNC_m(CheckStatusAndSense);

    scsi_Status_e status = GetCDBStatus();

    log_DBG_m(dbg_DETAIL,
        "CDB Status: 0x" <<
        hex << status << dec << " " <<
        scsi_GetStatusText(status)
    );

    // HEX dump of a command.
    const UInt8_t *cdb = a_cdb.GetCmdPointer();
    UInt8_t cdbCode = cdb[0];
    UInt32_t cdbSize = a_cdb.GetCmdSize();
    // HEX dump of data.
    UInt8_t *data = a_cdb.GetBufferPointer();
    UInt32_t dataSize = a_cdb.GetBufferSize();

    string senseTxt = scsi_GetSenseText(m_sense, m_deviceType, m_vndSenseText);

    ostringstream shortText;
    shortText
        << scsi_GetSenseKeyText((scsi_SenseKey_e)m_sense.senseKey)
        << " (" << scsi_GetASCText(m_sense, m_vndSenseText) << ")";

    // Detailed dump
    ostringstream dump;
    dump
        << "Device: " << m_vendorID << " " << m_productID << " "
        << m_productRevision << " s/n: " << m_productSerialNumber << endl
        << senseTxt << endl
        << "Sense dump (" << static_cast<UInt32_t>(m_sense.additionalLen+8) << " bytes) :" << endl
        << cmn_HexDump(
            reinterpret_cast<const void*>(&m_sense), m_sense.additionalLen+8, 8, true) << endl

        << "CDB: " << scsi_GetOpcodeText(cdbCode) << endl
        << cmn_HexDump(
            reinterpret_cast<const void*>(cdb), cdbSize, 8, true) << endl

        << "DATA length: " << dataSize << endl
        << "DATA:" << endl
        << cmn_HexDump(
            reinterpret_cast<const void*>(data), (dataSize < 256)? dataSize : 256, 16, true);


    switch (status) {
        case st_GOOD:
            break;
        case st_CHECK_CONDITION:
        case st_BUSY:
        case st_COMMAND_TERMINATED:
            break;
        case st_RESERVATION_CONFLICT:
            log_MARKLINE_m;
            throw ivd_InternalError(
                ie_SCSI_STATUS, "Reservation not used.", dump.str());
            break;

        case st_CONDITION_GOOD:
        case st_INTERMEDIATE_GOOD:
        case st_INTERMEDIATE_C_GOOD:
        case st_QUEUE_FULL:
        case st_ACA_ACTIVE:
        default:
            log_MARKLINE_m;
            throw ivd_InternalError(
                ie_SCSI_STATUS, scsi_GetStatusText(status), dump.str());
            break;
    }

    //
    // Detect and log cleaning and media warning (works for AIT tape drives)
    //
    if (m_deviceType == dt_TAPE && m_sense.additionalLen > 19) {
        if (m_sense.ait.clean != 0) {
            ostringstream sstr;
            sstr
                << "Device: " << m_vendorID << " " << m_productID << " "
                << m_productRevision << " s/n: " << m_productSerialNumber
                << " is requesting cleaning.";
            log_WriteEvent(
                evt_WARNING, sstr.str(), "SCSI", 0, m_strSCSIID);
        }
        if (m_sense.ait.mew != 0) {
            ostringstream sstr;
            sstr
                << "Device: " << m_vendorID << " " << m_productID << " "
                << m_productRevision << " s/n: " << m_productSerialNumber
                << " is reporting media warning.";
            log_WriteEvent(
                evt_WARNING, sstr.str(), "SCSI", 0, m_strSCSIID);
        }
    }

    // Decode sense information
    if (status == st_BUSY || status == st_COMMAND_TERMINATED) {
        log_MARKLINE_m;
        throw ivd_Error(ie_SCSI_RETRY, shortText.str(), dump.str(), true);
    }
    switch (m_sense.senseKey) {
        case sk_ILLEGAL_REQUEST:
            log_MARKLINE_m;
            if (m_sense.asc == 0x3B && m_sense.ascq == 0x0D) {
                log_WriteEvent(
                    evt_WARNING,
                    shortText.str(), "SCSI", 0, m_strSCSIID);
                throw ivd_Error(ie_SCSI_DESTFULL, shortText.str(), dump.str());
            }
            else if (m_sense.asc == 0x3B && m_sense.ascq == 0x0E) {
                log_WriteEvent(
                    evt_WARNING,
                    shortText.str(), "SCSI", 0, m_strSCSIID);
                throw ivd_Error(ie_SCSI_SRCEMPTY, shortText.str(), dump.str());
            }
            log_WriteEvent(
                evt_ERROR,
                shortText.str(), "SCSI", 0, m_strSCSIID);
            throw ivd_Error(ie_SCSI_ILREQ, shortText.str(), dump.str(), true);
            break;
        case sk_NOT_READY:
            log_MARKLINE_m;
            if (m_sense.asc == 0x3A) {
                throw ivd_Error(ie_SCSI_NO_MEDIUM, shortText.str(), dump.str());
            }
            throw ivd_Error(ie_SCSI_NOT_READY, shortText.str(), dump.str());
            break;
        case sk_RECOVERED_ERROR:
            log_MARKLINE_m;
            // See SCSI documentation (or scsi_err.cpp) for details.
            if (m_sense.asc == 0x00 && m_sense.ascq == 0x01) {
                throw ivd_Error(ie_SCSI_FILEMARK, shortText.str(), dump.str());
            }
            if (m_sense.asc == 0x00 && m_sense.ascq == 0x02) {
                throw ivd_Error(ie_SCSI_EOM, shortText.str(), dump.str());
            }
            // Else log and check file mark, etc after the switch.
            log_WRN_m("RECOVERED ERROR: " << dump.str());
            break;
        case sk_MEDIUM_ERROR:
            log_MARKLINE_m;
            log_WriteEvent(evt_ERROR, shortText.str(), "SCSI", 0, m_strSCSIID);
            throw ivd_Error(ie_SCSI_MEDERR, shortText.str(), dump.str(), true);
            break;
        case sk_HARDWARE_ERROR:
            log_MARKLINE_m;
            log_WriteEvent(evt_ERROR, shortText.str(), "SCSI", 0, m_strSCSIID);
            throw ivd_Error(ie_SCSI_HWERR, shortText.str(), dump.str(), true);
            break;
        case sk_UNIT_ATTENTION:
            log_MARKLINE_m;
            // See SCSI documentation (or scsi_err.cpp) for details.
            if (   ((m_sense.asc  == 0x28) && (m_sense.ascq == 0x00))
                || ((m_sense.asc  == 0x29) && (m_sense.ascq == 0x00)) ) {
                // 28: Not ready to transition (medium may have changed)
                // 29: Power on, reset, or bus device reset occurred
                m_possibleMediumChange = true;
            }
            throw ivd_Error(ie_SCSI_UNIT_ATT, shortText.str(), dump.str());
            break;
        case sk_DATA_PROTECT:
            log_MARKLINE_m;
            throw ivd_Error(ie_SCSI_PROTECTED, shortText.str(), dump.str(), true);
            break;
        case sk_BLANK_CHECK:
            log_MARKLINE_m;
            // See SCSI documentation (or scsi_err.cpp) for details.
            if (m_sense.asc  == 0x00 && m_sense.ascq == 0x05) {
                throw ivd_Error(ie_SCSI_EOD, shortText.str(), dump.str());
            }
            throw ivd_Error(ie_SCSI_BLANK, shortText.str(), dump.str());
            break;
        case sk_VOLUME_OVERFLOW:
            log_MARKLINE_m;
            log_WriteEvent(
                evt_WARNING,
                shortText.str() + " Physical end of medium or media volume",
                "SCSI", 0, m_strSCSIID);
            throw ivd_Error(ie_SCSI_OVERFLOW, shortText.str(), dump.str(), true);
            break;

        // The following sense codes are treated as critical.
        case sk_VENDOR_SPECIFIC:
            log_MARKLINE_m;
            //
            // Throw ivd_Error for:
            //   AIT: MIC exists but is not used.
            //
            if (m_sense.asc  == 0x83 &&
                m_sense.ascq == 0x83) {
                throw ivd_Error(ie_SCSI_SENSE, shortText.str(), dump.str());
            }

            log_WriteEvent(
                evt_CRITICAL,
                shortText.str(), "SCSI", 0, m_strSCSIID);

            throw ivd_Error(ie_SCSI_SENSE, shortText.str(), dump.str(), true);
            break;
        case sk_COPY_ABORTED:
        case sk_ABORTED_COMMAND:
        case sk_OBSOLETE:
        case sk_MISCOMPARE:
        case sk_RESERVED:
            log_MARKLINE_m;

            log_WriteEvent(
                evt_CRITICAL,
                shortText.str(), "SCSI", 0, m_strSCSIID);

            throw ivd_Error(ie_SCSI_SENSE, shortText.str(), dump.str(), true);
            break;
        case sk_NO_SENSE:
            log_MARKLINE_m;
            log_DBG_m(dbg_DETAIL, "No sense.");
            break;
        default:
            log_MARKLINE_m;

            log_WriteEvent(
                evt_CRITICAL,
                shortText.str(), "SCSI", 0, m_strSCSIID);

            throw ivd_InternalError(
                ie_SCSI_SENSE,
                string("Unknown sense key! ") + shortText.str(), dump.str());
            break;
    }

    // sk_NO_SENSE

    // We prefer to have file mark reported over the early end of medium
    if (m_sense.fileMark) {
        log_MARKLINE_m;
        throw ivd_Error(ie_SCSI_FILEMARK, shortText.str(), dump.str());
    }
    if (m_sense.eom) {
        log_MARKLINE_m;
        throw ivd_Error(ie_SCSI_EOM, shortText.str(), dump.str());
    }
    if (m_sense.incorrectLength) {
        log_MARKLINE_m;
        throw ivd_Error(ie_SCSI_ILENGTH, shortText.str(), dump.str());
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

virtual void scsi_IO::Close (  )  [pure virtual]

Implemented in scsi_LnxSG, and scsi_WinSG.

Referenced by la_SCSILibrary::Close(), la_SCSILibrary::EjectMedium(), main(), la_SCSILibrary::Open(), ParseTapeMedium(), STapeClose(), and STapeOpen().

Here is the caller graph for this function:

virtual int scsi_IO::DoIOCtl ( const scsi_CDB a_cdb,
UInt32_t  a_timeout 
) [protected, pure virtual]

Function to actually execute CDB commands.

Returns:
result code of platform specific ioctl command.

Implemented in scsi_LnxSG, and scsi_WinSG.

Referenced by IOCtl().

Here is the caller graph for this function:

virtual scsi_Status_e scsi_IO::GetCDBStatus (  )  [pure virtual]

Implemented in scsi_LnxSG, and scsi_WinSG.

Referenced by CheckStatusAndSense(), and scsi_WinSG::IsSenseValid().

Here is the caller graph for this function:

UInt32_t scsi_IO::GetChannel (  )  const

Definition at line 166 of file scsi_io.cpp.

References m_channel.

Referenced by main(), and STapeOpen().

                                   {
    return m_channel;
}

Here is the caller graph for this function:

const string & scsi_IO::GetDeviceName (  )  const

Definition at line 186 of file scsi_io.cpp.

References m_deviceName.

Referenced by main().

                                           {
    return m_deviceName;
}

Here is the caller graph for this function:

scsi_DeviceType_e scsi_IO::GetDeviceType (  )  const

Definition at line 190 of file scsi_io.cpp.

References m_deviceType.

Referenced by la_SCSILibrary::EjectMedium(), main(), la_SCSILibrary::Open(), and STapeOpen().

                                               {
    return m_deviceType;
}

Here is the caller graph for this function:

UInt32_t scsi_IO::GetID (  )  const

Definition at line 159 of file scsi_io.cpp.

References m_id.

Referenced by main(), and STapeOpen().

                              {
    return m_id;
}

Here is the caller graph for this function:

UInt32_t scsi_IO::GetLUN (  )  const

Definition at line 163 of file scsi_io.cpp.

References m_lun.

Referenced by main(), and STapeOpen().

                               {
    return m_lun;
}

Here is the caller graph for this function:

UInt32_t scsi_IO::GetPort (  )  const

Definition at line 170 of file scsi_io.cpp.

References m_port.

Referenced by main(), and STapeOpen().

                                {
    return m_port;
}

Here is the caller graph for this function:

bool scsi_IO::GetPossibleMediumChange (  )  const

Definition at line 213 of file scsi_io.cpp.

References m_possibleMediumChange.

const string & scsi_IO::GetProductID (  )  const

Definition at line 198 of file scsi_io.cpp.

References m_productID.

Referenced by Append(), Fmt(), bea_TapeMedium::Format(), la_SCSILibrary::GetProductID(), main(), and la_SCSILibrary::Open().

                                          {
    return m_productID;
}

Here is the caller graph for this function:

const string & scsi_IO::GetProductRevision (  )  const

Definition at line 202 of file scsi_io.cpp.

References m_productRevision.

Referenced by bea_TapeMedium::Format(), la_SCSILibrary::GetProductRevision(), and main().

                                                {
    return m_productRevision;
}

Here is the caller graph for this function:

const string & scsi_IO::GetProductSerialNumber (  )  const

Definition at line 205 of file scsi_io.cpp.

References m_productSerialNumber.

Referenced by bea_TapeMedium::Format(), la_SCSILibrary::GetSerialNumber(), and main().

                                                    {
    return m_productSerialNumber;
}

Here is the caller graph for this function:

UInt32_t scsi_IO::GetReadDifference (  )  const

The difference between the requested and read data if SILI bit is set.

Definition at line 226 of file scsi_io.cpp.

References data_Sense_t::incorrectLength, data_Sense_t::infoBytes, data_Sense_t::isValid, m_sense, and ntoh().

Referenced by Rd(), and ReadOneBackupFromMedium().

                                          {
    if (m_sense.incorrectLength == 0 || m_sense.isValid == 0) {
        return 0;
    }
    return static_cast<UInt32_t>(ntoh(m_sense.infoBytes));
}

Here is the call graph for this function:

Here is the caller graph for this function:

string scsi_IO::GetSCSIID (  )  const

Definition at line 174 of file scsi_io.cpp.

References m_channel, m_id, m_lun, and m_port.

Referenced by la_SCSILibrary::GetSCSIID(), and scsi_LnxSG::InqSCSIID().

                                {
    ostringstream sstr;
    sstr
        << "id:"
        << m_port << ":"
        << m_channel << ":"
        << m_id << ":"
        << m_lun;

    return sstr.str();
}

Here is the caller graph for this function:

const data_Sense_t * scsi_IO::GetSense (  )  const

Definition at line 218 of file scsi_io.cpp.

References m_sense.

Referenced by scsi_LnxSG::DoIOCtl(), ParseTapeMedium(), and SkipAttAndDeferred().

                                            {
    return &m_sense;
}

Here is the caller graph for this function:

UInt32_t scsi_IO::GetSenseSize (  )  const

Definition at line 222 of file scsi_io.cpp.

References m_sense.

Referenced by scsi_LnxSG::DoIOCtl().

                                     {
    return sizeof(m_sense);
}

Here is the caller graph for this function:

UInt8_t scsi_IO::GetStandard (  )  const

Definition at line 209 of file scsi_io.cpp.

References m_standard.

Referenced by main().

                                   {
    return m_standard;
}

Here is the caller graph for this function:

const string & scsi_IO::GetVendorID (  )  const

Definition at line 194 of file scsi_io.cpp.

References m_vendorID.

Referenced by Append(), Fmt(), bea_TapeMedium::Format(), la_SCSILibrary::GetVendorID(), main(), la_SCSILibrary::Open(), ParseMICMediumNote(), and ParseMICVolNote().

                                         {
    return m_vendorID;
}

Here is the caller graph for this function:

virtual void scsi_IO::InqSCSIID (  )  [protected, pure virtual]

Get SCSI ID of the currently opened device.

Implemented in scsi_LnxSG, and scsi_WinSG.

void scsi_IO::InqSerialNumber (  )  [protected]

Do inquiries necessary to get the serial number of the device.

Do inquiries necessary to get the serial number of the SCSI device.

Warning:
May not be successful; not all devices support serial #.

Definition at line 861 of file scsi_io.cpp.

References dbg_DETAIL, dbg_LOW, dbg_NORM, data_InqDeviceID_t::devID, data_Inquiry_t::devID, cdb_Inquiry::GetInquiry(), data_Inquiry::GetInquiryData(), id, data_InqDevId_t::idType, ie_NYI, ie_SCSI_INVRESULT, data_InqDevId_t::ieee, data_Inquiry::inq_DEVID, data_Inquiry::inq_SERNO, IOCtl(), IsPageSupported(), log_DBG_m, log_ERR_m, log_FUNC_m, log_WRN_m, m_productSerialNumber, data_InqDeviceID_t::pageLen, data_InqSerialNo_t::pageLen, data_InqDevId_t::pcph, data_Inquiry::pg_DEVID, data_Inquiry::pg_SERNO, data_InqSerialNo_t::serNumber, data_Inquiry_t::serNumber, and data_InqDevId_t::vendor.

Referenced by scsi_LnxSG::OpenByDeviceName().

                              {
    log_FUNC_m(InqSerialNumber);

    try {
        if (IsPageSupported(data_Inquiry::pg_SERNO)) {
            // Serial number page
            cdb_Inquiry ser(data_Inquiry::inq_SERNO);
            IOCtl(ser);
            const data_Inquiry_t &inquiry = ser.GetInquiry().GetInquiryData();
            log_DBG_m(dbg_DETAIL,
                "serNumber.pageLen = " << (int)(inquiry.serNumber.pageLen));

            if (inquiry.serNumber.pageLen > 0) {

                m_productSerialNumber = string(
                    (const char*)inquiry.serNumber.serNumber,
                    inquiry.serNumber.pageLen);

                 // strip potentional trailing blanks
                string::size_type last = m_productSerialNumber.find_last_not_of(string(" \0",2));
                if ( (last != string::npos) && ((last+1) < m_productSerialNumber.size())) {
                    m_productSerialNumber.erase(last+1);
                }

                log_DBG_m(dbg_LOW,
                    "Device serial number " << m_productSerialNumber);
            }
            else {
                log_WRN_m(
                    "Serial number page supported but it does not contain any info");
            }
        }
        else if (IsPageSupported(data_Inquiry::pg_DEVID)) {
            // Device ID
            log_WRN_m("pg_DEVID is untested. Will it work??");
            cdb_Inquiry id(data_Inquiry::inq_DEVID);
            IOCtl(id);
            const data_Inquiry_t &inquiry = id.GetInquiry().GetInquiryData();
            if (inquiry.devID.pageLen > 0) {
                switch (inquiry.devID.devID.idType) {
                    case 1:
                        log_DBG_m(dbg_NORM, "Serial number from DEV ID.");
                        m_productSerialNumber = string(
                            (const char*)inquiry.devID.devID.vendor.serialNo,
                            inquiry.devID.pageLen-8-16);
                        break;
                    case 2:
                        log_ERR_m("IEEE INQ page not supported: " <<
                            string((const char*)inquiry.devID.devID.ieee, 64) );
                        throw ivd_InternalError(ie_SCSI_INVRESULT);
                        break;
                    case 3:
                        log_ERR_m("PCPH INQ page not supported: " <<
                            string((const char*)inquiry.devID.devID.pcph, 64) );
                        throw ivd_InternalError(ie_SCSI_INVRESULT);
                        break;
                    default:
                        log_ERR_m("Unknown DEV ID Type " << inquiry.devID.devID.idType);
                        throw ivd_InternalError(ie_SCSI_INVRESULT);
                        break;
                }
                log_DBG_m(dbg_LOW, "Device serial number " << m_productSerialNumber);
                throw ivd_InternalError(ie_NYI, "Device ID Inquiry");
            }
            else {
                log_WRN_m(
                    "Device ID page supported but it does not contain any info.");
            }
        } // if (IsPage...
        else {
            log_DBG_m(dbg_LOW, "Device does not support serial number.");
        }
    }
    catch (ivd_Error &ie) {
        log_DBG_m(dbg_NORM, "Error doing device version inquiry: " << endl << ie);
        throw;
    }
    catch (ivd_SysError &ie) {
        log_DBG_m(dbg_NORM, "Error doing device version inquiry: " << endl << ie);
        throw;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void scsi_IO::InqStandard (  )  [protected]

Do standard inquiry.

It gets:

  • Device type
  • Vendor ID
  • Product ID
  • Product revision
  • SCSI Standard

Definition at line 805 of file scsi_io.cpp.

References data_StdInquiry_t::ansi, cmn_Num2Str(), dbg_DETAIL, dbg_LOW, dbg_NORM, dt_MEDIUM_CHANGER, dt_TAPE, ivd_BaseException::GetFriendly(), cdb_Inquiry::GetInquiry(), data_Inquiry::GetInquiryData(), data_Inquiry::inq_PAGES, data_Inquiry_t::inqstd, inqstd_PROD_REVISION_LEN_d, inqstd_PRODUCT_ID_LEN_d, inqstd_VENDOR_ID_LEN_d, IOCtl(), log_DBG_m, log_FUNC_m, m_deviceType, m_productID, m_productRevision, m_standard, m_supportedPages, m_vendorID, m_vndSenseText, data_InqPages_t::pageLen, data_InqPages_t::pages, data_StdInquiry_t::productID, data_StdInquiry_t::productRevision, scsi_GetDeviceTypeText(), scsi_GetVndAddSnsTbl(), data_Inquiry_t::supportedPages, data_StdInquiry_t::type, and data_StdInquiry_t::vendorID.

Referenced by scsi_LnxSG::OpenByDeviceName().

                          {
    log_FUNC_m(InqStandard);

    {
        log_DBG_m(dbg_NORM, "Standard INQ:")
        // Standard inquiry

        cdb_Inquiry scsistd;
        IOCtl(scsistd);
        const data_Inquiry_t &inquiry = scsistd.GetInquiry().GetInquiryData();

        this->m_deviceType = scsi_DeviceType_e(inquiry.inqstd.type);
        log_DBG_m(dbg_DETAIL, "Device type: "
                << scsi_GetDeviceTypeText(m_deviceType)
                << "(" << m_deviceType << ")");
        m_vendorID = string(
            (const char*)inquiry.inqstd.vendorID, inqstd_VENDOR_ID_LEN_d);
        m_productID = string(
            (const char*)inquiry.inqstd.productID, inqstd_PRODUCT_ID_LEN_d);
        m_productRevision = string(
            (const char*)inquiry.inqstd.productRevision, inqstd_PROD_REVISION_LEN_d);
        m_standard = inquiry.inqstd.ansi;
    }

    try {
        if ( (m_deviceType == dt_MEDIUM_CHANGER) || (m_deviceType == dt_TAPE)) {
            // Supported pages
            cdb_Inquiry pages(data_Inquiry::inq_PAGES);
            IOCtl(pages);

            const data_Inquiry_t &inquiry = pages.GetInquiry().GetInquiryData();
            string strpages;

            for (int i = 0; i < inquiry.supportedPages.pageLen; i++) {
                strpages += cmn_Num2Str(inquiry.supportedPages.pages[i], true) + " ";
                m_supportedPages.push_back(
                    (data_Inquiry::inq_Page_t)inquiry.supportedPages.pages[i]);
            }
            log_DBG_m(dbg_LOW, "Supported INQUIRY pages " << strpages);
        }
        else {
            log_DBG_m(dbg_LOW, "Device type ("
                    << scsi_GetDeviceTypeText(m_deviceType)
                    << ") not supported. => INQUIRY pages empty");
        }
    }
    catch (const ivd_Error& ie) {
        log_DBG_m(dbg_NORM,
            "Vital product data not supported by this device." <<
            ie.GetFriendly());
    }

    m_vndSenseText = scsi_GetVndAddSnsTbl(m_vendorID, m_productID);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void scsi_IO::Inquiry (  )  [protected]
void scsi_IO::IOCtl ( const scsi_CDB a_cdb,
UInt32_t  a_timeout = scsi_TIMEOUT_NORMAL_d 
) [virtual]

################### DoIOCtl ###################

################### DoIOCtl ###################

Definition at line 447 of file scsi_io.cpp.

References data_Sense_t::additionalLen, CheckDriverStatus(), CheckHostStatus(), CheckStatusAndSense(), cmn_HexDump(), cmn_Num2Str(), dbg_DETAIL, dbg_GetLevel(), dbg_IsActive(), dbg_NORM, DoIOCtl(), evt_WARNING, scsi_CDB::GetBufferPointer(), scsi_CDB::GetBufferSize(), scsi_CDB::GetCmdPointer(), scsi_CDB::GetCmdSize(), ie_INVALID_ARG, ie_SCSI_HWERR, ie_SCSI_MEDERR, IsOpen(), data_Sense_t::isValid, ivd_Error, log_DBG_m, log_FUNC_m, log_WriteEvent(), m_deviceID, m_sense, m_strSCSIID, m_testHWErrProbability, m_testMedErrProbability, m_timeoutOverride, op_READ_10, op_READ_6, op_WRITE_10, op_WRITE_6, data_Sense_t::responseCode, scsi_CommandSize(), scsi_GetOpcodeText(), scsi_testProbUnit(), data_Sense_t::senseKey, and size.

Referenced by Ait(), Append(), bea_TapeMedium::AppendVolume(), bea_TapeMedium::ChangeVolume(), CheckIVDHeader(), Ci(), Compression(), Cp(), Dens(), bea_MicMemory::Detect(), bea_TapeMedium::DetectAITWORM(), bea_TapeMedium::DetectLTOWORM(), Ea(), la_SCSILibrary::EjectMedium(), Eod(), Erase(), bea_TapeVolume::Erase(), FMSeek(), Fmt(), bea_TapeMedium::Format(), bea_MicMemory::GetAvailable(), bea_MamMemory::GetAvailable(), GetCapacityInfo(), bea_MicMemory::GetChecksum(), bea_MicMemory::GetManufacturer(), bea_MamMemory::GetManufacturer(), GetPos(), bea_TapeVolume::GetPosition(), bea_MicMemory::GetSecondaryID(), bea_MicMemory::GetSerialNumber(), bea_MamMemory::GetSerialNumber(), bea_MicMemory::GetSize(), InqSerialNumber(), InqStandard(), la_SCSILibrary::Inventory(), Inventory(), la_SCSILibrary::Load(), Load(), main(), Mamcapacity(), Mamdetect(), Mamfree(), Mamisworm(), Mamrmedinfo(), Mamrvolinfo(), Mamserial(), Mamwmedinfo(), Mamwvolinfo(), Micfree(), Micnote(), Micnotelen(), Micnotemap(), Micnotesize(), Micserial(), Micwritenote(), Mv(), ParseMICMediumNote(), ParseMICVolNote(), ParseTapeMedium(), ParseTapeMediumVolume(), ParseTapeMediumVolumeData(), ParseTapeMediumVolumeFRI(), ParseTapeMediumVolumeHeader(), Pi(), Pn(), Pos(), Rate(), Rd(), bea_MicMemory::Read(), bea_MamMemory::Read(), bea_MamMemory::ReadAttributeList(), ReadBlockPos(), bea_TapeMedium::ReadCurrentVolume(), la_SCSILibrary::ReadElementAssignment(), bea_TapeVolume::ReadEstimSizes(), ReadFromMedium(), ReadOneBackupFromMedium(), bea_TapeVolume::ReadRaw(), bea_TapeMedium::RefreshCompressionState(), bea_TapeMedium::RefreshTapeInfo(), Rewind(), bea_TapeVolume::Rewind(), RewindMedium(), Seek(), bea_TapeVolume::SeekBlock(), bea_TapeVolume::SeekEOD(), bea_TapeVolume::SeekFileMark(), SeekLastBackupFM(), Space(), Spacefm(), STapeOpen(), STapeWriteFileMark(), la_SCSILibrary::Status(), Status(), TestUnitReady(), la_SCSILibrary::Unload(), Unload(), Wfm(), bea_MicMemory::Write(), bea_MamMemory::Write(), bea_TapeVolume::WriteFileMarks(), bea_TapeVolume::WriteRaw(), WriteScsi(), and WriteToMedium().

                                                             {
    log_FUNC_m(IOCtl);

    if (!IsOpen()) {
        throw ivd_Error(
            ie_INVALID_ARG, "Device is not open. " + m_deviceID);
    }

    UInt8_t cdbCode = a_cdb.GetCmdPointer()[0];
    log_DBG_m(dbg_NORM,
        "CDB: " << scsi_GetOpcodeText(cdbCode) <<
        " size: " << a_cdb.GetCmdSize());

    if (a_cdb.GetCmdSize() != scsi_CommandSize(cdbCode)) {
        log_MARKLINE_m;
        throw ivd_InternalError(
            ie_INVALID_ARG,
            string("Expected cdb size ") + cmn_Num2Str(scsi_CommandSize(cdbCode)) +
            string(" for CDB ") + scsi_GetOpcodeText(cdbCode));
     }

    // Init sense structure.
    m_sense.responseCode = 0, m_sense.isValid = 0,
    m_sense.senseKey = 0, m_sense.additionalLen = 0;

    UInt32_t timeout(a_timeout);
    if (m_timeoutOverride > 0) {
        timeout = m_timeoutOverride;
    }

    log_DBG_m(dbg_DETAIL, "Timeout = " << (timeout/1000/60) << " min.")

    if (dbg_IsActive()) {
        // HEX dump of a command.
        const UInt8_t *cdb = a_cdb.GetCmdPointer();
        UInt32_t size = a_cdb.GetCmdSize();
        string dump = cmn_HexDump((const void*)cdb, size, 8, true);
        log_DBG_m(dbg_DETAIL,
            endl << "**** CDB HEX DUMP: ****" << endl << dump);
    }

    int result = DoIOCtl(a_cdb, timeout);
    if (result != 0) {
        log_MARKLINE_m;
        throw ivd_SysError(result, scsi_GetOpcodeText(cdbCode), true);
    };

    // Do hex dump of data for non read/write operations.
    if (    cdbCode != op_READ_6
        &&  cdbCode != op_READ_10
        &&  cdbCode != op_WRITE_6
        &&  cdbCode != op_WRITE_10
        && dbg_IsActive()) {
        // HEX dump of data.
        UInt8_t *data = a_cdb.GetBufferPointer();
        UInt32_t size = a_cdb.GetBufferSize();

        log_DBG_m(dbg_NORM, "DATA length " << a_cdb.GetBufferSize());
        if (size > 0 && dbg_GetLevel() >= dbg_DETAIL) {
            string dump = cmn_HexDump(
                (const void*)data, (size < 256)? size : 256, 16, true);
            log_DBG_m(dbg_DETAIL,
                endl << "**** DATA HEX DUMP: ****" << endl << dump);
        }
    }

    // Checks and throws
    CheckDriverStatus(cdbCode);
    // Checks and throws
    CheckHostStatus(cdbCode);
    // Checks and throws
    CheckStatusAndSense(a_cdb);

#ifdef scsi_SIMULATE_ERRORS_d
    if (m_testHWErrProbability > 0) {
        if (   cdbCode == op_READ_6 || cdbCode == op_READ_10
            || cdbCode == op_WRITE_6 || cdbCode == op_WRITE_10) {

            if ( (rand() % scsi_testProbUnit) < m_testHWErrProbability ) {
                log_WriteEvent(
                    evt_WARNING, "Simulated HW error.", "SCSI", 0, m_strSCSIID);
                throw ivd_Error(ie_SCSI_HWERR, "Triggered HW error for testing.", true);
            }
        }
    }

    if (m_testMedErrProbability > 0) {
        if (   cdbCode == op_READ_6 || cdbCode == op_READ_10
            || cdbCode == op_WRITE_6 || cdbCode == op_WRITE_10) {

            if ( (rand() % scsi_testProbUnit) < m_testMedErrProbability ) {
                log_WriteEvent(
                    evt_WARNING, "Simulated medium error.", "SCSI", 0, m_strSCSIID);
                throw ivd_Error(ie_SCSI_MEDERR, "Triggered medium error for testing.", true);
            }
        }
    }
#endif

}

Here is the call graph for this function:

virtual bool scsi_IO::IsOpen (  )  [pure virtual]

Implemented in scsi_LnxSG, and scsi_WinSG.

Referenced by la_SCSILibrary::Close(), IOCtl(), and SetDeviceID().

Here is the caller graph for this function:

bool scsi_IO::IsPageSupported ( data_Inquiry::inq_Page_t  a_page  )  [inline, private]

Definition at line 219 of file scsi_io.h.

Referenced by InqSerialNumber().

                                                        {
        for (unsigned int i = 0; i < m_supportedPages.size(); i++) {
            if (m_supportedPages[i] == a_page) {
                return true;
            }
        }
        return false;
    }

Here is the caller graph for this function:

virtual bool scsi_IO::IsSenseValid (  )  [pure virtual]

Implemented in scsi_LnxSG, and scsi_WinSG.

Referenced by CheckStatusAndSense().

Here is the caller graph for this function:

void scsi_IO::Open (  ) 

Open SCSI device.

Calls one of the OpenBy.. functions..

Definition at line 238 of file scsi_io.cpp.

References dbg_LOW, idPrefix_c, ie_INVALID_ARG, ivd_Error, log_DBG_m, log_FUNC_m, m_channel, m_deviceID, m_deviceName, m_deviceType, m_id, m_lun, m_port, m_possibleMediumChange, m_productID, m_productRevision, m_productSerialNumber, m_standard, m_vendorID, OpenByDeviceName(), OpenBySCSIID(), OpenBySerialNumber(), scsi_GetDeviceTypeText(), and snPrefix_c.

Referenced by la_SCSILibrary::EjectMedium(), main(), la_SCSILibrary::Open(), ParseTapeMedium(), and STapeOpen().

                   {
    log_FUNC_m(Open);

    log_DBG_m(dbg_LOW, "Opening device ID: " << m_deviceID);

    m_possibleMediumChange = false;

    if (m_deviceID.substr(0, 3) == snPrefix_c) {
        //
        // Device should be open by its serial number.
        // Name is:
        // sn:VENDOR:PRODUCT:SERIAL_NUMBER
        //
        string::size_type start = snPrefix_c.length();
        string::size_type end = m_deviceID.find(":", start);
        if (end == string::npos) {
            goto lbl_error;
        }
        m_vendorID = m_deviceID.substr(start, end-start);

        start = end + 1;
        end = m_deviceID.find(":", start);
        if (end == string::npos) {
            goto lbl_error;
        }
        m_productID = m_deviceID.substr(start, end-start);

        start = end + 1;
        m_productSerialNumber = m_deviceID.substr(start);

        OpenBySerialNumber();
    }
    else if (m_deviceID.substr(0, 3) == idPrefix_c) {
        //
        // Device should be open by its SCSI ID.
        // Name is:
        // id:PORT:CHANNEL:ID:LUN
        //
        string::size_type start = idPrefix_c.length();
        string::size_type end = m_deviceID.find(":", start);
        if (end == string::npos) {
            goto lbl_error;
        }
        m_port = atoi(m_deviceID.substr(start, end-start).c_str());

        start = end + 1;
        end = m_deviceID.find(":", start);
        if (end == string::npos) {
            goto lbl_error;
        }
        m_channel = atoi(m_deviceID.substr(start, end-start).c_str());

        start = end + 1;
        end = m_deviceID.find(":", start);
        if (end == string::npos) {
            goto lbl_error;
        }
        m_id = atoi(m_deviceID.substr(start, end-start).c_str());

        start = end + 1;
        m_lun = atoi(m_deviceID.substr(start).c_str());

        OpenBySCSIID();
    }
    else {
        //
        // Device should be open by its name directly.
        //
        m_deviceName = m_deviceID;

        OpenByDeviceName();
    }

    log_DBG_m(dbg_LOW, endl <<
        "** Device parameters **" << endl <<
        "devName  : " << "\'" << m_deviceName << "\'" << endl << endl <<
        "port     : " << m_port << endl <<
        "channel  : " << m_channel << endl <<
        "id       : " << m_id << endl <<
        "lun      : " << m_lun << endl << endl <<
        "vendorID : " << "\'" << m_vendorID << "\'" << endl <<
        "prodID   : " << "\'" << m_productID << "\'" << endl <<
        "prodSN   : " << "\'" << m_productSerialNumber << "\'" << endl <<
        "prodRev  : " << "\'" << m_productRevision << "\'" << endl << endl <<
        "devType  : " << scsi_GetDeviceTypeText(m_deviceType) << endl <<
        "standard : " << (int)m_standard);

    return;

lbl_error:
    throw ivd_Error(
        ie_INVALID_ARG,
        "Invalid device name format: " + m_deviceID);
}

Here is the call graph for this function:

Here is the caller graph for this function:

virtual void scsi_IO::OpenByDeviceName (  )  [protected, pure virtual]

Open SCSI device by its (platform specific!) name.

Implemented in scsi_LnxSG, and scsi_WinSG.

Referenced by Open().

Here is the caller graph for this function:

virtual void scsi_IO::OpenBySCSIID (  )  [protected, pure virtual]

Open SCSI device by its (current) SCSI ID.

Warning:
Implementations must take care to close the device if an error occurs.

Implemented in scsi_LnxSG, and scsi_WinSG.

Referenced by Open().

Here is the caller graph for this function:

virtual void scsi_IO::OpenBySerialNumber (  )  [protected, pure virtual]

Open SCSI device by its unique identification.

Warning:
Implementations must take care to close the device if an error occurs.

Implemented in scsi_LnxSG, and scsi_WinSG.

Referenced by Open().

Here is the caller graph for this function:

void scsi_IO::SetDeviceID ( string  a_deviceID  ) 

Definition at line 148 of file scsi_io.cpp.

References ie_INVALID_ARG, IsOpen(), ivd_Error, log_FUNC_A_m, and m_deviceID.

Referenced by la_SCSILibrary::SetDeviceID().

                                           {
    log_FUNC_A_m(SetDeviceID, "device: " << a_deviceID);

    if (IsOpen()) {
        throw ivd_Error(
            ie_INVALID_ARG, "Trying to change device's ID while open.");
    }
    m_deviceID = a_deviceID;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void scsi_IO::SkipAttAndDeferred (  ) 

Definition at line 401 of file scsi_io.cpp.

References dbg_NORM, ivd_BaseException::GetError(), GetSense(), ie_SCSI_UNIT_ATT, ivd_USleep, log_DBG_m, log_FUNC_m, log_WRN_m, m_deviceID, m_deviceName, m_vendorID, NULL, data_Sense_t::responseCode, and TestUnitReady().

Referenced by main(), and WaitToBecomeReady().

                                 {
    log_FUNC_m(SkipAttAndDeferred);

    UInt32_t c_timeout = 60 * 20; // Timeout to finish TUR: 20 minutes
    ivd_Time_t timeStart = time(NULL);

    log_DBG_m(dbg_NORM, "Skipping ATTENTION and old senses...");

    while(1) {
        try {
            TestUnitReady();
            break;
        }
        catch (ivd_Error &ie) {
            ivd_Time_t now = time(NULL);

            if (now - timeStart > c_timeout) {
                log_WRN_m(
                    "Timeout doing TEST UNIT READY. " <<
                    "Device ID: " << m_deviceID << " " <<
                    "Device Name: " << m_deviceName << " " <<
                    "Vendor: " << m_vendorID);

                throw;
            }

            if (ie.GetError() == ie_SCSI_UNIT_ATT ||
                GetSense()->responseCode == sns_DEFERRED) {
                log_DBG_m(dbg_NORM,
                    "Skipping UNIT ATTENTION and DEFERRED senses.");

                ivd_USleep(1000 * 10); // 1/100 s
            }
            else {
                throw;
            }
        }
    }; // while
}

Here is the call graph for this function:

Here is the caller graph for this function:

void scsi_IO::TestUnitReady (  )  [protected]

Definition at line 441 of file scsi_io.cpp.

References IOCtl().

Referenced by SkipAttAndDeferred(), and WaitToBecomeReady().

                            {
    cdb_TestUnitReady tur;
    IOCtl(tur);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void scsi_IO::WaitToBecomeReady (  ) 

Definition at line 335 of file scsi_io.cpp.

References data_Sense_t::additionalLen, data_Sense_t::asc, data_Sense_t::ascq, cmn_HexDump(), dbg_NORM, ivd_BaseException::GetError(), ie_SCSI_HWERR, ie_SCSI_NOT_READY, ivd_Error, ivd_Sleep, log_DBG_m, log_FUNC_m, log_WRN_m, m_deviceID, m_deviceName, m_deviceType, m_productID, m_productRevision, m_productSerialNumber, m_sense, m_vendorID, m_vndSenseText, NULL, scsi_GetASCText(), scsi_GetSenseKeyText(), scsi_GetSenseText(), data_Sense_t::senseKey, SkipAttAndDeferred(), and TestUnitReady().

Referenced by la_SCSILibrary::EjectMedium(), bea_TapeVolume::GetPosition(), la_SCSILibrary::Inventory(), la_SCSILibrary::Load(), la_SCSILibrary::Open(), bea_TapeVolume::Rewind(), bea_TapeVolume::SeekBlock(), bea_TapeVolume::SeekEOD(), STapeOpen(), and la_SCSILibrary::Unload().

                                {
    log_FUNC_m(WaitToBecomeReady);

    UInt32_t c_timeout = 60 * 20; // Timeout to become ready: 20 minutes
    ivd_Time_t timeStart = time(NULL);

    log_DBG_m(dbg_NORM, "Waiting to become ready...");

    while(1) {
        try {
            SkipAttAndDeferred();
            TestUnitReady();
            break;
        }
        catch (ivd_Error &ie) {
            ivd_Time_t now = time(NULL);

            if (now - timeStart > c_timeout) {

                if (m_sense.asc  == 0x04 &&
                    m_sense.ascq == 0x00) {

                    string senseTxt = scsi_GetSenseText(m_sense, m_deviceType, m_vndSenseText);

                    ostringstream shortText;
                    shortText
                        << scsi_GetSenseKeyText((scsi_SenseKey_e)m_sense.senseKey)
                        << " (" << scsi_GetASCText(m_sense, m_vndSenseText) << ")";

                    // Detailed dump
                    ostringstream dump;
                    dump
                        << "Device: " << m_vendorID << " " << m_productID << " "
                        << m_productRevision << " s/n: " << m_productSerialNumber << endl
                        << senseTxt << endl
                        << "Sense dump (" << static_cast<UInt32_t>(m_sense.additionalLen+8) << " bytes) :" << endl
                        << cmn_HexDump(
                            reinterpret_cast<const void*>(&m_sense), m_sense.additionalLen+8, 8, true) << endl;

                    throw ivd_Error(ie_SCSI_HWERR, shortText.str(), dump.str());
                }

                log_WRN_m(
                    "Timeout waiting device to become ready. " <<
                    "Device ID: " << m_deviceID << " " <<
                    "Device Name: " << m_deviceName << " " <<
                    "Vendor: " << m_vendorID);

                throw;
            }

            if (   ie.GetError() == ie_SCSI_NOT_READY
                || ie.GetError() == ie_SCSI_RETRY) {

                log_DBG_m(dbg_NORM, "Device not ready yet. Retrying.");

                ivd_Sleep(2);
            }
            else {
                throw;
            }
        }
    }; // while

}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Reimplemented in scsi_LnxSG, and scsi_WinSG.

Definition at line 217 of file scsi_io.h.

string scsi_IO::m_deviceID [protected]

Unique device identification, passed in constructor or SetDeviceID.

Definition at line 172 of file scsi_io.h.

Referenced by scsi_LnxSG::Close(), IOCtl(), Open(), SetDeviceID(), SkipAttAndDeferred(), and WaitToBecomeReady().

string scsi_IO::m_deviceName [protected]

Device name.

It can be a file system entry or whatever name that uniquely identifies the SCSI device on a certain platform.

Definition at line 178 of file scsi_io.h.

Referenced by GetDeviceName(), Open(), scsi_LnxSG::OpenByDeviceName(), scsi_LnxSG::SGOpen(), SkipAttAndDeferred(), WaitToBecomeReady(), and scsi_LnxSG::~scsi_LnxSG().

Definition at line 196 of file scsi_io.h.

Referenced by CheckStatusAndSense(), GetDeviceType(), InqStandard(), Open(), and WaitToBecomeReady().

UInt32_t scsi_IO::m_id [protected]

Definition at line 183 of file scsi_io.h.

Referenced by GetID(), GetSCSIID(), scsi_LnxSG::InqSCSIID(), Open(), and scsi_LnxSG::OpenBySCSIID().

UInt32_t scsi_IO::m_lun [protected]

Definition at line 184 of file scsi_io.h.

Referenced by GetLUN(), GetSCSIID(), scsi_LnxSG::InqSCSIID(), Open(), and scsi_LnxSG::OpenBySCSIID().

bool scsi_IO::m_pdDirectMode [protected]

Direct passthrough mode can be disabled via env variable.

Definition at line 206 of file scsi_io.h.

Referenced by scsi_LnxSG::DoIOCtl(), and scsi_IO().

Also known as bus or host.

Definition at line 181 of file scsi_io.h.

Referenced by GetPort(), GetSCSIID(), scsi_LnxSG::InqSCSIID(), Open(), and scsi_LnxSG::OpenBySCSIID().

Definition at line 201 of file scsi_io.h.

Referenced by CheckStatusAndSense(), GetPossibleMediumChange(), and Open().

string scsi_IO::m_productID [protected]
string scsi_IO::m_productRevision [protected]
string scsi_IO::m_productSerialNumber [protected]

Definition at line 200 of file scsi_io.h.

Referenced by GetStandard(), InqStandard(), and Open().

string scsi_IO::m_strSCSIID [protected]

Definition at line 198 of file scsi_io.h.

Referenced by InqStandard().

Definition at line 213 of file scsi_io.h.

Referenced by IOCtl(), and scsi_IO().

Definition at line 214 of file scsi_io.h.

Referenced by IOCtl(), and scsi_IO().

Default timeouts can be overridden with env.

variable.

Definition at line 209 of file scsi_io.h.

Referenced by IOCtl(), and scsi_IO().

string scsi_IO::m_vendorID [protected]

Definition at line 192 of file scsi_io.h.

Referenced by CheckStatusAndSense(), InqStandard(), and WaitToBecomeReady().


The documentation for this class was generated from the following files: