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);
}
|