Commit 14a165d0 authored by Victor Kotlyar's avatar Victor Kotlyar
Browse files

added implementation for getDeviceInfo based on INQUIRY command.

child function getSerialNumber was added.
parent ff8d77a3
......@@ -56,6 +56,7 @@ namespace Tape {
std::string vendor;
std::string product;
std::string productRevisionLevel;
std::string serialNumber;
};
/**
......@@ -154,9 +155,64 @@ namespace Tape {
/**
* Information about the drive. The vendor id is used in the user labels of the files.
* @return
* @return The deviceInfo structure with the information about the drive.
*/
virtual deviceInfo getDeviceInfo() throw (Exception) { throw Exception("Not implemented"); }
virtual deviceInfo getDeviceInfo() throw (Exception) {
SCSI::Structures::inquiryCDB_t cdb;
SCSI::Structures::inquiryData_t inquiryData;
SCSI::Structures::senseData_t<255> senseBuff;
SCSI::Structures::LinuxSGIO_t sgh;
deviceInfo devInfo;
sgh.setCDB(&cdb);
sgh.setDataBuffer(&inquiryData);
sgh.setSenseBuffer(&senseBuff);
sgh.dxfer_direction = SG_DXFER_FROM_DEV;
/* Manage both system error and SCSI errors. */
if (-1 == m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh))
throw Tape::Exceptions::Errnum("Failed SG_IO ioctl");
SCSI::ExceptionLauncher(sgh, std::string("SCSI error in getDeviceInfo: ") +
SCSI::statusToString(sgh.status));
devInfo.product = SCSI::Structures::toString(inquiryData.prodId);
devInfo.productRevisionLevel = SCSI::Structures::toString(inquiryData.prodRevLvl);
devInfo.vendor = SCSI::Structures::toString(inquiryData.T10Vendor);
devInfo.serialNumber = getSerialNumber();
return devInfo;
}
/**
* Information about the serial number of the drive.
* @return Right-aligned ASCII data for the vendor-assigned serial number.
*/
virtual std::string getSerialNumber() throw (Exception) {
SCSI::Structures::inquiryCDB_t cdb;
SCSI::Structures::inquiryUnitSerialNumberData_t inquirySerialData;
SCSI::Structures::senseData_t<255> senseBuff;
SCSI::Structures::LinuxSGIO_t sgh;
cdb.EVPD = 1; /* Enable Vital Product Data */
cdb.pageCode = SCSI::inquiryVPDPages::unitSerialNumber;
cdb.allocationLength[0] = 0;
cdb.allocationLength[1] = sizeof (SCSI::Structures::inquiryUnitSerialNumberData_t);
sgh.setCDB(&cdb);
sgh.setDataBuffer(&inquirySerialData);
sgh.setSenseBuffer(&senseBuff);
sgh.dxfer_direction = SG_DXFER_FROM_DEV;
/* Manage both system error and SCSI errors. */
if (-1 == m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh))
throw Tape::Exceptions::Errnum("Failed SG_IO ioctl");
SCSI::ExceptionLauncher(sgh, std::string("SCSI error in getSerialInfo: ") +
SCSI::statusToString(sgh.status));
std::string serialNumber;
serialNumber.append(inquirySerialData.productSerialNumber,inquirySerialData.pageLength);
return serialNumber;
}
/**
* Position to logical object identifier (i.e. block address).
......
......@@ -195,6 +195,44 @@ TEST(TapeDrive, setStDriverOptions) {
}
}
TEST(TapeDrive, getDeviceInfo) {
/* Prepare the test harness */
Tape::System::mockWrapper sysWrapper;
sysWrapper.fake.setupSLC5();
sysWrapper.delegateToFake();
/* We expect the following calls: */
EXPECT_CALL(sysWrapper, opendir(_)).Times(3);
EXPECT_CALL(sysWrapper, readdir(_)).Times(AtLeast(30));
EXPECT_CALL(sysWrapper, closedir(_)).Times(3);
EXPECT_CALL(sysWrapper, realpath(_, _)).Times(3);
EXPECT_CALL(sysWrapper, open(_, _)).Times(14);
EXPECT_CALL(sysWrapper, read(_, _, _)).Times(20);
EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0);
EXPECT_CALL(sysWrapper, ioctl(_,_,An<mtget*>())).Times(2);
EXPECT_CALL(sysWrapper, close(_)).Times(14);
EXPECT_CALL(sysWrapper, readlink(_, _, _)).Times(3);
EXPECT_CALL(sysWrapper, stat(_,_)).Times(7);
/* Test: detect devices, then open the device files */
SCSI::DeviceVector<Tape::System::mockWrapper> dl(sysWrapper);
for (std::vector<SCSI::DeviceInfo>::iterator i = dl.begin();
i != dl.end(); i++) {
if (SCSI::Types::tape == i->type) {
Tape::Drive<Tape::System::mockWrapper> drive(*i, sysWrapper);
Tape::deviceInfo devInfo;
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 );
}
}
}
TEST(TapeDrive, getCompressionAndClearCompressionStats) {
/* Prepare the test harness */
Tape::System::mockWrapper sysWrapper;
......
......@@ -237,6 +237,29 @@ namespace SCSI {
unsigned char vendorSpecific2[1];
};
/**
* Inquiry unit serial number vital product data as described in SPC-4.
*/
class inquiryUnitSerialNumberData_t {
public:
inquiryUnitSerialNumberData_t() { zeroStruct(this); }
// byte 0
unsigned char peripheralDeviceType: 5; // (000b) connected to this LUN
unsigned char peripheralQualifier : 3; // (01h) tape drive
// byte 1
unsigned char pageCode; // (80h) Vital Product Data page for serial
// byte 2
unsigned char :8; // Reserved
// byte 3
unsigned char pageLength; // n-3
// bytes 4-n
char productSerialNumber[12]; // 12 bytes for T10000&IBM, 10 for LTO
};
/**
* LOCATE(10) CDB as described in SSC-3.
*/
......
......@@ -127,6 +127,39 @@ namespace UnitTests {
ASSERT_EQ(0xCA, inqCDB.control);
}
TEST(SCSI_Structures, inquiryUnitSerialNumberData_t) {
SCSI::Structures::inquiryUnitSerialNumberData_t inqSerialNumber;
unsigned char *buff = (unsigned char *)&inqSerialNumber;
/*
* Make sure this struct is a POD (plain old data without virtual table)
* (and has the right size).
*/
ASSERT_EQ(16U, sizeof(inqSerialNumber));
ASSERT_EQ(0, inqSerialNumber.peripheralDeviceType);
buff[0] |= (0x15 & 0x1F) << 0;
ASSERT_EQ(0x15, inqSerialNumber.peripheralDeviceType);
ASSERT_EQ(0, inqSerialNumber.peripheralQualifier);
buff[0] |= (0x5 & 0x7) <<5;
ASSERT_EQ(0x5,inqSerialNumber.peripheralQualifier);
ASSERT_EQ(0, inqSerialNumber.pageCode);
buff[1] |= 0xAB ;
ASSERT_EQ(0xAB, inqSerialNumber.pageCode);
buff[2] |= 0xFF;
ASSERT_EQ(0, inqSerialNumber.pageLength);
buff[3] |= 0xCD ;
ASSERT_EQ(0xCD, inqSerialNumber.pageLength);
ASSERT_EQ("", SCSI::Structures::toString(inqSerialNumber.productSerialNumber));
const char serialNumber[13] = "XYZZY_A2 ";
memcpy(&buff[4],serialNumber,12);
ASSERT_EQ("XYZZY_A2 ", SCSI::Structures::toString(inqSerialNumber.productSerialNumber));
}
TEST(SCSI_Structures, logSelectCDB_t) {
SCSI::Structures::logSelectCDB_t logSelectCDB;
unsigned char *buff = (unsigned char *)&logSelectCDB;
......
......@@ -373,6 +373,57 @@ int Tape::System::stDeviceFile::ioctl(unsigned long int request, sg_io_hdr_t * s
}
break;
} // end MODE_SELECT_6
case SCSI::Commands::INQUIRY:
{ // start INQUIRY
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 = "T10000B ";
memcpy(inqData.prodId,prodId, sizeof(inqData.prodId));
const char *prodRevLvl = "0104 ";
memcpy(inqData.prodRevLvl,prodRevLvl, sizeof(inqData.prodRevLvl));
const char *T10Vendor = "STK ";
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;
}
break;
} // end INQURY
}
return 0;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment