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

added implementation for setDensityAndCompression.

We use MODE SENSE(6) to query the tape information and then MODE SELECT(6)
to set parameters which we only change.

By default we only enable compression.
parent d8b92a22
......@@ -264,10 +264,67 @@ namespace Tape {
return ret;
}
/**
* Set the tape density and compression. This is both driven by parameters and expert system knowing the hardware.
* This function is a good candidate for overloading in drive-specific child classes.
* Set the tape density and compression.
* We use MODE SENSE/SELECT Device Configuration (10h) mode page.
* As soon as there is no definition in SPC-4 or SSC-3 it depends on the
* drives documentation.
*
* @param densityCode The tape specific density code.
* If it is 0 (default) than we use the density code
* detected by the drive itself means no changes.
*
* @param compression The boolean variable to enable or disable compression
* on the drive for the tape. By default it is enabled.
*/
virtual void setDensityAndCompression(/* todo: clarify parameters*/) throw (Exception) { throw Exception("Not implemented"); }
virtual void setDensityAndCompression(unsigned char densityCode = 0,
bool compression = true) throw (Exception) {
SCSI::Structures::modeSenseDeviceConfiguration_t devConfig;
{ // get info from the drive
SCSI::Structures::modeSense6CDB_t cdb;
SCSI::Structures::senseData_t<255> senseBuff;
SCSI::Structures::LinuxSGIO_t sgh;
cdb.pageCode = SCSI::modeSensePages::deviceConfiguration;
cdb.allocationLenght = sizeof(devConfig);
sgh.setCDB(&cdb);
sgh.setDataBuffer(&devConfig);
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 setDensityAndCompression: ") +
SCSI::statusToString(sgh.status));
}
{ // set parameters and we use filled structure devConfig from the previous SCSI call
SCSI::Structures::modeSelect6CDB_t cdb;
SCSI::Structures::senseData_t<255> senseBuff;
SCSI::Structures::LinuxSGIO_t sgh;
cdb.PF = 1; // means nothing for IBM, LTO, T10000
cdb.paramListLength = sizeof(devConfig);
devConfig.header.modeDataLength = 0 ; // must be 0 for IBM, LTO ignored by T10000
if (0 != densityCode) devConfig.blockDescriptor.densityCode = densityCode;
if (compression) devConfig.modePage.selectDataComprAlgorithm = 1;
sgh.setCDB(&cdb);
sgh.setDataBuffer(&devConfig);
sgh.setSenseBuffer(&senseBuff);
sgh.dxfer_direction = SG_DXFER_TO_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 setDensityAndCompression: ") +
SCSI::statusToString(sgh.status));
}
}
/**
* Get drive status.
......
......@@ -76,11 +76,13 @@ namespace SCSI {
INQUIRY = 0x12,
RECOVER_BUFFERED_DATA = 0x14,
MODE_SELECT = 0x15,
MODE_SELECT_6 = 0x15,
RESERVE = 0x16,
RELEASE = 0x17,
COPY = 0x18,
ERASE = 0x19,
MODE_SENSE = 0x1a,
MODE_SENSE_6 = 0x1a,
START_STOP = 0x1b,
RECEIVE_DIAGNOSTIC = 0x1c,
SEND_DIAGNOSTIC = 0x1d,
......@@ -235,6 +237,13 @@ namespace SCSI {
blockBytesTransferred = 0x38 // parameters in this page are reset when a cartridge is loaded
};
};
class modeSensePages {
public:
enum {
deviceConfiguration = 0x10
};
};
/**
* Sun StorageTekTM T10000 Tape Drive Fibre Channel Interface Reference Manual
*/
......
......@@ -234,7 +234,7 @@ namespace SCSI {
unsigned char vendorSpecific2[1];
};
/*
/**
* LOCATE(10) CDB as described in SSC-3.
*/
class locate10CDB_t {
......@@ -268,7 +268,7 @@ namespace SCSI {
unsigned char control; // Control byte
};
/*
/**
* READ POSITION CDB as described in SSC-3.
*/
class readPositionCDB_t {
......@@ -295,7 +295,7 @@ namespace SCSI {
unsigned char control; // Control byte
};
/*
/**
* READ POSITION data format, short form as described in SSC-3.
*/
class readPositionDataShortForm_t {
......@@ -333,7 +333,7 @@ namespace SCSI {
unsigned char bytesInBuffer[4]; // Number if bytes in object buffer
};
/*
/**
* LOG SELECT CDB as described in SPC-4.
*/
class logSelectCDB_t {
......@@ -394,8 +394,8 @@ namespace SCSI {
};
/**
* Log sense Log Page Parameter Format as described in SPC-4,
*/
* Log sense Log Page Parameter Format as described in SPC-4,
*/
class logSenseParameterHeader_t {
public:
// bytes 0-1
......@@ -423,8 +423,8 @@ namespace SCSI {
};
/**
* Log sense Log Page Format as described in SPC-4,
*/
* Log sense Log Page Format as described in SPC-4,
*/
class logSenseLogPageHeader_t {
public:
// byte 0
......@@ -439,8 +439,8 @@ namespace SCSI {
unsigned char pageLength[2]; // n-3 number of bytes without header
};
/**
* Log sense Log Page Format as described in SPC-4,
*/
* Log sense Log Page Format as described in SPC-4,
*/
class logSenseLogPage_t {
public:
// bytes 0-3
......@@ -450,7 +450,186 @@ namespace SCSI {
logSenseParameter_t parameters [1]; // parameters have variable length
};
/**
* MODE SENSE(6) CDB as described in SPC-4.
*/
class modeSense6CDB_t {
public:
modeSense6CDB_t() {
zeroStruct(this);
opCode = SCSI::Commands::MODE_SENSE_6;
}
// byte 0
unsigned char opCode; // OPERATION CODE (1Ah)
// byte 1
unsigned char : 3; // Reserved
unsigned char DBD : 1; // Disable Block Descriptors
unsigned char : 4; // Reserved
// byte 2
unsigned char pageCode : 6; // Page code
unsigned char PC : 2; // Page Control
// byte3
unsigned char subPageCode ; // Subpage code
// byte4
unsigned char allocationLenght; // The maximum number of bytes to be transferred
// byte 5
unsigned char control; // Control byte
};
/**
* MODE SENSE(6) MODE SELECT(6) parameter header as described in SPC-4.
*/
class modeParameterHeader6_t {
public:
// byte 0
unsigned char modeDataLength; // The mode data length does not include itself
// byte 1
unsigned char mediumType; // The medium type in the drive
// byte 2
/* in SPC-4 we have device-specific parameter byte here
* but from all drive specifications the fields are the same
* so we use them here.
*/
unsigned char speed : 4; // Read/write speed
unsigned char bufferedMode : 3; // Returns after data is in the buffer or on the medium
unsigned char WP : 1; // Write Protect
// byte3
unsigned char blockDescriptorLength ; // (08h) or (00h)
};
/**
* MODE SENSE(6,10) and MODE SELECT(6,10) block descriptor as described in SPC-4.
*/
class modeParameterBlockDecriptor_t {
public:
// byte 0
unsigned char densityCode; // Density code
// bytes 1-3
unsigned char numberOfBlocks[3]; // Number of block or block count
// byte 4
unsigned char : 8; // Reserved
// bytes 5-7
unsigned char blockLength[3] ; // Block length
};
/**
* MODE SENSE(6) or MODE SENSE(10) mode page 10h: Device Configuration.
* There is no description in SPC-4 or SSC-3.
* We use descriptions from:
* IBM System Storage Tape Drive 3592 SCSI Reference,
* Sun StorageTekTM T10000 Tape Drive Fibre Channel Interface Reference Manual,
* IBM TotalStorage LTO Ultrium Tape Drive SCSI Reference.
*/
class modePageDeviceConfiguration_t {
public:
// byte 0
unsigned char pageCode :6; // Page code (10h)
unsigned char SPF :1; // SubPage Format (0b)
unsigned char PS :1; // Parameters Savable
// byte 1
unsigned char pageLength; // (0Eh)
// byte 2
unsigned char activeFormat : 5; // Active Format
unsigned char CAF : 1; // Change Active Format
unsigned char CAP : 1; // Change Active Partition
unsigned char : 1; // Reserved
// byte 3
unsigned char activePartition ; // Active Partition
// byte 4
unsigned char writeBufferFullRatio; // Write object buffer full ratio
// byte 5
unsigned char readBufferEmptyRatio; // Read object buffer empty ratio
// bytes 6-7
unsigned char writeDelayTime[2]; // Write delay time in 100ms for IBM, LTO and in sec for T1000
// byte 8
unsigned char REW : 1; // Report Early Warning
unsigned char RBO : 1; // Recover Buffer Order
unsigned char SOCF: 2; // Stop On Consecutive Filemarks
unsigned char AVC : 1; // Automatic Velocity Control
unsigned char RSMK : 1; // Report SetMarKs (obsolete for IBM,LTO)
unsigned char LOIS : 1; // Logical Object ID Supported or Block IDs Supported for T10000
unsigned char OBR : 1; // Object Buffer Recovery or Data Buffer Recovery for T10000
// byte 9
unsigned char gapSize; // Obsolete for IBM, LTO
// byte 10
unsigned char BAM : 1; // Block Address Mode or reserved for T10000
unsigned char BAML: 1; // Block Address Mode Lock or reserved for T10000
unsigned char SWP : 1; // Soft Write Protect
unsigned char SEW : 1; // Synchronize at Early Warning
unsigned char EEG : 1; // EOD Enabled Generation
unsigned char eodDefined :3; // End Of Data
// bytes 11-13
unsigned char bufSizeAtEarlyWarning[3]; // Object buffer size at early warning
// byte 14
unsigned char selectDataComprAlgorithm; // Select data compression algorithm
// byte 15
unsigned char PRMWP : 1; // PeRManent Write Protect
unsigned char PERSWP : 1; // PERSistent Write Protect
unsigned char ASOCWP : 1; // ASsOCiated Write Protect
unsigned char rewindOnReset : 2; // Reserved for T10000
unsigned char OIR : 1; // Only If Reserved or reserved for T10000
unsigned char WTRE : 2; // WORM Tamper Read Enable
};
class modeSenseDeviceConfiguration_t {
public:
modeSenseDeviceConfiguration_t() { zeroStruct(this); }
modeParameterHeader6_t header;
modeParameterBlockDecriptor_t blockDescriptor;
modePageDeviceConfiguration_t modePage;
};
/**
* MODE SELECT(6) CDB as described in SPC-4.
*/
class modeSelect6CDB_t {
public:
modeSelect6CDB_t() {
zeroStruct(this);
opCode = SCSI::Commands::MODE_SELECT_6;
}
// byte 0
unsigned char opCode; // OPERATION CODE (15h)
// byte 1
unsigned char SP : 1; // Save Parameters
unsigned char : 3; // Reserved
unsigned char PF : 1; // Page Format
unsigned char : 3; // Reserved
// bytes 2-3
unsigned char reserved[2]; // Reserved
// byte 4
unsigned char paramListLength; // Parameter list length
// byte 5
unsigned char control; // Control byte
};
/**
* Part of a tape alert log page.
* This structure does not need to be initialized, as the containing structure
......
......@@ -340,6 +340,108 @@ namespace UnitTests {
ASSERT_EQ(0x7ABCDEF7, SCSI::Structures::toU32(readPositionData.bytesInBuffer));
}
TEST(SCSI_Structures, modeSelect6CDB_t) {
SCSI::Structures::modeSelect6CDB_t modeSelect6CDB;
unsigned char *buff = (unsigned char *)&modeSelect6CDB;
/*
* Make sure this struct is a POD (plain old data without virtual table)
* (and has the right size).
*/
ASSERT_EQ(6, sizeof(modeSelect6CDB));
/* Check proper initialization an location of struct members match
the bit/byte locations defined in SPC-4 */
ASSERT_EQ(SCSI::Commands::MODE_SELECT_6, modeSelect6CDB.opCode);
buff[0] = 0xAB;
ASSERT_EQ(0xAB, modeSelect6CDB.opCode);
ASSERT_EQ(0, modeSelect6CDB.SP);
buff[1] |= (0x1 & 0xFF) << 0;
ASSERT_EQ(0x1, modeSelect6CDB.SP);
ASSERT_EQ(0, modeSelect6CDB.PF);
buff[1] |= (0x10 & 0xFF) << 0;
ASSERT_EQ(0x1, modeSelect6CDB.PF);
buff[2] |= 0xFF; buff[3] = 0xFF;
ASSERT_EQ(0, modeSelect6CDB.paramListLength);
buff[4] |= 0xBC;
ASSERT_EQ(0xBC, modeSelect6CDB.paramListLength);
ASSERT_EQ(0, modeSelect6CDB.control);
buff[5] |= 0xAB;
ASSERT_EQ(0xAB, modeSelect6CDB.control);
}
TEST(SCSI_Structures, modeSense6CDB_t) {
SCSI::Structures::modeSense6CDB_t modeSense6CDB;
unsigned char *buff = (unsigned char *)&modeSense6CDB;
/*
* Make sure this struct is a POD (plain old data without virtual table)
* (and has the right size).
*/
ASSERT_EQ(6, sizeof(modeSense6CDB));
/* Check proper initialization an location of struct members match
the bit/byte locations defined in SPC-4 */
ASSERT_EQ(SCSI::Commands::MODE_SENSE_6, modeSense6CDB.opCode);
buff[0] = 0xAB;
ASSERT_EQ(0xAB, modeSense6CDB.opCode);
ASSERT_EQ(0, modeSense6CDB.DBD);
buff[1] |= (0x8 & 0xFF) << 0;
ASSERT_EQ(0x1, modeSense6CDB.DBD);
ASSERT_EQ(0, modeSense6CDB.pageCode);
buff[2] |= (0x2A & 0xFF) << 0;
ASSERT_EQ(0x2A, modeSense6CDB.pageCode);
ASSERT_EQ(0, modeSense6CDB.PC);
buff[2] |= (0x8B & 0xFF) << 0;
ASSERT_EQ(0x2, modeSense6CDB.PC);
ASSERT_EQ(0, modeSense6CDB.subPageCode);
buff[3] |= 0xBC;
ASSERT_EQ(0xBC, modeSense6CDB.subPageCode);
ASSERT_EQ(0, modeSense6CDB.allocationLenght);
buff[4] |= 0xAB;
ASSERT_EQ(0xAB, modeSense6CDB.allocationLenght);
ASSERT_EQ(0, modeSense6CDB.control);
buff[5] |= 0xCD;
ASSERT_EQ(0xCD, modeSense6CDB.control);
}
TEST(SCSI_Structures, modeSenseDeviceConfiguration_t) {
SCSI::Structures::modeSenseDeviceConfiguration_t devConfig;
unsigned char *buff = (unsigned char *)&devConfig;
/*
* Make sure this struct is a POD (plain old data without virtual table)
* (and has the right size).
*/
ASSERT_EQ(28, sizeof(devConfig));
ASSERT_EQ(4, sizeof(devConfig.header));
ASSERT_EQ(8, sizeof(devConfig.blockDescriptor));
ASSERT_EQ(16, sizeof(devConfig.modePage));
/* We will only check used by us parameters */
ASSERT_EQ(0, devConfig.header.modeDataLength);
buff[0] |= 0xAB;
ASSERT_EQ(0xAB, devConfig.header.modeDataLength);
buff[1] = buff[2] = buff[3] = 0xFF;
ASSERT_EQ(0, devConfig.blockDescriptor.densityCode);
buff[4] |= 0xCD;
ASSERT_EQ(0xCD, devConfig.blockDescriptor.densityCode);
for(int i=5;i<26;i++) buff[i] = 0xFF; // fill the space
ASSERT_EQ(0, devConfig.modePage.selectDataComprAlgorithm );
buff[26] |= 0xEF;
ASSERT_EQ(0xEF, devConfig.modePage.selectDataComprAlgorithm);
}
TEST(SCSI_Structures, tapeAlertLogPage_t_and_parameters) {
SCSI::Structures::tapeAlertLogPage_t<12> tal;
unsigned char * buff = (unsigned char *) & tal;
......
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