Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
dCache
cta
Commits
14a165d0
Commit
14a165d0
authored
Aug 14, 2013
by
Victor Kotlyar
Browse files
added implementation for getDeviceInfo based on INQUIRY command.
child function getSerialNumber was added.
parent
ff8d77a3
Changes
5
Hide whitespace changes
Inline
Side-by-side
Drive/Drive.hh
View file @
14a165d0
...
...
@@ -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).
...
...
Drive/DriveTest.cc
View file @
14a165d0
...
...
@@ -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
;
...
...
SCSI/Structures.hh
View file @
14a165d0
...
...
@@ -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.
*/
...
...
SCSI/StructuresTest.cc
View file @
14a165d0
...
...
@@ -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
;
...
...
System/FileWrappers.cc
View file @
14a165d0
...
...
@@ -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
;
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment