summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nscsi/pc98_hd.cpp
blob: 264c2000af1e9706c6c04f30affa276675f38677 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// license:BSD-3-Clause
// copyright-holders:Angelo Salese

// Generic option for NEC-based hard disk drives

#include "emu.h"
#include "bus/nscsi/pc98_hd.h"

#define LOG_COMMAND     (1U << 1)
#define LOG_DATA        (1U << 2)
#define LOG_UNSUPPORTED (1U << 3)

#define VERBOSE 0

#include "logmacro.h"


DEFINE_DEVICE_TYPE(NSCSI_PC98_HD, nscsi_pc98_hd_device, "scsi_pc98_hd", "NEC PC-98 SCSI Hard Disk")

nscsi_pc98_hd_device::nscsi_pc98_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	nscsi_harddisk_device(mconfig, NSCSI_PC98_HD, tag, owner, clock)
{
}

void nscsi_pc98_hd_device::scsi_command()
{
	if(m_scsi_cmdbuf[0] != SC_READ_6) {
		LOGMASKED(LOG_COMMAND, "%02x %02x %02x %02x %02x %02x\n",
			m_scsi_cmdbuf[0], m_scsi_cmdbuf[1], m_scsi_cmdbuf[2],
			m_scsi_cmdbuf[3], m_scsi_cmdbuf[4], m_scsi_cmdbuf[5]);
	}

	switch(m_scsi_cmdbuf[0]) {
	case SC_INQUIRY: {
		int lun = get_lun(m_scsi_cmdbuf[1] >> 5);
		LOG("command INQUIRY lun=%d EVPD=%d page=%d alloc=%02x link=%02x\n",
			lun, m_scsi_cmdbuf[1] & 1, m_scsi_cmdbuf[2], m_scsi_cmdbuf[4], m_scsi_cmdbuf[5]);

		int page = m_scsi_cmdbuf[2];
		int size = m_scsi_cmdbuf[4];
		switch(page) {
		case 0:
			std::fill_n(m_scsi_cmdbuf, 148, 0);

			// vendor and product information must be padded with spaces
			std::fill_n(&m_scsi_cmdbuf[8], 28, 0x20);

			if (lun != 0)
				m_scsi_cmdbuf[0] = 0x7f;
			else
				m_scsi_cmdbuf[0] = 0x00; // device is direct-access (e.g. hard disk)
			m_scsi_cmdbuf[1] = 0x00; // media is not removable
			m_scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard
			m_scsi_cmdbuf[3] = 0x01; // response data format = CCS
			m_scsi_cmdbuf[4] = 52;   // additional length
			if(m_inquiry_data.empty()) {
				LOG("IDNT tag not found in chd metadata, using default inquiry data\n");

				// from np2kai, pc9801_55 wants to see "NEC" as part of their protection scheme
				strcpy((char *)&m_scsi_cmdbuf[8], "NECITSU ");
				// TODO: copied over base HD, to be filled properly
				strcpy((char *)&m_scsi_cmdbuf[16], "          ST225N");
				strcpy((char *)&m_scsi_cmdbuf[32], "1.00");
				m_scsi_cmdbuf[36] = 0x00; // # of extents high
				m_scsi_cmdbuf[37] = 0x08; // # of extents low
				m_scsi_cmdbuf[38] = 0x00; // group 0 commands 0-1f
				m_scsi_cmdbuf[39] = 0x99; // commands 0,3,4,7
				m_scsi_cmdbuf[40] = 0xa0; // commands 8, a
				m_scsi_cmdbuf[41] = 0x27; // commands 12,15,16,17
				m_scsi_cmdbuf[42] = 0x34; // commands 1a,1b,1d
				m_scsi_cmdbuf[43] = 0x01; // group 1 commands 20-3f
				m_scsi_cmdbuf[44] = 0x04;
				m_scsi_cmdbuf[45] = 0xa0;
				m_scsi_cmdbuf[46] = 0x01;
				m_scsi_cmdbuf[47] = 0x18;
				m_scsi_cmdbuf[48] = 0x07; // group 7 commands e0-ff
				m_scsi_cmdbuf[49] = 0x00;
				m_scsi_cmdbuf[50] = 0xa0; // commands 8, a
				m_scsi_cmdbuf[51] = 0x00;
				m_scsi_cmdbuf[52] = 0x00;
				m_scsi_cmdbuf[53] = 0xff; // end of list
			}
			else
				std::copy_n(m_inquiry_data.begin(), std::min(m_inquiry_data.size(), size_t(48)), &m_scsi_cmdbuf[8]);

			if(size > 56)
				size = 56;
			scsi_data_in(0, size);
			break;
		}
		scsi_status_complete(SS_GOOD);
		break;
	}


	default:
		// Parent may handle this
		nscsi_harddisk_device::scsi_command();
		break;
	}
}


attotime nscsi_pc98_hd_device::scsi_data_byte_period()
{
	// throttle a bit so that wd33c9x can catch up with DRQ with lha201 controller
	// playing safe, minimum threshold is ~307
	return attotime::from_nsec(500);
}