mirror of
https://github.com/moibenko/mtx.git
synced 2026-01-11 22:12:49 +00:00
Compare commits
28 Commits
absolute_a
...
mtx_jinr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a853cdcc02 | ||
|
|
7546e2c57e | ||
|
|
d34c705ce7 | ||
|
|
9e3d2efa57 | ||
|
|
ab9addfb69 | ||
|
|
dad84047e8 | ||
|
|
8104596ed7 | ||
|
|
6c234f1c21 | ||
|
|
05ec4400ed | ||
|
|
a56ce2af7b | ||
|
|
14e20937d3 | ||
|
|
7af3420045 | ||
|
|
87be1da937 | ||
|
|
fe53bbe0be | ||
|
|
a3913d382d | ||
|
|
26dcc32e8c | ||
|
|
c99bf45420 | ||
|
|
3fafa03313 | ||
|
|
92c01f1626 | ||
|
|
8bce01fc88 | ||
|
|
2ce5e5dfb1 | ||
|
|
9b1e508466 | ||
|
|
3396b63b27 | ||
|
|
280fa25936 | ||
|
|
7f69c4fac7 | ||
|
|
a23e89db56 | ||
|
|
5bb358145a | ||
|
|
6ca40adeba |
@@ -1,2 +1,2 @@
|
||||
# mtx
|
||||
The MTX program controls the robotic mechanism in autoloaders and tape libraries. Taken from Souceforge, patches from centOS were applied, plus my changes to allow to use mtx over library calls.
|
||||
The MTX program controls the robotic mechanism in autoloaders and tape libraries. Taken from Sourceforge, patches from centOS were applied, plus my changes to allow to use mtx over library calls.
|
||||
|
||||
BIN
mtx-1.3.12.tgz
BIN
mtx-1.3.12.tgz
Binary file not shown.
195
mtx-1.3.12/mtx.c
195
mtx-1.3.12/mtx.c
@@ -31,15 +31,15 @@
|
||||
Near complete re-write Feb 2000 Eric Lee Green <eric@badtux.org> to add support for
|
||||
multi-drive tape changers, extract out library stuff into mtxl.c,
|
||||
and otherwise bring things up to date for dealing with LARGE tape jukeboxes
|
||||
and other such enterprise-class storage subsystems.
|
||||
and other such enterprise-class storage subsystems.
|
||||
*/
|
||||
|
||||
char *argv0;
|
||||
|
||||
#include <ctype.h>
|
||||
#include "mtx.h" /* various defines for bit order etc. */
|
||||
#include "mtxl.h"
|
||||
|
||||
/* A table for printing out the peripheral device type as ASCII. */
|
||||
/* A table for printing out the peripheral device type as ASCII. */
|
||||
static char *PeripheralDeviceType[32] =
|
||||
{
|
||||
"Disk Drive", /* 0 */
|
||||
@@ -49,10 +49,10 @@ static char *PeripheralDeviceType[32] =
|
||||
"Write-once", /* 4 */
|
||||
"CD-ROM", /* 5 */
|
||||
"Scanner", /* 6 */
|
||||
"Optical", /* 7 */
|
||||
"Optical", /* 7 */
|
||||
"Medium Changer", /* 8 */
|
||||
"Communications", /* 9 */
|
||||
"ASC IT8", /* a */
|
||||
"ASC IT8", /* a */
|
||||
"ASC IT8", /* b */
|
||||
"RAID Array", /* c */
|
||||
"Enclosure Services", /* d */
|
||||
@@ -80,8 +80,7 @@ static int argc;
|
||||
static char **argv;
|
||||
|
||||
char *device=NULL; /* the device name passed as argument */
|
||||
int absolute_addressing=1; /* if not 0 - use absolute adresses of storage and tranport elements as known to the robot */
|
||||
|
||||
int absolute_addressing=0; /* if not 0 - use absolute adresses of storage and tranport elements as known to the robot */
|
||||
/* Unfortunately this must be true for SGI, because SGI does not
|
||||
use an int :-(.
|
||||
*/
|
||||
@@ -113,7 +112,7 @@ static void Transfer(void);
|
||||
static void Eepos(void);
|
||||
static void NoAttach(void);
|
||||
static void Version(void);
|
||||
static void do_Inventory(void);
|
||||
static void do_Inventory(void);
|
||||
static void do_Unload(void);
|
||||
static void do_Erase(void);
|
||||
static void NoBarCode(void);
|
||||
@@ -150,7 +149,7 @@ command_table[] =
|
||||
{ 0, "erase", do_Erase, 1, 0},
|
||||
{ 0, "nobarcode", NoBarCode, 0,0},
|
||||
{ 1, "position", do_Position, 1, 1},
|
||||
{ 0, "invert2", Invert2, 0, 0},
|
||||
{ 0, "invert2", Invert2, 0, 0},
|
||||
{ 3, "exchange", Exchange, 1, 1 },
|
||||
{ 0, "altres", AltReadElementStatus, 0,0},
|
||||
{ 0, NULL, NULL }
|
||||
@@ -185,7 +184,7 @@ static void Usage()
|
||||
static void Version(void)
|
||||
{
|
||||
fprintf(stderr, "mtx version %s\n\n", VERSION);
|
||||
Usage();
|
||||
Usage();
|
||||
}
|
||||
|
||||
|
||||
@@ -259,7 +258,7 @@ static void First(void)
|
||||
arg1 = ElementStatus->DataTransferElementSourceStorageElementNumber[driveno] + 1;
|
||||
if (arg1 == 1)
|
||||
{
|
||||
printf("loading...done.\n"); /* it already has tape #1 in it! */
|
||||
printf("loading...done.\n"); /* it already has tape #1 in it! */
|
||||
return;
|
||||
}
|
||||
arg2 = driveno;
|
||||
@@ -293,7 +292,7 @@ static void Last(void)
|
||||
arg1 = ElementStatus->DataTransferElementSourceStorageElementNumber[driveno] + 1;
|
||||
if (arg1 >= (ElementStatus->StorageElementCount - ElementStatus->ImportExportCount))
|
||||
{
|
||||
printf("loading...done.\n"); /* it already has last tape in it! */
|
||||
printf("loading...done.\n"); /* it already has last tape in it! */
|
||||
return;
|
||||
}
|
||||
arg2 = driveno;
|
||||
@@ -393,7 +392,7 @@ static void Next(void)
|
||||
FatalError("No More Media\n"); /* last slot */
|
||||
}
|
||||
|
||||
static void do_Inventory(void)
|
||||
static void do_Inventory(void)
|
||||
{
|
||||
if (Inventory(MediumChangerFD) < 0)
|
||||
{
|
||||
@@ -421,7 +420,7 @@ static void do_Erase(void)
|
||||
exit(1); /* exit with an error status. */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This should eject a tape or magazine, depending upon the device sent
|
||||
* to.
|
||||
@@ -442,12 +441,12 @@ static void ReportInquiry(void)
|
||||
int i;
|
||||
|
||||
Inquiry = RequestInquiry(MediumChangerFD,&RequestSense);
|
||||
if (Inquiry == NULL)
|
||||
if (Inquiry == NULL)
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
FatalError("INQUIRY Command Failed\n");
|
||||
}
|
||||
|
||||
|
||||
printf("Product Type: %s\n", PeripheralDeviceType[Inquiry->PeripheralDeviceType]);
|
||||
printf("Vendor ID: '");
|
||||
for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++)
|
||||
@@ -494,7 +493,7 @@ static void Status(void)
|
||||
ElementStatus->ImportExportCount);
|
||||
|
||||
|
||||
for (TransferElementNumber = 0;
|
||||
for (TransferElementNumber = 0;
|
||||
TransferElementNumber < ElementStatus->DataTransferElementCount;
|
||||
TransferElementNumber++)
|
||||
{
|
||||
@@ -504,11 +503,22 @@ static void Status(void)
|
||||
else {
|
||||
printf("Data Transfer Element %d ", ElementStatus->DataTransferElementAddress[TransferElementNumber]);
|
||||
phys_loc = (PhysicalLocation_T *) &ElementStatus->DataTransferElementPhysicalLocation[TransferElementNumber];
|
||||
printf("Phys Loc F%u,C%u,R%u,Z%u SN%s ID %s:",
|
||||
if (ElementStatus->DataTransferElementSerialNumber[TransferElementNumber][0] == " ")
|
||||
{
|
||||
printf("Phys Loc F%u,C%u,R%u,Z%u SN%s ID %s:",
|
||||
phys_loc->frame, phys_loc->column, phys_loc->row, phys_loc->zone,
|
||||
ElementStatus->DataTransferElementSerialNumber[TransferElementNumber],
|
||||
ElementStatus->DataTransferElementProductId[TransferElementNumber]
|
||||
);
|
||||
}
|
||||
else {
|
||||
printf("Phys Loc F%u,C%u,R%u,Z%u SN %s ID %s:",
|
||||
phys_loc->frame, phys_loc->column, phys_loc->row, phys_loc->zone,
|
||||
ElementStatus->DataTransferElementSerialNumber[TransferElementNumber],
|
||||
ElementStatus->DataTransferElementProductId[TransferElementNumber]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
if (ElementStatus->DataTransferElementFull[TransferElementNumber])
|
||||
{
|
||||
@@ -535,7 +545,7 @@ static void Status(void)
|
||||
|
||||
if (ElementStatus->DataTransferAlternateVolumeTag[TransferElementNumber][0])
|
||||
{
|
||||
printf(":AlternateVolumeTag = %s", ElementStatus->DataTransferAlternateVolumeTag[TransferElementNumber]);
|
||||
printf(":AlternateVolumeTag = %s", ElementStatus->DataTransferAlternateVolumeTag[TransferElementNumber]);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
@@ -555,11 +565,29 @@ static void Status(void)
|
||||
(ElementStatus->StorageElementFull[StorageElementNumber] ? "Full " : "Empty"));
|
||||
}
|
||||
else {
|
||||
/* some libraries return garbage in physical location */
|
||||
/* see if entry has non-printable character */
|
||||
int sl = strlen(ElementStatus->StorageElementPhysicalLocation[StorageElementNumber]);
|
||||
int sind = 0;
|
||||
|
||||
if (sl > 1) {
|
||||
for (sind = 0; sind < sl; sind++)
|
||||
{
|
||||
if ( !isprint(ElementStatus->StorageElementPhysicalLocation[StorageElementNumber][sind])) {
|
||||
ElementStatus->StorageElementPhysicalLocation[StorageElementNumber][0] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ElementStatus->StorageElementPhysicalLocation[StorageElementNumber][0] = 0;
|
||||
}
|
||||
|
||||
printf( " Storage Element %d Phys Loc %s %s:%s ", ElementStatus->StorageElementAddress[StorageElementNumber],
|
||||
ElementStatus->StorageElementPhysicalLocation[StorageElementNumber],
|
||||
(ElementStatus->StorageElementIsImportExport[StorageElementNumber]) ? " IMPORT/EXPORT" : "",
|
||||
(ElementStatus->StorageElementFull[StorageElementNumber] ? "Full " : "Empty"));
|
||||
}
|
||||
}
|
||||
|
||||
if (ElementStatus->PrimaryVolumeTag[StorageElementNumber][0])
|
||||
{
|
||||
@@ -588,7 +616,7 @@ void Position(int dest)
|
||||
|
||||
void Move(int src, int dest) {
|
||||
RequestSense_T *result; /* from MoveMedium */
|
||||
|
||||
|
||||
result = MoveMedium(MediumChangerFD, src, dest, ElementStatus, inquiry_info, &SCSI_Flags);
|
||||
if (result)
|
||||
{
|
||||
@@ -623,6 +651,21 @@ void Move(int src, int dest) {
|
||||
}
|
||||
}
|
||||
|
||||
void Test_UnitReady(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = testUnitReady(MediumChangerFD);
|
||||
if (result == 0)
|
||||
{
|
||||
printf("Ready:yes\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Ready:no\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* okay, now for the Load, Unload, etc. logic: */
|
||||
|
||||
@@ -646,7 +689,7 @@ static void Load(void)
|
||||
if (!device_opened)
|
||||
{
|
||||
FatalError("No Media Changer Device Specified\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (arg1 < 0 || arg1 >= ElementStatus->StorageElementCount)
|
||||
{
|
||||
@@ -750,7 +793,7 @@ static void Exchange(void)
|
||||
src = ElementStatus->StorageElementAddress[arg1 - 1];
|
||||
dest = ElementStatus->StorageElementAddress[arg2 - 1];
|
||||
dest2 = ElementStatus->StorageElementAddress[arg3 - 1];
|
||||
|
||||
|
||||
result = ExchangeMedium(MediumChangerFD, src, dest, dest2, ElementStatus, &SCSI_Flags);
|
||||
if (result)
|
||||
{
|
||||
@@ -809,7 +852,7 @@ static void Unload(void)
|
||||
if (!device_opened)
|
||||
{
|
||||
FatalError("No Media Changer Device Specified\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* okay, we should be there: */
|
||||
if (arg1 < 0)
|
||||
@@ -866,7 +909,7 @@ static void Unload(void)
|
||||
}
|
||||
|
||||
fprintf(stdout, "Unloading drive %d into Storage Element %d...", arg2, arg1 + 1);
|
||||
fflush(stdout); /* make it real-time :-( */
|
||||
fflush(stdout); /* make it real-time :-( */
|
||||
|
||||
Move(src,dest);
|
||||
|
||||
@@ -878,7 +921,7 @@ static void Unload(void)
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
** ARGUMENT PARSING SUBROUTINES: Parse arguments, dispatch.
|
||||
** ARGUMENT PARSING SUBROUTINES: Parse arguments, dispatch.
|
||||
*****************************************************************/
|
||||
|
||||
/* ***
|
||||
@@ -886,9 +929,9 @@ static void Unload(void)
|
||||
*
|
||||
* If we have an actual argument at the index position indicated (i.e. we
|
||||
* have not gone off the edge of the world), we return
|
||||
* its number. If we don't, or it's not a numeric argument,
|
||||
* we return -1. Note that 'get_arg' is kind of misleading, we only accept
|
||||
* numeric arguments, not any other kind.
|
||||
* its number. If we don't, or it's not a numeric argument,
|
||||
* we return -1. Note that 'get_arg' is kind of misleading, we only accept
|
||||
* numeric arguments, not any other kind.
|
||||
*/
|
||||
int get_arg(int idx)
|
||||
{
|
||||
@@ -924,12 +967,11 @@ void open_device(void)
|
||||
|
||||
|
||||
/* we see if we've got a file open. If not, we open one :-(. Then
|
||||
* we execute the actual command. Or not :-(.
|
||||
*/
|
||||
* we execute the actual command. Or not :-(.
|
||||
*/
|
||||
void execute_command(struct command_table_struct *command)
|
||||
{
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
if (device == NULL && command->need_device)
|
||||
{
|
||||
/* try to get it from TAPE environment variable... */
|
||||
@@ -944,6 +986,11 @@ void execute_command(struct command_table_struct *command)
|
||||
}
|
||||
open_device();
|
||||
}
|
||||
if (command->need_status && absolute_addressing)
|
||||
{
|
||||
FreeElementData(ElementStatus);
|
||||
ElementStatus = NULL;
|
||||
}
|
||||
if (!ElementStatus && command->need_status)
|
||||
{
|
||||
inquiry_info = RequestInquiry(MediumChangerFD,&RequestSense);
|
||||
@@ -957,7 +1004,7 @@ void execute_command(struct command_table_struct *command)
|
||||
if (!ElementStatus)
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
FatalError("READ ELEMENT STATUS Command Failed\n");
|
||||
FatalError("READ ELEMENT STATUS Command Failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -965,14 +1012,68 @@ void execute_command(struct command_table_struct *command)
|
||||
command->command();
|
||||
}
|
||||
|
||||
/*
|
||||
execute_command used in python call stopped working with
|
||||
new swig and Alma linux 9. The extern declaration did not work
|
||||
As the only command called over python was Status the call to it was
|
||||
implemented
|
||||
*/
|
||||
void execute_status_command(void)
|
||||
{
|
||||
struct command_table_struct command;
|
||||
RequestSense_T RequestSense;
|
||||
|
||||
command = command_table[1];
|
||||
if (device == NULL && command.need_device)
|
||||
{
|
||||
/* try to get it from TAPE environment variable... */
|
||||
device = getenv("CHANGER");
|
||||
if (device == NULL)
|
||||
{
|
||||
device = getenv("TAPE");
|
||||
if (device == NULL)
|
||||
{
|
||||
device = "/dev/changer"; /* Usage(); */
|
||||
}
|
||||
}
|
||||
open_device();
|
||||
}
|
||||
if (command.need_status && absolute_addressing)
|
||||
{
|
||||
FreeElementData(ElementStatus);
|
||||
ElementStatus = NULL;
|
||||
}
|
||||
if (!ElementStatus && command.need_status)
|
||||
{
|
||||
inquiry_info = RequestInquiry(MediumChangerFD,&RequestSense);
|
||||
if (!inquiry_info)
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
FatalError("INQUIRY command Failed\n");
|
||||
}
|
||||
|
||||
ElementStatus = ReadElementStatus(MediumChangerFD, &RequestSense, inquiry_info, &SCSI_Flags);
|
||||
if (!ElementStatus)
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
FatalError("READ ELEMENT STATUS Command Failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* okay, now to execute the command... */
|
||||
command.command();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* parse_args():
|
||||
* Basically, we are parsing argv/argc. We can have multiple commands
|
||||
* on a line now, such as "unload 3 0 load 4 0" to unload one tape and
|
||||
* load in another tape into drive 0, and we execute these commands one
|
||||
* at a time as we come to them. If we don't have a -f at the start, we
|
||||
* barf. If we leave out a drive #, we default to drive 0 (the first drive
|
||||
* in the cabinet).
|
||||
*/
|
||||
* in the cabinet).
|
||||
*/
|
||||
|
||||
int parse_args(void)
|
||||
{
|
||||
@@ -993,6 +1094,17 @@ int parse_args(void)
|
||||
device = argv[i++];
|
||||
open_device(); /* open the device and do a status scan on it... */
|
||||
}
|
||||
else if (strcmp(argv[i], "-a") == 0)
|
||||
{
|
||||
printf("absolute addressing\n");
|
||||
i++;
|
||||
if (i >= argc)
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
absolute_addressing = 1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
cmd_tbl_idx = 0; /* default to the first command... */
|
||||
@@ -1033,7 +1145,7 @@ int parse_args(void)
|
||||
|
||||
if (command->num_args>=2 && arg1 != -1)
|
||||
{
|
||||
arg2 = get_arg(i);
|
||||
arg2 = get_arg(i);
|
||||
if (arg2 != -1)
|
||||
{
|
||||
i++;
|
||||
@@ -1060,6 +1172,15 @@ int parse_args(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_scsi_timeout(int timeout) /* in seconds */
|
||||
{
|
||||
set_timeout(timeout);
|
||||
}
|
||||
|
||||
int get_scsi_timeout(void)
|
||||
{
|
||||
return get_timeout();
|
||||
}
|
||||
|
||||
|
||||
int main(int ArgCount, char *ArgVector[])
|
||||
@@ -1089,7 +1210,7 @@ int main(int ArgCount, char *ArgVector[])
|
||||
if (!ElementStatus)
|
||||
{
|
||||
PrintRequestSense(&RequestSense);
|
||||
FatalError("READ ELEMENT STATUS Command Failed\n");
|
||||
FatalError("READ ELEMENT STATUS Command Failed\n");
|
||||
}
|
||||
VMS_DefineStatusSymbols();
|
||||
SCSI_CloseDevice(device, MediumChangerFD);
|
||||
|
||||
@@ -565,7 +565,10 @@ TransportElementDescriptor_T;
|
||||
/* Now for element status data; */
|
||||
|
||||
typedef unsigned char barcode[37];
|
||||
//typedef unsigned char serialnumber[13];
|
||||
typedef unsigned char serialnumber[13];
|
||||
typedef unsigned char devicetype[17];
|
||||
|
||||
|
||||
typedef struct ElementStatus {
|
||||
|
||||
@@ -575,7 +578,7 @@ typedef struct ElementStatus {
|
||||
int *DataTransferElementAddress; /* array. */
|
||||
int *DataTransferElementSourceStorageElementNumber; /* array */
|
||||
int *DataTransferElementPhysicalLocation; /*array */
|
||||
serialnumber *DataTransferElementProductId; /*array */
|
||||
devicetype *DataTransferElementProductId; /*array */
|
||||
serialnumber *DataTransferElementSerialNumber; /*array */
|
||||
barcode *StorageElementPhysicalLocation; /*array */
|
||||
barcode *DataTransferPrimaryVolumeTag; /* array. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Name: mtx
|
||||
Version: 1.3.12
|
||||
Release: 14fnal%{?dist}
|
||||
Release: 29fnal_jinr%{?dist}
|
||||
Summary: SCSI media changer control program
|
||||
License: GPLv2
|
||||
Group: Applications/System
|
||||
@@ -51,6 +51,17 @@ rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
|
||||
%changelog
|
||||
* Tue Apr 01 2025 Alexander Moibenko <moibenko@jinr.ru> - 1.3.12.29fnal_jinr
|
||||
- execute_command stopped working on new system replaced it
|
||||
* Wed Aug 28 2024 Alexander Moibenko <moibenko@fnal.gov> - 1.3.12.22fnal_jinr
|
||||
- More fixes in copying serial number
|
||||
* Thu Dec 07 2023 Alexander Moibenko <moibenko@jinr.ru> - 1.3.12-19fnal
|
||||
- mtx CLI hasn hidden option (-a) to show status information with absolute addresses
|
||||
- Fixed problem seen in JINR where serial number was missing few last symbols
|
||||
|
||||
* Wed Jan 23 2019 Alexander Moibenko <moibenko@fnal.gov> - 1.3.12-15fnal
|
||||
- For absolute_addressing refresh elements data when status command is executed. This is needed to update tape library infortion in the calling program.
|
||||
- Changes to allow to use mtx as library and show absolute transfer and storage elements as output of status call
|
||||
* Wed Aug 1 2018 Alexander Moibenko <moibenko@fnal.gov> - 1.3.12-14fnal
|
||||
- All patches applied to code and new source mtx.tgz created to build rpm
|
||||
- Changes to allow to use mtx as library and show absolute transfer and storage elements as output of status call
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
* overflow :-(. That could be important if mtxl is SUID for some reason.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "mtx.h"
|
||||
#include "mtxl.h"
|
||||
|
||||
@@ -523,8 +524,12 @@ ElementModeSense_T *ReadAssignmentPage(DEVICE_TYPE MediumChangerFD)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void FreeElementData(ElementStatus_T *data)
|
||||
void FreeElementData(ElementStatus_T *data)
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
free(data->DataTransferElementAddress);
|
||||
free(data->DataTransferElementSourceStorageElementNumber);
|
||||
free(data->DataTransferElementPhysicalLocation);
|
||||
@@ -559,7 +564,7 @@ static ElementStatus_T *AllocateElementData(ElementModeSense_T *mode_sense)
|
||||
retval->DataTransferElementPhysicalLocation =
|
||||
(int *)xzmalloc(sizeof(int) * (mode_sense->NumDataTransfer + 1));
|
||||
retval->DataTransferElementProductId =
|
||||
(serialnumber *)xzmalloc(sizeof(serialnumber) * (mode_sense->NumDataTransfer + 1));
|
||||
(devicetype *)xzmalloc(sizeof(devicetype) * (mode_sense->NumDataTransfer + 1));
|
||||
retval->DataTransferElementSerialNumber =
|
||||
(serialnumber *)xzmalloc(sizeof(serialnumber) * (mode_sense->NumDataTransfer + 1));
|
||||
retval->StorageElementPhysicalLocation =
|
||||
@@ -614,21 +619,32 @@ void copy_physical_location(unsigned char *src, unsigned char *dest)
|
||||
void copy_char_buffer(unsigned char *src, unsigned char *dest, int num)
|
||||
{
|
||||
int i;
|
||||
while ((*src< 32) || (*src > 127)) {
|
||||
unsigned char *dest_tmp;
|
||||
dest_tmp = dest;
|
||||
|
||||
for (i=0; i <= num; i++)
|
||||
{
|
||||
*dest_tmp++ = 0;
|
||||
}
|
||||
dest_tmp = dest;
|
||||
/* there happen cases when serial number begins with several ' ' */
|
||||
/* skip them */
|
||||
while (*src == ' ') {
|
||||
src++;
|
||||
}
|
||||
for (i=0; i < num; i++)
|
||||
{
|
||||
*dest = *src++;
|
||||
|
||||
if ((*dest < 32) || (*dest > 127))
|
||||
{
|
||||
*dest = 0;
|
||||
break;
|
||||
}
|
||||
dest++;
|
||||
if (isxdigit(*src)) {
|
||||
*dest++ = *src;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
*dest = 0;
|
||||
/* there happen cases when serial number is '' */
|
||||
/* take care of this */
|
||||
if (strlen(dest_tmp) == 0) {
|
||||
*dest++ = 'X';
|
||||
*dest = 'X';
|
||||
}
|
||||
}
|
||||
|
||||
/* This #%!@# routine has more parameters than I can count! */
|
||||
@@ -1099,8 +1115,23 @@ static void ParseElementStatus( int *EmptyStorageElementAddress,
|
||||
BigEndian16(TransportElementDescriptor->SourceStorageElementAddress);
|
||||
InquiryShort_T *inqs;
|
||||
inqs = (InquiryShort_T *) TransportElementDescriptor->PrimaryVolumeTag;
|
||||
copy_char_buffer(inqs->SerialNumber, ElementStatus->DataTransferElementSerialNumber[ElementStatus->DataTransferElementCount], 12);
|
||||
copy_char_buffer(inqs->ProductIdentification+2, ElementStatus->DataTransferElementProductId[ElementStatus->DataTransferElementCount], 12);
|
||||
/* This is a hack to differentiate TS4500 and TFinity returned data */
|
||||
/* For TFinity
|
||||
inqs->VendorIdentification[0] == 0x0
|
||||
and inqs->VendorIdentification[1] == 0x20
|
||||
*/
|
||||
if (inqs->VendorIdentification[0] == 0x0 && inqs->VendorIdentification[1] == 0x20)
|
||||
{
|
||||
|
||||
unsigned char * cptr;
|
||||
cptr = (unsigned char *) &inqs->VendorIdentification[2];
|
||||
copy_char_buffer(cptr, ElementStatus->DataTransferElementSerialNumber[ElementStatus->DataTransferElementCount], 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_char_buffer(inqs->SerialNumber, ElementStatus->DataTransferElementSerialNumber[ElementStatus->DataTransferElementCount], 12);
|
||||
copy_char_buffer(inqs->ProductIdentification+2, ElementStatus->DataTransferElementProductId[ElementStatus->DataTransferElementCount], 12);
|
||||
}
|
||||
ElementStatus->DataTransferElementCount++;
|
||||
break;
|
||||
}
|
||||
@@ -1200,6 +1231,8 @@ ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T *
|
||||
int FirstElem, NumElements, NumThisRES;
|
||||
|
||||
ElementModeSense_T *mode_sense = NULL;
|
||||
unsigned char no_barcodes_saved;
|
||||
|
||||
|
||||
if (inquiry_info->MChngr && inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE)
|
||||
{
|
||||
@@ -1349,6 +1382,7 @@ ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T *
|
||||
#endif
|
||||
flags->elementtype = DataTransferElement; /* sigh! */
|
||||
flags->absolute_addressing = 0;
|
||||
|
||||
DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense,
|
||||
inquiry_info, flags,
|
||||
mode_sense->DataTransferStart,
|
||||
@@ -1376,11 +1410,14 @@ ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T *
|
||||
free(DataBuffer); /* sigh! */
|
||||
|
||||
flags->absolute_addressing = 1;
|
||||
no_barcodes_saved = flags->no_barcodes;
|
||||
flags->no_barcodes = 1;
|
||||
DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense,
|
||||
inquiry_info, flags,
|
||||
mode_sense->DataTransferStart,
|
||||
mode_sense->NumDataTransfer,
|
||||
SCSI_RES_ELEMENTS * 52 +120);
|
||||
flags->no_barcodes = no_barcodes_saved;
|
||||
if (!DataBuffer)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@@ -1866,7 +1903,7 @@ int ClearUnitAttention(DEVICE_TYPE fd, RequestSense_T *RequestSense)
|
||||
&unit_attention_sense, sizeof(unit_attention_sense),
|
||||
RequestSense) != 0)
|
||||
{
|
||||
fprintf(stderr, "RequestSense (0x03) failed\n");
|
||||
fprintf(stderr, "RequestSense (0x03) failed\n");
|
||||
return -1; /* could not do! */
|
||||
}
|
||||
|
||||
@@ -1880,6 +1917,27 @@ int ClearUnitAttention(DEVICE_TYPE fd, RequestSense_T *RequestSense)
|
||||
|
||||
}
|
||||
|
||||
/* Test unit ready: This will tell us whether the tape drive
|
||||
* is currently ready to read or write.
|
||||
*/
|
||||
|
||||
int testUnitReady(DEVICE_TYPE fd)
|
||||
{
|
||||
RequestSense_T sense;
|
||||
CDB_T CDB;
|
||||
unsigned char buffer[6];
|
||||
|
||||
CDB[0] = 0x00; /* TEST_UNIT_READY */
|
||||
CDB[1] = 0;
|
||||
CDB[2] = 0;
|
||||
CDB[3] = 0; /* 1-5 all unused. */
|
||||
CDB[4] = 0;
|
||||
CDB[5] = 0;
|
||||
|
||||
slow_bzero((char *)&sense,sizeof(RequestSense_T));
|
||||
return SCSI_ExecuteCommand(fd,Input,&CDB,6,buffer,0,&sense);
|
||||
}
|
||||
|
||||
static char Spaces[] = " ";
|
||||
|
||||
void PrintHex(int Indent, unsigned char *Buffer, int Length)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
/*
|
||||
MTX -- SCSI Tape Attached Medium Changer Control Program
|
||||
|
||||
Copyright 1997-1998 Leonard N. Zubkoff <lnz@dandelion.com>
|
||||
Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
|
||||
This file created by Eric Lee Green <eric@badtux.org>
|
||||
|
||||
|
||||
This program is free software; you may redistribute and/or modify it under
|
||||
the terms of the GNU General Public License Version 2 as published by the
|
||||
Free Software Foundation.
|
||||
@@ -60,14 +60,15 @@ ElementStatus_T *ReadElementStatus( DEVICE_TYPE MediumChangerFD,
|
||||
RequestSense_T *RequestSense,
|
||||
Inquiry_T *inquiry_info,
|
||||
SCSI_Flags_T *flags);
|
||||
void FreeElementData(ElementStatus_T *data);
|
||||
|
||||
Inquiry_T *RequestInquiry( DEVICE_TYPE fd,
|
||||
RequestSense_T *RequestSense);
|
||||
|
||||
RequestSense_T *MoveMedium( DEVICE_TYPE MediumChangerFD,
|
||||
int SourceAddress,
|
||||
int DestinationAddress,
|
||||
ElementStatus_T *ElementStatus,
|
||||
int DestinationAddress,
|
||||
ElementStatus_T *ElementStatus,
|
||||
Inquiry_T *inquiry_info,
|
||||
SCSI_Flags_T *flags);
|
||||
|
||||
@@ -75,7 +76,7 @@ RequestSense_T *ExchangeMedium( DEVICE_TYPE MediumChangerFD,
|
||||
int SourceAddress,
|
||||
int DestinationAddress,
|
||||
int Dest2Address,
|
||||
ElementStatus_T *ElementStatus,
|
||||
ElementStatus_T *ElementStatus,
|
||||
SCSI_Flags_T *flags);
|
||||
|
||||
RequestSense_T *PositionElement(DEVICE_TYPE MediumChangerFD,
|
||||
@@ -90,6 +91,9 @@ RequestSense_T *Erase(DEVICE_TYPE fd); /* send SHORT erase to drive */
|
||||
|
||||
void SCSI_Set_Timeout(int secs); /* set the SCSI timeout */
|
||||
void SCSI_Default_Timeout(void); /* go back to default timeout */
|
||||
int testUnitReady(DEVICE_TYPE fd); /* issue Test Unit Ready SCSI command */
|
||||
void set_timeout(int timeout); /* set scsi operation timeout */
|
||||
int get_timeout(void); /* get scsi operation timeout */
|
||||
|
||||
/* we may not have this function :-(. */
|
||||
#ifdef HAVE_GET_ID_LUN
|
||||
@@ -97,12 +101,12 @@ void SCSI_Default_Timeout(void); /* go back to default timeout */
|
||||
#endif
|
||||
|
||||
/* These two hacks are so that I can stick the tongue out on an
|
||||
* NSM optical jukebox.
|
||||
*/
|
||||
NSM_Result_T *RecNSMHack(DEVICE_TYPE MediumChangerFD,
|
||||
* NSM optical jukebox.
|
||||
*/
|
||||
NSM_Result_T *RecNSMHack(DEVICE_TYPE MediumChangerFD,
|
||||
int param_len, int timeout);
|
||||
|
||||
int SendNSMHack(DEVICE_TYPE MediumChangerFD, NSM_Param_T *nsm_command,
|
||||
int SendNSMHack(DEVICE_TYPE MediumChangerFD, NSM_Param_T *nsm_command,
|
||||
int param_len, int timeout);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -57,10 +57,21 @@ $Revision: 193 $
|
||||
|
||||
static int pack_id;
|
||||
static int sg_timeout;
|
||||
int sg_scsi_default_timeout = SG_SCSI_DEFAULT_TIMEOUT;
|
||||
|
||||
void set_timeout(int timeout)
|
||||
{
|
||||
sg_scsi_default_timeout = HZ*timeout;
|
||||
}
|
||||
|
||||
int get_timeout(void)
|
||||
{
|
||||
return(sg_scsi_default_timeout/HZ);
|
||||
}
|
||||
|
||||
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
|
||||
{
|
||||
int timeout = SG_SCSI_DEFAULT_TIMEOUT;
|
||||
int timeout = sg_scsi_default_timeout;
|
||||
#ifdef SG_IO
|
||||
int k; /* version */
|
||||
#endif
|
||||
@@ -93,7 +104,7 @@ void SCSI_Set_Timeout(int secs)
|
||||
|
||||
void SCSI_Default_Timeout(void)
|
||||
{
|
||||
sg_timeout = SG_SCSI_DEFAULT_TIMEOUT;
|
||||
sg_timeout = sg_scsi_default_timeout;
|
||||
}
|
||||
|
||||
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
|
||||
@@ -256,13 +267,13 @@ int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
|
||||
int write_length = sizeof(struct sg_header)+CDB_Length;
|
||||
int i; /* a random index... */
|
||||
int result; /* the result of the write... */
|
||||
int result; /* the result of the write... */
|
||||
|
||||
struct sg_header *Header; /* we actually point this into Command... */
|
||||
struct sg_header *ResultHeader; /* we point this into ResultBuf... */
|
||||
|
||||
/* First, see if we need to set our SCSI timeout to something different */
|
||||
if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
|
||||
if (sg_timeout != sg_scsi_default_timeout)
|
||||
{
|
||||
/* if not default, set it: */
|
||||
#ifdef DEBUG_TIMEOUT
|
||||
@@ -448,9 +459,9 @@ int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
|
||||
}
|
||||
|
||||
/* See if we need to reset our SCSI timeout */
|
||||
if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
|
||||
if (sg_timeout != sg_scsi_default_timeout)
|
||||
{
|
||||
sg_timeout = SG_SCSI_DEFAULT_TIMEOUT; /* reset it back to default */
|
||||
sg_timeout = sg_scsi_default_timeout; /* reset it back to default */
|
||||
|
||||
#ifdef DEBUG_TIMEOUT
|
||||
fprintf(stderr,"Setting timeout to %d\n", sg_timeout);
|
||||
|
||||
@@ -483,7 +483,7 @@ static void ReportTapeAlert(DEVICE_TYPE fd)
|
||||
{
|
||||
if (result->data[i])
|
||||
{
|
||||
printf("TapeAlert[%d]: %s.\n", i, tapealert_messages[i]);
|
||||
printf("TapeAlert[%x]: %s.\n", i, tapealert_messages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user