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

336 lines
7.4 KiB
C

#include <assert.h>
#include <bstring.h>
#include <dslib.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/dkio.h>
#include <sys/smfd.h>
#include <unistd.h>
#include <mediad.h>
#include "DeviceInfo.H"
#include "Device.H"
#include "DSReq.H"
#include "Log.H"
#include "PartitionAddress.H"
#include "SCSIAddress.H"
class FloppyDevice : public Device {
public:
FloppyDevice(const DeviceInfo&);
const char *short_name() const { return "floppy"; }
const char *full_name() const { return "floppy"; }
const char *ftr_name() const { return "floppy"; }
const char *dev_name(FormatIndex, int partno) const;
// Device capabilities
virtual int features();
// Media presence support
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();
int read_data(char *, __uint64_t, unsigned, unsigned);
private:
// Device-specific constants
enum Brand { GENERIC, INSITE, TEAC, NCR };
enum { SECTOR_SIZE = 512 };
enum States { NORMAL, EXPECTING_EJECT };
// Device-specific method
States state;
Brand _brand;
bool _supports_sw_eject;
bool _supports_sw_lock;
char _smfd_name_hi[24];
char _smfd_name_lo[24];
int _capacity;
DSReq _dsr;
};
static const char Insite[] = "INSITE";
static const char Teac[] = "TEAC";
static const char Ncr[] = "NCR";
//////////////////////////////////////////////////////////////////////////////
FloppyDevice::FloppyDevice(const DeviceInfo& info)
: Device(info),
_brand(GENERIC),
_dsr(*info.address().as_SCSIAddress()),
_supports_sw_eject(true),
_supports_sw_lock(true),
_capacity(-1)
{
const SCSIAddress *sa = info.address().as_SCSIAddress();
(void) sprintf(_smfd_name_hi, "/dev/rdsk/fds%ud%u.3.5hi",
sa->ctlr(), sa->id());
(void) sprintf(_smfd_name_lo, "/dev/rdsk/fds%ud%u.3.5",
sa->ctlr(), sa->id());
const char *inquiry = info.inquiry();
const char *vendor = inquiry + 8;
if (!strncasecmp(vendor, Insite, strlen(Insite)))
_brand = INSITE;
else if (!strncasecmp(vendor, Teac, strlen(Teac))){
_brand = TEAC;
_supports_sw_eject = true;
_supports_sw_lock = false;
}
else if (!strncasecmp(vendor, Ncr, strlen(Ncr))){
_brand = NCR;
_supports_sw_eject = false;
_supports_sw_lock = false;
}
state = NORMAL;
}
const char *
FloppyDevice::dev_name(FormatIndex, int /* partno */ ) const
{
// The TEAC SCSI floppy only supports two capacities:
// 1440 and 2880. The Insite floptical works fine
// no matter which device you access it through.
// So we skimp a little on generating the device name.
return _capacity == 1440 ? _smfd_name_lo : _smfd_name_hi;
}
int
FloppyDevice::features()
{
int remove = FILESYS_EFS | FILESYS_XFS;
if (!_supports_sw_lock)
remove |= FEATURE_SW_LOCK;
if (!_supports_sw_eject)
remove |= FEATURE_SW_EJECT;
return feature_set(0, remove);
}
int
FloppyDevice::is_media_present()
{
dsreq *dsp = _dsr;
char asc, asq;
if (state == NORMAL){
if (!dsp)
return -1;
testunitready00(dsp);
if (STATUS(dsp) != STA_GOOD){
if (dsp->ds_sensebuf != NULL && dsp->ds_senselen >= 14){
asc = dsp->ds_sensebuf[12];
asq = dsp->ds_sensebuf[13];
if (asc == 0x04 && asq == 0x00)
{ _capacity = -1;
return (false);
}
}
return (true);
}
return (true);
}
else {
if (!dsp)
return -1;
testunitready00(dsp);
if (dsp->ds_sensebuf != NULL && dsp->ds_senselen >= 14){
asc = dsp->ds_sensebuf[12];
asq = dsp->ds_sensebuf[13];
if (STATUS(dsp) != STA_GOOD){
if (asc == 0x28 && asq == 0x00)
state = NORMAL;
}
}
_capacity = -1;
return (false);
}
}
int
FloppyDevice::eject()
{
#define FLEJECT_RETRY_COUNT 3
#define FLEJECT_RETRY_INTERVAL 2
Log::debug("FloppyDevice::eject()");
if (_supports_sw_eject){
int fd = open(_smfd_name_hi, O_RDONLY);
if (fd < 0)
return RMED_ENODISC;
if (ioctl(fd, SMFDEJECT, 0) != 0)
{ Log::perror("floppy device \"%s\"", _smfd_name_hi);
(void) close(fd);
return RMED_ECANTEJECT;
}
(void) close(fd);
}
else {
state = EXPECTING_EJECT;
}
_capacity = -1;
return RMED_NOERROR;
}
int
FloppyDevice::lock_media()
{
return 0;
}
int
FloppyDevice::unlock_media()
{
return 0; // No real lock/unlock, just be happy
}
int
FloppyDevice::capacity()
{
switch (_brand)
{
default:
{
// On Insite floptical drive, READ CAPACITY command works.
// Assume, brashly, that other drives work as well.
int fd = open(_smfd_name_hi, O_RDONLY);
if (fd < 0)
return -1;
_capacity = -1;
(void) ioctl(fd, DIOCREADCAPACITY, &_capacity);
(void) close(fd);
}
break;
case TEAC:
{
// Try reading the high density device.
char sector[512];
int fd, rc;
_capacity = -1;
fd = open(_smfd_name_hi, O_RDONLY);
if (fd < 0)
return -1;
rc = read(fd, sector, sizeof sector);
(void) close(fd);
if (rc == sizeof sector)
_capacity = 2880; // High density read works.
if (_capacity == -1)
{
fd = open(_smfd_name_lo, O_RDONLY);
if (fd < 0)
return -1;
rc = read(fd, sector, sizeof sector);
(void) close(fd);
if (rc == sizeof sector)
_capacity = 1440; // Low density read works.
}
}
}
Log::debug("Floppy capacity is %d sectors", _capacity);
return _capacity;
}
bool
FloppyDevice::is_write_protected()
{
int fd = open(_smfd_name_hi, O_RDONLY);
if (fd < 0)
return false;
int status;
if (ioctl(fd, SMFDMEDIA, &status) == -1)
{ (void) close(fd);
return false;
}
(void) close(fd);
return (status & SMFDMEDIA_WRITE_PROT) ? true : false;
}
int
FloppyDevice::read_data(char *buffer,
__uint64_t start_sector,
unsigned nsectors,
unsigned sectorsize)
{
assert(start_sector < 65536);
assert(nsectors < 256);
if (sectorsize != SECTOR_SIZE)
return EINVAL; // Is this necessary?
if (_capacity == -1)
(void) capacity(); // initialize _capacity so we open
// the right device.
int fd = open(dev_name(FMT_RAW, PartitionAddress::WholeDisk), O_RDONLY);
if (fd < 0)
return errno;
if (lseek(fd, (off_t) (sectorsize * start_sector), SEEK_SET) == -1)
{ (void) close(fd);
return errno;
}
int nbytes = nsectors * sectorsize;
for (int i = 0, j = 0; i < nbytes; i += j)
{ j = read(fd, buffer + i, nbytes - i);
if (j <= 0)
{ (void) close(fd);
return j == 0 ? ENOSPC : errno;
}
}
(void) close(fd);
return 0;
}
//////////////////////////////////////////////////////////////////////////////
extern "C"
Device *
instantiate(const DeviceInfo& info)
{
const inventory_s& inv = info.inventory();
if (inv.inv_class != INV_DISK || inv.inv_type != INV_SCSIFLOPPY)
return NULL;
const SCSIAddress *sa = info.address().as_SCSIAddress();
if (!sa)
return NULL;
if (sa->lun() != 0)
return NULL;
const char *inquiry = info.inquiry();
if (!inquiry)
return NULL;
const char *vendor = inquiry + 8;
if (strncasecmp(vendor, Insite, strlen(Insite)) &&
strncasecmp(vendor, Teac, strlen(Teac)) &&
strncasecmp(vendor, Ncr, strlen(Ncr)))
return NULL;
return new FloppyDevice(info);
}