Commit 95b7971c authored by Eric Cano's avatar Eric Cano
Browse files

Added constants for SCSI statuses.

Added support for log sense command.
Added support for tape alert log, with convertion from code to string.
Updated test harness to support ioctl overloaded.
Fixed some formatting in the doc.
parent c05d9d49
......@@ -74,7 +74,7 @@ and the Linux SCSI Generic (sg) HOWTO
More details regarding the Generic SCSI driver can be found on the SCSI subsystem maintainer's web site
\footnote{ \href{http://sg.danny.cz/sg/}{http://sg.danny.cz/sg/} }.
The section on the SG\_IO ioctl, \footnote{ \href{http://sg.danny.cz/sg/sg\_io.html}{http://sg.danny.cz/sg/sg\_io.html} } details the usage of the
The section on the SG\_IO ioctl, \footnote{ \href{http://sg.danny.cz/sg/sg\textunderscore{}io.html}{http://sg.danny.cz/sg/sg\textunderscore{}io.html} } details the usage of the
simplest ioctl for the generic SCSI driver, which allows the invocation of a SCSI command and the collection of the
result in a single system call.
......@@ -202,11 +202,11 @@ takes care of string extraction from fixed sized char arrays. See listing \ref{S
\begin{table}
\begin{lstlisting}[caption=SCSI::Structures helper functions,label=SCSI_data_helpers]
SCSI::Structures::uint32\_t toU32(const char(\& t)\[4\]);
SCSI::Structures::uint32\_t toU32(const char(\& t)\[4\]);
SCSI::Structures::uint32_t toU32(const char(& t)[4]);
SCSI::Structures::uint32_t toU32(const char(& t)[4]);
template <size\_t n>
std::string toString(const char(\& t)[n]);
template <size_t n>
std::string toString(const char(& t)[n]);
\end{lstlisting}
\end{table}
......
......@@ -30,6 +30,7 @@
using ::testing::AtLeast;
using ::testing::Return;
using ::testing::_;
using ::testing::An;
namespace UnitTests {
......@@ -47,7 +48,7 @@ TEST(TapeDrive, OpensCorrectly) {
EXPECT_CALL(sysWrapper, open(_, _)).Times(14);
EXPECT_CALL(sysWrapper, read(_, _, _)).Times(20);
EXPECT_CALL(sysWrapper, write(_, _, _)).Times(0);
EXPECT_CALL(sysWrapper, ioctl(_,_,_)).Times(2);
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);
......
......@@ -41,6 +41,11 @@ int main ()
if (dev.type == SCSI::Types::tape) {
Tape::Drive<Tape::System::realWrapper> drive(dev,sWrapper);
drive.SCSI_inquiry();
std::vector<std::string> Alerts(drive.getTapeAlerts());
while (Alerts.size()) {
std::cout << "Tape alert: " << Alerts.back() << std::endl;
Alerts.pop_back();
}
}
}
}
// ----------------------------------------------------------------------
// File: SCSI/Constants.hh
// Author: Eric Cano - CERN
// ----------------------------------------------------------------------
/************************************************************************
* Tape Server *
* Copyright (C) 2013 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
************************************************************************/
#include "Constants.hh"
#include <sstream>
std::string SCSI::tapeAlertToString(uint16_t parameterCode)
{
std::stringstream ret;
ret << std::hex << std::nouppercase << std::showbase;
if (parameterCode < 1 || parameterCode > 64) {
ret << "Unexpected tapeAlert code: " << parameterCode;
return ret.str();
} else if (parameterCode >= 0x28 && parameterCode <= 0x2e) {
ret << "Obsolete tapeAlert code: " << parameterCode;
return ret.str();
}
switch(parameterCode) {
/* This is generated with the following small perl and a copy-paste from SSC-3:
* #!/usr/bin/perl -w
*
* my $step=0;
* while (<>) {
* chomp;
* if ($step == 0) {
* s/h//;
* print " case 0x".$_.":\n";
* } elsif ($step == 1) {
* print " return \"".$_."\";\n";
* }
* $step = ( $step + 1 ) % 4;
* }
*/
case 0x01:
return "Read warning";
case 0x02:
return "Write warning";
case 0x03:
return "Hard error";
case 0x04:
return "Medium";
case 0x05:
return "Read failure";
case 0x06:
return "Write failure";
case 0x07:
return "Medium life";
case 0x08:
return "Not data grade";
case 0x09:
return "Write protect";
case 0x0A:
return "Volume removal prevented";
case 0x0B:
return "Cleaning volume";
case 0x0C:
return "Unsupported format";
case 0x0D:
return "Recoverable mechanical cartridge failure";
case 0x0E:
return "Unrecoverable mechanical cartridge failure";
case 0x0F:
return "Memory chip in cartridge failure";
case 0x10:
return "Forced eject";
case 0x11:
return "Read only format";
case 0x12:
return "Tape directory corrupted on load";
case 0x13:
return "Nearing medium life";
case 0x14:
return "Cleaning required";
case 0x15:
return "Cleaning requested";
case 0x16:
return "Expired cleaning volume";
case 0x17:
return "Invalid cleaning volume";
case 0x18:
return "Retension requested";
case 0x19:
return "Multi-port interface error on a primary port";
case 0x1A:
return "Cooling fan failure";
case 0x1B:
return "Power supply failure";
case 0x1C:
return "Power consumption";
case 0x1D:
return "Drive preventive maintenance required";
case 0x1E:
return "Hardware A";
case 0x1F:
return "Hardware B";
case 0x20:
return "Primary interface";
case 0x21:
return "Eject volume";
case 0x22:
return "Microcode update fail";
case 0x23:
return "Drive humidity";
case 0x24:
return "Drive temperature";
case 0x25:
return "Drive voltage";
case 0x26:
return "Predictive failure";
case 0x27:
return "Diagnostics required";
case 0x2F:
return "External data encryption control - communication failure";
case 0x30:
return "External data encryption control - key manager returned an error";
case 0x31:
return "Diminished native capacity";
case 0x32:
return "Lost statistics";
case 0x33:
return "Tape directory invalid at unload";
case 0x34:
return "Tape system area write failure";
case 0x35:
return "Tape system area read failure";
case 0x36:
return "No start of data";
case 0x37:
return "Loading or threading failure";
case 0x38:
return "Unrecoverable unload failure";
case 0x39:
return "Automation interface failure";
case 0x3A:
return "Microcode failure";
case 0x3B:
return "WORM volume - integrity check failed";
case 0x3C:
return "WORM volume - overwrite attempted";
default:
ret << "Reserved tapeAlert code: " << parameterCode;
return ret.str();
}
}
/**
* Turn a SCSI status code into a string
* @param status
* @return
*/
std::string SCSI::statusToString(unsigned char status)
{
switch (status) {
case 0x00:
return "GOOD";
case 0x02:
return "CHECK CONDITION";
case 0x04:
return "CONDITION MET";
case 0x08:
return "BUSY";
case 0x18:
return "Reservation conflict";
case 0x28:
return "TASK SET FULL";
case 0x30:
return "ACA ACTIVE";
case 0x40:
return "TASK ABORTED";
default:
std::stringstream ret;
ret << "Reserved of obsolete code: "
<< std::hex << std::nouppercase << std::showbase
<< status;
return ret.str();
}
}
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// File: SCSI/Constants.hh
// Author: Eric Cano - CERN
// ----------------------------------------------------------------------
......@@ -23,6 +23,8 @@
#pragma once
#include <string>
namespace SCSI {
/* Extracted from linux kernel's include/scsi/scsi.h. System-level include
is less complete */
......@@ -197,4 +199,35 @@ namespace SCSI {
ATA_12 = 0xa1 /* 12-byte pass-thru */
};
}; // class OtherConstans
/**
* Helper function turning tape alerts to strings.
*/
std::string tapeAlertToString(uint16_t parameterCode);
class Status {
public:
enum {
GOOD = 0x00,
CHECK_CONDITION = 0x02,
CONDITION_MET = 0x04,
BUSY = 0x08,
RESERVATION_CONFLICT = 0x18,
TASK_SET_FULL = 0x28,
ACA_ACTIVE = 0x30,
TASK_ABORTED = 0x40
};
};
/**
* Helper function turning SCSI status to string
*/
std::string statusToString(unsigned char status);
class logSensePages {
public:
enum {
tapeAlert = 0x2e
};
};
}; // namespace SCSI
......@@ -41,7 +41,30 @@ namespace SCSI {
* http://hackipedia.org/Hardware/SCSI/Stream%20Commands/SCSI%20Stream%20Commands%20-%203.pdf
*/
namespace Structures {
/*
/**
* Helper function to deal with endianness.
* @param t byte array in SCSI order representing a 32 bits number
* @return
*/
inline uint32_t toU32(const char(& t)[4])
{
/* Like network, SCSI is BigEndian */
return ntohl (*((uint32_t *) t));
}
/**
* Helper function to deal with endianness.
* @param t byte array in SCSI order representing a 16 bits number
* @return
*/
inline uint16_t toU16(const char(& t)[2])
{
/* Like network, SCSI is BigEndian */
return ntohs (*((uint16_t *) t));
}
/**
* Inquiry CDB as described in SPC-4.
*/
class inquiryCDB_t {
......@@ -59,7 +82,7 @@ namespace SCSI {
inquiryCDB_t() { memset(this, 0, sizeof(*this)); opCode = SCSI::Commands::INQUIRY; }
};
/*
/**
* Inquiry data as described in SPC-4.
*/
typedef struct {
......@@ -152,6 +175,68 @@ namespace SCSI {
}
};
/**
* Log sense CDB as decribed in SPC-4,
*/
class logSenseCDB_t {
public:
unsigned char opCode;
unsigned char SP : 1;
unsigned char : 7;
unsigned char pageCode : 6;
unsigned char PC : 2;
unsigned char subPage;
unsigned char parameterPointer[2];
unsigned char allocationLength[2];
unsigned char control;
logSenseCDB_t() { memset(this, 0, sizeof(*this)); opCode = SCSI::Commands::LOG_SENSE; }
};
class tapeAlertLogParameter_t {
public:
char parameterCode [2];
unsigned char formatAndLinking : 2;
unsigned char TMC : 2;
unsigned char ETC : 1;
unsigned char TSD : 1;
unsigned char : 1;
unsigned char DU : 1;
unsigned char parameterLength;
unsigned char flag : 1;
unsigned char : 7;
};
/**
* Tape alert log mage, returned by LOG SENSE. Defined in SSC-3, section 8.2.3 TapeAler log page.
*/
class tapeAlertLogPage_t {
public:
unsigned char pageCode : 6;
unsigned char : 2;
unsigned char subPageCode;
char pageLength[2];
tapeAlertLogParameter_t parameters [1];
/**
* Utility function computing the number of parameters.
* @return number of parameters.
*/
int parameterNumber() { return SCSI::Structures::toU16(pageLength) / sizeof (tapeAlertLogPage_t); }
};
template <size_t n>
std::string toString(const char(& t)[n]) {
std::stringstream r;
......@@ -189,18 +274,6 @@ namespace SCSI {
}
return hex.str();
}
inline uint32_t toU32(const char(& t)[4])
{
/* Like network, SCSI is BigEndian */
return ntohl (*((uint32_t *) t));
}
inline uint16_t toU16(const char(& t)[2])
{
/* Like network, SCSI is BigEndian */
return ntohs (*((uint16_t *) t));
}
};
......
......@@ -27,6 +27,8 @@
#include <stdexcept>
using ::testing::_;
using ::testing::A;
using ::testing::An;
using ::testing::Invoke;
DIR* Tape::System::fakeWrapper::opendir(const char* name) {
......@@ -184,7 +186,10 @@ void Tape::System::mockWrapper::delegateToFake() {
ON_CALL(*this, open(_, _)).WillByDefault(Invoke(&fake, &fakeWrapper::open));
ON_CALL(*this, read(_, _, _)).WillByDefault(Invoke(&fake, &fakeWrapper::read));
ON_CALL(*this, write(_, _, _)).WillByDefault(Invoke(&fake, &fakeWrapper::write));
ON_CALL(*this, ioctl(_, _, _)).WillByDefault(Invoke(&fake, &fakeWrapper::ioctl));
/* We have an overloaded function. Have to use a static_cast trick to indicate
the pointer to which function we want.*/
ON_CALL(*this, ioctl(_, _, A<struct mtget *>())).WillByDefault(Invoke(&fake,
static_cast<int(fakeWrapper::*)(int , unsigned long int , mtget*)>(&fakeWrapper::ioctl)));
ON_CALL(*this, close(_)).WillByDefault(Invoke(&fake, &fakeWrapper::close));
ON_CALL(*this, stat(_, _)).WillByDefault(Invoke(&fake, &fakeWrapper::stat));
}
......
......@@ -151,6 +151,7 @@ namespace System {
MOCK_METHOD3(read, ssize_t(int fd, void* buf, size_t nbytes));
MOCK_METHOD3(write, ssize_t(int fd, const void *buf, size_t nbytes));
MOCK_METHOD3(ioctl, int(int fd, unsigned long int request, struct mtget * mt_status));
MOCK_METHOD3(ioctl, int(int fd, unsigned long int request, sg_io_hdr_t * sg_hdr));
MOCK_METHOD1(close, int(int fd));
MOCK_METHOD2(stat, int(const char *, struct stat *));
DIR* m_DIR;
......
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