diff --git a/tapeserver/castor/tape/tapeserver/SCSI/Constants.hpp b/tapeserver/castor/tape/tapeserver/SCSI/Constants.hpp index 97d71f8e4ce0116494b54d349b7bf430e96fd129..a5b63f94a01a4536d502fec0466dad919c336201 100644 --- a/tapeserver/castor/tape/tapeserver/SCSI/Constants.hpp +++ b/tapeserver/castor/tape/tapeserver/SCSI/Constants.hpp @@ -238,9 +238,18 @@ namespace SCSI { class logSensePages { public: enum { + writeErrors = 0x02, + readErrors = 0x03, + nonMediumErrors = 0x06, sequentialAccessDevicePage = 0x0C, + volumeStatistics = 0x17, // IBM specific page tapeAlert = 0x2e, dataCompression32h = 0x32, // for LTO, SDLT. We have Data Compression 1Bh for LTO5,6 and DataComppression 0Fh in SSC-3 + driveWriteErrors = 0x32, // IBM specific page + driveReadForwardErrors = 0x34, // IBM specific page + driveReadBackwardErrors = 0x36, // IBM specific page + performanceCharacteristics = 0x37, // IBM specific page + vendorUniqueDriveStatistics= 0x3d, // Oracle T1000D/E specific page blockBytesTransferred = 0x38 // parameters in this page are reset when a cartridge is loaded }; }; @@ -272,7 +281,109 @@ namespace SCSI { unitSerialNumber = 0x80 }; }; - + + class writeErrorsDevicePage { + public: + enum { + totalCorrectedErrors = 0x0003, + totalProcessed = 0x0005, + totalUncorrectedErrors = 0x0006 + }; + }; + + class readErrorsDevicePage { + public: + enum { + totalCorrectedErrors = 0x0003, + totalProcessed = 0x0005, + totalUncorrectedErrors = 0x0006 + }; + }; + + class nonMediumErrorsDevicePage { + public: + enum { + totalCount = 0x0000 + }; + }; + + class volumeStatisticsPage { // IBM 3592 specific + public: + enum { + validityFlag = 0x0000, + volumeMounts = 0x0001, + volumeRecoveredWriteDataErrors = 0x0003, + volumeUnrecoveredWriteDataErrors = 0x0004, + volumeRecoveredReadErrors = 0x0008, + volumeUnrecoveredReadErrors = 0x0009, + volumeManufacturingDate = 0x0046, + BOTPasses = 0x0101, + MOTPasses = 0x0102 + }; + }; + + class performanceCharacteristicsQualitySummaryPage { // IBM 3592 specific + public: + enum { + driveEfficiency = 0x0000, + mediaEfficiency = 0x0001, + primaryInterfaceEfficiency0 = 0x0011, + primaryInterfaceEfficiency1 = 0x0012, + libraryInterfaceEfficiency = 0x001a + }; + }; + + class performanceCharacteristicsHostCommandsPage { // IBM 3592 specific + public: + enum { + readPerformanceEfficiency = 0x03d0, + writePerformanceEfficiency = 0x04d0 + }; + }; + + class driveWriteErrorsPage { // IBM 3592 specific + public: + enum { + servoTransients = 0x0001, + dataTransients = 0x0002, + servoTemps = 0x0006, + dataTemps = 0x0007, + totalRetries = 0x0008 + }; + }; + + class driveReadErrorsPage { // IBM 3592 specific (both FW and BW) + public: + enum { + servoTransients = 0x0001, + dataTransients = 0x0002, + servoTemps = 0x0006, + dataTemps = 0x0007, + totalRetries = 0x0015 + }; + }; + + class vendorUniqueDriveStatistics { // Oracle T10K specific + public: + enum { + // Drive stats + readRecoveryRetries = 0x0104, + readTransientConditions = 0x0105, + writeTransientConditions = 0x0106, + servoTepomporaries = 0x0107, + servoTransientConditions = 0x0108, + writeRecoveryRetries = 0x0112, + temporaryDriveErrors = 0x0203, + permanentDriveErrors = 0x0204, + + // Quality stats + tapeEfficiency = 0x0400, + readQualityIndex = 0x0401, + readBackCheckQualityIndex = 0x0402, + writeEfficiency = 0x0407 + }; + }; + /** * Sun StorageTekTM T10000 Tape Drive Fibre Channel Interface Reference Manual */ diff --git a/tapeserver/castor/tape/tapeserver/SCSI/DeviceTest.cpp b/tapeserver/castor/tape/tapeserver/SCSI/DeviceTest.cpp index 0d89e4d91bb915d1b9c4b4f040bdbc62971022e8..25b5ed38cdbf574368ffdf49b36db14b02c3b8a9 100644 --- a/tapeserver/castor/tape/tapeserver/SCSI/DeviceTest.cpp +++ b/tapeserver/castor/tape/tapeserver/SCSI/DeviceTest.cpp @@ -51,57 +51,97 @@ TEST(castor_tape_SCSI_DeviceList, ScansCorrectly) { sysWrapper.delegateToFake(); /* Populate the test harness */ sysWrapper.fake.setupSLC5(); + // TODO: Test against SLC6 setup /* We expect the following calls: */ EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(19); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(38); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(19); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(38); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); + /* Everything should have been found correctly */ castor::tape::SCSI::DeviceVector dl(sysWrapper); - ASSERT_EQ(3U, dl.size()); + ASSERT_EQ(6U, dl.size()); ASSERT_EQ(castor::tape::SCSI::Types::mediumChanger, dl[0].type); ASSERT_EQ(castor::tape::SCSI::Types::tape, dl[1].type); ASSERT_EQ(castor::tape::SCSI::Types::tape, dl[2].type); + ASSERT_EQ(castor::tape::SCSI::Types::mediumChanger, dl[3].type); + ASSERT_EQ(castor::tape::SCSI::Types::tape, dl[4].type); + ASSERT_EQ(castor::tape::SCSI::Types::tape, dl[5].type); + ASSERT_EQ( "/dev/sg2", dl[0].sg_dev); ASSERT_EQ( "/dev/sg0", dl[1].sg_dev); ASSERT_EQ( "/dev/sg1", dl[2].sg_dev); + ASSERT_EQ( "/dev/sg5", dl[3].sg_dev); + ASSERT_EQ( "/dev/sg3", dl[4].sg_dev); + ASSERT_EQ( "/dev/sg4", dl[5].sg_dev); + ASSERT_EQ( "", dl[0].st_dev); ASSERT_EQ( "/dev/st0", dl[1].st_dev); ASSERT_EQ( "/dev/st1", dl[2].st_dev); + ASSERT_EQ( "", dl[3].st_dev); + ASSERT_EQ( "/dev/st2", dl[4].st_dev); + ASSERT_EQ( "/dev/st3", dl[5].st_dev); + ASSERT_EQ( "", dl[0].nst_dev); ASSERT_EQ("/dev/nst0", dl[1].nst_dev); ASSERT_EQ("/dev/nst1", dl[2].nst_dev); + ASSERT_EQ( "", dl[3].nst_dev); + ASSERT_EQ("/dev/nst2", dl[4].nst_dev); + ASSERT_EQ("/dev/nst3", dl[5].nst_dev); + ASSERT_EQ("/sys/devices/pseudo_0/adapter0/host3/target3:0:0/3:0:0:0", dl[0].sysfs_entry); ASSERT_EQ("/sys/devices/pseudo_0/adapter0/host3/target3:0:1/3:0:1:0", dl[1].sysfs_entry); ASSERT_EQ("/sys/devices/pseudo_0/adapter0/host3/target3:0:2/3:0:2:0", dl[2].sysfs_entry); + ASSERT_EQ("/sys/devices/pseudo_0/adapter0/host2/target2:0:0/2:0:0:0", dl[3].sysfs_entry); + ASSERT_EQ("/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0", dl[4].sysfs_entry); + ASSERT_EQ("/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0", dl[5].sysfs_entry); + ASSERT_EQ( 21U, dl[0].sg.major); ASSERT_EQ( 2U, dl[0].sg.minor); ASSERT_EQ( 21U, dl[1].sg.major); ASSERT_EQ( 0U, dl[1].sg.minor); ASSERT_EQ( 21U, dl[2].sg.major); ASSERT_EQ( 1U, dl[2].sg.minor); + ASSERT_EQ( 21U, dl[3].sg.major); + ASSERT_EQ( 5U, dl[3].sg.minor); + ASSERT_EQ( 21U, dl[4].sg.major); + ASSERT_EQ( 3U, dl[4].sg.minor); + ASSERT_EQ( 21U, dl[5].sg.major); + ASSERT_EQ( 4U, dl[5].sg.minor); ASSERT_EQ( 0U, dl[0].st.major); ASSERT_EQ( 0U, dl[0].st.minor); ASSERT_EQ( 9U, dl[1].st.major); ASSERT_EQ( 0U, dl[1].st.minor); ASSERT_EQ( 9U, dl[2].st.major); ASSERT_EQ( 1U, dl[2].st.minor); + ASSERT_EQ( 0U, dl[3].st.major); + ASSERT_EQ( 0U, dl[3].st.minor); + ASSERT_EQ( 9U, dl[4].st.major); + ASSERT_EQ( 2U, dl[4].st.minor); + ASSERT_EQ( 9U, dl[5].st.major); + ASSERT_EQ( 3U, dl[5].st.minor); ASSERT_EQ( 0U, dl[0].nst.major); ASSERT_EQ( 0U, dl[0].nst.minor); ASSERT_EQ( 9U, dl[1].nst.major); ASSERT_EQ(128U, dl[1].nst.minor); ASSERT_EQ( 9U, dl[2].nst.major); ASSERT_EQ(129U, dl[2].nst.minor); + ASSERT_EQ( 0U, dl[3].nst.major); + ASSERT_EQ( 0U, dl[3].nst.minor); + ASSERT_EQ( 9U, dl[4].nst.major); + ASSERT_EQ(130U, dl[4].nst.minor); + ASSERT_EQ( 9U, dl[5].nst.major); + ASSERT_EQ(131U, dl[5].nst.minor); ASSERT_EQ("STK", dl[0].vendor); ASSERT_EQ("STK", dl[1].vendor); ASSERT_EQ("STK", dl[2].vendor); @@ -111,6 +151,15 @@ TEST(castor_tape_SCSI_DeviceList, ScansCorrectly) { ASSERT_EQ("0104", dl[0].productRevisionLevel); ASSERT_EQ("0104", dl[1].productRevisionLevel); ASSERT_EQ("0104", dl[2].productRevisionLevel); + ASSERT_EQ("IBM", dl[3].vendor); + ASSERT_EQ("IBM", dl[4].vendor); + ASSERT_EQ("IBM", dl[5].vendor); + ASSERT_EQ("03584L22", dl[3].product); + ASSERT_EQ("03592E08", dl[4].product); + ASSERT_EQ("03592E08", dl[5].product); + ASSERT_EQ("F030", dl[3].productRevisionLevel); + ASSERT_EQ("460E", dl[4].productRevisionLevel); + ASSERT_EQ("460E", dl[5].productRevisionLevel); } TEST(castor_tape_SCSI_DeviceList, FindBySymlink) { diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp index be04595b6764c8bb7bdd1614b19d91d459bfc274..b1e2a124e81a87f21b9bfca3e1838545f410c815 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp @@ -453,6 +453,18 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayRecall) { ASSERT_EQ(0, statRc); ASSERT_EQ(1000, statBuf.st_size); //same size of data } + + // 10) Check logs + std::string logToCheck = logger.getLog(); + logToCheck += ""; + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" " + "mountTotalCorrectedReadErrors=\"5\" mountTotalReadBytesProcessed=\"4096\" " + "mountTotalUncorrectedReadErrors=\"1\" mountTotalNonMediumErrorCounts=\"2\"")); + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" lifetimeMediumEfficiencyPrct=\"100\" " + "mountReadEfficiencyPrct=\"100\" mountWriteEfficiencyPrct=\"100\" " + "mountReadTransients=\"10\" " + "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " + "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); } TEST_P(DataTransferSessionTest, DataTransferSessionWrongRecall) { @@ -621,6 +633,18 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongRecall) { // 10) Check the remote files exist and have the correct size std::string temp = logger.getLog(); ASSERT_NE(std::string::npos, logger.getLog().find("trying to position beyond the end of data")); + + // 11) Check logs for drive statistics + std::string logToCheck = logger.getLog(); + logToCheck += ""; + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" " + "mountTotalCorrectedReadErrors=\"5\" mountTotalReadBytesProcessed=\"4096\" " + "mountTotalUncorrectedReadErrors=\"1\" mountTotalNonMediumErrorCounts=\"2\"")); + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" lifetimeMediumEfficiencyPrct=\"100\" " + "mountReadEfficiencyPrct=\"100\" mountWriteEfficiencyPrct=\"100\" " + "mountReadTransients=\"10\" " + "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " + "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); } TEST_P(DataTransferSessionTest, DataTransferSessionNoSuchDrive) { @@ -894,6 +918,18 @@ TEST_P(DataTransferSessionTest, DataTransferSessionFailtoMount) { ASSERT_NO_THROW(sess.execute()); std::string temp = logger.getLog(); ASSERT_NE(std::string::npos, logger.getLog().find("Failed to mount the tape")); + + // 10) Check logs for drive statistics + std::string logToCheck = logger.getLog(); + logToCheck += ""; + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" " + "mountTotalCorrectedReadErrors=\"5\" mountTotalReadBytesProcessed=\"4096\" " + "mountTotalUncorrectedReadErrors=\"1\" mountTotalNonMediumErrorCounts=\"2\"")); + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" lifetimeMediumEfficiencyPrct=\"100\" " + "mountReadEfficiencyPrct=\"100\" mountWriteEfficiencyPrct=\"100\" " + "mountReadTransients=\"10\" " + "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " + "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); } TEST_P(DataTransferSessionTest, DataTransferSessionEmptyOnVolReq) { @@ -1058,6 +1094,17 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayMigration) { ASSERT_EQ(sf->adler32(), afs.checksumValue); ASSERT_EQ(1000, afs.fileSize); } + + // Check logs for drive statistics + ASSERT_NE(std::string::npos, temp.find("firmwareVersion=\"123A\" " + "mountTotalCorrectedWriteErrors=\"5\" mountTotalUncorrectedWriteErrors=\"1\" " + "mountTotalWriteBytesProcessed=\"4096\" mountTotalNonMediumErrorCounts=\"2\"")); + + ASSERT_NE(std::string::npos, temp.find("firmwareVersion=\"123A\" lifetimeMediumEfficiencyPrct=\"100\" " + "mountReadEfficiencyPrct=\"100\" mountWriteEfficiencyPrct=\"100\" " + "mountReadTransients=\"10\" " + "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " + "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); } // @@ -1172,6 +1219,18 @@ TEST_P(DataTransferSessionTest, DataTransferSessionMissingFilesMigration) { ASSERT_EQ(s_vid, sess.getVid()); // We should no have logged a single successful file read. ASSERT_EQ(std::string::npos, logger.getLog().find("MSG=\"File successfully read from disk\"")); + // Check logs for drive statistics + std::string logToCheck = logger.getLog(); + logToCheck += ""; + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" " + "mountTotalCorrectedWriteErrors=\"5\" mountTotalUncorrectedWriteErrors=\"1\" " + "mountTotalWriteBytesProcessed=\"4096\" mountTotalNonMediumErrorCounts=\"2\"")); + + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" lifetimeMediumEfficiencyPrct=\"100\" " + "mountReadEfficiencyPrct=\"100\" mountWriteEfficiencyPrct=\"100\" " + "mountReadTransients=\"10\" " + "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " + "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); } // @@ -1303,6 +1362,18 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullMigration) { ASSERT_EQ(s_vid, tapes.front().vid); ASSERT_EQ(true, tapes.front().full); } + // Check logs for drive statistics + std::string logToCheck = logger.getLog(); + logToCheck += ""; + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" " + "mountTotalCorrectedWriteErrors=\"5\" mountTotalUncorrectedWriteErrors=\"1\" " + "mountTotalWriteBytesProcessed=\"4096\" mountTotalNonMediumErrorCounts=\"2\"")); + + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" lifetimeMediumEfficiencyPrct=\"100\" " + "mountReadEfficiencyPrct=\"100\" mountWriteEfficiencyPrct=\"100\" " + "mountReadTransients=\"10\" " + "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " + "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); } TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullOnFlushMigration) { @@ -1430,6 +1501,17 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullOnFlushMigration) { ASSERT_EQ(s_vid, tapes.front().vid); ASSERT_EQ(true, tapes.front().full); } + // Check logs for drive statistics + std::string logToCheck = logger.getLog(); + logToCheck += ""; + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" " + "mountTotalCorrectedWriteErrors=\"5\" mountTotalUncorrectedWriteErrors=\"1\" " + "mountTotalWriteBytesProcessed=\"4096\" mountTotalNonMediumErrorCounts=\"2\"")); + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" lifetimeMediumEfficiencyPrct=\"100\" " + "mountReadEfficiencyPrct=\"100\" mountWriteEfficiencyPrct=\"100\" " + "mountReadTransients=\"10\" " + "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " + "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); } #undef TEST_MOCK_DB diff --git a/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjectorTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjectorTest.cpp index 7626de821b67016efe867e4de59452371eee75bc..0291381fe9cd647ac5735b04442fb29e5f1da986 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjectorTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjectorTest.cpp @@ -128,6 +128,8 @@ namespace unitTests } virtual void countTapeLogError(const std::string & error) {}; + protected: + virtual void logSCSIMetrics() {}; }; class TestingDatabaseRetrieveMount: public cta::SchedulerDatabase::RetrieveMount { diff --git a/tapeserver/castor/tape/tapeserver/daemon/TapeReadSingleThread.cpp b/tapeserver/castor/tape/tapeserver/daemon/TapeReadSingleThread.cpp index abe1924951cb2860818cb0c8e5bd737248f01426..5f0f0c065743419374f29499703de75160cf5c3f 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/TapeReadSingleThread.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/TapeReadSingleThread.cpp @@ -57,6 +57,10 @@ castor::tape::tapeserver::daemon::TapeReadSingleThread::TapeCleaning::~TapeClean m_this.m_stats.waitReportingTime += m_timer.secs(cta::utils::Timer::resetCounter); // Log (safely, exception-wise) the tape alerts (if any) at the end of the session try { m_this.logTapeAlerts(); } catch (...) {} + // Log safely SCSI Metrits + try { m_this.logSCSIMetrics(); } catch (...) {} + + // Log safely errors at the end of the session // This out-of-try-catch variables allows us to record the stage of the // process we're in, and to count the error if it occurs. // We will not record errors for an empty string. This will allow us to @@ -279,6 +283,7 @@ void castor::tape::tapeserver::daemon::TapeReadSingleThread::run() { } } } + // The session completed successfully, and the cleaner (unmount) executed // at the end of the previous block. Log the results. cta::log::ScopedParamContainer params(m_logContext); @@ -345,3 +350,59 @@ void castor::tape::tapeserver::daemon::TapeReadSingleThread::logWithStat( /1000/1000/m_stats.totalTime:0.0); m_logContext.log(level,msg); } + +//------------------------------------------------------------------------------ +//logSCSIMetrics +//------------------------------------------------------------------------------ +void castor::tape::tapeserver::daemon::TapeReadSingleThread::logSCSIMetrics() { + try { + // mount general statistics + cta::log::ScopedParamContainer scopedContainer(m_logContext); + appendDriveAndTapeInfoToScopedParams(scopedContainer); + // get mount general stats + std::map<std::string, uint32_t> scsi_read_metrics_hash = m_drive.getTapeReadErrors(); + appendMetricsToScopedParams(scopedContainer, scsi_read_metrics_hash); + std::map<std::string, uint32_t> scsi_nonmedium_metrics_hash = m_drive.getTapeNonMediumErrors(); + appendMetricsToScopedParams(scopedContainer, scsi_nonmedium_metrics_hash); + logSCSIStats("Logging mount general statistics", + scsi_read_metrics_hash.size() + scsi_nonmedium_metrics_hash.size()); + } + catch (const cta::exception::Exception &ex) { + cta::log::ScopedParamContainer scoped(m_logContext); + scoped.add("exception_message", ex.getMessageValue()); + m_logContext.log(cta::log::ERR, "Exception in logging mount general statistics"); + } + + // drive statistic + try { + cta::log::ScopedParamContainer scopedContainer(m_logContext); + appendDriveAndTapeInfoToScopedParams(scopedContainer); + // get drive stats + std::map<std::string,float> scsi_quality_metrics_hash = m_drive.getQualityStats(); + appendMetricsToScopedParams(scopedContainer, scsi_quality_metrics_hash); + std::map<std::string,uint32_t> scsi_drive_metrics_hash = m_drive.getDriveStats(); + appendMetricsToScopedParams(scopedContainer, scsi_drive_metrics_hash); + logSCSIStats("Logging drive statistics", + scsi_quality_metrics_hash.size()+scsi_drive_metrics_hash.size()); + } + catch (const cta::exception::Exception &ex) { + cta::log::ScopedParamContainer scoped(m_logContext); + scoped.add("exception_message", ex.getMessageValue()); + m_logContext.log(cta::log::ERR, "Exception in logging drive statistics"); + } + + // volume statistics + try { + cta::log::ScopedParamContainer scopedContainer(m_logContext); + appendDriveAndTapeInfoToScopedParams(scopedContainer); + std::map<std::string,uint32_t> scsi_metrics_hash = m_drive.getVolumeStats(); + appendMetricsToScopedParams(scopedContainer, scsi_metrics_hash); + logSCSIStats("Logging volume statistics", scsi_metrics_hash.size()); + } + catch (const cta::exception::Exception &ex) { + cta::log::ScopedParamContainer scoped(m_logContext); + scoped.add("exception_message", ex.getMessageValue()); + m_logContext.log(cta::log::ERR, "Exception in logging volume statistics"); + } +} + diff --git a/tapeserver/castor/tape/tapeserver/daemon/TapeReadSingleThread.hpp b/tapeserver/castor/tape/tapeserver/daemon/TapeReadSingleThread.hpp index f1a64c25fa531c0b9382c0847a5d995b11b8bf51..cd94fdb07ac9041afdd52e930e0637ea5ef28e8b 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/TapeReadSingleThread.hpp +++ b/tapeserver/castor/tape/tapeserver/daemon/TapeReadSingleThread.hpp @@ -150,6 +150,11 @@ private: m_watchdog.addToErrorCount(error); } +protected: + /** + * Logs SCSI metrics for read session. + */ + virtual void logSCSIMetrics(); }; // class TapeReadSingleThread } // namespace daemon diff --git a/tapeserver/castor/tape/tapeserver/daemon/TapeSingleThreadInterface.hpp b/tapeserver/castor/tape/tapeserver/daemon/TapeSingleThreadInterface.hpp index ec1bcee2c691600eb5c58a5f2f55ca7ff42abac7..5173291a50abe92bd788375fdf5a6ffab0c3757e 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/TapeSingleThreadInterface.hpp +++ b/tapeserver/castor/tape/tapeserver/daemon/TapeSingleThreadInterface.hpp @@ -203,7 +203,43 @@ protected: } return true; } - + + /** + * Log SCSI metrics for session. + */ + virtual void logSCSIMetrics() = 0; + + /** + * Function iterating through the map of available SCSI metrics and logging them. + */ + void logSCSIStats(const std::string & logTitle, size_t metricsHashLength) { + if(metricsHashLength == 0) { // skip logging entirely if hash is empty. + m_logContext.log(cta::log::INFO, "SCSI Statistics could not be acquired from drive"); + return; + } + m_logContext.log(cta::log::INFO, logTitle); + } + + /** + * Function appending Tape VID, drive manufacturer and model and firmware version to the Scoped Container passed. + */ + void appendDriveAndTapeInfoToScopedParams(cta::log::ScopedParamContainer &scopedContainer) { + drive::deviceInfo di = m_drive.getDeviceInfo(); + scopedContainer.add("driveManufacturer", di.vendor); + scopedContainer.add("driveType", di.product); + scopedContainer.add("firmwareVersion", m_drive.getDriveFirmwareVersion()); + } + + /** + * Function appending SCSI Metrics to the Scoped Container passed. + */ + template<class N> + static void appendMetricsToScopedParams( cta::log::ScopedParamContainer &scopedContainer, const std::map<std::string,N> & metricsHash) { + for(auto it = metricsHash.cbegin(); it != metricsHash.end(); it++) { + scopedContainer.add(it->first, it->second); + } + } + /** * Helper virtual function allowing the access to the m_watchdog member * in the inherited classes (TapeReadSingleThread and TapeWriteSingleThread) diff --git a/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.cpp b/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.cpp index 331ec0f7dd9777a370b0830d0f960488218a6b00..94f3e00cf2011599c878ce3b6b826edae12e0077 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.cpp @@ -266,6 +266,7 @@ void castor::tape::tapeserver::daemon::TapeWriteSingleThread::run() { } } //end of while(1)) } + // The session completed successfully, and the cleaner (unmount) executed // at the end of the previous block. Log the results. cta::log::ScopedParamContainer params(m_logContext); @@ -372,3 +373,59 @@ int level,const std::string& msg, cta::log::ScopedParamContainer& params){ /1000/1000/m_stats.totalTime:0.0); m_logContext.log(level, msg); } + +//------------------------------------------------------------------------------ +//logSCSIMetrics +//------------------------------------------------------------------------------ +void castor::tape::tapeserver::daemon::TapeWriteSingleThread::logSCSIMetrics() { + try { + // mount general statistics + cta::log::ScopedParamContainer scopedContainer(m_logContext); + appendDriveAndTapeInfoToScopedParams(scopedContainer); + // get mount general stats + std::map<std::string, uint32_t> scsi_write_metrics_hash = m_drive.getTapeWriteErrors(); + appendMetricsToScopedParams(scopedContainer, scsi_write_metrics_hash); + std::map<std::string, uint32_t> scsi_nonmedium_metrics_hash = m_drive.getTapeNonMediumErrors(); + appendMetricsToScopedParams(scopedContainer, scsi_nonmedium_metrics_hash); + logSCSIStats("Logging mount general statistics", + scsi_write_metrics_hash.size() + scsi_nonmedium_metrics_hash.size()); + } + catch (const cta::exception::Exception &ex) { + cta::log::ScopedParamContainer scoped(m_logContext); + scoped.add("exception_message", ex.getMessageValue()); + m_logContext.log(cta::log::ERR, "Exception in logging mount general statistics"); + } + + // drive statistics + try { + cta::log::ScopedParamContainer scopedContainer(m_logContext); + appendDriveAndTapeInfoToScopedParams(scopedContainer); + // get drive stats + std::map<std::string,float> scsi_quality_metrics_hash = m_drive.getQualityStats(); + appendMetricsToScopedParams(scopedContainer, scsi_quality_metrics_hash); + std::map<std::string,uint32_t> scsi_drive_metrics_hash = m_drive.getDriveStats(); + appendMetricsToScopedParams(scopedContainer, scsi_drive_metrics_hash); + logSCSIStats("Logging drive statistics", + scsi_quality_metrics_hash.size()+scsi_drive_metrics_hash.size()); + } + catch (const cta::exception::Exception &ex) { + cta::log::ScopedParamContainer scoped(m_logContext); + scoped.add("exception_message", ex.getMessageValue()); + m_logContext.log(cta::log::ERR, "Exception in logging drive statistics"); + } + + // volume statistics + try { + cta::log::ScopedParamContainer scopedContainer(m_logContext); + appendDriveAndTapeInfoToScopedParams(scopedContainer); + std::map<std::string,uint32_t> scsi_metrics_hash = m_drive.getVolumeStats(); + appendMetricsToScopedParams(scopedContainer, scsi_metrics_hash); + logSCSIStats("Logging volume statistics", scsi_metrics_hash.size()); + } + catch (const cta::exception::Exception &ex) { + cta::log::ScopedParamContainer scoped(m_logContext); + scoped.add("exception_message", ex.getMessageValue()); + m_logContext.log(cta::log::ERR, "Exception in logging volume statistics"); + } +} + diff --git a/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.hpp b/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.hpp index b44e5907ffbf5b88c17a2f5e8ec828773c6a0285..3b7132be6033499a031489fed14c36aa91be8c68 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.hpp +++ b/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.hpp @@ -111,12 +111,16 @@ private: // prevent counting where error happened upstream. // Log (safely, exception-wise) the tape alerts (if any) at the end of the session try { m_this.logTapeAlerts(); } catch (...) {} + // Log (safely, exception-wise) the tape SCSI metrics at the end of the session + try { m_this.logSCSIMetrics(); } catch(...) {} + std::string currentErrorToCount = "Error_tapeUnload"; try{ // Do the final cleanup // First check that a tape is actually present in the drive. We can get here // after failing to mount (library error) in which case there is nothing to // do (and trying to unmount will only lead to a failure.) + const uint32_t waitMediaInDriveTimeout = 60; try { m_this.m_drive.waitUntilReady(waitMediaInDriveTimeout); @@ -263,6 +267,11 @@ protected: virtual void countTapeLogError(const std::string & error) { m_watchdog.addToErrorCount(error); } + + /** + * Logs SCSI metrics for write session. + */ + virtual void logSCSIMetrics(); private: /** diff --git a/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.cpp b/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.cpp index 2268b51e6352abb1e69a1d9d3e3bab4514059269..130d143fca7f51654f3975c36886f3f0d784d149 100644 --- a/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.cpp +++ b/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.cpp @@ -1135,6 +1135,902 @@ drive::compressionStats drive::DriveIBM3592::getCompression() { return driveCompressionStats; } +//------------------------------------------------------------------------------ +// pre-emptive evaluation statistics (SCSI Statistics) +//------------------------------------------------------------------------------ +std::map<std::string,uint32_t> drive::DriveGeneric::getTapeWriteErrors() { + // No available data + return std::map<std::string,uint32_t>(); +} + +std::map<std::string,uint32_t> drive::DriveGeneric::getTapeReadErrors() { + // No available data + return std::map<std::string,uint32_t>(); +} + +std::map<std::string,float> drive::DriveGeneric::getQualityStats() { + // No available data + return std::map<std::string,float>(); +} + +std::map<std::string,uint32_t> drive::DriveGeneric::getDriveStats() { + // No available data + return std::map<std::string,uint32_t>(); +} + +std::map<std::string,uint32_t> drive::DriveGeneric::getVolumeStats() { + // No available data + return std::map<std::string,uint32_t>(); +} + +std::map<std::string,uint32_t> drive::DriveIBM3592::getTapeWriteErrors() { + // SCSI counters get reset after read in DriveIBM3592. + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,uint32_t> driveWriteErrorStats; + unsigned char dataBuff[1024]; //big enough to fit all the results + + memset(dataBuff, 0, sizeof (dataBuff)); + + cdb.pageCode = SCSI::logSensePages::writeErrors; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getTapeWriteErrors"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getTapeWriteErrors"); + + SCSI::Structures::logSenseLogPageHeader_t & logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + while (logParameter < endPage) { /* values in KiBs and we use shift <<10 to get bytes */ + SCSI::Structures::logSenseParameter_t & logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::writeErrorsDevicePage::totalCorrectedErrors: + driveWriteErrorStats["mountTotalCorrectedWriteErrors"] = logPageParam.getU64Value(); + break; + case SCSI::writeErrorsDevicePage::totalProcessed: + driveWriteErrorStats["mountTotalWriteBytesProcessed"] = logPageParam.getU64Value() << 10; + break; + case SCSI::writeErrorsDevicePage::totalUncorrectedErrors: + driveWriteErrorStats["mountTotalUncorrectedWriteErrors"] = logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + return driveWriteErrorStats; +} + +std::map<std::string,uint32_t> drive::DriveT10000::getTapeWriteErrors() { + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,uint32_t> driveWriteErrorStats; + unsigned char dataBuff[1024]; //big enough to fit all the results + + memset(dataBuff, 0, sizeof (dataBuff)); + + cdb.pageCode = SCSI::logSensePages::writeErrors; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveT10000::getTapeWriteErrors"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveT10000::getTapeWriteErrors"); + + SCSI::Structures::logSenseLogPageHeader_t & logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t & logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::writeErrorsDevicePage::totalCorrectedErrors: + driveWriteErrorStats["mountTotalCorrectedWriteErrors"] = logPageParam.getU64Value(); + break; + case SCSI::writeErrorsDevicePage::totalProcessed: + driveWriteErrorStats["mountTotalWriteBytesProcessed"] = logPageParam.getU64Value(); // already in bytes + break; + case SCSI::writeErrorsDevicePage::totalUncorrectedErrors: + driveWriteErrorStats["mountTotalUncorrectedWriteErrors"] = logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + return driveWriteErrorStats; +} + +std::map<std::string,uint32_t> drive::DriveIBM3592::getTapeReadErrors() { + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,uint32_t> driveReadErrorStats; + unsigned char dataBuff[1024]; //big enough to fit all the results + + memset(dataBuff, 0, sizeof (dataBuff)); + + cdb.pageCode = SCSI::logSensePages::readErrors; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getTapeReadErrors"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getTapeReadErrors"); + + SCSI::Structures::logSenseLogPageHeader_t & logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { /* values in KiBs and we use shift <<10 to get bytes */ + SCSI::Structures::logSenseParameter_t & logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::readErrorsDevicePage::totalCorrectedErrors: + driveReadErrorStats["mountTotalCorrectedReadErrors"] = logPageParam.getU64Value(); + break; + case SCSI::readErrorsDevicePage::totalProcessed: + driveReadErrorStats["mountTotalReadBytesProcessed"] = logPageParam.getU64Value() << 10; + break; + case SCSI::readErrorsDevicePage::totalUncorrectedErrors: + driveReadErrorStats["mountTotalUncorrectedReadErrors"] = logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + return driveReadErrorStats; +} + +std::map<std::string,uint32_t> drive::DriveT10000::getTapeReadErrors() { + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,uint32_t> driveReadErrorStats; + unsigned char dataBuff[1024]; //big enough to fit all the results + + memset(dataBuff, 0, sizeof (dataBuff)); + + cdb.pageCode = SCSI::logSensePages::readErrors; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveT10000::getTapeReadErrors"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveT10000::getTapeReadErrors"); + + SCSI::Structures::logSenseLogPageHeader_t & logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + while (logParameter < endPage) { /* values in KiBs and we use shift <<10 to get bytes */ + SCSI::Structures::logSenseParameter_t & logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::readErrorsDevicePage::totalCorrectedErrors: + driveReadErrorStats["mountTotalCorrectedReadErrors"] = logPageParam.getU64Value(); + break; + case SCSI::readErrorsDevicePage::totalProcessed: + driveReadErrorStats["mountTotalReadBytesProcessed"] = logPageParam.getU64Value(); // already in bytes + break; + case SCSI::readErrorsDevicePage::totalUncorrectedErrors: + driveReadErrorStats["mountTotalUncorrectedReadErrors"] = logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + return driveReadErrorStats; +} + +std::map<std::string,uint32_t> drive::DriveGeneric::getTapeNonMediumErrors() { + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,uint32_t> driveNonMediumErrorsStats; + unsigned char dataBuff[1024]; //big enough to fit all the results + + memset(dataBuff, 0, sizeof (dataBuff)); + + cdb.pageCode = SCSI::logSensePages::nonMediumErrors; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveGeneric::getTapeNonMediumErrors"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveGeneric::getTapeNonMediumErrors"); + + SCSI::Structures::logSenseLogPageHeader_t & logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t & logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::nonMediumErrorsDevicePage::totalCount: + driveNonMediumErrorsStats["mountTotalNonMediumErrorCounts"] = logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + return driveNonMediumErrorsStats; +} + +std::map<std::string,uint32_t> drive::DriveIBM3592::getVolumeStats() { + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,uint32_t> volumeStats; + unsigned char dataBuff[1024]; //big enough to fit all the results + + memset(dataBuff, 0, sizeof (dataBuff)); + + cdb.pageCode = SCSI::logSensePages::volumeStatistics; + cdb.subPageCode = 0x00; // 0x01 // for IBM latest revision drives + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getVolumeStats"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getVolumeStats"); + + SCSI::Structures::logSenseLogPageHeader_t & logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t & logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::volumeStatisticsPage::validityFlag: + volumeStats["validity"] = logPageParam.getU64Value(); + break; + case SCSI::volumeStatisticsPage::volumeMounts: + volumeStats["lifetimeVolumeMounts"] = logPageParam.getU64Value(); + break; + case SCSI::volumeStatisticsPage::volumeRecoveredWriteDataErrors: + volumeStats["lifetimeVolumeRecoveredWriteErrors"] = logPageParam.getU64Value(); + break; + case SCSI::volumeStatisticsPage::volumeUnrecoveredWriteDataErrors: + volumeStats["lifetimeVolumeUnrecoveredWriteErrors"] = logPageParam.getU64Value(); + break; + case SCSI::volumeStatisticsPage::volumeRecoveredReadErrors: + volumeStats["lifetimeVolumeRecoveredReadErrors"] = logPageParam.getU64Value(); + break; + case SCSI::volumeStatisticsPage::volumeUnrecoveredReadErrors: + volumeStats["lifetimeVolumeUnrecoveredReadErrors"] = logPageParam.getU64Value(); + break; + case SCSI::volumeStatisticsPage::volumeManufacturingDate: + char volumeManufacturingDate[9]; + for (int i = 0; i < 8; ++i) { + volumeManufacturingDate[i] = logPageParam.parameterValue[i]; + } + volumeManufacturingDate[8] = '\0'; + volumeStats["volumeManufacturingDate"] = std::atoi(volumeManufacturingDate); + break; + case SCSI::volumeStatisticsPage::BOTPasses: + volumeStats["lifetimeBOTPasses"] = logPageParam.getU64Value(); + break; + case SCSI::volumeStatisticsPage::MOTPasses: + volumeStats["lifetimeMOTPasses"] = logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + return volumeStats; +} + +std::map<std::string,float> drive::DriveIBM3592::getQualityStats() { + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,float> qualityStats; + unsigned char dataBuff[1024]; //big enough to fit all the results + + // Obtain data from QualitySummarySubpage + { + // Lifetime values + { + memset(dataBuff, 0, sizeof(dataBuff)); + + cdb.pageCode = SCSI::logSensePages::performanceCharacteristics; + cdb.subPageCode = 0x80; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getQualityStats_qualitySummaryBlock"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getQualityStats"); + + SCSI::Structures::logSenseLogPageHeader_t &logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t &logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + const int val = logPageParam.getU64Value(); + if (val != 0) + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::performanceCharacteristicsQualitySummaryPage::driveEfficiency: + qualityStats["lifetimeDriveEfficiencyPrct"] = 100-(val-1)*100/254.0; + break; + case SCSI::performanceCharacteristicsQualitySummaryPage::mediaEfficiency: + qualityStats["lifetimeMediumEfficiencyPrct"] = 100-(val-1)*100/254.0; + break; + case SCSI::performanceCharacteristicsQualitySummaryPage::primaryInterfaceEfficiency0: + qualityStats["lifetimeInterfaceEfficiency0Prct"] = 100-(val-1)*100/254.0; + break; + case SCSI::performanceCharacteristicsQualitySummaryPage::primaryInterfaceEfficiency1: + qualityStats["lifetimeInterfaceEfficiency1Prct"] = 100-(val-1)*100/254.0; + break; + case SCSI::performanceCharacteristicsQualitySummaryPage::libraryInterfaceEfficiency: + qualityStats["lifetimeLibraryEfficiencyPrct"] = 100-(val-1)*100/254.0; + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + } + + // Mount values + { + memset(dataBuff, 0, sizeof(dataBuff)); + + cdb.pageCode = SCSI::logSensePages::performanceCharacteristics; + cdb.subPageCode = 0x40; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getQualityStats_qualitySummaryBlock"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getQualityStats"); + + SCSI::Structures::logSenseLogPageHeader_t &logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t &logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + const int val = logPageParam.getU64Value(); + if (val != 0) + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::performanceCharacteristicsQualitySummaryPage::driveEfficiency: + qualityStats["mountDriveEfficiencyPrct"] = 100-(float)(val-1)*100/254.0; + break; + case SCSI::performanceCharacteristicsQualitySummaryPage::mediaEfficiency: + qualityStats["mountMediumEfficiencyPrct"] = 100-(float)(val-1)*100/254.0; + break; + case SCSI::performanceCharacteristicsQualitySummaryPage::primaryInterfaceEfficiency0: + qualityStats["mountInterfaceEfficiency0Prct"] = 100-(float)(val-1)*100/254.0; + break; + case SCSI::performanceCharacteristicsQualitySummaryPage::primaryInterfaceEfficiency1: + qualityStats["mountInterfaceEfficiency1Prct"] = 100-(float)(val-1)*100/254.0; + break; + case SCSI::performanceCharacteristicsQualitySummaryPage::libraryInterfaceEfficiency: + qualityStats["mountLibraryEfficiencyPrct"] = 100-(float)(val-1)*100/254.0; + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + } + } + + // Obtain data from HostCommandsSubpage + { + // lifetime values + { + memset(dataBuff, 0, sizeof(dataBuff)); + + cdb.pageCode = SCSI::logSensePages::performanceCharacteristics; + cdb.subPageCode = 0x91; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getQualityStats_hostCommandsBlock"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getQualityStats"); + + SCSI::Structures::logSenseLogPageHeader_t &logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t &logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::performanceCharacteristicsHostCommandsPage::readPerformanceEfficiency: + qualityStats["lifetimeReadEfficiencyPrct"] = (float)logPageParam.getU64Value()/65536; + break; + case SCSI::performanceCharacteristicsHostCommandsPage::writePerformanceEfficiency: + qualityStats["lifetimeWriteEfficiencyPrct"] = (float)logPageParam.getU64Value()/65536; + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + } + + // mount values + { + memset(dataBuff, 0, sizeof(dataBuff)); + + cdb.pageCode = SCSI::logSensePages::performanceCharacteristics; + cdb.subPageCode = 0x51; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getQualityStats_hostCommandsBlock"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getQualityStats"); + + SCSI::Structures::logSenseLogPageHeader_t &logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t &logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::performanceCharacteristicsHostCommandsPage::readPerformanceEfficiency: + qualityStats["mountReadEfficiencyPrct"] = (float)logPageParam.getU64Value()/65536; + break; + case SCSI::performanceCharacteristicsHostCommandsPage::writePerformanceEfficiency: + qualityStats["mountWriteEfficiencyPrct"] = (float)logPageParam.getU64Value()/65536; + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + } + } + return qualityStats; +} + +std::map<std::string,float> drive::DriveT10000::getQualityStats() { + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,float> qualityStats; + unsigned char dataBuff[4096]; //big enough to fit all the results + memset(dataBuff, 0, sizeof (dataBuff)); + + cdb.pageCode = SCSI::logSensePages::vendorUniqueDriveStatistics; + cdb.subPageCode = 0x00; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveT10000::getQualityStats"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveT10000::getQualityStats"); + + SCSI::Structures::logSenseLogPageHeader_t & logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t & logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::vendorUniqueDriveStatistics::readQualityIndex: + qualityStats["mountReadEfficiencyPrct"] = logPageParam.getU64Value()/160.0; + break; + case SCSI::vendorUniqueDriveStatistics::writeEfficiency: + qualityStats["mountWriteEfficiencyPrct"] = logPageParam.getU64Value()/10.0; + break; + case SCSI::vendorUniqueDriveStatistics::tapeEfficiency: + qualityStats["lifetimeMediumEfficiencyPrct"] = logPageParam.getU64Value()/10.0; + break; + case SCSI::vendorUniqueDriveStatistics::readBackCheckQualityIndex: + qualityStats["mountReadBackCheckQualityIndexPrct"] = logPageParam.getU64Value()/160.0; + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + return qualityStats; +} + +std::map<std::string,uint32_t> drive::DriveIBM3592::getDriveStats() { + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,uint32_t> driveStats; + unsigned char dataBuff[1024]; //big enough to fit all the results + + // write errors (0x34) + { + memset(dataBuff, 0, sizeof(dataBuff)); + + cdb.pageCode = SCSI::logSensePages::driveWriteErrors; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getDriveStats_writeErrors"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getDriveStats"); + + SCSI::Structures::logSenseLogPageHeader_t &logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t &logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::driveWriteErrorsPage::dataTemps: + driveStats["mountTemps"] = logPageParam.getU64Value(); + break; + case SCSI::driveWriteErrorsPage::servoTemps: + driveStats["mountServoTemps"] = logPageParam.getU64Value(); + break; + case SCSI::driveWriteErrorsPage::servoTransients: + driveStats["mountServoTransients"] = logPageParam.getU64Value(); + break; + case SCSI::driveWriteErrorsPage::dataTransients: + driveStats["mountWriteTransients"] = logPageParam.getU64Value(); + break; + case SCSI::driveWriteErrorsPage::totalRetries: + driveStats["mountTotalWriteRetries"] = logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + } + + // read FW errors + { + memset(dataBuff, 0, sizeof(dataBuff)); + + cdb.pageCode = SCSI::logSensePages::driveReadForwardErrors; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getDriveStats_readFWErrors"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getDriveStats"); + + SCSI::Structures::logSenseLogPageHeader_t &logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t &logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::driveReadErrorsPage::dataTemps: + driveStats["mountTemps"] += logPageParam.getU64Value(); + break; + case SCSI::driveReadErrorsPage::servoTemps: + driveStats["mountServoTemps"] += logPageParam.getU64Value(); + break; + case SCSI::driveReadErrorsPage::servoTransients: + driveStats["mountServoTransients"] += logPageParam.getU64Value(); + break; + case SCSI::driveReadErrorsPage::dataTransients: + driveStats["mountReadTransients"] = logPageParam.getU64Value(); + break; + case SCSI::driveReadErrorsPage::totalRetries: + driveStats["mountTotalReadRetries"] = logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + } + + // read BW errors + { + memset(dataBuff, 0, sizeof(dataBuff)); + + cdb.pageCode = SCSI::logSensePages::driveReadBackwardErrors; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveIBM3592::getDriveStats_readBWErrors"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::getDriveStats"); + + SCSI::Structures::logSenseLogPageHeader_t &logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t &logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::driveReadErrorsPage::dataTemps: + driveStats["mountTemps"] += logPageParam.getU64Value(); + break; + case SCSI::driveReadErrorsPage::servoTemps: + driveStats["mountServoTemps"] += logPageParam.getU64Value(); + break; + case SCSI::driveReadErrorsPage::servoTransients: + driveStats["mountServoTransients"] += logPageParam.getU64Value(); + break; + case SCSI::driveReadErrorsPage::dataTransients: + driveStats["mountReadTransients"] += logPageParam.getU64Value(); + break; + case SCSI::driveReadErrorsPage::totalRetries: + driveStats["mountTotalReadRetries"] += logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + } + return driveStats; +} + +std::map<std::string,uint32_t> drive::DriveT10000::getDriveStats() { + SCSI::Structures::LinuxSGIO_t sgh; + SCSI::Structures::logSenseCDB_t cdb; + SCSI::Structures::senseData_t<255> senseBuff; + std::map<std::string,uint32_t> driveStats; + unsigned char dataBuff[4096]; //big enough to fit all the results + memset(dataBuff, 0, sizeof (dataBuff)); + + cdb.pageCode = SCSI::logSensePages::vendorUniqueDriveStatistics; + cdb.PC = 0x01; // Current Cumulative Values + SCSI::Structures::setU16(cdb.allocationLength, sizeof(dataBuff)); + + sgh.setCDB(&cdb); + sgh.setDataBuffer(&dataBuff); + sgh.setSenseBuffer(&senseBuff); + sgh.dxfer_direction = SG_DXFER_FROM_DEV; + + /* Manage both system error and SCSI errors. */ + cta::exception::Errnum::throwOnMinusOne( + m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh), + "Failed SG_IO ioctl in DriveT10000::getDriveStats"); + SCSI::ExceptionLauncher(sgh, "SCSI error in DriveT10000::getDriveStats"); + + SCSI::Structures::logSenseLogPageHeader_t & logPageHeader = + *(SCSI::Structures::logSenseLogPageHeader_t *) dataBuff; + + unsigned char *endPage = dataBuff + + SCSI::Structures::toU16(logPageHeader.pageLength) + sizeof(logPageHeader); + + unsigned char *logParameter = dataBuff + sizeof(logPageHeader); + + while (logParameter < endPage) { + SCSI::Structures::logSenseParameter_t & logPageParam = + *(SCSI::Structures::logSenseParameter_t *) logParameter; + switch (SCSI::Structures::toU16(logPageParam.header.parameterCode)) { + case SCSI::vendorUniqueDriveStatistics::readRecoveryRetries: + driveStats["mountTotalReadRetries"] = logPageParam.getU64Value(); + break; + case SCSI::vendorUniqueDriveStatistics::readTransientConditions: + driveStats["mountReadTransients"] = logPageParam.getU64Value(); + break; + case SCSI::vendorUniqueDriveStatistics::writeTransientConditions: + driveStats["mountWriteTransients"] = logPageParam.getU64Value(); + break; + case SCSI::vendorUniqueDriveStatistics::servoTepomporaries: + driveStats["mountServoTemps"] = logPageParam.getU64Value(); + break; + case SCSI::vendorUniqueDriveStatistics::servoTransientConditions: + driveStats["mountServoTransients"] = logPageParam.getU64Value(); + break; + case SCSI::vendorUniqueDriveStatistics::writeRecoveryRetries: + driveStats["mountTotalWriteRetries"] = logPageParam.getU64Value(); + break; + case SCSI::vendorUniqueDriveStatistics::temporaryDriveErrors: + driveStats["mountTemps"] = logPageParam.getU64Value(); + break; + } + logParameter += logPageParam.header.parameterLength + sizeof(logPageParam.header); + } + return driveStats; +} + +std::string drive::DriveGeneric::getDriveFirmwareVersion() { + std::ifstream scsiProcFile; + try { + scsiProcFile.open("/proc/scsi/scsi", std::ios::in); + int currentLineNo = 0; + std::string line; + bool found = false; + while (getline(scsiProcFile, line)) { + if (std::string::npos != line.find("Type: Sequential-Access", 0)) { + found = true; + break; + } + ++currentLineNo; + } + if (found) { + scsiProcFile.seekg(0, std::ios::beg); + for (int i = 0; i < currentLineNo - 2; ++i) { + // skipping lines + scsiProcFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); + } + } + getline(scsiProcFile, line); + scsiProcFile.close(); + return line.substr(line.find("Rev:") + 5); + } + catch(std::ios_base::failure) { + return std::string(""); + } +} + +/* + * Override as not implemented of all SCSI metrics functions for MHVTL virtual drives as SCSI log sense pages + * are not implemented as vendor(Oracle) specific, but inherits from DriveT10000. + */ +std::map<std::string,uint32_t> drive::DriveMHVTL::getTapeWriteErrors() { + // No available data + return std::map<std::string,uint32_t>(); +} + +std::map<std::string,uint32_t> drive::DriveMHVTL::getTapeReadErrors() { + // No available data + return std::map<std::string,uint32_t>(); +} + +std::map<std::string,uint32_t> drive::DriveMHVTL::getTapeNonMediumErrors() { + // No available data + return std::map<std::string,uint32_t>(); +} + +std::map<std::string,float> drive::DriveMHVTL::getQualityStats(){ + // No available data + return std::map<std::string,float>(); +} + +std::map<std::string,uint32_t> drive::DriveMHVTL::getDriveStats() { + // No available data + return std::map<std::string,uint32_t>(); +} + //------------------------------------------------------------------------------ // testUnitReady //------------------------------------------------------------------------------ diff --git a/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.hpp b/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.hpp index ff887739203b4a0f8323dab98cf0dd7ff43ec07d..08423e4f58c2f925dec0b75db36e7c9f3338c379 100644 --- a/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.hpp +++ b/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.hpp @@ -53,6 +53,44 @@ namespace drive { */ virtual compressionStats getCompression() = 0; + /** + * Get write error information from the drive. + * @return writeErrorsStats + */ + virtual std::map<std::string,uint32_t> getTapeWriteErrors(); + + /** + * Get read error information from the drive. + * @return readErrorsStats + */ + virtual std::map<std::string,uint32_t> getTapeReadErrors(); + + /** + * Get error information (other than read/write) from the drive. + */ + virtual std::map<std::string,uint32_t> getTapeNonMediumErrors(); + + /** + * Get quality-related metrics (ratings, efficiencies) from the drive. + */ + virtual std::map<std::string,float> getQualityStats(); + + /** + * Get drive error information happened during mount from the drive. + */ + virtual std::map<std::string,uint32_t> getDriveStats(); + + /** + * Get volume information happened during the mount. + */ + virtual std::map<std::string,uint32_t> getVolumeStats(); + + /** + * Get the firmware revision of the drive. + * Reads it from /proc/scsi/scsi file. + */ + virtual std::string getDriveFirmwareVersion(); + /** * Reset all statistics about data movements on the drive. * All cumulative and threshold log counter values will be reset to their @@ -398,7 +436,11 @@ namespace drive { DriveT10000(SCSI::DeviceInfo di, System::virtualWrapper & sw) : DriveGeneric(di, sw) { } - virtual compressionStats getCompression() ; + virtual compressionStats getCompression(); + virtual std::map<std::string,uint32_t> getTapeWriteErrors() ; + virtual std::map<std::string,uint32_t> getTapeReadErrors() ; + virtual std::map<std::string,float> getQualityStats(); + virtual std::map<std::string,uint32_t> getDriveStats(); }; /** @@ -417,6 +459,11 @@ namespace drive { virtual void setLogicalBlockProtection(const unsigned char method, unsigned char methodLength, const bool enableLPBforRead, const bool enableLBBforWrite); + virtual std::map<std::string,uint32_t> getTapeWriteErrors(); + virtual std::map<std::string,uint32_t> getTapeReadErrors(); + virtual std::map<std::string,uint32_t> getTapeNonMediumErrors(); + virtual std::map<std::string,float> getQualityStats(); + virtual std::map<std::string,uint32_t> getDriveStats(); }; class DriveLTO : public DriveGeneric { @@ -425,7 +472,7 @@ namespace drive { DriveLTO(SCSI::DeviceInfo di, System::virtualWrapper & sw) : DriveGeneric(di, sw) { } - virtual compressionStats getCompression() ; + virtual compressionStats getCompression(); }; class DriveIBM3592 : public DriveGeneric { @@ -434,7 +481,12 @@ namespace drive { DriveIBM3592(SCSI::DeviceInfo di, System::virtualWrapper & sw) : DriveGeneric(di, sw) { } - virtual compressionStats getCompression() ; + virtual compressionStats getCompression(); + virtual std::map<std::string,uint32_t> getTapeWriteErrors(); + virtual std::map<std::string,uint32_t> getTapeReadErrors(); + virtual std::map<std::string,uint32_t> getVolumeStats(); + virtual std::map<std::string,float> getQualityStats(); + virtual std::map<std::string,uint32_t> getDriveStats(); }; }}}} diff --git a/tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp b/tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp index b24b7421889689817913238a9e1f960dde9d1a27..36ce1d5ef6c72281d7c44ca458b3b8f5c610d653 100644 --- a/tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp +++ b/tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp @@ -172,7 +172,13 @@ namespace drive { virtual compressionStats getCompression() = 0; virtual void clearCompressionStats() = 0; - + virtual std::map<std::string,uint32_t> getTapeWriteErrors() = 0; + virtual std::map<std::string,uint32_t> getTapeReadErrors() = 0; + virtual std::map<std::string,uint32_t> getTapeNonMediumErrors() = 0; + virtual std::map<std::string,float> getQualityStats() = 0; + virtual std::map<std::string,uint32_t> getDriveStats() = 0; + virtual std::map<std::string,uint32_t> getVolumeStats() = 0; + virtual std::string getDriveFirmwareVersion() = 0; virtual deviceInfo getDeviceInfo() = 0; virtual std::string getSerialNumber() = 0; virtual void positionToLogicalObject(uint32_t blockId) = 0; diff --git a/tapeserver/castor/tape/tapeserver/drive/DriveTest.cpp b/tapeserver/castor/tape/tapeserver/drive/DriveTest.cpp index 1e7ac7977b65df23f7ac34b4221a3854a365dec9..2bf23d0e71ea09ad19729a11c29ffa4c59087166 100644 --- a/tapeserver/castor/tape/tapeserver/drive/DriveTest.cpp +++ b/tapeserver/castor/tape/tapeserver/drive/DriveTest.cpp @@ -45,17 +45,18 @@ TEST(castor_tape_drive_Drive, OpensCorrectly) { sysWrapper.delegateToFake(); /* We expect the following calls: */ - EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(4)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); - EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(21); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(4)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(42); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(21); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(42); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); + /* Test: detect devices, then open the device files */ castor::tape::SCSI::DeviceVector dl(sysWrapper); @@ -69,9 +70,16 @@ TEST(castor_tape_drive_Drive, OpensCorrectly) { for (std::vector<castor::tape::SCSI::DeviceInfo>::iterator i = dl.begin(); i != dl.end(); i++) { if (castor::tape::SCSI::Types::tape == i->type) { - std::string expected_classid (typeid(castor::tape::tapeserver::drive::DriveT10000).name()); std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface>drive( castor::tape::tapeserver::drive::createDrive(*i, sysWrapper)); + std::string expected_classid; + if (dynamic_cast<castor::tape::tapeserver::drive::DriveIBM3592 *>(drive.get())) { + expected_classid = std::string(typeid(castor::tape::tapeserver::drive::DriveIBM3592).name()); + } + else if (dynamic_cast<castor::tape::tapeserver::drive::DriveT10000 *>(drive.get())) { + expected_classid = std::string(typeid(castor::tape::tapeserver::drive::DriveT10000).name()); + } + else {/* Fill in other vendors in the future here. */} std::string found_classid (typeid(*drive).name()); ASSERT_EQ(expected_classid, found_classid); } @@ -85,17 +93,17 @@ TEST(castor_tape_drive_Drive, getPositionInfoAndPositionToLogicalObject) { sysWrapper.delegateToFake(); /* We expect the following calls: */ - EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(4)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); - EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(21); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(4)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(42); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(21); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(42); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); /* Test: detect devices, then open the device files */ castor::tape::SCSI::DeviceVector dl(sysWrapper); @@ -134,17 +142,17 @@ TEST(castor_tape_drive_Drive, setDensityAndCompression) { sysWrapper.delegateToFake(); /* We expect the following calls: */ - EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(4)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); - EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(21); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(4)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(42); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(21); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(42); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); /* Test: detect devices, then open the device files */ castor::tape::SCSI::DeviceVector dl(sysWrapper); @@ -179,17 +187,17 @@ TEST(castor_tape_drive_Drive, setStDriverOptions) { sysWrapper.delegateToFake(); /* We expect the following calls: */ - EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(4)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); - EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(21); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(4)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(42); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(21); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(42); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); /* Test: detect devices, then open the device files */ castor::tape::SCSI::DeviceVector dl(sysWrapper); @@ -214,17 +222,17 @@ TEST(castor_tape_drive_Drive, getDeviceInfo) { sysWrapper.delegateToFake(); /* We expect the following calls: */ - EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(4)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); - EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(21); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(4)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(42); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(21); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(42); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); /* Test: detect devices, then open the device files */ castor::tape::SCSI::DeviceVector dl(sysWrapper); @@ -235,15 +243,22 @@ TEST(castor_tape_drive_Drive, getDeviceInfo) { castor::tape::tapeserver::drive::createDrive(*i, sysWrapper)); castor::tape::tapeserver::drive::deviceInfo devInfo; - devInfo.isPIsupported = false; EXPECT_CALL(sysWrapper, ioctl(_,_,An<sg_io_hdr_t*>())).Times(2); devInfo = drive->getDeviceInfo(); - ASSERT_EQ("STK ",devInfo.vendor); - ASSERT_EQ("T10000B ",devInfo.product); - ASSERT_EQ("0104",devInfo.productRevisionLevel ); - ASSERT_EQ("XYZZY_A2 ",devInfo.serialNumber ); - ASSERT_TRUE(devInfo.isPIsupported); + if (dynamic_cast<castor::tape::tapeserver::drive::DriveIBM3592 *>(drive.get())) { + ASSERT_EQ("IBM ",devInfo.vendor); + ASSERT_EQ("03592E08 ",devInfo.product); + ASSERT_EQ("460E",devInfo.productRevisionLevel ); + ASSERT_EQ("XYZZY_A2 ",devInfo.serialNumber ); + } + else if (dynamic_cast<castor::tape::tapeserver::drive::DriveIBM3592 *>(drive.get())) { + ASSERT_EQ("STK ",devInfo.vendor); + ASSERT_EQ("T10000B ",devInfo.product); + ASSERT_EQ("0104",devInfo.productRevisionLevel ); + ASSERT_EQ("XYZZY_A2 ",devInfo.serialNumber ); + } + else { /* Fill in other vendors in the future here. */ } } } } @@ -255,23 +270,29 @@ TEST(castor_tape_drive_Drive, getCompressionAndClearCompressionStats) { sysWrapper.delegateToFake(); /* We expect the following calls: */ - EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(4)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(25); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(44); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(25); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(44); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); /* Test: detect devices, then open the device files */ castor::tape::SCSI::DeviceVector dl(sysWrapper); for (std::vector<castor::tape::SCSI::DeviceInfo>::iterator i = dl.begin(); - i != dl.end(); i++) { - if (castor::tape::SCSI::Types::tape == i->type) { + i != dl.end(); i++) { + /* + * The second condition relates to the fact that LTO drives and IBM 3592 have the same + * logSense page code for different metrics. + * The current test is written in such a way that does not really use vfs files. So, there + * is no need take into consideration the IBM tapes at all. + */ + if (castor::tape::SCSI::Types::tape == i->type && i->product != "03592E08") { castor::tape::tapeserver::drive::DriveGeneric *drive; castor::tape::tapeserver::drive::compressionStats comp; @@ -355,14 +376,14 @@ TEST(castor_tape_drive_Drive, getLBPInfo) { EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(21); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(42); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(21); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(42); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); /* Test: detect devices, then open the device files */ castor::tape::SCSI::DeviceVector dl(sysWrapper); @@ -394,14 +415,14 @@ TEST(castor_tape_drive_Drive, setLogicalBlockProtection) { EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(21); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(42); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(21); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(42); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); /* Test: detect devices, then open the device files */ castor::tape::SCSI::DeviceVector dl(sysWrapper); @@ -439,14 +460,14 @@ TEST(castor_tape_drive_Drive, disableLogicalBlockProtection) { EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(3)); EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30)); EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(3)); - EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3); - EXPECT_CALL(sysWrapper, open(_, _)).Times(21); - EXPECT_CALL(sysWrapper, read(_, _, _)).Times(38); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(6); + EXPECT_CALL(sysWrapper, open(_, _)).Times(42); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(76); EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(0); - EXPECT_CALL(sysWrapper, close(_)).Times(21); - EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3); - EXPECT_CALL(sysWrapper, stat(_,_)).Times(7); + EXPECT_CALL(sysWrapper, close(_)).Times(42); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(6); + EXPECT_CALL(sysWrapper, stat(_,_)).Times(14); /* Test: detect devices, then open the device files */ castor::tape::SCSI::DeviceVector dl(sysWrapper); @@ -474,6 +495,321 @@ TEST(castor_tape_drive_Drive, disableLogicalBlockProtection) { } } +TEST(castor_tape_drive_Drive, getReadErrors) { + struct { + void operator()(castor::tape::System::mockWrapper &sysWrapper) { + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(68)); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, open(_, _)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(AtLeast(76)); + EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<mtget*>())).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<sg_io_hdr_t *>())).Times(4); + EXPECT_CALL(sysWrapper, close(_)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, stat(_, _)).Times(AtLeast(14)); + + /* Test: detect devices, then open the device files */ + castor::tape::SCSI::DeviceVector dl(sysWrapper); + for (std::vector<castor::tape::SCSI::DeviceInfo>::iterator i = dl.begin(); + i != dl.end(); i++) { + if (castor::tape::SCSI::Types::tape == i->type) { + std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive( + castor::tape::tapeserver::drive::createDrive(*i, sysWrapper)); + std::map<std::string,uint32_t> readErrorsStats = + drive->getTapeReadErrors(); + ASSERT_EQ(2, readErrorsStats["mountTotalCorrectedReadErrors"]); + ASSERT_EQ(2048, readErrorsStats["mountTotalReadBytesProcessed"]); + ASSERT_EQ(1, readErrorsStats["mountTotalUncorrectedReadErrors"]); + } + } + } + } test_functor; + + castor::tape::System::mockWrapper sysWrapperSLC5; + castor::tape::System::mockWrapper sysWrapperSLC6; + sysWrapperSLC5.fake.setupSLC5(); + sysWrapperSLC6.fake.setupSLC6(); + sysWrapperSLC5.delegateToFake(); + sysWrapperSLC6.delegateToFake(); + test_functor(sysWrapperSLC5); + test_functor(sysWrapperSLC6); +} + +TEST(castor_tape_drive_Drive, getWriteErrors) { + struct { + void operator()(castor::tape::System::mockWrapper &sysWrapper) { + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(68)); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, open(_, _)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(AtLeast(76)); + EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<mtget*>())).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<sg_io_hdr_t *>())).Times(4); + EXPECT_CALL(sysWrapper, close(_)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, stat(_, _)).Times(AtLeast(14)); + + /* Test: detect devices, then open the device files */ + castor::tape::SCSI::DeviceVector dl(sysWrapper); + for (std::vector<castor::tape::SCSI::DeviceInfo>::iterator i = dl.begin(); + i != dl.end(); i++) { + if (castor::tape::SCSI::Types::tape == i->type) { + std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive( + castor::tape::tapeserver::drive::createDrive(*i, sysWrapper)); + std::map<std::string,uint32_t> writeErrorsStats = + drive->getTapeWriteErrors(); + ASSERT_EQ(2, writeErrorsStats["mountTotalCorrectedWriteErrors"]); + ASSERT_EQ(2048, writeErrorsStats["mountTotalWriteBytesProcessed"]); + ASSERT_EQ(1, writeErrorsStats["mountTotalUncorrectedWriteErrors"]); + } + } + } + } test_functor; + + castor::tape::System::mockWrapper sysWrapperSLC5; + castor::tape::System::mockWrapper sysWrapperSLC6; + sysWrapperSLC5.fake.setupSLC5(); + sysWrapperSLC6.fake.setupSLC6(); + sysWrapperSLC5.delegateToFake(); + sysWrapperSLC6.delegateToFake(); + test_functor(sysWrapperSLC5); + test_functor(sysWrapperSLC6); +} + +TEST(castor_tape_drive_Drive, getNonMediumErrors) { + struct { + void operator()(castor::tape::System::mockWrapper &sysWrapper) { + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(68)); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, open(_, _)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(AtLeast(76)); + EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<mtget*>())).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<sg_io_hdr_t *>())).Times(4); + EXPECT_CALL(sysWrapper, close(_)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, stat(_, _)).Times(AtLeast(14)); + + /* Test: detect devices, then open the device files */ + castor::tape::SCSI::DeviceVector dl(sysWrapper); + for (std::vector<castor::tape::SCSI::DeviceInfo>::iterator i = dl.begin(); + i != dl.end(); i++) { + if (castor::tape::SCSI::Types::tape == i->type) { + std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive( + castor::tape::tapeserver::drive::createDrive(*i, sysWrapper)); + std::map<std::string,uint32_t> nonMediumErrorsStats = + drive->getTapeNonMediumErrors(); + ASSERT_EQ(3, nonMediumErrorsStats["mountTotalNonMediumErrorCounts"]); + } + } + } + } test_functor; + + castor::tape::System::mockWrapper sysWrapperSLC5; + castor::tape::System::mockWrapper sysWrapperSLC6; + sysWrapperSLC5.fake.setupSLC5(); + sysWrapperSLC6.fake.setupSLC6(); + sysWrapperSLC5.delegateToFake(); + sysWrapperSLC6.delegateToFake(); + test_functor(sysWrapperSLC5); + test_functor(sysWrapperSLC6); +} + +TEST(castor_tape_drive_Drive, getVolumeStats) { + struct { + void operator()(castor::tape::System::mockWrapper &sysWrapper) { + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(68)); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, open(_, _)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(AtLeast(76)); + EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<mtget*>())).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<sg_io_hdr_t *>())).Times(2); + EXPECT_CALL(sysWrapper, close(_)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, stat(_, _)).Times(AtLeast(14)); + + + /* Test: detect devices, then open the device files */ + castor::tape::SCSI::DeviceVector dl(sysWrapper); + for (std::vector<castor::tape::SCSI::DeviceInfo>::iterator i = dl.begin(); + i != dl.end(); i++) { + if (castor::tape::SCSI::Types::tape == i->type) { + std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive( + castor::tape::tapeserver::drive::createDrive(*i, sysWrapper)); + if (castor::tape::tapeserver::drive::DriveIBM3592* ibm_drive = + dynamic_cast<castor::tape::tapeserver::drive::DriveIBM3592*>(drive.get())) { + std::map<std::string,uint32_t> volumeStats = + ibm_drive->getVolumeStats(); + ASSERT_EQ(true, volumeStats["validity"]); + ASSERT_EQ(18886754, volumeStats["lifetimeVolumeMounts"]); + ASSERT_EQ(16843223, volumeStats["lifetimeVolumeRecoveredReadErrors"]); + ASSERT_EQ(514, volumeStats["lifetimeVolumeUnrecoveredReadErrors"]); + ASSERT_EQ(16909057, volumeStats["lifetimeVolumeRecoveredWriteErrors"]); + ASSERT_EQ(1, volumeStats["lifetimeVolumeUnrecoveredWriteErrors"]); + ASSERT_EQ(20140815, volumeStats["volumeManufacturingDate"]); + ASSERT_EQ(33752868, volumeStats["lifetimeBOTPasses"]); + ASSERT_EQ(16908566, volumeStats["lifetimeMOTPasses"]); + } + } + } + } + } test_functor; + + castor::tape::System::mockWrapper sysWrapperSLC5; + castor::tape::System::mockWrapper sysWrapperSLC6; + sysWrapperSLC5.fake.setupSLC5(); + sysWrapperSLC6.fake.setupSLC6(); + sysWrapperSLC5.delegateToFake(); + sysWrapperSLC6.delegateToFake(); + test_functor(sysWrapperSLC5); + test_functor(sysWrapperSLC6); +} + +TEST(castor_tape_drive_Drive, getQualityStats) { + struct { + void operator()(castor::tape::System::mockWrapper &sysWrapper) { + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(68)); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, open(_, _)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(AtLeast(76)); + EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<mtget*>())).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<sg_io_hdr_t *>())).Times(10); + EXPECT_CALL(sysWrapper, close(_)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, stat(_, _)).Times(AtLeast(14)); + + /* Test: detect devices, then open the device files */ + castor::tape::SCSI::DeviceVector dl(sysWrapper); + for (std::vector<castor::tape::SCSI::DeviceInfo>::iterator i = dl.begin(); + i != dl.end(); i++) { + if (castor::tape::SCSI::Types::tape == i->type) { + std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive( + castor::tape::tapeserver::drive::createDrive(*i, sysWrapper)); + std::map<std::string,float> qualityStats = drive->getQualityStats(); + /* + * Assertions for common metrics are moved inside the special cases + * due to different scales and representation of the same quality metrics. + */ + if (dynamic_cast<castor::tape::tapeserver::drive::DriveIBM3592 *>(drive.get())) { + + ASSERT_EQ(68, (int)qualityStats["lifetimeDriveEfficiencyPrct"]); + ASSERT_EQ(68, (int)qualityStats["lifetimeInterfaceEfficiency0Prct"]); + ASSERT_EQ(68, (int)qualityStats["lifetimeInterfaceEfficiency1Prct"]); + ASSERT_EQ(68, (int)qualityStats["lifetimeLibraryEfficiencyPrct"]); + ASSERT_EQ(96, (int)qualityStats["lifetimeReadEfficiencyPrct"]); + ASSERT_EQ(98, (int)qualityStats["lifetimeWriteEfficiencyPrct"]); + ASSERT_EQ(68, (int)qualityStats["lifetimeMediumEfficiencyPrct"]); + + ASSERT_EQ(68, (int)qualityStats["mountDriveEfficiencyPrct"]); + ASSERT_EQ(68, (int)qualityStats["mountInterfaceEfficiency0Prct"]); + ASSERT_EQ(68, (int)qualityStats["mountInterfaceEfficiency1Prct"]); + ASSERT_EQ(68, (int)qualityStats["mountLibraryEfficiencyPrct"]); + ASSERT_EQ(96, (int)qualityStats["mountReadEfficiencyPrct"]); + ASSERT_EQ(98, (int)qualityStats["mountWriteEfficiencyPrct"]); + ASSERT_EQ(68, (int)qualityStats["mountMediumEfficiencyPrct"]); + } + else if (dynamic_cast<castor::tape::tapeserver::drive::DriveT10000 *>(drive.get())) { + + ASSERT_EQ(87, (int)qualityStats["mountReadEfficiencyPrct"]); + ASSERT_EQ(100, (int)qualityStats["mountWriteEfficiencyPrct"]); + ASSERT_EQ(99, (int)qualityStats["lifetimeMediumEfficiencyPrct"]); + ASSERT_EQ(100, (int)qualityStats["mountReadBackCheckQualityIndexPrct"]); + } + else { + // write test code in case quality statistics are populated of other vendors + } + } + } + } + } test_functor; + + castor::tape::System::mockWrapper sysWrapperSLC5; + castor::tape::System::mockWrapper sysWrapperSLC6; + sysWrapperSLC5.fake.setupSLC5(); + sysWrapperSLC6.fake.setupSLC6(); + sysWrapperSLC5.delegateToFake(); + sysWrapperSLC6.delegateToFake(); + test_functor(sysWrapperSLC5); + test_functor(sysWrapperSLC6); +} + +TEST(castor_tape_drive_Drive, getDriveStats) { + struct { + void operator()(castor::tape::System::mockWrapper &sysWrapper) { + EXPECT_CALL(sysWrapper, opendir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(68)); + EXPECT_CALL(sysWrapper, closedir(_)).Times(AtLeast(5)); + EXPECT_CALL(sysWrapper, realpath(_, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, open(_, _)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, read(_, _, _)).Times(AtLeast(76)); + EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<mtget*>())).Times(0); + EXPECT_CALL(sysWrapper, ioctl(_, _, An<sg_io_hdr_t *>())).Times(8); + EXPECT_CALL(sysWrapper, close(_)).Times(AtLeast(42)); + EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(AtLeast(6)); + EXPECT_CALL(sysWrapper, stat(_, _)).Times(AtLeast(14)); + + /* Test: detect devices, then open the device files */ + castor::tape::SCSI::DeviceVector dl(sysWrapper); + for (std::vector<castor::tape::SCSI::DeviceInfo>::iterator i = dl.begin(); + i != dl.end(); i++) { + if (castor::tape::SCSI::Types::tape == i->type) { + std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive( + castor::tape::tapeserver::drive::createDrive(*i, sysWrapper)); + std::map<std::string,uint32_t> driveStats = drive->getDriveStats(); + + /* + * Assertions for common metrics are moved inside the special cases + * due to different scales. Moreover, ibm gathers the statistics from multiple source + * So, this distinction aims to deduplicate as far as possible the tests of different + * drives in order for future changes to be easier to test. + */ + + if (dynamic_cast<castor::tape::tapeserver::drive::DriveIBM3592 *>(drive.get())) { + ASSERT_EQ(687, driveStats["mountServoTemps"]); + ASSERT_EQ(771, driveStats["mountServoTransients"]); + ASSERT_EQ(753, driveStats["mountTemps"]); + ASSERT_EQ(497, driveStats["mountReadTransients"]); + ASSERT_EQ(258, driveStats["mountWriteTransients"]); + ASSERT_EQ(273, driveStats["mountTotalReadRetries"]); + ASSERT_EQ(306, driveStats["mountTotalWriteRetries"]); + } + else if (dynamic_cast<castor::tape::tapeserver::drive::DriveT10000 *>(drive.get())) { + ASSERT_EQ(531, driveStats["mountServoTemps"]); + ASSERT_EQ(137743, driveStats["mountServoTransients"]); + ASSERT_EQ(16777217, driveStats["mountTemps"]); + ASSERT_EQ(65794, driveStats["mountReadTransients"]); + ASSERT_EQ(16843266, driveStats["mountWriteTransients"]); + ASSERT_EQ(16909060, driveStats["mountTotalReadRetries"]); + ASSERT_EQ(65535, driveStats["mountTotalWriteRetries"]); + } + } + } + } + } test_functor; + castor::tape::System::mockWrapper sysWrapperSLC5; + castor::tape::System::mockWrapper sysWrapperSLC6; + sysWrapperSLC5.fake.setupSLC5(); + sysWrapperSLC6.fake.setupSLC6(); + sysWrapperSLC5.delegateToFake(); + sysWrapperSLC6.delegateToFake(); + test_functor(sysWrapperSLC5); + test_functor(sysWrapperSLC6); +} + TEST(castor_tape_drive_Drive, getTapeAlerts) { /** diff --git a/tapeserver/castor/tape/tapeserver/drive/FakeDrive.cpp b/tapeserver/castor/tape/tapeserver/drive/FakeDrive.cpp index 5922947fc8205062b8873a82623f9f0bc6cf8835..758756afa7f2a013b962532dd70b784e7cc5a5a3 100644 --- a/tapeserver/castor/tape/tapeserver/drive/FakeDrive.cpp +++ b/tapeserver/castor/tape/tapeserver/drive/FakeDrive.cpp @@ -276,3 +276,62 @@ castor::tape::tapeserver::drive::lbpToUse bool castor::tape::tapeserver::drive::FakeDrive::hasTapeInPlace() { return true; } + +std::map<std::string,uint32_t> castor::tape::tapeserver::drive::FakeDrive::getTapeWriteErrors() { + std::map<std::string,uint32_t> writeErrorsStats; + writeErrorsStats["mountTotalCorrectedWriteErrors"] = 5; + writeErrorsStats["mountTotalWriteBytesProcessed"] = 4096; + writeErrorsStats["mountTotalUncorrectedWriteErrors"] = 1; + + return writeErrorsStats; +} + +std::map<std::string,uint32_t> castor::tape::tapeserver::drive::FakeDrive::getTapeReadErrors() { + std::map<std::string,uint32_t> readErrorsStats; + readErrorsStats["mountTotalCorrectedReadErrors"]= 5; + readErrorsStats["mountTotalReadBytesProcessed"] = 4096; + readErrorsStats["mountTotalUncorrectedReadErrors"]= 1; + + return readErrorsStats; +} + +std::map<std::string,uint32_t> castor::tape::tapeserver::drive::FakeDrive::getTapeNonMediumErrors() { + std::map<std::string,uint32_t> nonMediumErrorsStats; + nonMediumErrorsStats["mountTotalNonMediumErrorCounts"] = 2; + + return nonMediumErrorsStats; +} + +std::map<std::string,float> castor::tape::tapeserver::drive::FakeDrive::getQualityStats() { + // Only common IBM and Oracle stats are included in the return value; + std::map<std::string,float> qualityStats; + qualityStats["lifetimeMediumEfficiencyPrct"] = 100.0; + qualityStats["mountReadEfficiencyPrct"] = 100.0; + qualityStats["mountWriteEfficiencyPrct"] = 100.0; + + return qualityStats; +} + +std::map<std::string,uint32_t> castor::tape::tapeserver::drive::FakeDrive::getDriveStats() { + std::map<std::string,uint32_t> driveStats; + + driveStats["mountTemps"] = 100; + driveStats["mountReadTransients"] = 10; + driveStats["mountWriteTransients"] = 10; + driveStats["mountTotalReadRetries"] = 25; + driveStats["mountTotalWriteRetries"] = 25; + driveStats["mountServoTemps"] = 10; + driveStats["mountServoTransients"] = 5; + + return driveStats; +} + +std::string castor::tape::tapeserver::drive::FakeDrive::getDriveFirmwareVersion() { + return std::string("123A"); +} + +std::map<std::string,uint32_t> castor::tape::tapeserver::drive::FakeDrive::getVolumeStats() { + // No available data + return std::map<std::string,uint32_t>(); +} + diff --git a/tapeserver/castor/tape/tapeserver/drive/FakeDrive.hpp b/tapeserver/castor/tape/tapeserver/drive/FakeDrive.hpp index 2bdd73982464bc8678529b26606991ea172bb5ef..fa9845f657a72357417b3d277aa0d31020ddde97 100644 --- a/tapeserver/castor/tape/tapeserver/drive/FakeDrive.hpp +++ b/tapeserver/castor/tape/tapeserver/drive/FakeDrive.hpp @@ -59,6 +59,13 @@ namespace drive { virtual ~FakeDrive() throw(){} virtual compressionStats getCompression() ; virtual void clearCompressionStats() ; + virtual std::map<std::string,uint32_t> getTapeWriteErrors(); + virtual std::map<std::string,uint32_t> getTapeReadErrors(); + virtual std::map<std::string,uint32_t> getTapeNonMediumErrors(); + virtual std::map<std::string,float> getQualityStats(); + virtual std::map<std::string,uint32_t> getDriveStats(); + virtual std::map<std::string,uint32_t> getVolumeStats(); + virtual std::string getDriveFirmwareVersion(); virtual deviceInfo getDeviceInfo() ; virtual std::string getSerialNumber() ; virtual void positionToLogicalObject(uint32_t blockId) ; diff --git a/tapeserver/castor/tape/tapeserver/system/FileWrappers.cpp b/tapeserver/castor/tape/tapeserver/system/FileWrappers.cpp index 692c0d633714b284819ddfdb8ff2f4a9548f06fb..b8ce64335ce95f0fc1671c3ac57f38d443c382fe 100644 --- a/tapeserver/castor/tape/tapeserver/system/FileWrappers.cpp +++ b/tapeserver/castor/tape/tapeserver/system/FileWrappers.cpp @@ -252,9 +252,15 @@ int System::stDeviceFile::ioctlLogSense(sg_io_hdr_t * sgio_h) { return -1; } switch (cdb.pageCode) { + case SCSI::logSensePages::readErrors: + return logSenseReadErrorsPage(sgio_h); + case SCSI::logSensePages::writeErrors: + return logSenseWriteErrorsPage(sgio_h); + case SCSI::logSensePages::nonMediumErrors: + return logSenseNonMediumErrorsPage(sgio_h); case SCSI::logSensePages::sequentialAccessDevicePage: return logSenseSequentialAccessDevicePage(sgio_h); - case SCSI::logSensePages::dataCompression32h: + case SCSI::logSensePages::dataCompression32h: // SCSI::logSensePages::driveWriteErrors return logSenseDataCompression32h(sgio_h); case SCSI::logSensePages::blockBytesTransferred: return logSenseBlockBytesTransferred(sgio_h); @@ -264,6 +270,534 @@ int System::stDeviceFile::ioctlLogSense(sg_io_hdr_t * sgio_h) { errno = EINVAL; return -1; } + +int System::stOracleT10000Device::ioctlLogSense(sg_io_hdr_t * sgio_h) { + int superRes = System::stDeviceFile::ioctlLogSense(sgio_h); + /* + * The following checks have to be redone because we don't know why the super + * function might have failed. It may be because of the checks, it may be because + * it did not find any page, it may be because the specific ioctl failed. + */ + if (superRes == -1) { + if (SG_DXFER_FROM_DEV != sgio_h->dxfer_direction) { + errno = EINVAL; + return -1; + } + SCSI::Structures::logSenseCDB_t &cdb = + *(SCSI::Structures::logSenseCDB_t *) sgio_h->cmdp; + if (1 != cdb.PC || 0 == SCSI::Structures::toU16(cdb.allocationLength)) { + errno = EINVAL; + return -1; + } + /* + * Here we are parsing only Oracle T10000 specific pages. + */ + switch (cdb.pageCode) { + case SCSI::logSensePages::vendorUniqueDriveStatistics: + return logSenseVendorUniqueDriveStatisticsPage(sgio_h); + } + errno = EINVAL; + return -1; + } + else + return superRes; +} + +int System::stIBM3592DeviceFile::ioctlLogSense(sg_io_hdr_t * sgio_h) { + int superRes = System::stDeviceFile::ioctlLogSense(sgio_h); + /* + * The following checks have to be redone because we don't know why the super + * function might have failed. It may be because of the checks, it may be because + * it did not find any page, it may be because the specific ioctl failed. + */ + + /* + * In this function, we deliberately don't check the result of the parent function's + * output because we have a conflict between the LogSense codes (dataCompression32h and + * driveWriteErrors). So, even if the logSenseDataCompression32h() gets executed, we still want to execute + * the logSenseDriveWriteErrorsPage() function. + * Still, we need to **account for the redundant ioctl call** in the assertions. + */ + + if (SG_DXFER_FROM_DEV != sgio_h->dxfer_direction) { + errno = EINVAL; + return -1; + } + SCSI::Structures::logSenseCDB_t &cdb = + *(SCSI::Structures::logSenseCDB_t *) sgio_h->cmdp; + if (1 != cdb.PC || 0 == SCSI::Structures::toU16(cdb.allocationLength)) { + errno = EINVAL; + return -1; + } + /* + * Here we are parsing only IBM 3592 specific pages. + */ + switch (cdb.pageCode) { + case SCSI::logSensePages::volumeStatistics: + return logSenseVolumeStatisticsPage(sgio_h); + case SCSI::logSensePages::driveWriteErrors: + return logSenseDriveWriteErrorsPage(sgio_h); + case SCSI::logSensePages::driveReadForwardErrors: + return logSenseDriveReadForwardErrorsPage(sgio_h); + case SCSI::logSensePages::driveReadBackwardErrors: + return logSenseDriveReadBackwardErrorsPage(sgio_h); + case SCSI::logSensePages::performanceCharacteristics: + return logSensePerformanceCharacteristicsPage(sgio_h); + } + if (superRes == -1) { + errno = EINVAL; + return -1; + } + else + return superRes; +} + +int System::stOracleT10000Device::logSenseReadErrorsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x03, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x04, // 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x74, 0x04, // 0x10 + 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x74, 0x08, // 0x20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x06, 0x74, 0x04, 0x00, 0x00, 0x00, 0x01 // 0x30 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stIBM3592DeviceFile::logSenseReadErrorsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x03, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x60, 0x02, 0x00, 0x02, // 0x00 + 0x00, 0x05, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x60, 0x02, 0x00, 0x01 // 0x10 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stOracleT10000Device::logSenseWriteErrorsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x02, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x04, // 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x74, 0x04, // 0x10 + 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x74, 0x08, // 0x20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x06, 0x74, 0x04, 0x00, 0x00, 0x00, 0x01 // 0x30 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stIBM3592DeviceFile::logSenseWriteErrorsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x02, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x60, 0x02, 0x00, 0x02, // 0x00 + 0x00, 0x05, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x60, 0x02, 0x00, 0x01 // 0x10 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stOracleT10000Device::logSenseNonMediumErrorsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x06, 0x00, 0x00, 0x08, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, 0x00, 0x03 // 0x00 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stIBM3592DeviceFile::logSenseNonMediumErrorsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x06, 0x00, 0x00, 0x08, 0x00, 0x00, 0x74, 0x04, 0x00, 0x00, 0x00, 0x03 // 0x00 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stIBM3592DeviceFile::logSenseVolumeStatisticsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x57, 0x01, 0x02, 0x4c, 0x00, 0x00, 0x43, 0x01, 0x01, 0x00, 0x01, 0x43, 0x04, 0x01, 0x20, 0x30, //0x00 + 0x62, 0x00, 0x02, 0x43, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xce, 0xf8, 0x00, 0x03, 0x43, //0x10 + 0x04, 0x01, 0x02, 0x03, 0x01, 0x00, 0x04, 0x43, 0x02, 0x00, 0x01, 0x00, 0x05, 0x43, 0x02, 0x00, //0x20 + 0x04, 0x00, 0x06, 0x43, 0x02, 0x00, 0x00, 0x00, 0x07, 0x43, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, //0x30 + 0x16, 0x98, 0x68, 0x00, 0x08, 0x43, 0x04, 0x01, 0x01, 0x01, 0xd7, 0x00, 0x09, 0x43, 0x02, 0x02, //0x40 + 0x02, 0x00, 0x0c, 0x43, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x43, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x43, //0x50 + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0f, 0x43, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x10, 0x43, //0x60 + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x98, 0x2b, 0x00, 0x11, 0x43, 0x08, 0x00, 0x00, 0x00, //0x70 + 0x00, 0x00, 0x71, 0xad, 0x59, 0x00, 0x12, 0x43, 0x02, 0x00, 0x00, 0x00, 0x13, 0x43, 0x02, 0x00, //0x80 + 0xc3, 0x00, 0x14, 0x43, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x82, 0x00, 0x15, 0x43, 0x06, 0x00, //0x90 + 0x00, 0x00, 0x00, 0x2c, 0x2f, 0x00, 0x16, 0x43, 0x04, 0x00, 0x98, 0x96, 0x80, 0x00, 0x17, 0x43, //0xa0 + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x40, 0x41, 0x20, 0x31, 0x34, 0x37, 0x45, 0x42, 0x30, 0x32, //0xb0 + 0x35, 0x36, 0x35, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, //0xc0 + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x41, 0x41, 0x08, 0x32, 0x30, 0x32, //0xd0 + 0x30, 0x32, 0x30, 0x32, 0x30, 0x00, 0x42, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, //0xe0 + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, //0xf0 + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x43, 0x41, 0x08, 0x49, 0x42, 0x4d, //0x100 + 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x44, 0x41, 0x04, 0x55, 0x31, 0x30, 0x37, 0x00, 0x45, 0x41, //0x110 + 0x08, 0x33, 0x35, 0x39, 0x32, 0x4a, 0x44, 0x47, 0x35, 0x00, 0x46, 0x41, 0x08, 0x32, 0x30, 0x31, //0x120 + 0x34, 0x30, 0x38, 0x31, 0x35, 0x00, 0x80, 0x43, 0x01, 0x00, 0x00, 0x81, 0x43, 0x01, 0x00, 0x00, //0x130 + 0x82, 0x43, 0x01, 0x00, 0x01, 0x00, 0x43, 0x04, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x01, 0x43, 0x04, //0x140 + 0x02, 0x03, 0x07, 0x24, 0x01, 0x02, 0x43, 0x04, 0x01, 0x02, 0x01, 0x16, 0x02, 0x00, 0x43, 0x0a, //0x150 + 0x09, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x01, 0x43, 0x0a, 0x09, 0x00, //0x160 + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x02, 0x43, 0x08, 0x07, 0x00, 0x00, 0x00, //0x170 + 0x00, 0x98, 0x96, 0x80, 0x02, 0x03, 0x43, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, //0x180 + 0x02, 0x04, 0x43, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00, 0x98, 0x96, 0x79, 0x03, 0x00, 0x43, 0xb0, //0x190 + 0x2c, 0x00, 0x00, 0x00, 0x49, 0x42, 0x4d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x30, 0x37, //0x1a0 + 0x38, 0x44, 0x38, 0x34, 0x39, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, //0x1b0 + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2c, 0x00, 0x00, 0x01, //0x1c0 + 0x49, 0x42, 0x4d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x30, 0x37, 0x38, 0x44, 0x38, 0x34, //0x1d0 + 0x39, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, //0x1e0 + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2c, 0x00, 0x00, 0x02, 0x49, 0x42, 0x4d, 0x20, //0x1f0 + 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x30, 0x37, 0x38, 0x44, 0x38, 0x34, 0x39, 0x41, 0x20, 0x20, //0x200 + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, //0x210 + 0x20, 0x20, 0x20, 0x20, 0x2c, 0x00, 0x00, 0x03, 0x49, 0x42, 0x4d, 0x20, 0x20, 0x20, 0x20, 0x20, //0x220 + 0x30, 0x30, 0x30, 0x37, 0x38, 0x44, 0x38, 0x34, 0x39, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, //0x230 + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 //0x240 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stOracleT10000Device::logSenseVendorUniqueDriveStatisticsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x3d, 0x00, 0x0c, 0x08, 0x01, 0x00, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x74, 0x04, // 0x00 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x74, 0x04, // 0x10 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x74, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x05, 0x74, 0x04, // 0x20 + 0x00, 0x01, 0x01, 0x02, 0x01, 0x06, 0x74, 0x04, 0x01, 0x01, 0x02, 0x02, 0x01, 0x07, 0x74, 0x04, // 0x30 + 0x00, 0x00, 0x02, 0x13, 0x01, 0x08, 0x74, 0x04, 0x00, 0x02, 0x1a, 0x0f, 0x01, 0x09, 0x74, 0x04, // 0x40 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0b, 0x74, 0x04, // 0x50 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x74, 0x04, // 0x60 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x74, 0x04, 0x00, 0x00, 0x01, 0x9a, 0x01, 0x10, 0x74, 0x04, // 0x70 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x74, 0x04, // 0x80 + 0x00, 0x00, 0xff, 0xff, 0x01, 0x14, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x15, 0x74, 0x04, // 0x90 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x16, 0x74, 0x04, 0x00, 0x00, 0x00, 0x65, 0x01, 0x17, 0x74, 0x04, // 0xa0 + 0x00, 0x00, 0x00, 0x01, 0x01, 0x18, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x74, 0x04, // 0xb0 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x74, 0x04, // 0xc0 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x74, 0x04, // 0xd0 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x74, 0x04, // 0xe0 + 0x01, 0x00, 0x00, 0x01, 0x02, 0x04, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x74, 0x08, // 0xf0 + 0x00, 0x00, 0x00, 0x00, 0x0f, 0xa8, 0x03, 0x70, 0x03, 0x01, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, // 0x100 + 0x0f, 0xb0, 0x54, 0x58, 0x03, 0x02, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x110 + 0x03, 0x03, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x74, 0x08, // 0x120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf9, 0x03, 0x05, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, // 0x130 + 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf9, // 0x140 + 0x03, 0x07, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0x74, 0x08, // 0x150 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x03, 0x09, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, // 0x160 + 0x00, 0x00, 0x00, 0x00, 0x03, 0x0b, 0x74, 0x04, 0x00, 0x00, 0x00, 0x07, 0x03, 0x0c, 0x74, 0x08, // 0x170 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0d, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, // 0x180 + 0x00, 0x00, 0x0f, 0x8d, 0x03, 0x0e, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0f, 0x74, 0x08, // 0x190 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x03, 0x10, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, // 0x1a0 + 0x00, 0x00, 0x52, 0xa0, 0x03, 0x11, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0xf1, // 0x1b0 + 0x03, 0x12, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x7f, 0x03, 0x13, 0x74, 0x08, // 0x1c0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, // 0x1d0 + 0x00, 0x00, 0x00, 0x00, 0x03, 0x15, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1e0 + 0x03, 0x16, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x74, 0x04, // 0x1f0 + 0x00, 0x00, 0x03, 0xde, 0x04, 0x01, 0x74, 0x04, 0x00, 0x00, 0x36, 0xaf, 0x04, 0x02, 0x74, 0x04, // 0x200 + 0x00, 0x00, 0x3e, 0x80, 0x04, 0x03, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x74, 0x04, // 0x210 + 0x00, 0x00, 0x00, 0x00, 0x04, 0x07, 0x74, 0x04, 0x00, 0x00, 0x03, 0xe8, 0x04, 0x08, 0x74, 0x04, // 0x220 + 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x74, 0x40, 0x00, 0x00, 0x01, 0x63, 0x00, 0x00, 0x00, 0x05, // 0x230 + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x240 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x250 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x260 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x74, 0x10, 0x00, 0x00, 0x53, 0x65, // 0x270 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x74, 0x10, // 0x280 + 0x00, 0x00, 0x53, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x290 + 0x12, 0x00, 0x74, 0x20, 0x00, 0x00, 0x53, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // 0x2a0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, // 0x2b0 + 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x74, 0x20, 0x00, 0x00, 0x53, 0x58, 0x00, 0x00, 0x00, 0x00, // 0x2c0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // 0x2d0 + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x74, 0x20, 0x00, 0x00, 0x53, 0x65, // 0x2e0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2f0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x03, 0x74, 0x20, // 0x300 + 0x00, 0x00, 0x53, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x310 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x320 + 0x13, 0x10, 0x74, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x330 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x340 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x350 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x360 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x370 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x380 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x390 + 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x2d, 0x00, 0x00, 0x00, 0x00, // 0x3a0 + 0x00, 0x00, 0x25, 0x99, 0x13, 0x11, 0x74, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0b, // 0x3b0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, // 0x3c0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3d0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3e0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3f0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x400 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x410 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x420 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x74, 0x80, 0x00, 0x00, 0x00, 0x00, // 0x430 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x440 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x450 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x460 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x470 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x480 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x490 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, // 0x4a0 + 0x00, 0x00, 0x03, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0xd5, 0x13, 0x21, 0x74, 0x80, // 0x4b0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x24, // 0x4c0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x4d0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x4e0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x4f0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x500 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x510 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x520 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x530 + 0x14, 0x00, 0x74, 0x80, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, // 0x540 + 0x00, 0x00, 0x01, 0x6b, 0x00, 0x00, 0x01, 0x6b, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, // 0x550 + 0x00, 0x00, 0x01, 0x6b, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, // 0x560 + 0x00, 0x00, 0x01, 0x6b, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, // 0x570 + 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, // 0x580 + 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6a, // 0x590 + 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6b, 0x00, 0x00, 0x01, 0x6c, // 0x5a0 + 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, 0x00, 0x00, 0x01, 0x6c, // 0x5b0 + 0x00, 0x00, 0x01, 0x6c, 0x14, 0x02, 0x74, 0x80, 0x00, 0x00, 0x22, 0x01, 0x00, 0x00, 0x0c, 0xb6, // 0x5c0 + 0x00, 0x00, 0x1a, 0x70, 0x00, 0x00, 0x1c, 0xf7, 0x00, 0x00, 0x1b, 0x11, 0x00, 0x00, 0x13, 0x98, // 0x5d0 + 0x00, 0x00, 0x22, 0x21, 0x00, 0x00, 0x09, 0xea, 0x00, 0x00, 0x0d, 0xe5, 0x00, 0x00, 0x0c, 0x4e, // 0x5e0 + 0x00, 0x00, 0x0b, 0x07, 0x00, 0x00, 0x14, 0x07, 0x00, 0x00, 0x21, 0xd9, 0x00, 0x00, 0x17, 0x3d, // 0x5f0 + 0x00, 0x00, 0x1a, 0x70, 0x00, 0x00, 0x16, 0x2b, 0x00, 0x00, 0x16, 0xb2, 0x00, 0x00, 0x28, 0xc7, // 0x600 + 0x00, 0x00, 0x12, 0x8a, 0x00, 0x00, 0x18, 0x07, 0x00, 0x00, 0x14, 0x66, 0x00, 0x00, 0x18, 0x8a, // 0x610 + 0x00, 0x00, 0x3d, 0xee, 0x00, 0x00, 0x1e, 0x8d, 0x00, 0x00, 0x0f, 0xf5, 0x00, 0x00, 0x1d, 0xf6, // 0x620 + 0x00, 0x00, 0x11, 0xb1, 0x00, 0x00, 0x11, 0x68, 0x00, 0x00, 0x2d, 0xb4, 0x00, 0x00, 0x18, 0xd3, // 0x630 + 0x00, 0x00, 0x1d, 0x7f, 0x00, 0x00, 0x1d, 0x4e, 0x14, 0x04, 0x74, 0x80, 0x00, 0x00, 0x00, 0x00, // 0x640 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x650 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x660 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x670 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x680 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x690 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x6a0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x6b0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x05, 0x74, 0x80, // 0x6c0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x6d0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x6e0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x6f0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x700 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x710 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x720 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x730 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x740 + 0x14, 0x06, 0x74, 0x80, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0e, // 0x750 + 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d, // 0x760 + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, // 0x770 + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0a, // 0x780 + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, // 0x790 + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5e, // 0x7a0 + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, // 0x7b0 + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, // 0x7c0 + 0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x74, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x7d0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x7e0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x7f0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x800 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x810 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x820 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x830 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x840 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x01, 0x74, 0x80, 0x00, 0x00, 0x01, 0x42, // 0x850 + 0x00, 0x00, 0x02, 0x1d, 0x00, 0x00, 0x01, 0x72, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x74, // 0x860 + 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x01, 0x53, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x00, 0x01, 0xff, // 0x870 + 0x00, 0x00, 0x02, 0x26, 0x00, 0x00, 0x02, 0x17, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x01, 0x35, // 0x880 + 0x00, 0x00, 0x01, 0x9b, 0x00, 0x00, 0x01, 0x77, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x01, 0xa3, // 0x890 + 0x00, 0x00, 0x01, 0x17, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x01, 0x8f, 0x00, 0x00, 0x01, 0xb4, // 0x8a0 + 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x01, 0x6b, 0x00, 0x00, 0x01, 0xe7, // 0x8b0 + 0x00, 0x00, 0x01, 0x65, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x01, 0x0a, // 0x8c0 + 0x00, 0x00, 0x01, 0x85, 0x00, 0x00, 0x01, 0x54, 0x00, 0x00, 0x01, 0x66, 0x15, 0x02, 0x74, 0x80, // 0x8d0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x8e0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x8f0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x900 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x910 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x920 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x930 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x940 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x950 + 0x15, 0x03, 0x74, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, // 0x960 + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, // 0x970 + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, // 0x980 + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, // 0x990 + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, // 0x9a0 + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, // 0x9b0 + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, // 0x9c0 + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, // 0x9d0 + 0x00, 0x00, 0x04, 0x00, 0x15, 0x04, 0x74, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x9e0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x9f0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa30 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa40 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa50 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x05, 0x74, 0x80, 0x00, 0x00, 0x00, 0x00, // 0xa60 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa70 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa80 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa90 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xaa0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xab0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xac0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xad0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x05, 0x74, 0x04, // 0xae0 + 0x00, 0x00, 0x00, 0x00, 0x24, 0x06, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x24, 0x07, 0x74, 0x04, // 0xaf0 + 0x00, 0x00, 0x4d, 0x5a, 0x24, 0x08, 0x74, 0x04, 0x00, 0x00, 0x4d, 0x5a, 0x25, 0x00, 0x74, 0x04, // 0xb00 + 0x28, 0x00, 0x28, 0x28, 0x25, 0x01, 0x74, 0x04, 0x28, 0x00, 0x28, 0x28, 0x25, 0x02, 0x74, 0x04, // 0xb10 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x03, 0x74, 0x04, 0x00, 0x00, 0x00, 0x04, 0x25, 0x04, 0x74, 0x04, // 0xb20 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x05, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x06, 0x74, 0x04, // 0xb30 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x07, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x08, 0x74, 0x04, // 0xb40 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x09, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0a, 0x74, 0x04, // 0xb50 + 0x00, 0x01, 0x1b, 0x15, 0x25, 0x0b, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0c, 0x74, 0x04, // 0xb60 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x0d, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0e, 0x74, 0x04, // 0xb70 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x0f, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x10, 0x74, 0x04, // 0xb80 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x11, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x12, 0x74, 0x04, // 0xb90 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x13, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x14, 0x74, 0x04, // 0xba0 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x15, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x16, 0x74, 0x04, // 0xbb0 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x17, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x18, 0x74, 0x04, // 0xbc0 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1a, 0x74, 0x04, // 0xbd0 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x1b, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1c, 0x74, 0x04, // 0xbe0 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1e, 0x74, 0x04, // 0xbf0 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x1f, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00 // 0xc00 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stIBM3592DeviceFile::logSenseDriveWriteErrorsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x32, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x00, 0x01, 0x60, 0x02, 0x01, 0x01, // 0x00 + 0x00, 0x02, 0x60, 0x02, 0x01, 0x02, 0x00, 0x03, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x60, 0x02, // 0x10 + 0x00, 0x00, 0x00, 0x05, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x60, 0x02, 0x00, 0xac, 0x00, 0x07, // 0x20 + 0x60, 0x02, 0x01, 0x22, 0x00, 0x08, 0x60, 0x02, 0x01, 0x32, 0x00, 0x09, 0x60, 0x02, 0x00, 0x00, // 0x30 + 0x00, 0x0a, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x60, 0x02, // 0x40 + 0x00, 0x00, 0x00, 0x0d, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0f, // 0x50 + 0x60, 0x02, 0x00, 0x00, 0x00, 0x10, 0x60, 0x02, 0x00, 0x00, 0x00, 0x11, 0x60, 0x02, 0x00, 0x00 // 0x60 + }; + + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stIBM3592DeviceFile::logSenseDriveReadForwardErrorsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x34, 0x00, 0x00, 0xba, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x00, 0x01, 0x60, 0x02, 0x01, 0x01, //0x00 + 0x00, 0x02, 0x60, 0x02, 0x00, 0xff, 0x00, 0x03, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x60, 0x02, //0x10 + 0x00, 0x00, 0x00, 0x05, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x60, 0x02, 0x01, 0x01, 0x00, 0x07, //0x20 + 0x60, 0x02, 0x00, 0xcf, 0x00, 0x08, 0x60, 0x02, 0x00, 0x00, 0x00, 0x09, 0x60, 0x02, 0x00, 0x00, //0x30 + 0x00, 0x0a, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x60, 0x02, //0x40 + 0x00, 0x00, 0x00, 0x0d, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0f, //0x50 + 0x60, 0x02, 0x00, 0x00, 0x00, 0x10, 0x60, 0x02, 0x00, 0x00, 0x00, 0x11, 0x60, 0x02, 0x00, 0x00, //0x60 + 0x00, 0x12, 0x60, 0x02, 0x00, 0x00, 0x00, 0x13, 0x60, 0x02, 0x00, 0x00, 0x00, 0x14, 0x60, 0x02, //0x70 + 0x00, 0x00, 0x00, 0x15, 0x60, 0x02, 0x01, 0x11, 0x00, 0x16, 0x60, 0x02, 0x00, 0x00, 0x00, 0x17, //0x80 + 0x60, 0x02, 0x00, 0x00, 0x00, 0x18, 0x60, 0x02, 0x00, 0x00, 0x00, 0x19, 0x60, 0x02, 0x00, 0x00, //0x90 + 0x00, 0x1a, 0x60, 0x02, 0x00, 0x00, 0x00, 0x1b, 0x60, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x60, 0x02, //0xa0 + 0x00, 0x00, 0x00, 0x1d, 0x60, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x60, 0x02, 0x00, 0x00 //0xb0 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stIBM3592DeviceFile::logSenseDriveReadBackwardErrorsPage(sg_io_hdr_t * sgio_h) { + unsigned char output[] = { + 0x36, 0x00, 0x00, 0xba, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x00, 0x01, 0x60, 0x02, 0x01, 0x01, //0x00 + 0x00, 0x02, 0x60, 0x02, 0x00, 0xf2, 0x00, 0x03, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x60, 0x02, //0x10 + 0x00, 0x00, 0x00, 0x05, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x60, 0x02, 0x01, 0x02, 0x00, 0x07, //0x20 + 0x60, 0x02, 0x01, 0x00, 0x00, 0x08, 0x60, 0x02, 0x00, 0x00, 0x00, 0x09, 0x60, 0x02, 0x00, 0x00, //0x30 + 0x00, 0x0a, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x60, 0x02, //0x40 + 0x00, 0x00, 0x00, 0x0d, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0f, //0x50 + 0x60, 0x02, 0x00, 0x00, 0x00, 0x10, 0x60, 0x02, 0x00, 0x00, 0x00, 0x11, 0x60, 0x02, 0x00, 0x00, //0x60 + 0x00, 0x12, 0x60, 0x02, 0x00, 0x00, 0x00, 0x13, 0x60, 0x02, 0x00, 0x00, 0x00, 0x14, 0x60, 0x02, //0x70 + 0x00, 0x00, 0x00, 0x15, 0x60, 0x02, 0x00, 0x00, 0x00, 0x16, 0x60, 0x02, 0x00, 0x00, 0x00, 0x17, //0x80 + 0x60, 0x02, 0x00, 0x00, 0x00, 0x18, 0x60, 0x02, 0x00, 0x00, 0x00, 0x19, 0x60, 0x02, 0x00, 0x00, //0x90 + 0x00, 0x1a, 0x60, 0x02, 0x00, 0x00, 0x00, 0x1b, 0x60, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x60, 0x02, //0xa0 + 0x00, 0x00, 0x00, 0x1d, 0x60, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x60, 0x02, 0x00, 0x00 //0xb0 + }; + if (sizeof (output) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, sizeof (output)); + return 0; +} + +int System::stIBM3592DeviceFile::logSensePerformanceCharacteristicsPage(sg_io_hdr_t * sgio_h) { + SCSI::Structures::logSenseCDB_t* cdb = (SCSI::Structures::logSenseCDB_t*) (sgio_h->cmdp); + unsigned char *output; + unsigned int output_size = 0; + if(cdb->subPageCode == 0x80 || cdb->subPageCode == 0x40) { + unsigned char output_80[] = { + 0x77, 0x80, 0x00, 0x1e, 0x00, 0x00, 0x60, 0x01, 0x50, 0x00, 0x01, 0x60, 0x01, 0x50, 0x00, 0x10, // 0x00 + 0x60, 0x01, 0x01, 0x00, 0x11, 0x60, 0x01, 0x50, 0x00, 0x12, 0x60, 0x01, 0x50, 0x00, 0x1a, 0x60, // 0x10 + 0x01, 0x50 // 0x20 + }; + output = output_80; + output_size = sizeof(output_80); + } + else if(cdb->subPageCode == 0x91 || cdb->subPageCode == 0x51) { ; + unsigned char output_91[] = { + 0x77, 0x91, 0x00, 0xd0, 0x01, 0x02, 0x60, 0x04, 0x00, 0x00, 0x05, 0x59, 0x02, 0x02, 0x60, 0x04, //0x00 + 0x00, 0x00, 0x10, 0x4b, 0x03, 0x02, 0x60, 0x04, 0x00, 0x11, 0x34, 0x7d, 0x03, 0xd0, 0x60, 0x04, //0x10 + 0x00, 0x60, 0x1a, 0xd3, 0x04, 0x02, 0x60, 0x04, 0x00, 0x0f, 0x7c, 0x0b, 0x04, 0xd0, 0x60, 0x04, //0x20 + 0x00, 0x62, 0xf3, 0x75, 0x05, 0x02, 0x60, 0x04, 0x00, 0x02, 0xb1, 0x68, 0x05, 0xd4, 0x60, 0x04, //0x30 + 0x00, 0x00, 0x05, 0x1b, 0x06, 0x02, 0x60, 0x04, 0x00, 0x20, 0x49, 0x13, 0x07, 0x02, 0x60, 0x04, //0x40 + 0x00, 0x06, 0xa7, 0xe9, 0x08, 0x02, 0x60, 0x04, 0x00, 0x00, 0x72, 0xcf, 0x09, 0x02, 0x60, 0x04, //0x50 + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, 0x60, 0x04, 0x00, 0x00, 0x00, 0x2a, 0x0c, 0x02, 0x60, 0x04, //0x60 + 0x00, 0x4d, 0xcb, 0x5c, 0x0c, 0x0e, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x12, 0x60, 0x04, //0x70 + 0x00, 0x4d, 0xcb, 0x5c, 0x0c, 0x1e, 0x60, 0x04, 0x00, 0x00, 0x07, 0x03, 0x0c, 0x22, 0x60, 0x04, //0x80 + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x2e, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xa2, 0x60, 0x04, //0x90 + 0x00, 0x00, 0x22, 0x39, 0x0c, 0xae, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x14, 0x60, 0x04, //0xa0 + 0x00, 0x02, 0x23, 0xac, 0x0d, 0x24, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xa4, 0x60, 0x04, //0xb0 + 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf1, 0x60, 0x04, //0xc0 + 0x00, 0x00, 0x00, 0x00 //0xd0 + }; + output = output_91; + output_size = sizeof(output_91); + } + if (output_size > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + memcpy(sgio_h->dxferp, output, output_size); + return 0; +} + + + + + + + + + int System::stDeviceFile::logSenseSequentialAccessDevicePage(sg_io_hdr_t * sgio_h) { /** * This is a real reply from the enterprise T10000C STK drive. @@ -579,7 +1113,7 @@ int System::stDeviceFile::modeSelectControlDataProtection(sg_io_hdr_t * sgio_h) return 0; } -int System::stDeviceFile::ioctlInquiry(sg_io_hdr_t * sgio_h) { +int System::stOracleT10000Device::ioctlInquiry(sg_io_hdr_t * sgio_h) { if (SG_DXFER_FROM_DEV != sgio_h->dxfer_direction) { errno = EINVAL; return -1; @@ -630,3 +1164,55 @@ int System::stDeviceFile::ioctlInquiry(sg_io_hdr_t * sgio_h) { } return 0; } + +int System::stIBM3592DeviceFile::ioctlInquiry(sg_io_hdr_t * sgio_h) { + if (SG_DXFER_FROM_DEV != sgio_h->dxfer_direction) { + errno = EINVAL; + return -1; + } + SCSI::Structures::inquiryCDB_t & cdb = + *(SCSI::Structures::inquiryCDB_t *) sgio_h->cmdp; + + if (0 == cdb.EVPD && 0 == cdb.pageCode) { + /* the Standard Inquiry Data is returned*/ + SCSI::Structures::inquiryData_t & inqData = + *(SCSI::Structures::inquiryData_t *) sgio_h->dxferp; + if (sizeof (inqData) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + /* fill the replay with random data */ + srandom(SCSI::Commands::INQUIRY); + memset(sgio_h->dxferp, random(), sizeof (inqData)); + /* We fill only fields we need. + * The emptiness in the strings fields we fill with spaces. + * And we do not need '\0' in the end of strings. For the tests + * there are mhvtl data. + */ + const char *prodId = "03592E08 "; + memcpy(inqData.prodId, prodId, sizeof (inqData.prodId)); + const char *prodRevLvl = "460E "; + memcpy(inqData.prodRevLvl, prodRevLvl, sizeof (inqData.prodRevLvl)); + const char *T10Vendor = "IBM "; + memcpy(inqData.T10Vendor, T10Vendor, sizeof (inqData.T10Vendor)); + } else if (1 == cdb.EVPD && SCSI::inquiryVPDPages::unitSerialNumber == cdb.pageCode) { + /* the unit serial number VPD page is returned*/ + SCSI::Structures::inquiryUnitSerialNumberData_t & inqSerialData = + *(SCSI::Structures::inquiryUnitSerialNumberData_t *) sgio_h->dxferp; + if (sizeof (inqSerialData) > sgio_h->dxfer_len) { + errno = EINVAL; + return -1; + } + /* fill the replay with random data */ + srandom(SCSI::Commands::INQUIRY); + memset(sgio_h->dxferp, random(), sgio_h->dxfer_len); + const char serialNumber[11] = "XYZZY_A2 "; + memcpy(inqSerialData.productSerialNumber, serialNumber, 10); + inqSerialData.pageLength = 10; + } else { + errno = EINVAL; + return -1; + } + return 0; +} + diff --git a/tapeserver/castor/tape/tapeserver/system/FileWrappers.hpp b/tapeserver/castor/tape/tapeserver/system/FileWrappers.hpp index 6d7083f42cfbe86fc0df0c96583935139f53e629..e8648c67f17eaeca8d3c0b1d867a8aac9e5d7ad7 100644 --- a/tapeserver/castor/tape/tapeserver/system/FileWrappers.hpp +++ b/tapeserver/castor/tape/tapeserver/system/FileWrappers.hpp @@ -73,7 +73,7 @@ namespace System { virtual int ioctl(unsigned long int request, struct mtop * mt_cmd); virtual int ioctl(unsigned long int request, struct mtget * mt_status); virtual int ioctl(unsigned long int request, sg_io_hdr_t * sgio_h); - private: + protected: struct mtget m_mtStat; struct mtop m_mtCmd; uint32_t blockID; @@ -90,7 +90,7 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int ioctlReadPosition(sg_io_hdr_t * sgio_h); + virtual int ioctlReadPosition(sg_io_hdr_t * sgio_h); /** * This function handles LOG_SELECT CDB and only checks the CDB for the @@ -101,7 +101,7 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int ioctlLogSelect(sg_io_hdr_t * sgio_h); + virtual int ioctlLogSelect(sg_io_hdr_t * sgio_h); /** * This function handles LOCATE_10 CDB and only checks the CDB for the @@ -112,7 +112,7 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int ioctlLocate10(sg_io_hdr_t * sgio_h); + virtual int ioctlLocate10(sg_io_hdr_t * sgio_h); /** * This function handles LOG_SENSE CDB and prepares the replay with @@ -123,7 +123,7 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int ioctlLogSense(sg_io_hdr_t * sgio_h); + virtual int ioctlLogSense(sg_io_hdr_t * sgio_h); /** * This function handles MODE_SENSE_6 CDB and prepares the replay with @@ -134,7 +134,7 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int ioctlModSense6(sg_io_hdr_t * sgio_h); + virtual int ioctlModSense6(sg_io_hdr_t * sgio_h); /** * This function handles MODE_SELECT_6 CDB and only checks the CDB for the @@ -145,7 +145,7 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int ioctlModSelect6(sg_io_hdr_t * sgio_h); + virtual int ioctlModSelect6(sg_io_hdr_t * sgio_h); /** * This function handles INQUIRY CDB and prepares the standard inquiry @@ -156,8 +156,32 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int ioctlInquiry(sg_io_hdr_t * sgio_h); - + virtual int ioctlInquiry(sg_io_hdr_t * sgio_h) = 0; + + /** + * Simulates the response of a LogSense ioctl from the drive to ReadErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseReadErrorsPage(sg_io_hdr_t * sgio_h) = 0; + + /** + * Simulates the response of a LogSense ioctl from the drive to WriteErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseWriteErrorsPage(sg_io_hdr_t * sgio_h) = 0; + + /** + * Simulates the response of a LogSense ioctl from the drive to NonMediumErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseNonMediumErrorsPage(sg_io_hdr_t * sgio_h) = 0; + /** * This function prepares the replay with compression statistics for * LOG SENSE CDB with log page Sequential Access Device Page. We use this @@ -168,7 +192,7 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int logSenseSequentialAccessDevicePage(sg_io_hdr_t * sgio_h); + virtual int logSenseSequentialAccessDevicePage(sg_io_hdr_t * sgio_h); /** * This function prepares the replay with compression statistics for @@ -180,7 +204,7 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int logSenseDataCompression32h(sg_io_hdr_t * sgio_h); + virtual int logSenseDataCompression32h(sg_io_hdr_t * sgio_h); /** * This function prepares the replay with compression statistics for @@ -192,7 +216,8 @@ namespace System { * @return Returns 0 in success and * -1 with appropriate errno if an error occurred. */ - int logSenseBlockBytesTransferred(sg_io_hdr_t * sgio_h); + virtual int logSenseBlockBytesTransferred(sg_io_hdr_t * sgio_h); + /** * This function replies with a pre-cooked error record. As with the real devices, * many parameter codes get reported with a flag set to 0, and a few will @@ -249,6 +274,142 @@ namespace System { */ int modeSelectControlDataProtection(sg_io_hdr_t * sgio_h); }; + + /** + * Specific st device class for IBM 3592. + * Used to test vendor specific features. + */ + class stIBM3592DeviceFile : public stDeviceFile { + public: + /** + * This function handles LOG_SENSE CDB and prepares the replay with + * compression data. + * + * @param sgio_h The pointer to the sg_io_hdr_t structure with + * ioctl call data + * @return Returns 0 in success and + * -1 with appropriate errno if an error occurred. + */ + virtual int ioctlLogSense(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to ReadErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseReadErrorsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to WriteErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseWriteErrorsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to NonMediumErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseNonMediumErrorsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to VolumeStatisticsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseVolumeStatisticsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to driveWriteErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseDriveWriteErrorsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to ReadForwardErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseDriveReadForwardErrorsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to ReadBackwardErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseDriveReadBackwardErrorsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to PerformanceCharacteristicsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSensePerformanceCharacteristicsPage(sg_io_hdr_t * sgio_h); + + virtual int ioctlInquiry(sg_io_hdr_t * sgio_h); + }; + + /** + * Specific st device class for Oracle T10000D. + * Used to test vendor specific features. + */ + class stOracleT10000Device : public stDeviceFile { + public: + /** + * This function handles LOG_SENSE CDB and prepares the replay with + * compression data. + * + * @param sgio_h The pointer to the sg_io_hdr_t structure with + * ioctl call data + * @return Returns 0 in success and + * -1 with appropriate errno if an error occurred. + */ + virtual int ioctlLogSense(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to ReadErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseReadErrorsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to WriteErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseWriteErrorsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to NonMediumErrorsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseNonMediumErrorsPage(sg_io_hdr_t * sgio_h); + + /** + * Simulates the response of a LogSense ioctl from the drive to VendorUniqueDriveStatisticsPage. + * @param sgio_h The pointer to the sg_io_hdr_t structure with + ioctl call data. + * @return Returns 0 in success and -1 with appropriate errno if an error has occurred. + */ + virtual int logSenseVendorUniqueDriveStatisticsPage(sg_io_hdr_t * sgio_h); + + virtual int ioctlInquiry(sg_io_hdr_t * sgio_h); + }; } // namespace System } // namespace tape } // namespace castor diff --git a/tapeserver/castor/tape/tapeserver/system/Wrapper.cpp b/tapeserver/castor/tape/tapeserver/system/Wrapper.cpp index 82fc91d6099dfaa2f684b665f4d75bbac78824a6..70995e3427b9afca86167e587b9eeb1d5c8a01d8 100644 --- a/tapeserver/castor/tape/tapeserver/system/Wrapper.cpp +++ b/tapeserver/castor/tape/tapeserver/system/Wrapper.cpp @@ -213,18 +213,22 @@ void System::fakeWrapper::referenceFiles() { for (std::map<std::string, regularFile>::iterator i = m_regularFiles.begin(); i != m_regularFiles.end(); i++) m_files[i->first] = &m_regularFiles[i->first]; - for (std::map<std::string, stDeviceFile>::iterator i = m_stFiles.begin(); + for (std::map<std::string, stDeviceFile *>::iterator i = m_stFiles.begin(); i != m_stFiles.end(); i++) - m_files[i->first] = &m_stFiles[i->first]; + m_files[i->first] = m_stFiles[i->first]; } /** - * Destructor: delete leftover drive objects + * Destructor: delete leftover drive and device objects */ System::fakeWrapper::~fakeWrapper() { for (auto d=m_pathToDrive.begin(); d!=m_pathToDrive.end(); d++) { delete d->second; d->second = NULL; } + + for (std::map<std::string, stDeviceFile *>::iterator i = m_stFiles.begin(); + i != m_stFiles.end(); i++) + delete m_stFiles[i->first]; } System::mockWrapper::mockWrapper() { @@ -278,6 +282,22 @@ void System::fakeWrapper::setupSLC5() { * Setup an tree similar to what we'll find in * and SLC5 system with mvhtl library (one media exchanger, 2 drives) */ + + /************************************************************************** + * + * == VFS Setup == + * + * - SLC5 + * 3.0.0.0 oracle mediumx sg2 + * 3.0.1.0 oracle tape0 sg0 st0 nst0 + * 3.0.2.0 oracle tape1 sg1 st1 nst1 + * 2.0.0.0 ibm mediumx sg5 + * 2.0.1.0 ibm tape0 sg3 st2 nst2 + * 2.0.2.0 ibm tape1 sg4 st3 nst3 + * + * + **************************************************************************/ + /* * First of, the description of all devices in sysfs. * In SLC5, sysfs is mounted on /sys/. If other mount point appear in the @@ -286,9 +306,10 @@ void System::fakeWrapper::setupSLC5() { */ m_directories["/sys/bus/scsi/devices"].push_back("."); m_directories["/sys/bus/scsi/devices"].push_back(".."); - m_directories["/sys/bus/scsi/devices"].push_back("3:0:0:0"); - m_directories["/sys/bus/scsi/devices"].push_back("3:0:1:0"); - m_directories["/sys/bus/scsi/devices"].push_back("3:0:2:0"); + // Oracle + m_directories["/sys/bus/scsi/devices"].push_back("3:0:0:0"); // mediumx + m_directories["/sys/bus/scsi/devices"].push_back("3:0:1:0"); // tape0 + m_directories["/sys/bus/scsi/devices"].push_back("3:0:2:0"); // tape1 m_realpathes["/sys/bus/scsi/devices/3:0:0:0"] = "/sys/devices/pseudo_0/adapter0/host3/target3:0:0/3:0:0:0"; m_realpathes["/sys/bus/scsi/devices/3:0:1:0"] @@ -408,8 +429,135 @@ void System::fakeWrapper::setupSLC5() { m_stats["/dev/st1"].st_mode = S_IFCHR; m_stats["/dev/nst1"].st_rdev = makedev(9, 129); m_stats["/dev/nst1"].st_mode = S_IFCHR; - m_stFiles["/dev/nst0"]; - m_stFiles["/dev/nst1"]; + m_stFiles["/dev/nst0"] = new stOracleT10000Device(); + m_stFiles["/dev/nst1"] = new stOracleT10000Device(); + + // IBM + m_directories["/sys/bus/scsi/devices"].push_back("2:0:0:0"); // mediumx + m_directories["/sys/bus/scsi/devices"].push_back("2:0:1:0"); // tape0 + m_directories["/sys/bus/scsi/devices"].push_back("2:0:2:0"); // tape1 + m_realpathes["/sys/bus/scsi/devices/2:0:0:0"] + = "/sys/devices/pseudo_0/adapter0/host2/target2:0:0/2:0:0:0"; + m_realpathes["/sys/bus/scsi/devices/2:0:1:0"] + = "/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"; + m_realpathes["/sys/bus/scsi/devices/2:0:2:0"] + = "/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:0/2:0:0:0/type"] = "8\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0/type"] = "1\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0/type"] = "1\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:0/2:0:0:0/vendor"] = "IBM \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0/vendor"] = "IBM \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0/vendor"] = "IBM \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:0/2:0:0:0/model"] = "03584L22 \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0/model"] = "03592E08 \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0/model"] = "03592E08 \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:0/2:0:0:0/rev"] = "F030\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0/rev"] = "460E\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0/rev"] = "460E\n"; + m_links["/sys/devices/pseudo_0/adapter0/host2/target2:0:0/2:0:0:0/generic"] + = "../../../../../../class/scsi_generic/sg5"; + m_links["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0/generic"] + = "../../../../../../class/scsi_generic/sg3"; + m_links["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0/generic"] + = "../../../../../../class/scsi_generic/sg4"; + m_stats["/dev/sg3"].st_rdev = makedev(21, 3); + m_stats["/dev/sg3"].st_mode = S_IFCHR; + m_stats["/dev/sg4"].st_rdev = makedev(21, 4); + m_stats["/dev/sg4"].st_mode = S_IFCHR; + m_stats["/dev/sg5"].st_rdev = makedev(21, 5); + m_stats["/dev/sg5"].st_mode = S_IFCHR; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:0/2:0:0:0/generic/dev"] = "21:5\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0/generic/dev"] = "21:3\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0/generic/dev"] = "21:4\n"; + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("."); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back(".."); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("bus"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("delete"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("device_blocked"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("driver"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("generic"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("iocounterbits"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("iodone_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("ioerr_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("iorequest_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("model"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("power"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("queue_depth"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("queue_type"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("rescan"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("rev"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_device:2:0:1:0"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_generic:sg3"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_level"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_tape:nst2"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_tape:nst2a"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_tape:nst2l"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_tape:nst2m"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_tape:st2"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_tape:st2a"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_tape:st2l"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("scsi_tape:st2m"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("state"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("subsystem"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("tape"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("timeout"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("type"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("uevent"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0"].push_back("vendor"); + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0/scsi_tape:st2/dev"] = + "9:2\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:1/2:0:1:0/scsi_tape:nst2/dev"] = + "9:130\n"; + m_stats["/dev/st2"].st_rdev = makedev(9, 2); + m_stats["/dev/st2"].st_mode = S_IFCHR; + m_stats["/dev/nst2"].st_rdev = makedev(9, 130); + m_stats["/dev/nst2"].st_mode = S_IFCHR; + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("."); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back(".."); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("bus"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("delete"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("device_blocked"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("driver"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("generic"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("iocounterbits"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("iodone_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("ioerr_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("iorequest_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("model"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("power"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("queue_depth"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("queue_type"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("rescan"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("rev"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_device:2:0:2:0"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_generic:sg4"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_level"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_tape:nst3"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_tape:nst3a"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_tape:nst3l"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_tape:nst3m"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_tape:st3"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_tape:st3a"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_tape:st3l"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("scsi_tape:st3m"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("state"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("subsystem"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("tape"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("timeout"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("type"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("uevent"); + m_directories["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0"].push_back("vendor"); + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0/scsi_tape:st3/dev"] = + "9:3\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host2/target2:0:2/2:0:2:0/scsi_tape:nst3/dev"] = + "9:131\n"; + m_stats["/dev/st3"].st_rdev = makedev(9, 3); + m_stats["/dev/st3"].st_mode = S_IFCHR; + m_stats["/dev/nst3"].st_rdev = makedev(9, 131); + m_stats["/dev/nst3"].st_mode = S_IFCHR; + m_stFiles["/dev/nst2"] = new stIBM3592DeviceFile(); + m_stFiles["/dev/nst3"] = new stIBM3592DeviceFile(); + referenceFiles(); } @@ -424,9 +572,25 @@ void System::fakeWrapper::setupSLC6() { * In SLC6, sysfs is mounted on /sys/. If other mount point appear in the * future, we'll have to provide /proc/mounts (and use it). */ + /************************************************************************** + * + * == VFS Setup == + * + * - SLC6 + * 0.0.0.0 hdd sg0 + * 6.0.0.0 oracle mediumx sg3 + * 6.0.1.0 oracle tape0 sg1 st0 nst0 + * 6.0.2.0 oracle tape1 sg2 st1 nst1 + * 5.0.0.0 ibm mediumx sg6 + * 5.0.1.0 ibm tape0 sg4 st2 nst2 + * 5.0.2.0 ibm tape1 sg5 st3 nst3 + * + * + **************************************************************************/ m_directories["/sys/bus/scsi/devices"].push_back("."); m_directories["/sys/bus/scsi/devices"].push_back(".."); m_directories["/sys/bus/scsi/devices"].push_back("0:0:0:0"); /* disk */ + // Oracle - host 6 m_directories["/sys/bus/scsi/devices"].push_back("6:0:0:0"); /* mediumx */ m_directories["/sys/bus/scsi/devices"].push_back("6:0:1:0"); /* tape */ m_directories["/sys/bus/scsi/devices"].push_back("6:0:2:0"); /* tape */ @@ -462,7 +626,7 @@ void System::fakeWrapper::setupSLC6() { m_realpathes["/sys/bus/scsi/devices/host4"] = "/sys/devices/pci0000:00/0000:00:1f.2/host4"; m_realpathes["/sys/bus/scsi/devices/host5"] - = "/sys/devices/pci0000:00/0000:00:1f.2/host5"; + = "/sys/devices/pseudo_0/adapter0/host5"; m_realpathes["/sys/bus/scsi/devices/host6"] = "/sys/devices/pseudo_0/adapter0/host6"; m_realpathes["/sys/bus/scsi/devices/target0:0:0"] @@ -620,8 +784,170 @@ void System::fakeWrapper::setupSLC6() { m_stats["/dev/nst1"].st_rdev = makedev(9, 129); m_stats["/dev/nst1"].st_mode = S_IFCHR; - m_stFiles["/dev/nst0"]; - m_stFiles["/dev/nst1"]; + m_stFiles["/dev/nst0"] = new stOracleT10000Device(); + m_stFiles["/dev/nst1"]= new stOracleT10000Device(); + + // IBM - host 5 + m_directories["/sys/bus/scsi/devices"].push_back("5:0:0:0"); /* mediumx */ + m_directories["/sys/bus/scsi/devices"].push_back("5:0:1:0"); /* tape */ + m_directories["/sys/bus/scsi/devices"].push_back("5:0:2:0"); /* tape */ + + m_directories["/sys/bus/scsi/devices"].push_back("target5:0:0"); + m_directories["/sys/bus/scsi/devices"].push_back("target5:0:1"); + m_directories["/sys/bus/scsi/devices"].push_back("target5:0:2"); + + m_realpathes["/sys/bus/scsi/devices/5:0:0:0"] + = "/sys/devices/pseudo_0/adapter0/host5/target5:0:0/5:0:0:0"; + m_realpathes["/sys/bus/scsi/devices/5:0:1:0"] + = "/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"; + m_realpathes["/sys/bus/scsi/devices/5:0:2:0"] + = "/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"; + + m_realpathes["/sys/bus/scsi/devices/target5:0:0"] + = "/sys/devices/pseudo_0/adapter0/host5/target5:0:0"; + m_realpathes["/sys/bus/scsi/devices/target5:0:1"] + = "/sys/devices/pseudo_0/adapter0/host5/target5:0:1"; + m_realpathes["/sys/bus/scsi/devices/target5:0:2"] + = "/sys/devices/pseudo_0/adapter0/host5/target5:0:2"; + + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:0/5:0:0:0/type"] = "8\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/type"] = "1\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/type"] = "1\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:0/5:0:0:0/vendor"] = "IBM \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/vendor"] = "IBM \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/vendor"] = "IBM \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:0/5:0:0:0/model"] = "03584L22 \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/model"] = "03592E08 \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/model"] = "03592E08 \n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:0/5:0:0:0/rev"] = "F030\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/rev"] = "460E\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/rev"] = "460E\n"; + + m_links["/sys/devices/pseudo_0/adapter0/host5/target5:0:0/5:0:0:0/generic"] + = "scsi_generic/sg6"; + m_links["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/generic"] + = "scsi_generic/sg4"; + m_links["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/generic"] + = "scsi_generic/sg5"; + + m_stats["/dev/sg4"].st_rdev = makedev(21, 4); + m_stats["/dev/sg4"].st_mode = S_IFCHR; + m_stats["/dev/sg5"].st_rdev = makedev(21, 5); + m_stats["/dev/sg5"].st_mode = S_IFCHR; + m_stats["/dev/sg6"].st_rdev = makedev(21, 6); + m_stats["/dev/sg6"].st_mode = S_IFCHR; + + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:0/5:0:0:0/generic/dev"] = "21:6\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/generic/dev"] = "21:4\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/generic/dev"] = "21:5\n"; + + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("."); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back(".."); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("bsg"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("delete"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("device_blocked"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("dh_state"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("driver"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("evt_media_change"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("generic"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("iocounterbits"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("iodone_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("ioerr_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("iorequest_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("modalias"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("model"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("power"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("queue_depth"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("queue_ramp_up_period"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("queue_type"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("rescan"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("rev"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("scsi_device"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("scsi_generic"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("scsi_level"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("scsi_tape"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("state"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("subsystem"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("tape"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("timeout"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("type"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("uevent"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0"].push_back("vendor"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back("."); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back(".."); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back("nst2"); // not really sure + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back("nst2a"); // not really sure + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back("nst2l"); // not really sure + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back("nst2m"); // not really sure + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back("st2"); // not really sure + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back("st2a"); // not really sure + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back("st2l"); // not really sure + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape"].push_back("st2m"); // not really sure + + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape/st2/dev"] = + "9:2\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:1/5:0:1:0/scsi_tape/nst2/dev"] = + "9:130\n"; + m_stats["/dev/st2"].st_rdev = makedev(9, 2); + m_stats["/dev/st2"].st_mode = S_IFCHR; + m_stats["/dev/nst2"].st_rdev = makedev(9, 130); + m_stats["/dev/nst2"].st_mode = S_IFCHR; + + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("."); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back(".."); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("bsg"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("delete"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("device_blocked"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("dh_state"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("driver"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("evt_media_change"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("generic"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("iocounterbits"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("iodone_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("ioerr_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("iorequest_cnt"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("modalias"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("model"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("power"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("queue_depth"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("queue_ramp_up_period"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("queue_type"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("rescan"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("rev"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("scsi_device"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("scsi_generic"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("scsi_level"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("scsi_tape"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("state"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("subsystem"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("tape"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("timeout"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("type"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("uevent"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0"].push_back("vendor"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back("."); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back(".."); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back("nst3"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back("nst3a"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back("nst3l"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back("nst3m"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back("st3"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back("st3a"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back("st3l"); + m_directories["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape"].push_back("st3m"); + + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape/st3/dev"] = + "9:3\n"; + m_regularFiles["/sys/devices/pseudo_0/adapter0/host5/target5:0:2/5:0:2:0/scsi_tape/nst3/dev"] = + "9:131\n"; + m_stats["/dev/st3"].st_rdev = makedev(9, 3); + m_stats["/dev/st3"].st_mode = S_IFCHR; + m_stats["/dev/nst3"].st_rdev = makedev(9, 131); + m_stats["/dev/nst3"].st_mode = S_IFCHR; + + m_stFiles["/dev/nst2"] = new stIBM3592DeviceFile(); + m_stFiles["/dev/nst3"] = new stIBM3592DeviceFile(); + referenceFiles(); } diff --git a/tapeserver/castor/tape/tapeserver/system/Wrapper.hpp b/tapeserver/castor/tape/tapeserver/system/Wrapper.hpp index 326579a215e20050ce6062d946db629eba3f3814..5fe8c41f873eaa22c00829e10e754a8af0dab656 100644 --- a/tapeserver/castor/tape/tapeserver/system/Wrapper.hpp +++ b/tapeserver/castor/tape/tapeserver/system/Wrapper.hpp @@ -144,7 +144,7 @@ namespace System { std::map<std::string, vfsFile *> m_files; std::map<std::string, struct stat> m_stats; std::map<std::string, regularFile> m_regularFiles; - std::map<std::string, stDeviceFile> m_stFiles; + std::map<std::string, stDeviceFile *> m_stFiles; std::map<std::string, castor::tape::tapeserver::drive::DriveInterface *> m_pathToDrive; void setupSLC5(); void setupSLC6();