summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/machine/nscsi_hd.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/machine/nscsi_hd.c')
-rw-r--r--trunk/src/emu/machine/nscsi_hd.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/nscsi_hd.c b/trunk/src/emu/machine/nscsi_hd.c
new file mode 100644
index 00000000000..4138cc96127
--- /dev/null
+++ b/trunk/src/emu/machine/nscsi_hd.c
@@ -0,0 +1,286 @@
+#include "machine/nscsi_hd.h"
+#include "imagedev/harddriv.h"
+
+const device_type NSCSI_HARDDISK = &device_creator<nscsi_harddisk_device>;
+
+nscsi_harddisk_device::nscsi_harddisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ nscsi_full_device(mconfig, NSCSI_HARDDISK, "SCSI HARDDISK", tag, owner, clock)
+{
+}
+
+void nscsi_harddisk_device::device_start()
+{
+ nscsi_full_device::device_start();
+}
+
+void nscsi_harddisk_device::device_reset()
+{
+ nscsi_full_device::device_reset();
+ harddisk_image_device *hd = subdevice<harddisk_image_device>("image");
+ harddisk = hd->get_hard_disk_file();
+ if(!harddisk) {
+ scsi_id = -1;
+ bytes_per_sector = 0;
+ } else {
+ const hard_disk_info *hdinfo = hard_disk_get_info(harddisk);
+ bytes_per_sector = hdinfo->sectorbytes;
+ }
+ cur_lba = -1;
+}
+
+harddisk_interface nscsi_harddisk_device::hd_intf = { 0, 0 };
+
+static MACHINE_CONFIG_FRAGMENT(scsi_harddisk)
+ MCFG_HARDDISK_CONFIG_ADD("image", nscsi_harddisk_device::hd_intf)
+MACHINE_CONFIG_END
+
+machine_config_constructor nscsi_harddisk_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(scsi_harddisk);
+}
+
+UINT8 nscsi_harddisk_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(!hard_disk_read(harddisk, cur_lba, block)) {
+ logerror("%s: HD READ ERROR !\n", tag());
+ memset(block, 0, sizeof(block));
+ }
+ }
+ return block[pos % bytes_per_sector];
+}
+
+void nscsi_harddisk_device::scsi_put_data(int id, int pos, UINT8 data)
+{
+ if(id != 2) {
+ nscsi_full_device::scsi_put_data(id, pos, data);
+ return;
+ }
+
+ int offset = pos % bytes_per_sector;
+ block[offset] = data;
+ int clba = lba + pos / bytes_per_sector;
+ if(offset == bytes_per_sector-1) {
+ if(!hard_disk_write(harddisk, clba, block))
+ logerror("%s: HD WRITE ERROR !\n", tag());
+ }
+}
+
+void nscsi_harddisk_device::scsi_command()
+{
+ switch(scsi_cmdbuf[0]) {
+ case SC_TEST_UNIT_READY:
+ logerror("%s: command TEST UNIT READY\n", tag());
+ scsi_status_complete(SS_GOOD);
+ break;
+
+ case SC_READ:
+ lba = ((scsi_cmdbuf[1] & 0x1f)<<16) | (scsi_cmdbuf[2]<<8) | scsi_cmdbuf[3];
+ blocks = scsi_cmdbuf[4];
+ if(!blocks)
+ blocks = 256;
+
+ logerror("%s: command READ start=%08x blocks=%04x\n",
+ tag(), lba, blocks);
+
+ scsi_data_in(2, blocks*bytes_per_sector);
+ 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(),
+ lun, scsi_cmdbuf[1] & 1, scsi_cmdbuf[2], scsi_cmdbuf[4], scsi_cmdbuf[5]);
+ if(lun) {
+ bad_lun();
+ return;
+ }
+
+ int page = scsi_cmdbuf[2];
+ int size = scsi_cmdbuf[4];
+ switch(page) {
+ case 0:
+ memset(scsi_cmdbuf, 0, 148);
+ scsi_cmdbuf[0] = 0x00; // device is direct-access (e.g. hard disk)
+ scsi_cmdbuf[1] = 0x00; // media is not removable
+ scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard
+ scsi_cmdbuf[3] = 0x02; // response data format = SPC-3 standard
+ // Apple HD SC setup utility needs to see this
+ strcpy((char *)&scsi_cmdbuf[8], " SEAGATE");
+ strcpy((char *)&scsi_cmdbuf[16], " ST225N");
+ strcpy((char *)&scsi_cmdbuf[32], "1.0");
+ if(size > 148)
+ size = 148;
+ scsi_data_in(0, size);
+ break;
+ }
+ 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(),
+ lun, scsi_cmdbuf[2] & 0x3f, scsi_cmdbuf[4], scsi_cmdbuf[5]);
+ if(lun) {
+ bad_lun();
+ return;
+ }
+
+ int page = scsi_cmdbuf[2] & 0x3f;
+ int size = scsi_cmdbuf[4];
+ int pos = 1;
+ scsi_cmdbuf[pos++] = 0x00; // medium type
+ scsi_cmdbuf[pos++] = 0x00; // WP, cache
+
+ hard_disk_info *info = hard_disk_get_info(harddisk);
+ UINT32 dsize = info->cylinders * info->heads * info->sectors - 1;
+ scsi_cmdbuf[pos++] = 0x08; // Block descriptor length
+ scsi_cmdbuf[pos++] = 0x00;
+ scsi_cmdbuf[pos++] = (dsize>>16) & 0xff;
+ scsi_cmdbuf[pos++] = (dsize>>8) & 0xff;
+ scsi_cmdbuf[pos++] = (dsize & 0xff);
+ scsi_cmdbuf[pos++] = 0x00;
+ scsi_cmdbuf[pos++] = (info->sectorbytes>>16)&0xff;
+ scsi_cmdbuf[pos++] = (info->sectorbytes>>8)&0xff;
+ scsi_cmdbuf[pos++] = (info->sectorbytes & 0xff);
+
+ int pmax = page == 0x3f ? 0x3e : page;
+ int pmin = page == 0x3f ? 0x00 : page;
+ for(int page=pmax; page >= pmin; page--) {
+ switch(page) {
+ case 0x00: // Unit attention parameters page (weird)
+ scsi_cmdbuf[pos++] = 0x80; // PS, page id
+ scsi_cmdbuf[pos++] = 0x02; // Page length
+ scsi_cmdbuf[pos++] = 0x00; // Meh
+ scsi_cmdbuf[pos++] = 0x00; // Double meh
+ break;
+
+ case 0x03: { // Format parameters page
+ scsi_cmdbuf[pos++] = 0x83; // PS, page id
+ scsi_cmdbuf[pos++] = 0x16; // Page length
+ scsi_cmdbuf[pos++] = (info->cylinders * info->heads) >> 8; // Track/zone
+ scsi_cmdbuf[pos++] = info->cylinders * info->heads; // Track/zone
+ scsi_cmdbuf[pos++] = 0x00; // Alt sect/zone
+ scsi_cmdbuf[pos++] = 0x00; // Alt sect/zone
+ scsi_cmdbuf[pos++] = 0x00; // Alt track/zone
+ scsi_cmdbuf[pos++] = 0x00; // Alt track/zone
+ scsi_cmdbuf[pos++] = 0x00; // Alt track/volume
+ scsi_cmdbuf[pos++] = 0x00; // Alt track/volume
+ scsi_cmdbuf[pos++] = info->sectors >> 8; // Sectors/track
+ scsi_cmdbuf[pos++] = info->sectors; // Sectors/track
+ scsi_cmdbuf[pos++] = info->sectorbytes >> 8; // Bytes/sector
+ scsi_cmdbuf[pos++] = info->sectorbytes; // Bytes/sector
+ scsi_cmdbuf[pos++] = 0x00; // Interleave
+ scsi_cmdbuf[pos++] = 0x00; // Interleave
+ scsi_cmdbuf[pos++] = 0x00; // Track skew
+ scsi_cmdbuf[pos++] = 0x00; // Track skew
+ scsi_cmdbuf[pos++] = 0x00; // Cylinder skew
+ scsi_cmdbuf[pos++] = 0x00; // Cylinder skew
+ scsi_cmdbuf[pos++] = 0x00; // Sectoring type
+ scsi_cmdbuf[pos++] = 0x00; // Reserved
+ scsi_cmdbuf[pos++] = 0x00; // Reserved
+ scsi_cmdbuf[pos++] = 0x00; // Reserved
+ break;
+ }
+
+ case 0x04: { // Rigid drive geometry page
+ scsi_cmdbuf[pos++] = 0x84; // PS, page id
+ scsi_cmdbuf[pos++] = 0x16; // Page length
+ scsi_cmdbuf[pos++] = info->cylinders >> 16; // Cylinders
+ scsi_cmdbuf[pos++] = info->cylinders >> 8; // Cylinders
+ scsi_cmdbuf[pos++] = info->cylinders; // Cylinders
+ scsi_cmdbuf[pos++] = info->heads; // Heads
+ scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - write precomp
+ scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - write precomp
+ scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - write precomp
+ scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - reduced write current
+ scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - reduced write current
+ scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - reduced write current
+ scsi_cmdbuf[pos++] = 0x00; // Drive step rate
+ scsi_cmdbuf[pos++] = 0x00; // Drive step rate
+ scsi_cmdbuf[pos++] = 0x00; // Landing zone cylinder
+ scsi_cmdbuf[pos++] = 0x00; // Landing zone cylinder
+ scsi_cmdbuf[pos++] = 0x00; // Landing zone cylinder
+ scsi_cmdbuf[pos++] = 0x00; // RPL
+ scsi_cmdbuf[pos++] = 0x00; // Rotational offset
+ scsi_cmdbuf[pos++] = 0x00; // Reserved
+ scsi_cmdbuf[pos++] = UINT8(10000 >> 8); // Medium rotation rate
+ scsi_cmdbuf[pos++] = UINT8(10000); // Medium rotation rate
+ scsi_cmdbuf[pos++] = 0x00; // Reserved
+ scsi_cmdbuf[pos++] = 0x00; // Reserved
+ break;
+ }
+
+ default:
+ logerror("%s: mode sense page %02x unhandled\n", tag(), page);
+ break;
+ }
+ }
+ scsi_cmdbuf[0] = pos;
+ if(pos > size)
+ pos = size;
+
+ scsi_data_in(0, pos);
+ scsi_status_complete(SS_GOOD);
+ break;
+ }
+
+ case SC_START_STOP_UNIT:
+ logerror("%s: command START STOP UNIT\n", tag());
+ scsi_status_complete(SS_GOOD);
+ break;
+
+ case SC_READ_CAPACITY: {
+ logerror("%s: command READ CAPACITY\n", tag());
+
+ hard_disk_info *info = hard_disk_get_info(harddisk);
+ UINT32 size = info->cylinders * info->heads * info->sectors - 1;
+
+ scsi_cmdbuf[0] = (size>>24) & 0xff;
+ scsi_cmdbuf[1] = (size>>16) & 0xff;
+ scsi_cmdbuf[2] = (size>>8) & 0xff;
+ scsi_cmdbuf[3] = (size & 0xff);
+ scsi_cmdbuf[4] = (info->sectorbytes>>24)&0xff;
+ scsi_cmdbuf[5] = (info->sectorbytes>>16)&0xff;
+ scsi_cmdbuf[6] = (info->sectorbytes>>8)&0xff;
+ scsi_cmdbuf[7] = (info->sectorbytes & 0xff);
+
+ scsi_data_in(0, 8);
+ scsi_status_complete(SS_GOOD);
+ break;
+ }
+
+ case SC_READ_EXTENDED:
+ 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);
+
+ scsi_data_in(2, blocks*bytes_per_sector);
+ scsi_status_complete(SS_GOOD);
+ break;
+
+ case SC_WRITE_EXTENDED:
+ 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 WRITE EXTENDED start=%08x blocks=%04x\n",
+ tag(), lba, blocks);
+
+ scsi_data_out(2, blocks*bytes_per_sector);
+ scsi_status_complete(SS_GOOD);
+ break;
+
+ default:
+ nscsi_full_device::scsi_command();
+ break;
+ }
+}