1
0
Files
irix-657m-src/eoe/cmd/mediad/dev_dat.C
2022-09-29 17:59:04 +03:00

302 lines
6.6 KiB
C

#include <assert.h>
#include <bstring.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mtio.h>
#include <sys/tpsc.h>
#include <mediad.h>
#include "DeviceInfo.H"
#include "Device.H"
#include "DSReq.H"
#include "Log.H"
#include "PartitionAddress.H"
#include "SCSIAddress.H"
#include "VolumeAddress.H"
class DATDevice : public Device {
public:
DATDevice(const DeviceInfo&);
~DATDevice();
const char *short_name() const { return "DAT"; }
const char *full_name() const { return "DAT"; }
const char *ftr_name() const { return "dat"; }
const char *dev_name(FormatIndex, int partno) const;
// Device capabilities
virtual int features();
// Media presence support
virtual int suspend_monitoring();
virtual int resume_monitoring();
virtual int is_media_present();
virtual int eject();
virtual int lock_media();
virtual int unlock_media();
// Media access
int capacity();
int sector_size(FormatIndex) { return SECTOR_SIZE; }
bool is_write_protected();
bool has_audio_data();
int read_data(char *, __uint64_t, unsigned, unsigned);
private:
// Device-specific constants
enum { SECTOR_SIZE = 512 };
// Device-specific variables
int _fd_stat;
char _rw_path[64]; // Path to rewinding device
char _nr_path[64]; // Path to nonrewinding device
char _stat_device[100]; // Path to stat device
};
//////////////////////////////////////////////////////////////////////////////
DATDevice::DATDevice(const DeviceInfo& info)
: Device(info)
{
const DeviceAddress& da = info.address();
const SCSIAddress *sa = info.address().as_SCSIAddress();
assert(sa != 0);
// Check whether this tape is /dev/tape. If not,
// generate a /dev/rmt/tps pathname.
VolumeAddress devtape("/dev/tape");
const PartitionAddress *tape_pa = devtape.partition(0);
if (tape_pa != NULL && tape_pa->device() == da)
strcpy(_rw_path, "/dev/tape");
else
sprintf(_rw_path, "/dev/rmt/tps%ud%uv", sa->ctlr(), sa->id());
// Check whether this tape is /dev/tape. If not,
// generate a /dev/rmt/tps pathname.
VolumeAddress devtapenr("/dev/nrtape");
const PartitionAddress *tapenr_pa = devtapenr.partition(0);
if (tapenr_pa != NULL && tapenr_pa->device() == da)
strcpy(_nr_path, "/dev/nrtape");
else
sprintf(_nr_path, "/dev/rmt/tps%ud%unrv", sa->ctlr(), sa->id());
sprintf(_stat_device, "/dev/rmt/tps%ud%ustat", sa->ctlr(), sa->id());
(void) resume_monitoring();
}
DATDevice::~DATDevice()
{
(void) close(_fd_stat);
}
const char *
DATDevice::dev_name(FormatIndex fi, int partno) const
{
if (fi == FMT_RAW && partno == PartitionAddress::WholeDisk)
return _rw_path;
else
return _nr_path;
}
int
DATDevice::features()
{
int add = FILESYS_AUDIO;
int remove = (0xFF & ~FILESYS_RAW) | FEATURE_MOUNTABLE;
return feature_set(add, remove);
}
int
DATDevice::suspend_monitoring()
{
(void) close(_fd_stat);
_fd_stat = -1;
return 0;
}
int
DATDevice::resume_monitoring()
{
_fd_stat = open(_stat_device, O_RDONLY);
if (_fd_stat < 0)
{
Log::perror("can't open DAT device %s", _stat_device);
return -1;
}
if (fcntl(_fd_stat, F_SETFD, FD_CLOEXEC) < 0)
{
Log::perror("DAT F_SETFD fcntl failed");
return -1;
}
return 0;
}
int
DATDevice::is_media_present()
{
struct mtget mt_status;
bzero(&mt_status, sizeof mt_status);
mt_status.mt_type = MTNOP;
if (ioctl(_fd_stat, MTIOCGET, &mt_status) != 0)
{ Log::perror("tape device \"%s\" MTIOCGET", _stat_device);
return false;
}
// The status is a 32bit word
// Lower 16 are returned in: mt_dsreg
// Upper 16 are returned in: mt_erreg
// We look for any of:
// (1) CT_LOADED = 0x20000 - in erreg
// (2) CT_MOTION = 0x20 - in dsreg
// (3) CT_ONL = 0x40 - in dsreg
if ((mt_status.mt_erreg & (CT_LOADED>>16)) ||
(mt_status.mt_dsreg & CT_MOTION) ||
(mt_status.mt_dsreg & CT_ONL)){
return (true);
}
else return (false);
}
int
DATDevice::eject()
{
Log::debug("DATDevice::eject()");
DSReq::close_all();
int fd = open(_nr_path, O_RDONLY);
if (fd < 0)
return errno == EIO ? RMED_NOERROR : RMED_ENODISC;
struct mtop mt_com;
bzero(&mt_com, sizeof mt_com);
mt_com.mt_op = MTUNLOAD;
if (ioctl(fd, MTIOCTOP, &mt_com) != 0)
{ if (errno != EAGAIN)
Log::perror("DAT device \"%s\"", _nr_path);
(void) close(fd);
return RMED_ECANTEJECT;
}
(void) close(fd);
return RMED_NOERROR;
}
int
DATDevice::lock_media()
{
return 0; // Don't bother locking tapes.
}
int
DATDevice::unlock_media()
{
return 0; // No real lock/unlock, just be happy.
}
int
DATDevice::capacity()
{
assert(0);
return -1;
}
bool
DATDevice::is_write_protected()
{
// Use an MTIOCGET ioctl to learn whether the tape is present.
struct mtget mt_status;
bzero(&mt_status, sizeof mt_status);
mt_status.mt_type = MTNOP;
if (ioctl(_fd_stat, MTIOCGET, &mt_status) != 0)
{ Log::perror("DAT device \"%s\" MTIOCGET", _stat_device);
return false;
}
// Return true iff the tape is write-protected.
if (mt_status.mt_dposn & MT_WPROT)
return true;
else
return false;
}
bool
DATDevice::has_audio_data()
{
// Use an MTIOCGET ioctl to learn whether the tape is audio.
struct mtget mt_status;
bzero(&mt_status, sizeof mt_status);
mt_status.mt_type = MTNOP;
if (ioctl(_fd_stat, MTIOCGET, &mt_status) != 0)
{ Log::perror("DAT device \"%s\" MTIOCGET", _stat_device);
return false;
}
// Return true iff the tape is an audio medium.
// The following code is weird -- I stole it from old mediad.
// If there's a better definition for the DAT-specific mtget
// structure, I don't know where it is.
return ((ulong) mt_status.mt_erreg << 16 & CT_AUD_MED) != 0;
}
int
DATDevice::read_data(char * /* buffer */,
__uint64_t /* start_sector */,
unsigned /* nsectors */,
unsigned /* sectorsize */ )
{
assert(0);
return -1;
}
//////////////////////////////////////////////////////////////////////////////
extern "C"
Device *
instantiate(const DeviceInfo& info)
{
// H/W inventory must say it's a tape.
const inventory_s& inv = info.inventory();
if (inv.inv_class != INV_TAPE)
return NULL;
// Must be a SCSI device.
const SCSIAddress *sa = info.address().as_SCSIAddress();
if (!sa)
return NULL;
// SCSI LUN must be zero;
if (sa->lun() != 0)
return NULL;
if (TPDAT != inv.inv_state)
return NULL;
// All tests passed -- create DATDevice.
return new DATDevice(info);
}