summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/machine/scsibus.h
blob: 7ed35a1534d75f95af7a146193d75538ff4bc189 (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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/*
    SCSIBus.h

*/

#pragma once

#ifndef _SCSIBUS_H_
#define _SCSIBUS_H_

#include "machine/scsicb.h"
#include "machine/scsidev.h"


/***************************************************************************
    MACROS
***************************************************************************/

#define MCFG_SCSIBUS_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, SCSIBUS, 0)


/***************************************************************************
    CONSTANTS
***************************************************************************/

#define SCSI_LINE_SEL   0
#define SCSI_LINE_BSY   1
#define SCSI_LINE_REQ   2
#define SCSI_LINE_ACK   3
#define SCSI_LINE_CD    4
#define SCSI_LINE_IO    5
#define SCSI_LINE_MSG   6
#define SCSI_LINE_RESET 7

// Perhaps thse should be in scsi.h ?
#define SCSI_PHASE_BUS_FREE 8
#define SCSI_PHASE_SELECT   9

#define REQ_DELAY_NS    90
#define ACK_DELAY_NS    90
#define BSY_DELAY_NS	50

#define CMD_BUF_SIZE    			32
#define ADAPTEC_BUF_SIZE			1024

// scsidev
#define SCSI_CMD_RECALIBRATE		0x01
#define SCSI_CMD_REQUEST_SENSE		0x03
#define SCSI_CMD_MODE_SELECT    	0x15
#define SCSI_CMD_SEND_DIAGNOSTIC	0x1D
#define SCSI_CMD_BUFFER_WRITE   	0x3B
#define SCSI_CMD_BUFFER_READ    	0x3C

// scsihd
#define SCSI_CMD_FORMAT_UNIT    	0x04
#define SCSI_CMD_SEARCH_DATA_EQUAL	0x31
#define SCSI_CMD_READ_DEFECT    	0x37


#define IS_COMMAND(cmd)         	(command[0]==cmd)
#define IS_READ_COMMAND()       	((command[0]==0x08) || (command[0]==0x28) || (command[0]==0xa8))
#define IS_WRITE_COMMAND()      	((command[0]==0x0a) || (command[0]==0x2a))
#define SET_STATUS_SENSE(stat,sen)	{ status=(stat); sense=(sen); }

#define FORMAT_UNIT_TIMEOUT			5

//
// Status / Sense data taken from Adaptec ACB40x0 documentation.
//

#define SCSI_STATUS_OK				0x00
#define SCSI_STATUS_CHECK			0x02
#define SCSI_STATUS_EQUAL			0x04
#define SCSI_STATUS_BUSY			0x08

#define SCSI_SENSE_ADDR_VALID		0x80
#define SCSI_SENSE_NO_SENSE			0x00
#define SCSI_SENSE_NO_INDEX			0x01
#define SCSI_SENSE_SEEK_NOT_COMP	0x02
#define SCSI_SENSE_WRITE_FAULT		0x03
#define SCSI_SENSE_DRIVE_NOT_READY	0x04
#define SCSI_SENSE_NO_TRACK0		0x06
#define SCSI_SENSE_ID_CRC_ERROR		0x10
#define SCSI_SENSE_UNCORRECTABLE	0x11
#define SCSI_SENSE_ADDRESS_NF		0x12
#define SCSI_SENSE_RECORD_NOT_FOUND	0x14
#define SCSI_SENSE_SEEK_ERROR		0x15
#define SCSI_SENSE_DATA_CHECK_RETRY	0x18
#define SCSI_SENSE_ECC_VERIFY		0x19
#define SCSI_SENSE_INTERLEAVE_ERROR	0x1A
#define SCSI_SENSE_UNFORMATTED		0x1C
#define SCSI_SENSE_ILLEGAL_COMMAND	0x20
#define SCSI_SENSE_ILLEGAL_ADDRESS	0x21
#define SCSI_SENSE_VOLUME_OVERFLOW	0x23
#define SCSI_SENSE_BAD_ARGUMENT		0x24
#define SCSI_SENSE_INVALID_LUN		0x25
#define SCSI_SENSE_CART_CHANGED		0x28
#define SCSI_SENSE_ERROR_OVERFLOW	0x2C

#define SCSI_SENSE_SIZE				4

struct adaptec_sense_t
{
	// parameter list
	UINT8		reserved1[3];
	UINT8		length;

	// descriptor list
	UINT8		density;
	UINT8		reserved2[4];
	UINT8		block_size[3];

	// drive parameter list
	UINT8		format_code;
	UINT8		cylinder_count[2];
	UINT8		head_count;
	UINT8		reduced_write[2];
	UINT8		write_precomp[2];
	UINT8		landing_zone;
	UINT8		step_pulse_code;
	UINT8		bit_flags;
	UINT8		sectors_per_track;
};

class scsibus_device : public device_t
{
public:
	// construction/destruction
	scsibus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
	/* SCSI Bus read/write */

	UINT8 scsi_data_r();
	void scsi_data_w( UINT8 data );
	DECLARE_READ8_MEMBER( scsi_data_r );
	DECLARE_WRITE8_MEMBER( scsi_data_w );

	/* Get/Set lines */

	UINT8 get_scsi_line(UINT8 lineno);
	void set_scsi_line(UINT8 line, UINT8 state);

	DECLARE_READ_LINE_MEMBER( scsi_bsy_r );
	DECLARE_READ_LINE_MEMBER( scsi_sel_r );
	DECLARE_READ_LINE_MEMBER( scsi_cd_r );
	DECLARE_READ_LINE_MEMBER( scsi_io_r );
	DECLARE_READ_LINE_MEMBER( scsi_msg_r );
	DECLARE_READ_LINE_MEMBER( scsi_req_r );
	DECLARE_READ_LINE_MEMBER( scsi_ack_r );
	DECLARE_READ_LINE_MEMBER( scsi_rst_r );

	DECLARE_WRITE_LINE_MEMBER( scsi_bsy_w );
	DECLARE_WRITE_LINE_MEMBER( scsi_sel_w );
	DECLARE_WRITE_LINE_MEMBER( scsi_cd_w );
	DECLARE_WRITE_LINE_MEMBER( scsi_io_w );
	DECLARE_WRITE_LINE_MEMBER( scsi_msg_w );
	DECLARE_WRITE_LINE_MEMBER( scsi_req_w );
	DECLARE_WRITE_LINE_MEMBER( scsi_ack_w );
	DECLARE_WRITE_LINE_MEMBER( scsi_rst_w );

	/* Initialisation at machine reset time */
	void init_scsibus(int sectorbytes);

protected:
	// device-level overrides
	virtual void device_start();
	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);

private:
	int get_scsi_cmd_len(int cbyte);
	UINT8 scsibus_driveno(UINT8  drivesel);
	void scsi_change_phase(UINT8 newphase);
	void set_scsi_line_now(UINT8 line, UINT8 state);
	void set_scsi_line_ack(UINT8 state);
	void scsi_in_line_changed(UINT8 line, UINT8 state);
	void scsi_out_line_change(UINT8 line, UINT8 state);
	void scsi_out_line_change_now(UINT8 line, UINT8 state);
	void scsi_out_line_req(UINT8 state);
	void scsibus_read_data();
	void scsibus_write_data();
	int datain_done();
	int dataout_done();
	void scsibus_exec_command();
	void check_process_dataout();
	void dump_command_bytes();
	void dump_data_bytes(int count);
	void dump_bytes(UINT8 *buff, int count);

	scsidev_device          *devices[8];
	scsicb_device *m_scsicb;

	UINT8       linestate;
	UINT8       last_id;
	UINT8       phase;

	UINT8       command[CMD_BUF_SIZE];
	UINT8       cmd_idx;
	UINT8       is_linked;

	UINT8       status;
	UINT8       sense;

	UINT8       buffer[ADAPTEC_BUF_SIZE];
	UINT16      data_idx;
	int         xfer_count;
	int         bytes_left;
	int         data_last;
	int         sectorbytes;

	emu_timer *req_timer;
	emu_timer *ack_timer;
	emu_timer *sel_timer;
	emu_timer *dataout_timer;
};

// device type definition
extern const device_type SCSIBUS;

#endif