mirror of
https://github.com/holub/mame
synced 2025-04-22 08:22:15 +03:00
nscsi: add support for CD-ROMs with 512-byte blocks (#3727)
* nscsi: add support for CD-ROMs with 512-byte blocks Older UNIX workstations used SCSI CD-ROM drives with 512-byte logical blocks instead of the now standard 2048. This change makes the block size configurable, and adds logic to translate logical blocks to/from the underlying 2048 byte sectors as needed. * add support for 512-byte logical blocks * logmacro.h logging (turned on by default to retain current behaviour) * added stub for "prevent/allow medium removal" command * removed some unnecessary state * minor fix for nscsi_hd "inquiry" command * minor changes (nw) * doh (nw) * this too (nw)
This commit is contained in:
parent
ab0f99373d
commit
5d9e33b786
@ -4,22 +4,23 @@
|
||||
#include "machine/nscsi_cd.h"
|
||||
#include "imagedev/chd_cd.h"
|
||||
|
||||
#define VERBOSE 1
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(NSCSI_CDROM, nscsi_cdrom_device, "scsi_cdrom", "SCSI CD-ROM")
|
||||
|
||||
nscsi_cdrom_device::nscsi_cdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
nscsi_full_device(mconfig, NSCSI_CDROM, tag, owner, clock), cdrom(nullptr), bytes_per_sector(0), lba(0), cur_lba(0), blocks(0)
|
||||
nscsi_full_device(mconfig, NSCSI_CDROM, tag, owner, clock), cdrom(nullptr), bytes_per_block(bytes_per_sector), lba(0), cur_sector(0)
|
||||
{
|
||||
}
|
||||
|
||||
void nscsi_cdrom_device::device_start()
|
||||
{
|
||||
nscsi_full_device::device_start();
|
||||
bytes_per_sector = 2048;
|
||||
save_item(NAME(block));
|
||||
save_item(NAME(sector_buffer));
|
||||
save_item(NAME(lba));
|
||||
save_item(NAME(cur_lba));
|
||||
save_item(NAME(blocks));
|
||||
save_item(NAME(bytes_per_sector));
|
||||
save_item(NAME(cur_sector));
|
||||
save_item(NAME(bytes_per_block));
|
||||
}
|
||||
|
||||
void nscsi_cdrom_device::device_reset()
|
||||
@ -27,8 +28,7 @@ void nscsi_cdrom_device::device_reset()
|
||||
nscsi_full_device::device_reset();
|
||||
cdrom = subdevice<cdrom_image_device>("image")->get_cdrom_file();
|
||||
lba = 0;
|
||||
blocks = 0;
|
||||
cur_lba = -1;
|
||||
cur_sector = -1;
|
||||
}
|
||||
|
||||
MACHINE_CONFIG_START(nscsi_cdrom_device::device_add_mconfig)
|
||||
@ -36,20 +36,28 @@ MACHINE_CONFIG_START(nscsi_cdrom_device::device_add_mconfig)
|
||||
MCFG_CDROM_INTERFACE("cdrom")
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
void nscsi_cdrom_device::set_block_size(u32 block_size)
|
||||
{
|
||||
assert_always(!started(), "block size should not be set after device start");
|
||||
assert_always(bytes_per_sector % block_size == 0, "block size must be a factor of sector size");
|
||||
|
||||
bytes_per_block = block_size;
|
||||
};
|
||||
|
||||
|
||||
uint8_t nscsi_cdrom_device::scsi_get_data(int id, int pos)
|
||||
{
|
||||
if(id != 2)
|
||||
return nscsi_full_device::scsi_get_data(id, pos);
|
||||
int clba = lba + pos / bytes_per_sector;
|
||||
if(clba != cur_lba) {
|
||||
cur_lba = clba;
|
||||
if(!cdrom_read_data(cdrom, cur_lba, block, CD_TRACK_MODE1)) {
|
||||
logerror("%s: CD READ ERROR !\n", tag());
|
||||
memset(block, 0, sizeof(block));
|
||||
int sector = (lba * bytes_per_block + pos) / bytes_per_sector;
|
||||
if(sector != cur_sector) {
|
||||
cur_sector = sector;
|
||||
if(!cdrom_read_data(cdrom, sector, sector_buffer, CD_TRACK_MODE1)) {
|
||||
LOG("CD READ ERROR sector %d!\n", sector);
|
||||
std::fill_n(sector_buffer, sizeof(sector_buffer), 0);
|
||||
}
|
||||
}
|
||||
return block[pos & (bytes_per_sector - 1)];
|
||||
return sector_buffer[pos & (bytes_per_sector - 1)];
|
||||
}
|
||||
|
||||
void nscsi_cdrom_device::return_no_cd()
|
||||
@ -60,9 +68,11 @@ void nscsi_cdrom_device::return_no_cd()
|
||||
|
||||
void nscsi_cdrom_device::scsi_command()
|
||||
{
|
||||
int blocks;
|
||||
|
||||
switch(scsi_cmdbuf[0]) {
|
||||
case SC_TEST_UNIT_READY:
|
||||
logerror("%s: command TEST UNIT READY\n", tag());
|
||||
LOG("command TEST UNIT READY\n");
|
||||
if(cdrom)
|
||||
scsi_status_complete(SS_GOOD);
|
||||
else
|
||||
@ -80,17 +90,15 @@ void nscsi_cdrom_device::scsi_command()
|
||||
if(!blocks)
|
||||
blocks = 256;
|
||||
|
||||
logerror("%s: command READ start=%08x blocks=%04x\n",
|
||||
tag(), lba, blocks);
|
||||
LOG("command READ start=%08x blocks=%04x\n", lba, blocks);
|
||||
|
||||
scsi_data_in(2, blocks*bytes_per_sector);
|
||||
scsi_data_in(2, blocks*bytes_per_block);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
case SC_INQUIRY: {
|
||||
int lun = get_lun(scsi_cmdbuf[1] >> 5);
|
||||
logerror("%s: command INQUIRY lun=%d EVPD=%d page=%d alloc=%02x link=%02x\n",
|
||||
tag(),
|
||||
LOG("command INQUIRY lun=%d EVPD=%d page=%d alloc=%02x link=%02x\n",
|
||||
lun, scsi_cmdbuf[1] & 1, scsi_cmdbuf[2], scsi_cmdbuf[4], scsi_cmdbuf[5]);
|
||||
if(lun) {
|
||||
bad_lun();
|
||||
@ -101,16 +109,20 @@ void nscsi_cdrom_device::scsi_command()
|
||||
int size = scsi_cmdbuf[4];
|
||||
switch(page) {
|
||||
case 0:
|
||||
memset(scsi_cmdbuf, 0, 148);
|
||||
std::fill_n(scsi_cmdbuf, 148, 0);
|
||||
|
||||
// vendor and product information must be padded with spaces
|
||||
std::fill_n(&scsi_cmdbuf[8], 28, 0x20);
|
||||
|
||||
scsi_cmdbuf[0] = 0x05; // device is present, device is CD/DVD (MMC-3)
|
||||
scsi_cmdbuf[1] = 0x80; // media is removable
|
||||
scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard
|
||||
scsi_cmdbuf[3] = 0x02; // response data format = SPC-3 standard
|
||||
// some Konami games freak out if this isn't "Sony", so we'll lie
|
||||
// this is the actual drive on my Nagano '98 board
|
||||
strcpy((char *)&scsi_cmdbuf[8], "Sony");
|
||||
strcpy((char *)&scsi_cmdbuf[16], "CDU-76S");
|
||||
strcpy((char *)&scsi_cmdbuf[32], "1.0");
|
||||
strncpy((char *)&scsi_cmdbuf[8], "Sony", 4);
|
||||
strncpy((char *)&scsi_cmdbuf[16], "CDU-76S", 7);
|
||||
strncpy((char *)&scsi_cmdbuf[32], "1.0", 3);
|
||||
if(size > 148)
|
||||
size = 148;
|
||||
scsi_data_in(SBUF_MAIN, size);
|
||||
@ -121,7 +133,7 @@ void nscsi_cdrom_device::scsi_command()
|
||||
}
|
||||
|
||||
case SC_START_STOP_UNIT:
|
||||
logerror("%s: command START STOP UNIT\n", tag());
|
||||
LOG("command START STOP UNIT\n");
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
@ -131,10 +143,10 @@ void nscsi_cdrom_device::scsi_command()
|
||||
break;
|
||||
}
|
||||
|
||||
logerror("%s: command READ CAPACITY\n", tag());
|
||||
LOG("command READ CAPACITY\n");
|
||||
|
||||
uint32_t temp = cdrom_get_track_start(cdrom, 0xaa);
|
||||
temp--; // return the last used block on the disc
|
||||
// get the last used block on the disc
|
||||
const uint32_t temp = cdrom_get_track_start(cdrom, 0xaa) * (bytes_per_sector / bytes_per_block) - 1;
|
||||
|
||||
scsi_cmdbuf[0] = (temp>>24) & 0xff;
|
||||
scsi_cmdbuf[1] = (temp>>16) & 0xff;
|
||||
@ -142,8 +154,8 @@ void nscsi_cdrom_device::scsi_command()
|
||||
scsi_cmdbuf[3] = (temp & 0xff);
|
||||
scsi_cmdbuf[4] = 0;
|
||||
scsi_cmdbuf[5] = 0;
|
||||
scsi_cmdbuf[6] = (bytes_per_sector>>8)&0xff;
|
||||
scsi_cmdbuf[7] = (bytes_per_sector & 0xff);
|
||||
scsi_cmdbuf[6] = (bytes_per_block>>8)&0xff;
|
||||
scsi_cmdbuf[7] = (bytes_per_block & 0xff);
|
||||
|
||||
scsi_data_in(SBUF_MAIN, 8);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
@ -159,17 +171,15 @@ void nscsi_cdrom_device::scsi_command()
|
||||
lba = (scsi_cmdbuf[2]<<24) | (scsi_cmdbuf[3]<<16) | (scsi_cmdbuf[4]<<8) | scsi_cmdbuf[5];
|
||||
blocks = (scsi_cmdbuf[7] << 8) | scsi_cmdbuf[8];
|
||||
|
||||
logerror("%s: command READ EXTENDED start=%08x blocks=%04x\n",
|
||||
tag(), lba, blocks);
|
||||
LOG("command READ EXTENDED start=%08x blocks=%04x\n", lba, blocks);
|
||||
|
||||
scsi_data_in(2, blocks*bytes_per_sector);
|
||||
scsi_data_in(2, blocks*bytes_per_block);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
case SC_MODE_SENSE_6: {
|
||||
int lun = get_lun(scsi_cmdbuf[1] >> 5);
|
||||
logerror("%s: command MODE SENSE 6 lun=%d page=%02x alloc=%02x link=%02x\n",
|
||||
tag(),
|
||||
LOG("command MODE SENSE 6 lun=%d page=%02x alloc=%02x link=%02x\n",
|
||||
lun, scsi_cmdbuf[2] & 0x3f, scsi_cmdbuf[4], scsi_cmdbuf[5]);
|
||||
if(lun) {
|
||||
bad_lun();
|
||||
@ -182,8 +192,8 @@ void nscsi_cdrom_device::scsi_command()
|
||||
scsi_cmdbuf[pos++] = 0x00; // medium type
|
||||
scsi_cmdbuf[pos++] = 0x80; // WP, cache
|
||||
|
||||
uint32_t temp = cdrom_get_track_start(cdrom, 0xaa);
|
||||
temp--; // return the last used block on the disc
|
||||
// get the last used block on the disc
|
||||
const uint32_t temp = cdrom_get_track_start(cdrom, 0xaa) * (bytes_per_sector / bytes_per_block) - 1;
|
||||
scsi_cmdbuf[pos++] = 0x08; // Block descriptor length
|
||||
|
||||
scsi_cmdbuf[pos++] = (temp>>24) & 0xff;
|
||||
@ -192,8 +202,8 @@ void nscsi_cdrom_device::scsi_command()
|
||||
scsi_cmdbuf[pos++] = (temp & 0xff);
|
||||
scsi_cmdbuf[pos++] = 0;
|
||||
scsi_cmdbuf[pos++] = 0;
|
||||
scsi_cmdbuf[pos++] = (bytes_per_sector>>8)&0xff;
|
||||
scsi_cmdbuf[pos++] = (bytes_per_sector & 0xff);
|
||||
scsi_cmdbuf[pos++] = (bytes_per_block>>8)&0xff;
|
||||
scsi_cmdbuf[pos++] = (bytes_per_block & 0xff);
|
||||
|
||||
int pmax = page == 0x3f ? 0x3e : page;
|
||||
int pmin = page == 0x3f ? 0x00 : page;
|
||||
@ -226,7 +236,7 @@ void nscsi_cdrom_device::scsi_command()
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("%s: mode sense page %02x unhandled\n", tag(), page);
|
||||
LOG("mode sense page %02x unhandled\n", page);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -239,8 +249,14 @@ void nscsi_cdrom_device::scsi_command()
|
||||
break;
|
||||
}
|
||||
|
||||
case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||
// TODO: support eject prevention
|
||||
LOG("command PREVENT ALLOW MEDIUM REMOVAL\n");
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "scsi %02x\n", scsi_cmdbuf[0]);
|
||||
logerror("unhandled command %02x\n", scsi_cmdbuf[0]);
|
||||
|
||||
nscsi_full_device::scsi_command();
|
||||
break;
|
||||
|
@ -13,6 +13,8 @@ class nscsi_cdrom_device : public nscsi_full_device
|
||||
public:
|
||||
nscsi_cdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
void set_block_size(u32 block_size);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
@ -22,10 +24,12 @@ protected:
|
||||
virtual uint8_t scsi_get_data(int id, int pos) override;
|
||||
|
||||
private:
|
||||
uint8_t block[2048];
|
||||
static constexpr uint32_t bytes_per_sector = 2048;
|
||||
|
||||
uint8_t sector_buffer[bytes_per_sector];
|
||||
cdrom_file *cdrom;
|
||||
int bytes_per_sector;
|
||||
int lba, cur_lba, blocks;
|
||||
uint32_t bytes_per_block;
|
||||
int lba, cur_sector;
|
||||
|
||||
void return_no_cd();
|
||||
};
|
||||
|
@ -136,7 +136,11 @@ void nscsi_harddisk_device::scsi_command()
|
||||
int size = scsi_cmdbuf[4];
|
||||
switch(page) {
|
||||
case 0:
|
||||
memset(scsi_cmdbuf, 0, 148);
|
||||
std::fill_n(scsi_cmdbuf, 148, 0);
|
||||
|
||||
// vendor and product information must be padded with spaces
|
||||
std::fill_n(&scsi_cmdbuf[8], 28, 0x20);
|
||||
|
||||
// From Seagate SCSI Commands Reference Manual (http://www.seagate.com/staticfiles/support/disc/manuals/scsi/100293068a.pdf), page 73:
|
||||
// If the SCSI target device is not capable of supporting a peripheral device connected to this logical unit, the
|
||||
// device server shall set these fields to 7Fh (i.e., PERIPHERAL QUALIFIER field set to 011b and PERIPHERAL DEVICE
|
||||
@ -148,6 +152,7 @@ void nscsi_harddisk_device::scsi_command()
|
||||
scsi_cmdbuf[1] = 0x00; // media is not removable
|
||||
scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard
|
||||
scsi_cmdbuf[3] = 0x01; // response data format = CCS
|
||||
scsi_cmdbuf[4] = 52; // additional length
|
||||
if(m_inquiry_data.empty()) {
|
||||
LOG("IDNT tag not found in chd metadata, using default inquiry data\n");
|
||||
|
||||
|
@ -786,8 +786,7 @@ void interpro_state::interpro_scsi_adapter(device_t *device)
|
||||
|
||||
void interpro_state::interpro_cdrom(device_t *device)
|
||||
{
|
||||
// FIXME: enable when dependent code is committed
|
||||
//downcast<nscsi_cdrom_device &>(*device).set_block_size(512);
|
||||
downcast<nscsi_cdrom_device &>(*device).set_block_size(512);
|
||||
}
|
||||
|
||||
MACHINE_CONFIG_START(interpro_state::ioga)
|
||||
|
Loading…
Reference in New Issue
Block a user