Classes | Public Member Functions | Private Member Functions | Private Attributes

la_SCSILibrary Class Reference
[IVD Library Agent]

#include <la_scsi.h>

Collaboration diagram for la_SCSILibrary:
Collaboration graph
[legend]

List of all members.

Classes

class  DriveInfo

Public Member Functions

 la_SCSILibrary ()
 ~la_SCSILibrary ()
void SetDeviceID (string a_deviceID)
void Open ()
void Close ()
const string & GetVendorID () const
const string & GetProductID () const
const string & GetProductRevision () const
const string & GetSerialNumber () const
string GetSCSIID () const
void Inventory (bool a_force, vector< data_ElementStatus::ElemStatus_t > &a_elem)
 Does an inventory and read element status.
void Load (UInt16_t a_slot, UInt16_t a_drive, const string &a_barcode)
 Load a tape from a slot into a drive.
void Unload (UInt16_t a_drive, UInt16_t a_slot, const string &a_barcode)
 Unload a tape from a drive into a slot.
bool MustRequestEject ()
void SetDriveIDs (vector< DriveInfo > &a_driveIDs)
UInt16_t GetNumDrives ()
bool HasBarcodeReader ()

Private Member Functions

vector
< data_ElementStatus::ElemStatus_t
Status (UInt16_t a_from, UInt16_t a_count, data_ElementStatus::ElemType_t a_type)
 Returns the status of elements in the specified range and of specified type.
void ReadElementAssignment ()
void EjectMedium (UInt16_t a_drive, const string &a_barcode)
void HandleDriveError (const ivd_Error &a_ie, UInt32_t a_drv, const string &a_bc)
UInt16_t GetTransElemAddr (UInt16_t a_seqNum)
UInt16_t GetSlotElemAddr (UInt16_t a_seqNum)
UInt16_t GetImpExElemAddr (UInt16_t a_seqNum)
UInt16_t GetDriveElemAddr (UInt16_t a_seqNum)

Private Attributes

 log_CLASSID_m
cmn_Mutex m_library_x
cmn_Mutex m_drives_x
scsi_IOm_scsi
string m_deviceID
vector< DriveInfom_driveID
 Device IDs of the drives that are used at Unload operation with some specific libraries.
bool m_hasBarcodeReader
bool m_hasMICReader
bool m_mustRequestEject
UInt16_t m_transStartAddr
UInt16_t m_transNum
UInt16_t m_slotStartAddr
UInt16_t m_slotNum
UInt16_t m_impexStartAddr
UInt16_t m_impexNum
UInt16_t m_driveStartAddr
UInt16_t m_driveNum

Detailed Description

Definition at line 44 of file la_scsi.h.


Constructor & Destructor Documentation

la_SCSILibrary::la_SCSILibrary (  ) 

Definition at line 57 of file la_scsi.cpp.

References log_FUNC_m, and m_scsi.

    : m_scsi(NULL),
    // Defaults. Can change after open. Check with capabilities.
      m_hasBarcodeReader(true),
      m_hasMICReader(true),
      m_mustRequestEject(false) {

    log_FUNC_m(la_SCSILibrary);

#if TGT_OS_linux
    m_scsi = new scsi_LnxSG("");
#elif TGT_OS_windows
    m_scsi = new scsi_WinSG("");
#endif
}

la_SCSILibrary::~la_SCSILibrary (  ) 

Definition at line 73 of file la_scsi.cpp.

References Close(), log_FUNC_m, m_scsi, and NULL.

                                {
    log_FUNC_m(~la_SCSILibrary);

    if (m_scsi != NULL) {
        Close();
        delete m_scsi; m_scsi = NULL;
    }
}

Here is the call graph for this function:


Member Function Documentation

void la_SCSILibrary::Close (  ) 

Definition at line 173 of file la_scsi.cpp.

References scsi_IO::Close(), scsi_IO::IsOpen(), log_FUNC_m, and m_scsi.

Referenced by i_LibraryAgentSCSI_i::Reconfigure(), i_LibraryAgentSCSI_i::~i_LibraryAgentSCSI_i(), and ~la_SCSILibrary().

                           {
    log_FUNC_m(Close);
    if (m_scsi->IsOpen()) {
        m_scsi->Close();
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void la_SCSILibrary::EjectMedium ( UInt16_t  a_drive,
const string &  a_barcode 
) [private]

Definition at line 531 of file la_scsi.cpp.

References scsi_IO::Close(), cmn_Num2Str(), dbg_NORM, evt_ERROR, evt_WARNING, scsi_IO::GetDeviceType(), ivd_BaseException::GetError(), ivd_BaseException::GetFriendly(), HandleDriveError(), ie_BEA_INVDEVTYPE, ie_LA_OUTOFRANGE, ie_LA_UNCONFIGURED, scsi_IO::IOCtl(), ivd_Error, log_DBG_m, log_ERR_m, log_FUNC_m, log_WriteEvent(), log_WRN_m, m_driveID, m_drives_x, NULL, scsi_IO::Open(), scsi_GetDeviceTypeText(), and scsi_IO::WaitToBecomeReady().

Referenced by Unload().

                                                                          {
    log_FUNC_m(EjectMedium);

    log_DBG_m(dbg_NORM, "Ejecting medium from drive #" << a_drive);

    if (a_drive == 0 || ( a_drive > m_driveID.size()) ) {
        throw ivd_Error(
            ie_LA_OUTOFRANGE,
            cmn_Num2Str(a_drive) + " > " +
            cmn_Num2Str(m_driveID.size()) );
    };

    scsi_IO* drive_p(NULL);
    auto_ptr<scsi_IO> drive_ap(NULL);
    string driveDevID;
    {
        cmn_MutexLock l(m_drives_x);

        driveDevID = m_driveID[a_drive - 1].scsiID;
        if ( driveDevID.empty() ) {

            log_WRN_m("Medium eject attempted on non-configured drive index: " << a_drive);

            throw ivd_Error(
                ie_LA_UNCONFIGURED,
                string("Drive index ") + cmn_Num2Str(a_drive) );
        };

#if TGT_OS_linux
        drive_p = new scsi_LnxSG(driveDevID);
#elif TGT_OS_windows
        drive_p = new scsi_WinSG(driveDevID);
#endif

        // Auto pointer will de-allocate allocated object
        drive_ap.reset(drive_p);
    }

    try {
        drive_p->Open();

        if (drive_p->GetDeviceType() != dt_TAPE) {
            ostringstream sstr;
            sstr
                << "Expected a tape drive to eject medium, but found "
                << scsi_GetDeviceTypeText(drive_p->GetDeviceType())
                << ".";
            log_WriteEvent(evt_ERROR, sstr.str());

            throw ivd_Error(ie_BEA_INVDEVTYPE,
                string("a_scsiID: ") + driveDevID +
                string(" type: ") +
                scsi_GetDeviceTypeText(drive_p->GetDeviceType()));
        };

        drive_p->WaitToBecomeReady();

        cdb_LoadUnload unload(false);
        drive_p->IOCtl(unload);

        drive_p->Close();
    }
    catch (ivd_Error &ie) {
        if (ie.GetError() == ie_SCSI_NO_MEDIUM) {
            ostringstream sstr;
            sstr
                << "No medium in drive with index " << a_drive
                << ". Will try to move medium anyway.";
            log_WriteEvent(evt_WARNING, sstr.str());
        }
        else {
            log_WRN_m(
                "Caught ivd_Error when trying to eject the medium from " <<
                a_drive << " " << driveDevID << ". Error: " << endl <<
                ie);

            ostringstream sstr;
            sstr
                << "Eject medium on unload FAILED. Possible hardware problem. ("
                << ie.GetFriendly() << ").";

            log_WriteEvent(evt_ERROR, sstr.str());
            HandleDriveError(ie, a_drive, a_barcode);
            throw;
        }
    }
    catch (ivd_BaseException &ie) {
        log_ERR_m(
            "Caught ivd_Exception when trying to eject the medium from " <<
            a_drive << " " << driveDevID << ". Error: " << endl <<
            ie);

        ostringstream sstr;
        sstr
            << "Eject medium on unload FAILED. Possible hardware problem. ("
            << ie.GetFriendly() << ").";

        log_WriteEvent(evt_ERROR, sstr.str());

        throw;
    }
    catch (...) {
        log_ERR_m(
            "Caught unknown exception when trying to eject the medium from " <<
            a_drive << " " << driveDevID << ".");

        log_WriteEvent(evt_ERROR,
            "Eject medium on unload FAILED. Possible hardware problem.");

        throw;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

UInt16_t la_SCSILibrary::GetDriveElemAddr ( UInt16_t  a_seqNum  )  [private]

Definition at line 777 of file la_scsi.cpp.

References ie_INVALID_ARG, ivd_Error, log_FUNC_A_m, m_driveNum, and m_driveStartAddr.

Referenced by Load(), and Unload().

                                                           {
    if ((a_seqNum - 1) > m_driveNum) {
        log_FUNC_A_m(GetDriveElemAddr, "seqNum: " << a_seqNum);
        throw ivd_Error(ie_INVALID_ARG, "Sequence number out of range.", true);
    }
    return (m_driveStartAddr + (a_seqNum - 1));
}

Here is the caller graph for this function:

UInt16_t la_SCSILibrary::GetImpExElemAddr ( UInt16_t  a_seqNum  )  [private]

Definition at line 769 of file la_scsi.cpp.

References ie_INVALID_ARG, ivd_Error, log_FUNC_A_m, m_impexNum, and m_impexStartAddr.

                                                           {
    if ((a_seqNum - 1) > m_impexNum) {
        log_FUNC_A_m(GetImpExElemAddr, "seqNum: " << a_seqNum);
        throw ivd_Error(ie_INVALID_ARG, "Sequence number out of range.", true);
    }
    return (m_impexStartAddr + (a_seqNum - 1));
}

UInt16_t la_SCSILibrary::GetNumDrives (  ) 

Definition at line 194 of file la_scsi.cpp.

References m_driveNum.

Referenced by i_LibraryAgentSCSI_i::ReadDriveInfo().

                                      {
    return m_driveNum;
}

Here is the caller graph for this function:

const string& la_SCSILibrary::GetProductID (  )  const [inline]

Definition at line 65 of file la_scsi.h.

References scsi_IO::GetProductID(), and m_scsi.

Referenced by i_LibraryAgentSCSI_i::UpdateIDs().

{return m_scsi->GetProductID(); };

Here is the call graph for this function:

Here is the caller graph for this function:

const string& la_SCSILibrary::GetProductRevision (  )  const [inline]

Definition at line 66 of file la_scsi.h.

References scsi_IO::GetProductRevision(), and m_scsi.

Referenced by i_LibraryAgentSCSI_i::UpdateIDs().

{return m_scsi->GetProductRevision(); };

Here is the call graph for this function:

Here is the caller graph for this function:

string la_SCSILibrary::GetSCSIID (  )  const [inline]

Definition at line 68 of file la_scsi.h.

References scsi_IO::GetSCSIID(), and m_scsi.

Referenced by i_LibraryAgentSCSI_i::UpdateIDs().

{return m_scsi->GetSCSIID(); };

Here is the call graph for this function:

Here is the caller graph for this function:

const string& la_SCSILibrary::GetSerialNumber (  )  const [inline]

Definition at line 67 of file la_scsi.h.

References scsi_IO::GetProductSerialNumber(), and m_scsi.

Referenced by i_LibraryAgentSCSI_i::UpdateIDs().

Here is the call graph for this function:

Here is the caller graph for this function:

UInt16_t la_SCSILibrary::GetSlotElemAddr ( UInt16_t  a_seqNum  )  [private]

Definition at line 761 of file la_scsi.cpp.

References ie_INVALID_ARG, ivd_Error, log_FUNC_A_m, m_slotNum, and m_slotStartAddr.

Referenced by Load(), and Unload().

                                                           {
    if ((a_seqNum - 1) > m_slotNum) {
        log_FUNC_A_m(GetSlotElemAddr, "seqNum: " << a_seqNum);
        throw ivd_Error(ie_INVALID_ARG, "Sequence number out of range.", true);
    }
    return (m_slotStartAddr + (a_seqNum - 1));
}

Here is the caller graph for this function:

UInt16_t la_SCSILibrary::GetTransElemAddr ( UInt16_t  a_seqNum  )  [private]

Definition at line 753 of file la_scsi.cpp.

References ie_INVALID_ARG, ivd_Error, log_FUNC_A_m, m_transNum, and m_transStartAddr.

                                                           {
    if ((a_seqNum - 1) > m_transNum) {
        log_FUNC_A_m(GetTransElemAddr, "seqNum: " << a_seqNum);
        throw ivd_Error(ie_INVALID_ARG, "Sequence number out of range.", true);
    }
    return (m_transStartAddr + (a_seqNum - 1));
}

const string& la_SCSILibrary::GetVendorID (  )  const [inline]

Definition at line 64 of file la_scsi.h.

References scsi_IO::GetVendorID(), and m_scsi.

Referenced by i_LibraryAgentSCSI_i::UpdateIDs().

{return m_scsi->GetVendorID(); };

Here is the call graph for this function:

Here is the caller graph for this function:

void la_SCSILibrary::HandleDriveError ( const ivd_Error a_ie,
UInt32_t  a_drv,
const string &  a_bc 
) [private]

Definition at line 645 of file la_scsi.cpp.

References dbg_LOW, evt_ERROR, evt_WARNING, ivd_BaseException::GetError(), ivd_BaseException::GetFriendly(), ie_SCSI_HOST, ie_SCSI_HWERR, ie_SCSI_MEDERR, ie_SCSI_NOT_READY, ie_SCSI_PROTECTED, ipc_EXEC_m, log_DBG_m, log_FUNC_m, log_WriteEvent(), m_driveID, ipc_Corba::ResolveRM(), and rmdb_MEDIUM_UNUSABLE.

Referenced by EjectMedium().

                                                               {
    
    log_FUNC_m(HandleDriveError);

    try {
        i_ResourceManager_var rm;
        i_Drive_t_var drv;
        ipc_EXEC_m (
            CORBA::Object_var obj = ipc_Corba::ResolveRM();
            rm = i_ResourceManager::_narrow(obj);
            drv = rm->SelectDriveByKey(m_driveID[a_drv - 1].drvKey);
        );

        switch (a_ie.GetError()) {
            case ie_SCSI_HOST:
            case ie_SCSI_HWERR:
            case ie_SCSI_MEDERR:
            case ie_SCSI_NOT_READY:
                {
                    log_DBG_m (dbg_LOW, "Setting drive error for drive " << a_drv);
                    ipc_EXEC_m (
                        rm->DriveError(m_driveID[a_drv - 1].drvKey);
                    );
                    ostringstream sdrive;
                    sdrive
                        << "Drive " <<  string(drv->driveName)
                        << " marked bad.";
                    log_WriteEvent(evt_ERROR, sdrive.str());
                }
                // intentionally continuing to the next case
            case ie_SCSI_PROTECTED:
                if (a_ie.GetError() != ie_SCSI_HWERR) {
                    ipc_EXEC_m (
                        rm->MediumStatusSet(
                            CORBA::string_dup(a_bc.c_str()), rmdb_MEDIUM_UNUSABLE);
                    );
                    ostringstream smedium;
                    smedium << "Medium bc:" << a_bc << " marked as unusable.";
                    log_WriteEvent(evt_ERROR, smedium.str());
                }
                break;
            default:
                {
                    ostringstream sstr;
                    sstr
                        << "Ignoring error when unloading medium from drive: "
                        << a_ie.GetFriendly();
                    log_WriteEvent(evt_WARNING, sstr.str());
                }
                break;
        };
    }
    catch(const ivd_Exception& ie) {
        log_DBG_m(dbg_LOW, "Ignore exception when marking drive/medium: " << ie.GetFriendly());
    }
    catch (...) {
        log_DBG_m(dbg_LOW, "Ignore exception when marking drive/medium.");
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool la_SCSILibrary::HasBarcodeReader (  ) 

Definition at line 184 of file la_scsi.cpp.

References m_hasBarcodeReader.

Referenced by i_LibraryAgentSCSI_i::Inventory().

                                      {
    return this->m_hasBarcodeReader;
}

Here is the caller graph for this function:

void la_SCSILibrary::Inventory ( bool  a_force,
vector< data_ElementStatus::ElemStatus_t > &  a_elem 
)

Does an inventory and read element status.

Definition at line 203 of file la_scsi.cpp.

References dbg_DETAIL, dbg_LOW, dbg_NORM, data_ElementStatus::et_DRIVE, data_ElementStatus::et_IMPEX, data_ElementStatus::et_SLOT, evt_WARNING, scsi_IO::IOCtl(), log_DBG_m, log_FUNC_A_m, log_WriteEvent(), m_driveNum, m_driveStartAddr, m_impexNum, m_impexStartAddr, m_library_x, m_scsi, m_slotNum, m_slotStartAddr, ReadElementAssignment(), Status(), and scsi_IO::WaitToBecomeReady().

Referenced by i_LibraryAgentSCSI_i::Inventory().

                                                        {

    log_FUNC_A_m(Inventory, "force: " << (a_force? "Yes" : "No") );

    cmn_MutexLock l(m_library_x);

    if (a_force) {
        log_DBG_m(dbg_LOW,
            "Starting Init Element Status. " <<
            "May last some time.");

        cdb_InitElementStatus  init;
        m_scsi->IOCtl(init);

        log_DBG_m(dbg_LOW, "Init Element Status complete. ");
    };

    m_scsi->WaitToBecomeReady();

    // Was done on open. But just to be sure.
    ReadElementAssignment();

    // Execute Status of all elements
    vector<data_ElementStatus::ElemStatus_t> drives;
    vector<data_ElementStatus::ElemStatus_t> slots;
    vector<data_ElementStatus::ElemStatus_t> impex;

    if (m_driveNum > 0) {
        drives = Status(m_driveStartAddr, m_driveNum, data_ElementStatus::et_DRIVE);

        if (drives.size() != m_driveNum) {
            ostringstream sstr;
            sstr
                << "Status reported different number of drives than element assignment. "
                << drives.size() << " vs. " << m_driveNum;

            log_WriteEvent(evt_WARNING, sstr.str());
        }
    }
    else {
        log_DBG_m(dbg_NORM, "No drives reported by the library?");
        log_WriteEvent(evt_WARNING, "Library reported no drives.");
    };

    if (m_slotNum > 0) {
        slots  = Status(m_slotStartAddr,  m_slotNum,  data_ElementStatus::et_SLOT);
        if (slots.size() != m_slotNum) {
            ostringstream sstr;
            sstr
                << "Status reported different number of slots than element assignment. "
                << slots.size() << " vs. " << m_slotNum;

            log_WriteEvent(evt_WARNING, sstr.str());
        }
    }
    else {
        log_DBG_m(dbg_NORM, "No slots reported by the library?");
        log_WriteEvent(evt_WARNING, "Library reported no slots.");
    };

    if (m_impexNum > 0) {
        impex  = Status(m_impexStartAddr, m_impexNum, data_ElementStatus::et_IMPEX);
        if (impex.size() != m_impexNum) {
            ostringstream sstr;
            sstr
                << "Status reported different number of import/export slots than element assignment. "
                << impex.size() << " vs. " << m_impexNum;

            log_WriteEvent(evt_WARNING, sstr.str());
        }
    }
    else {
        log_DBG_m(dbg_NORM, "No import/export slots reported by the library.");
    };

    // Fill RMDB with new values

    for (UInt32_t i = 0; i < drives.size(); i++) {
        // NOTE: Correcting _physical_ address to IVD logical number
        drives[i].slot -= (m_driveStartAddr-1);
        a_elem.push_back(drives[i]);
    }
    for (UInt32_t i = 0; i < slots.size(); i++) {
        // NOTE: Correcting _physical_ address to IVD logical number
        slots[i].slot -= (m_slotStartAddr-1);
        a_elem.push_back(slots[i]);
    }
    for (UInt32_t i = 0; i < impex.size(); i++) {
        // NOTE: Correcting _physical_ address to IVD logical number
        impex[i].slot -= (m_impexStartAddr-1);
        a_elem.push_back(impex[i]);
    }
    log_DBG_m(dbg_DETAIL, "All elements added to elem vector.");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void la_SCSILibrary::Load ( UInt16_t  a_slot,
UInt16_t  a_drive,
const string &  a_barcode 
)

Load a tape from a slot into a drive.

IVD sequence numbers are used and are converted internally to low level (hardware) numbers.

Parameters:
a_barcode Expected barcode to be tested before loading the medium. Throws an exception if the barcode does not match.

Definition at line 310 of file la_scsi.cpp.

References cmn_Num2Str(), dbg_NORM, data_ElementStatus::et_SLOT, GetDriveElemAddr(), GetSlotElemAddr(), ie_INVALID_ARG, ie_LA_INVBARCODE, scsi_IO::IOCtl(), ivd_Error, log_DBG_m, log_FUNC_A_m, m_hasBarcodeReader, m_library_x, m_scsi, m_transStartAddr, cdb_MoveMedium::SetDestination(), cdb_MoveMedium::SetSource(), cdb_MoveMedium::SetTransport(), Status(), and scsi_IO::WaitToBecomeReady().

Referenced by i_LibraryAgentSCSI_i::Load().

                                                                                    {
    log_FUNC_A_m(Load,
        "slot: " << a_slot << " drv: " << a_drive << " bc: " << a_barcode);

    if (a_slot == 0) {
        throw ivd_Error(ie_INVALID_ARG, "Slot number is zero.");
    }
    else if (a_drive == 0) {
        throw ivd_Error(ie_INVALID_ARG, "Drive number is zero.");
    }

    cmn_MutexLock l(m_library_x);

    cdb_MoveMedium  mv;

    UInt16_t slotL = GetSlotElemAddr(a_slot);
    UInt16_t driveL = GetDriveElemAddr(a_drive);

    log_DBG_m(dbg_NORM,
        "Move from slot " << a_slot << " (" << slotL << ") "
        "to drive " << a_drive << " (" << driveL << ") " );

    // SCSI reset might have occured. Check if necessary to become ready.
    m_scsi->WaitToBecomeReady();

    // Check if the barcode in the slot matches expected
    vector<data_ElementStatus::ElemStatus_t> est =
        Status(slotL, 1, data_ElementStatus::et_SLOT);

    if (est.size() < 1) {
        log_MARKLINE_m;
        throw ivd_Error(ie_LA_INVBARCODE,
            string("Element status can't be read for slot # ") +
            cmn_Num2Str(a_slot) +
            string("Does the slot exist and contain a medium?") );
    }
    if (   m_hasBarcodeReader
        && est[0].full
        && string(est[0].barcode) != a_barcode) {

        log_MARKLINE_m;
        throw ivd_Error(ie_LA_INVBARCODE,
            string("Slot # ") + cmn_Num2Str(a_slot) +
            string(" bc: ") + string(est[0].barcode) +
            string(" expected: ") + a_barcode);
    }

    // Just take the first robotic arm for now (DDS changer uses 0)
    mv.SetTransport(m_transStartAddr);
    mv.SetSource(slotL);
    mv.SetDestination(driveL);

    log_DBG_m(dbg_NORM, "Moving medium.");
    m_scsi->IOCtl(mv);
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool la_SCSILibrary::MustRequestEject (  ) 

Definition at line 180 of file la_scsi.cpp.

References m_mustRequestEject.

Referenced by i_LibraryAgentSCSI_i::Reconfigure(), and i_LibraryAgentSCSI_i::Unload().

                                      {
    return this->m_mustRequestEject;
}

Here is the caller graph for this function:

void la_SCSILibrary::Open (  ) 

Definition at line 89 of file la_scsi.cpp.

References scsi_IO::Close(), dbg_LOW, dbg_NORM, cmn_Global::dirs, ivd_Directories::etc, evt_ERROR, cfg_LibraryFile::FindLibrary(), g_cmn, scsi_IO::GetDeviceType(), scsi_IO::GetProductID(), scsi_IO::GetVendorID(), ie_LA_INVDEVTYPE, ie_LA_OPEN, ie_LA_UNSUPPORTED, ivd_Error, log_DBG_m, log_ERR_m, log_FUNC_m, log_WriteEvent(), cfg_Library::m_bcReader, m_deviceID, m_driveNum, m_driveStartAddr, cfg_Library::m_eject, m_hasBarcodeReader, m_impexNum, m_impexStartAddr, m_mustRequestEject, m_scsi, m_slotNum, m_slotStartAddr, m_transNum, m_transStartAddr, NULL, scsi_IO::Open(), pf_File::Parse(), ReadElementAssignment(), scsi_GetDeviceTypeText(), and scsi_IO::WaitToBecomeReady().

Referenced by i_LibraryAgentSCSI_i::Reconfigure().

                          {
    log_FUNC_m(Open);

    m_scsi->Open();

    if (m_scsi->GetDeviceType() != dt_MEDIUM_CHANGER) {
        log_MARKLINE_m;
        m_scsi->Close();

        ostringstream sstr;
        sstr
            << "The device is not medium changer but "
            << scsi_GetDeviceTypeText(m_scsi->GetDeviceType()) << ". "
            << "Check the configuration.";

        log_WriteEvent(evt_ERROR, sstr.str(), "", 0, m_deviceID);

        throw ivd_Error(ie_LA_INVDEVTYPE,
            string("a_deviceID: ") + m_deviceID +
            string(" type: ") +
            scsi_GetDeviceTypeText(m_scsi->GetDeviceType()),
            true);
    }
    try {

        log_DBG_m(dbg_NORM, "Waiting the library to become ready.");
        m_scsi->WaitToBecomeReady();

        ReadElementAssignment();
        log_DBG_m(dbg_LOW, 
            "Element assignment: " << endl <<
            " trans : " << m_transStartAddr << " " << m_transNum << endl <<
            " slot  : " << m_slotStartAddr << " " << m_slotNum << endl <<
            " impex : " << m_impexStartAddr << " " << m_impexNum << endl <<
            " drive : " << m_driveStartAddr << " " << m_driveNum );
    }
    catch (ivd_Error &ie) {
        m_scsi->Close();
        log_ERR_m(
            "Can't read element assignent addresses. Device " <<
            m_deviceID << endl << " Error: " << ie);

        throw ivd_Error(
            ie_LA_OPEN, "Can't read element assignment addresses");
    }
    catch (ivd_SysError &ie) {
        m_scsi->Close();
        log_ERR_m(
            "Can't read element assignent addresses. Device " <<
            m_deviceID << endl << " Error: " << ie);

        throw ivd_Error(
            ie_LA_OPEN, "Can't read element assignment addresses");
    }

    {
        pf_File libraryCfg;
        libraryCfg.Parse(g_cmn.dirs.etc + "library.cfg");
        cfg_LibraryFile lf(libraryCfg);
        
        const cfg_Library* lib = lf.FindLibrary(
            m_scsi->GetVendorID(), m_scsi->GetProductID() );
            
        if (lib == NULL) {
            ostringstream sstr;
            sstr
                << "Device: " << m_deviceID << " "
                << "Vendor: \'" << m_scsi->GetVendorID() << "\' "
                << "Product: \'" << m_scsi->GetProductID() << "\' ";
                
            m_scsi->Close();
            throw ivd_Error(ie_LA_UNSUPPORTED, sstr.str());
        }
        
        m_mustRequestEject = lib->m_eject;
        m_hasBarcodeReader = lib->m_bcReader;
        
        log_DBG_m(dbg_LOW,
            endl <<
            "Barcode reader available: " << m_hasBarcodeReader << endl <<
            "Request eject on unload : " << m_mustRequestEject);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void la_SCSILibrary::ReadElementAssignment (  )  [private]

Definition at line 708 of file la_scsi.cpp.

References data_ModeElemAddr_t::addr, data_ModeElemAddr_t::blk, data_ModeHdr_t::blkDescLen, cmn_Num2Str(), data_ModeElemAddrPage_t::code, dbg_NORM, data_ModeElemAddrPage_t::deviceAddr, data_ModeElemAddrPage_t::deviceNumber, data_Mode_t::elem, data_Mode::GetModeStruct(), data_Mode_t::hdr, ie_DATA_CORRUPTION, data_ModeElemAddrPage_t::impexAddr, data_ModeElemAddrPage_t::impexNumber, scsi_IO::IOCtl(), log_DBG_m, log_FUNC_m, m_driveNum, m_driveStartAddr, m_impexNum, m_impexStartAddr, m_scsi, m_slotNum, m_slotStartAddr, m_transNum, m_transStartAddr, ntoh(), data_Mode::pg_ELEMADDR, data_ModeElemAddrPage_t::storageAddr, data_ModeElemAddrPage_t::storageNumber, data_ModeElemAddrPage_t::transpAddr, and data_ModeElemAddrPage_t::transpNumber.

Referenced by Inventory(), and Open().

                                           {
    log_FUNC_m(ReadElementAssignment);

    data_Mode ea(data_Mode::pg_ELEMADDR);
    cdb_ModeSense  modesns(ea);

    log_DBG_m(dbg_NORM, "Getting exchanger element assignment page.");
    m_scsi->IOCtl(modesns);

    const data_Mode_t               &eaData = ea.GetModeStruct();
    const data_ModeElemAddrPage_t   &eaPage =
        (eaData.hdr.blkDescLen == 0)
        ? (eaData.elem.addr)
        : (eaData.elem.blk.addr);

    if (eaPage.code != data_Mode::pg_ELEMADDR) {
        log_MARKLINE_m;
        throw ivd_InternalError(
            ie_DATA_CORRUPTION,
            string("MODE SELECT: Expected Page Element Address (0x1D), got ") +
            cmn_Num2Str(eaPage.code, true) );
    }

    scsi_Wrapper16 addrW(eaPage.transpAddr);
    scsi_Wrapper16 transW(eaPage.transpNumber);
    m_transStartAddr    = ntoh(addrW);
    m_transNum          = ntoh(transW);

    addrW = eaPage.storageAddr;
    transW = eaPage.storageNumber;
    m_slotStartAddr    = ntoh(addrW);
    m_slotNum          = ntoh(transW);

    addrW = eaPage.impexAddr;
    transW = eaPage.impexNumber;
    m_impexStartAddr    = ntoh(addrW);
    m_impexNum          = ntoh(transW);

    addrW = eaPage.deviceAddr;
    transW = eaPage.deviceNumber;
    m_driveStartAddr    = ntoh(addrW);
    m_driveNum          = ntoh(transW);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void la_SCSILibrary::SetDeviceID ( string  a_deviceID  ) 

Definition at line 82 of file la_scsi.cpp.

References log_FUNC_m, m_deviceID, m_scsi, and scsi_IO::SetDeviceID().

Referenced by i_LibraryAgentSCSI_i::Reconfigure().

                                                  {
    log_FUNC_m(SetDeviceID);

    m_deviceID = a_deviceID;
    m_scsi->SetDeviceID(a_deviceID);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void la_SCSILibrary::SetDriveIDs ( vector< DriveInfo > &  a_driveIDs  ) 

Referenced by i_LibraryAgentSCSI_i::Reconfigure(), and i_LibraryAgentSCSI_i::Unload().

Here is the caller graph for this function:

vector< data_ElementStatus::ElemStatus_t > la_SCSILibrary::Status ( UInt16_t  a_from,
UInt16_t  a_count,
data_ElementStatus::ElemType_t  a_type 
) [private]

Returns the status of elements in the specified range and of specified type.

Definition at line 452 of file la_scsi.cpp.

References dbg_LOW, ivd_BaseException::GetError(), data_ElementStatus::GetReportSize(), ie_SCSI_ILREQ, scsi_IO::IOCtl(), log_DBG_m, log_ERR_m, log_FUNC_A_m, m_deviceID, m_hasBarcodeReader, m_scsi, data_ElementStatus::ParseElemStatus(), scsi_TIMEOUT_LONG_d, cdb_ReadElementStatus::SetCurData(), cdb_ReadElementStatus::SetDeviceId(), cdb_ReadElementStatus::SetElementNum(), cdb_ReadElementStatus::SetStartAddr(), cdb_ReadElementStatus::SetType(), and cdb_ReadElementStatus::SetVolTag().

Referenced by Inventory(), Load(), and Unload().

                                         {

    log_FUNC_A_m(Status,
        "from: " << a_from << " count: " << a_count <<
        " type: " << (int)a_type );

    UInt32_t reportSize(
        a_count * sizeof(data_ESDescriptor_t) +
        sizeof(data_ESHdr_t) +
        sizeof(data_ESPageHdr_t) );
        
    data_ElementStatus      est(reportSize);
    cdb_ReadElementStatus   res(est);

    res.SetType(a_type);
    res.SetStartAddr(a_from);
    res.SetElementNum(a_count);

    // Most probably must these be set to false
    res.SetCurData(false);
    res.SetDeviceId(false);

    // try status with barcodes first
    bool barcodeStatus = m_hasBarcodeReader;

    while (1) {
        try {
            res.SetVolTag(barcodeStatus);
            m_scsi->IOCtl(res, scsi_TIMEOUT_LONG_d);
            break;
        }
        catch (ivd_Error &ie) {
            if (ie.GetError() == ie_SCSI_ILREQ && barcodeStatus) {
                log_DBG_m(dbg_LOW,
                    "Most probably barcodes not supported by the library. " <<
                    "Retrying without barcodes.");
                barcodeStatus = false;
            }
            else {
                log_ERR_m("Can't perform RES CDB on " << m_deviceID);
                throw;
            }
        }
    } // while

    vector<data_ElementStatus::ElemStatus_t> elemStatus;

    if (est.GetReportSize() > reportSize) {
        // reportSize is too small. Increase and retry.
        data_ElementStatus      est2(est.GetReportSize());
        cdb_ReadElementStatus   res(est2);

        res.SetType(a_type);
        res.SetStartAddr(a_from);
        res.SetElementNum(a_count);

        // Most probably must these be set to false
        res.SetCurData(false);
        res.SetDeviceId(false);

        res.SetVolTag(barcodeStatus);

        m_hasBarcodeReader = barcodeStatus;

        m_scsi->IOCtl(res, scsi_TIMEOUT_LONG_d);

        // OK. We have the status. Let's extract it out.
        est2.ParseElemStatus(elemStatus);
    }
    else {
        // OK. We have the status. Let's extract it out.
        est.ParseElemStatus(elemStatus);
    }
    return elemStatus;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void la_SCSILibrary::Unload ( UInt16_t  a_drive,
UInt16_t  a_slot,
const string &  a_barcode 
)

Unload a tape from a drive into a slot.

IVD sequence numbers are used and are converted internally to low level (hardware) numbers.

Parameters:
a_barcode Expected barcode to be tested before loading the medium. Throws an exception if the barcode does not match.

Definition at line 376 of file la_scsi.cpp.

References cmn_Num2Str(), dbg_NORM, EjectMedium(), data_ElementStatus::et_DRIVE, GetDriveElemAddr(), GetSlotElemAddr(), ie_INVALID_ARG, ie_LA_INVBARCODE, scsi_IO::IOCtl(), ivd_Error, log_DBG_m, log_FUNC_A_m, m_hasBarcodeReader, m_library_x, m_mustRequestEject, m_scsi, m_transStartAddr, cdb_MoveMedium::SetDestination(), cdb_MoveMedium::SetSource(), cdb_MoveMedium::SetTransport(), Status(), and scsi_IO::WaitToBecomeReady().

Referenced by i_LibraryAgentSCSI_i::Unload().

                                                                                      {
    log_FUNC_A_m(Unload,
        "drv: " << a_drive << " slot: " << a_slot << " bc: " << a_barcode);

    if (a_slot == 0) {
        throw ivd_Error(ie_INVALID_ARG, "Slot number is zero.");
    }
    else if (a_drive == 0) {
        throw ivd_Error(ie_INVALID_ARG, "Drive number is zero.");
    }

    UInt16_t slotL, driveL;

    {
        cmn_MutexLock l(m_library_x);

        slotL = GetSlotElemAddr(a_slot);
        driveL = GetDriveElemAddr(a_drive);

        log_DBG_m(dbg_NORM,
            "Move from drive " << a_drive << " (" << driveL << ") "
            "to slot " << a_slot << " (" << slotL << ") " );

        // SCSI reset might have occured. Check if necessary to become ready.
        m_scsi->WaitToBecomeReady();

        // Check if the barcode in the slot matches expected
        vector<data_ElementStatus::ElemStatus_t> est =
            Status(driveL, 1, data_ElementStatus::et_DRIVE);

        if (est.size() < 1) {
            log_MARKLINE_m;
            throw ivd_Error(ie_LA_INVBARCODE,
                string("Element status can't be read for drive # ") +
                cmn_Num2Str(a_drive) +
                string("Does the drive exist and contain a medium?") );
        }
        if (   m_hasBarcodeReader
            && est[0].full
            && string(est[0].barcode) != a_barcode) {

            log_MARKLINE_m;
            throw ivd_Error(ie_LA_INVBARCODE,
                string("Drive # ") + cmn_Num2Str(a_drive) +
                string(" bc: ") + string(est[0].barcode) +
                string(" expected: ") + a_barcode);
        }
    } // protected by mutex to here

    if (m_mustRequestEject) {
        EjectMedium(a_drive, a_barcode);
    }

    {
        cmn_MutexLock l(m_library_x);
        cdb_MoveMedium  mv;

        // Just take the first robotic arm for now (DDS changer uses 0)
        mv.SetTransport(m_transStartAddr);
        mv.SetSource(driveL);
        mv.SetDestination(slotL);

        log_DBG_m(dbg_NORM, "Moving medium.");

        m_scsi->IOCtl(mv);
    } // protected by mutex to here
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 85 of file la_scsi.h.

string la_SCSILibrary::m_deviceID [private]

Definition at line 91 of file la_scsi.h.

Referenced by Open(), SetDeviceID(), and Status().

Device IDs of the drives that are used at Unload operation with some specific libraries.

Definition at line 97 of file la_scsi.h.

Referenced by EjectMedium(), and HandleDriveError().

Definition at line 117 of file la_scsi.h.

Referenced by GetDriveElemAddr(), GetNumDrives(), Inventory(), Open(), and ReadElementAssignment().

Definition at line 88 of file la_scsi.h.

Referenced by EjectMedium().

Definition at line 116 of file la_scsi.h.

Referenced by GetDriveElemAddr(), Inventory(), Open(), and ReadElementAssignment().

Definition at line 101 of file la_scsi.h.

Referenced by HasBarcodeReader(), Load(), Open(), Status(), and Unload().

Definition at line 102 of file la_scsi.h.

Definition at line 114 of file la_scsi.h.

Referenced by GetImpExElemAddr(), Inventory(), Open(), and ReadElementAssignment().

Definition at line 113 of file la_scsi.h.

Referenced by GetImpExElemAddr(), Inventory(), Open(), and ReadElementAssignment().

Definition at line 87 of file la_scsi.h.

Referenced by Inventory(), Load(), and Unload().

Definition at line 103 of file la_scsi.h.

Referenced by MustRequestEject(), Open(), and Unload().

Definition at line 111 of file la_scsi.h.

Referenced by GetSlotElemAddr(), Inventory(), Open(), and ReadElementAssignment().

Definition at line 110 of file la_scsi.h.

Referenced by GetSlotElemAddr(), Inventory(), Open(), and ReadElementAssignment().

Definition at line 108 of file la_scsi.h.

Referenced by GetTransElemAddr(), Open(), and ReadElementAssignment().

Definition at line 107 of file la_scsi.h.

Referenced by GetTransElemAddr(), Load(), Open(), ReadElementAssignment(), and Unload().


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