blob: fea08d87836c7133de955acc003aa107b3371290 [file] [log] [blame]
bellard6f7e9ae2005-03-13 09:43:36 +00001/*
bellard67e999b2006-09-03 16:09:07 +00002 * QEMU ESP/NCR53C9x emulation
bellard6f7e9ae2005-03-13 09:43:36 +00003 *
pbrook4e9aec72006-03-11 16:29:14 +00004 * Copyright (c) 2005-2006 Fabrice Bellard
bellard6f7e9ae2005-03-13 09:43:36 +00005 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include "vl.h"
25
26/* debug ESP card */
bellard2f275b82005-04-06 20:31:50 +000027//#define DEBUG_ESP
bellard6f7e9ae2005-03-13 09:43:36 +000028
bellard67e999b2006-09-03 16:09:07 +000029/*
30 * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), also
31 * produced as NCR89C100. See
32 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
33 * and
34 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
35 */
36
bellard6f7e9ae2005-03-13 09:43:36 +000037#ifdef DEBUG_ESP
38#define DPRINTF(fmt, args...) \
39do { printf("ESP: " fmt , ##args); } while (0)
40#else
41#define DPRINTF(fmt, args...)
42#endif
43
bellard6f7e9ae2005-03-13 09:43:36 +000044#define ESP_MAXREG 0x3f
pbrook2e5d83b2006-05-25 23:58:51 +000045#define TI_BUFSZ 32
thsfa1fb142006-12-24 17:12:43 +000046/* The HBA is ID 7, so for simplicitly limit to 7 devices. */
47#define ESP_MAX_DEVS 7
bellard67e999b2006-09-03 16:09:07 +000048
pbrook4e9aec72006-03-11 16:29:14 +000049typedef struct ESPState ESPState;
bellard6f7e9ae2005-03-13 09:43:36 +000050
pbrook4e9aec72006-03-11 16:29:14 +000051struct ESPState {
bellard6f7e9ae2005-03-13 09:43:36 +000052 BlockDriverState **bd;
bellard2f275b82005-04-06 20:31:50 +000053 uint8_t rregs[ESP_MAXREG];
54 uint8_t wregs[ESP_MAXREG];
bellard67e999b2006-09-03 16:09:07 +000055 int32_t ti_size;
bellard4f6200f2005-10-30 17:24:05 +000056 uint32_t ti_rptr, ti_wptr;
bellard4f6200f2005-10-30 17:24:05 +000057 uint8_t ti_buf[TI_BUFSZ];
pbrook0fc5c152006-05-26 21:53:41 +000058 int sense;
bellard4f6200f2005-10-30 17:24:05 +000059 int dma;
pbrook2e5d83b2006-05-25 23:58:51 +000060 SCSIDevice *scsi_dev[MAX_DISKS];
61 SCSIDevice *current_dev;
pbrook9f149aa2006-06-03 14:19:19 +000062 uint8_t cmdbuf[TI_BUFSZ];
63 int cmdlen;
64 int do_cmd;
pbrook4d611c92006-08-12 01:04:27 +000065
pbrook6787f5f2006-09-17 03:20:58 +000066 /* The amount of data left in the current DMA transfer. */
pbrook4d611c92006-08-12 01:04:27 +000067 uint32_t dma_left;
pbrook6787f5f2006-09-17 03:20:58 +000068 /* The size of the current DMA transfer. Zero if no transfer is in
69 progress. */
70 uint32_t dma_counter;
pbrooka917d382006-08-29 04:52:16 +000071 uint8_t *async_buf;
pbrook4d611c92006-08-12 01:04:27 +000072 uint32_t async_len;
bellard67e999b2006-09-03 16:09:07 +000073 void *dma_opaque;
pbrook4e9aec72006-03-11 16:29:14 +000074};
bellard6f7e9ae2005-03-13 09:43:36 +000075
bellard2f275b82005-04-06 20:31:50 +000076#define STAT_DO 0x00
77#define STAT_DI 0x01
78#define STAT_CD 0x02
79#define STAT_ST 0x03
80#define STAT_MI 0x06
81#define STAT_MO 0x07
82
83#define STAT_TC 0x10
pbrook4d611c92006-08-12 01:04:27 +000084#define STAT_PE 0x20
85#define STAT_GE 0x40
bellard2f275b82005-04-06 20:31:50 +000086#define STAT_IN 0x80
87
88#define INTR_FC 0x08
89#define INTR_BS 0x10
90#define INTR_DC 0x20
bellard9e61bde2005-11-11 00:24:58 +000091#define INTR_RST 0x80
bellard2f275b82005-04-06 20:31:50 +000092
93#define SEQ_0 0x0
94#define SEQ_CD 0x4
95
pbrook9f149aa2006-06-03 14:19:19 +000096static int get_cmd(ESPState *s, uint8_t *buf)
bellard2f275b82005-04-06 20:31:50 +000097{
pbrooka917d382006-08-29 04:52:16 +000098 uint32_t dmalen;
bellard2f275b82005-04-06 20:31:50 +000099 int target;
100
pbrook6787f5f2006-09-17 03:20:58 +0000101 dmalen = s->rregs[0] | (s->rregs[1] << 8);
bellard4f6200f2005-10-30 17:24:05 +0000102 target = s->wregs[4] & 7;
pbrook9f149aa2006-06-03 14:19:19 +0000103 DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
bellard4f6200f2005-10-30 17:24:05 +0000104 if (s->dma) {
bellard67e999b2006-09-03 16:09:07 +0000105 espdma_memory_read(s->dma_opaque, buf, dmalen);
bellard4f6200f2005-10-30 17:24:05 +0000106 } else {
107 buf[0] = 0;
108 memcpy(&buf[1], s->ti_buf, dmalen);
109 dmalen++;
110 }
pbrook2e5d83b2006-05-25 23:58:51 +0000111
bellard2f275b82005-04-06 20:31:50 +0000112 s->ti_size = 0;
bellard4f6200f2005-10-30 17:24:05 +0000113 s->ti_rptr = 0;
114 s->ti_wptr = 0;
bellard2f275b82005-04-06 20:31:50 +0000115
pbrooka917d382006-08-29 04:52:16 +0000116 if (s->current_dev) {
117 /* Started a new command before the old one finished. Cancel it. */
118 scsi_cancel_io(s->current_dev, 0);
119 s->async_len = 0;
120 }
121
bellard67e999b2006-09-03 16:09:07 +0000122 if (target >= MAX_DISKS || !s->scsi_dev[target]) {
pbrook2e5d83b2006-05-25 23:58:51 +0000123 // No such drive
bellard2f275b82005-04-06 20:31:50 +0000124 s->rregs[4] = STAT_IN;
125 s->rregs[5] = INTR_DC;
126 s->rregs[6] = SEQ_0;
bellard67e999b2006-09-03 16:09:07 +0000127 espdma_raise_irq(s->dma_opaque);
pbrook9f149aa2006-06-03 14:19:19 +0000128 return 0;
bellard2f275b82005-04-06 20:31:50 +0000129 }
pbrook2e5d83b2006-05-25 23:58:51 +0000130 s->current_dev = s->scsi_dev[target];
pbrook9f149aa2006-06-03 14:19:19 +0000131 return dmalen;
132}
133
134static void do_cmd(ESPState *s, uint8_t *buf)
135{
136 int32_t datalen;
137 int lun;
138
139 DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
140 lun = buf[0] & 7;
pbrook0fc5c152006-05-26 21:53:41 +0000141 datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
bellard67e999b2006-09-03 16:09:07 +0000142 s->ti_size = datalen;
143 if (datalen != 0) {
pbrook2e5d83b2006-05-25 23:58:51 +0000144 s->rregs[4] = STAT_IN | STAT_TC;
pbrooka917d382006-08-29 04:52:16 +0000145 s->dma_left = 0;
pbrook6787f5f2006-09-17 03:20:58 +0000146 s->dma_counter = 0;
pbrook2e5d83b2006-05-25 23:58:51 +0000147 if (datalen > 0) {
148 s->rregs[4] |= STAT_DI;
pbrooka917d382006-08-29 04:52:16 +0000149 scsi_read_data(s->current_dev, 0);
pbrook2e5d83b2006-05-25 23:58:51 +0000150 } else {
151 s->rregs[4] |= STAT_DO;
pbrooka917d382006-08-29 04:52:16 +0000152 scsi_write_data(s->current_dev, 0);
bellardb9788fc2005-12-05 20:30:36 +0000153 }
bellard2f275b82005-04-06 20:31:50 +0000154 }
bellard2f275b82005-04-06 20:31:50 +0000155 s->rregs[5] = INTR_BS | INTR_FC;
156 s->rregs[6] = SEQ_CD;
bellard67e999b2006-09-03 16:09:07 +0000157 espdma_raise_irq(s->dma_opaque);
bellard2f275b82005-04-06 20:31:50 +0000158}
159
pbrook9f149aa2006-06-03 14:19:19 +0000160static void handle_satn(ESPState *s)
161{
162 uint8_t buf[32];
163 int len;
164
165 len = get_cmd(s, buf);
166 if (len)
167 do_cmd(s, buf);
168}
169
170static void handle_satn_stop(ESPState *s)
171{
172 s->cmdlen = get_cmd(s, s->cmdbuf);
173 if (s->cmdlen) {
174 DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
175 s->do_cmd = 1;
pbrook9f149aa2006-06-03 14:19:19 +0000176 s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
177 s->rregs[5] = INTR_BS | INTR_FC;
178 s->rregs[6] = SEQ_CD;
bellard67e999b2006-09-03 16:09:07 +0000179 espdma_raise_irq(s->dma_opaque);
pbrook9f149aa2006-06-03 14:19:19 +0000180 }
181}
182
pbrook0fc5c152006-05-26 21:53:41 +0000183static void write_response(ESPState *s)
bellard2f275b82005-04-06 20:31:50 +0000184{
pbrook0fc5c152006-05-26 21:53:41 +0000185 DPRINTF("Transfer status (sense=%d)\n", s->sense);
186 s->ti_buf[0] = s->sense;
187 s->ti_buf[1] = 0;
bellard4f6200f2005-10-30 17:24:05 +0000188 if (s->dma) {
bellard67e999b2006-09-03 16:09:07 +0000189 espdma_memory_write(s->dma_opaque, s->ti_buf, 2);
bellard4f6200f2005-10-30 17:24:05 +0000190 s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
191 s->rregs[5] = INTR_BS | INTR_FC;
192 s->rregs[6] = SEQ_CD;
bellard4f6200f2005-10-30 17:24:05 +0000193 } else {
pbrook0fc5c152006-05-26 21:53:41 +0000194 s->ti_size = 2;
bellard4f6200f2005-10-30 17:24:05 +0000195 s->ti_rptr = 0;
196 s->ti_wptr = 0;
pbrook0fc5c152006-05-26 21:53:41 +0000197 s->rregs[7] = 2;
bellard4f6200f2005-10-30 17:24:05 +0000198 }
bellard67e999b2006-09-03 16:09:07 +0000199 espdma_raise_irq(s->dma_opaque);
bellard2f275b82005-04-06 20:31:50 +0000200}
bellard4f6200f2005-10-30 17:24:05 +0000201
pbrooka917d382006-08-29 04:52:16 +0000202static void esp_dma_done(ESPState *s)
203{
204 s->rregs[4] |= STAT_IN | STAT_TC;
205 s->rregs[5] = INTR_BS;
206 s->rregs[6] = 0;
207 s->rregs[7] = 0;
pbrook6787f5f2006-09-17 03:20:58 +0000208 s->rregs[0] = 0;
209 s->rregs[1] = 0;
bellard67e999b2006-09-03 16:09:07 +0000210 espdma_raise_irq(s->dma_opaque);
pbrooka917d382006-08-29 04:52:16 +0000211}
212
pbrook4d611c92006-08-12 01:04:27 +0000213static void esp_do_dma(ESPState *s)
214{
bellard67e999b2006-09-03 16:09:07 +0000215 uint32_t len;
pbrook4d611c92006-08-12 01:04:27 +0000216 int to_device;
pbrooka917d382006-08-29 04:52:16 +0000217
bellard67e999b2006-09-03 16:09:07 +0000218 to_device = (s->ti_size < 0);
pbrooka917d382006-08-29 04:52:16 +0000219 len = s->dma_left;
pbrook4d611c92006-08-12 01:04:27 +0000220 if (s->do_cmd) {
pbrook4d611c92006-08-12 01:04:27 +0000221 DPRINTF("command len %d + %d\n", s->cmdlen, len);
bellard67e999b2006-09-03 16:09:07 +0000222 espdma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
pbrook4d611c92006-08-12 01:04:27 +0000223 s->ti_size = 0;
224 s->cmdlen = 0;
225 s->do_cmd = 0;
226 do_cmd(s, s->cmdbuf);
227 return;
pbrooka917d382006-08-29 04:52:16 +0000228 }
229 if (s->async_len == 0) {
230 /* Defer until data is available. */
231 return;
232 }
233 if (len > s->async_len) {
234 len = s->async_len;
235 }
236 if (to_device) {
bellard67e999b2006-09-03 16:09:07 +0000237 espdma_memory_read(s->dma_opaque, s->async_buf, len);
pbrook4d611c92006-08-12 01:04:27 +0000238 } else {
bellard67e999b2006-09-03 16:09:07 +0000239 espdma_memory_write(s->dma_opaque, s->async_buf, len);
pbrooka917d382006-08-29 04:52:16 +0000240 }
pbrooka917d382006-08-29 04:52:16 +0000241 s->dma_left -= len;
242 s->async_buf += len;
243 s->async_len -= len;
pbrook6787f5f2006-09-17 03:20:58 +0000244 if (to_device)
245 s->ti_size += len;
246 else
247 s->ti_size -= len;
pbrooka917d382006-08-29 04:52:16 +0000248 if (s->async_len == 0) {
pbrook4d611c92006-08-12 01:04:27 +0000249 if (to_device) {
bellard67e999b2006-09-03 16:09:07 +0000250 // ti_size is negative
pbrooka917d382006-08-29 04:52:16 +0000251 scsi_write_data(s->current_dev, 0);
pbrook4d611c92006-08-12 01:04:27 +0000252 } else {
pbrooka917d382006-08-29 04:52:16 +0000253 scsi_read_data(s->current_dev, 0);
pbrook6787f5f2006-09-17 03:20:58 +0000254 /* If there is still data to be read from the device then
255 complete the DMA operation immeriately. Otherwise defer
256 until the scsi layer has completed. */
257 if (s->dma_left == 0 && s->ti_size > 0) {
258 esp_dma_done(s);
259 }
pbrook4d611c92006-08-12 01:04:27 +0000260 }
pbrook6787f5f2006-09-17 03:20:58 +0000261 } else {
262 /* Partially filled a scsi buffer. Complete immediately. */
pbrooka917d382006-08-29 04:52:16 +0000263 esp_dma_done(s);
264 }
pbrook4d611c92006-08-12 01:04:27 +0000265}
266
pbrooka917d382006-08-29 04:52:16 +0000267static void esp_command_complete(void *opaque, int reason, uint32_t tag,
268 uint32_t arg)
pbrook2e5d83b2006-05-25 23:58:51 +0000269{
270 ESPState *s = (ESPState *)opaque;
271
pbrook4d611c92006-08-12 01:04:27 +0000272 if (reason == SCSI_REASON_DONE) {
273 DPRINTF("SCSI Command complete\n");
274 if (s->ti_size != 0)
275 DPRINTF("SCSI command completed unexpectedly\n");
276 s->ti_size = 0;
pbrooka917d382006-08-29 04:52:16 +0000277 s->dma_left = 0;
278 s->async_len = 0;
279 if (arg)
pbrook4d611c92006-08-12 01:04:27 +0000280 DPRINTF("Command failed\n");
pbrooka917d382006-08-29 04:52:16 +0000281 s->sense = arg;
282 s->rregs[4] = STAT_ST;
283 esp_dma_done(s);
284 s->current_dev = NULL;
pbrook4d611c92006-08-12 01:04:27 +0000285 } else {
286 DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
pbrooka917d382006-08-29 04:52:16 +0000287 s->async_len = arg;
288 s->async_buf = scsi_get_buf(s->current_dev, 0);
pbrook6787f5f2006-09-17 03:20:58 +0000289 if (s->dma_left) {
pbrooka917d382006-08-29 04:52:16 +0000290 esp_do_dma(s);
pbrook6787f5f2006-09-17 03:20:58 +0000291 } else if (s->dma_counter != 0 && s->ti_size <= 0) {
292 /* If this was the last part of a DMA transfer then the
293 completion interrupt is deferred to here. */
294 esp_dma_done(s);
295 }
pbrook4d611c92006-08-12 01:04:27 +0000296 }
pbrook2e5d83b2006-05-25 23:58:51 +0000297}
298
bellard2f275b82005-04-06 20:31:50 +0000299static void handle_ti(ESPState *s)
300{
pbrook4d611c92006-08-12 01:04:27 +0000301 uint32_t dmalen, minlen;
bellard2f275b82005-04-06 20:31:50 +0000302
pbrook6787f5f2006-09-17 03:20:58 +0000303 dmalen = s->rregs[0] | (s->rregs[1] << 8);
pbrookdb592032006-05-21 12:46:31 +0000304 if (dmalen==0) {
305 dmalen=0x10000;
306 }
pbrook6787f5f2006-09-17 03:20:58 +0000307 s->dma_counter = dmalen;
pbrookdb592032006-05-21 12:46:31 +0000308
pbrook9f149aa2006-06-03 14:19:19 +0000309 if (s->do_cmd)
310 minlen = (dmalen < 32) ? dmalen : 32;
bellard67e999b2006-09-03 16:09:07 +0000311 else if (s->ti_size < 0)
312 minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
pbrook9f149aa2006-06-03 14:19:19 +0000313 else
314 minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
pbrookdb592032006-05-21 12:46:31 +0000315 DPRINTF("Transfer Information len %d\n", minlen);
bellard4f6200f2005-10-30 17:24:05 +0000316 if (s->dma) {
pbrook4d611c92006-08-12 01:04:27 +0000317 s->dma_left = minlen;
318 s->rregs[4] &= ~STAT_TC;
319 esp_do_dma(s);
pbrook9f149aa2006-06-03 14:19:19 +0000320 } else if (s->do_cmd) {
321 DPRINTF("command len %d\n", s->cmdlen);
322 s->ti_size = 0;
323 s->cmdlen = 0;
324 s->do_cmd = 0;
325 do_cmd(s, s->cmdbuf);
326 return;
327 }
bellard2f275b82005-04-06 20:31:50 +0000328}
329
bellard67e999b2006-09-03 16:09:07 +0000330void esp_reset(void *opaque)
bellard6f7e9ae2005-03-13 09:43:36 +0000331{
332 ESPState *s = opaque;
bellard67e999b2006-09-03 16:09:07 +0000333
bellard2f275b82005-04-06 20:31:50 +0000334 memset(s->rregs, 0, ESP_MAXREG);
pbrook4e9aec72006-03-11 16:29:14 +0000335 memset(s->wregs, 0, ESP_MAXREG);
bellard2f275b82005-04-06 20:31:50 +0000336 s->rregs[0x0e] = 0x4; // Indicate fas100a
pbrook4e9aec72006-03-11 16:29:14 +0000337 s->ti_size = 0;
338 s->ti_rptr = 0;
339 s->ti_wptr = 0;
pbrook4e9aec72006-03-11 16:29:14 +0000340 s->dma = 0;
pbrook9f149aa2006-06-03 14:19:19 +0000341 s->do_cmd = 0;
bellard6f7e9ae2005-03-13 09:43:36 +0000342}
343
344static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
345{
346 ESPState *s = opaque;
347 uint32_t saddr;
348
349 saddr = (addr & ESP_MAXREG) >> 2;
bellard9e61bde2005-11-11 00:24:58 +0000350 DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
bellard6f7e9ae2005-03-13 09:43:36 +0000351 switch (saddr) {
bellard4f6200f2005-10-30 17:24:05 +0000352 case 2:
353 // FIFO
354 if (s->ti_size > 0) {
355 s->ti_size--;
pbrook2e5d83b2006-05-25 23:58:51 +0000356 if ((s->rregs[4] & 6) == 0) {
357 /* Data in/out. */
pbrooka917d382006-08-29 04:52:16 +0000358 fprintf(stderr, "esp: PIO data read not implemented\n");
359 s->rregs[2] = 0;
pbrook2e5d83b2006-05-25 23:58:51 +0000360 } else {
361 s->rregs[2] = s->ti_buf[s->ti_rptr++];
362 }
bellard67e999b2006-09-03 16:09:07 +0000363 espdma_raise_irq(s->dma_opaque);
bellard4f6200f2005-10-30 17:24:05 +0000364 }
365 if (s->ti_size == 0) {
366 s->ti_rptr = 0;
367 s->ti_wptr = 0;
368 }
369 break;
bellard9e61bde2005-11-11 00:24:58 +0000370 case 5:
371 // interrupt
pbrook4d611c92006-08-12 01:04:27 +0000372 // Clear interrupt/error status bits
373 s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE);
bellard67e999b2006-09-03 16:09:07 +0000374 espdma_clear_irq(s->dma_opaque);
bellard9e61bde2005-11-11 00:24:58 +0000375 break;
bellard6f7e9ae2005-03-13 09:43:36 +0000376 default:
377 break;
378 }
bellard2f275b82005-04-06 20:31:50 +0000379 return s->rregs[saddr];
bellard6f7e9ae2005-03-13 09:43:36 +0000380}
381
382static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
383{
384 ESPState *s = opaque;
385 uint32_t saddr;
386
387 saddr = (addr & ESP_MAXREG) >> 2;
bellard2f275b82005-04-06 20:31:50 +0000388 DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
bellard6f7e9ae2005-03-13 09:43:36 +0000389 switch (saddr) {
bellard4f6200f2005-10-30 17:24:05 +0000390 case 0:
391 case 1:
pbrook4d611c92006-08-12 01:04:27 +0000392 s->rregs[4] &= ~STAT_TC;
bellard4f6200f2005-10-30 17:24:05 +0000393 break;
394 case 2:
395 // FIFO
pbrook9f149aa2006-06-03 14:19:19 +0000396 if (s->do_cmd) {
397 s->cmdbuf[s->cmdlen++] = val & 0xff;
398 } else if ((s->rregs[4] & 6) == 0) {
pbrook2e5d83b2006-05-25 23:58:51 +0000399 uint8_t buf;
400 buf = val & 0xff;
401 s->ti_size--;
pbrooka917d382006-08-29 04:52:16 +0000402 fprintf(stderr, "esp: PIO data write not implemented\n");
pbrook2e5d83b2006-05-25 23:58:51 +0000403 } else {
404 s->ti_size++;
405 s->ti_buf[s->ti_wptr++] = val & 0xff;
406 }
bellard4f6200f2005-10-30 17:24:05 +0000407 break;
bellard6f7e9ae2005-03-13 09:43:36 +0000408 case 3:
bellard4f6200f2005-10-30 17:24:05 +0000409 s->rregs[saddr] = val;
bellard6f7e9ae2005-03-13 09:43:36 +0000410 // Command
bellard4f6200f2005-10-30 17:24:05 +0000411 if (val & 0x80) {
412 s->dma = 1;
pbrook6787f5f2006-09-17 03:20:58 +0000413 /* Reload DMA counter. */
414 s->rregs[0] = s->wregs[0];
415 s->rregs[1] = s->wregs[1];
bellard4f6200f2005-10-30 17:24:05 +0000416 } else {
417 s->dma = 0;
418 }
bellard6f7e9ae2005-03-13 09:43:36 +0000419 switch(val & 0x7f) {
420 case 0:
bellard2f275b82005-04-06 20:31:50 +0000421 DPRINTF("NOP (%2.2x)\n", val);
422 break;
423 case 1:
424 DPRINTF("Flush FIFO (%2.2x)\n", val);
bellard9e61bde2005-11-11 00:24:58 +0000425 //s->ti_size = 0;
bellard2f275b82005-04-06 20:31:50 +0000426 s->rregs[5] = INTR_FC;
bellard9e61bde2005-11-11 00:24:58 +0000427 s->rregs[6] = 0;
bellard6f7e9ae2005-03-13 09:43:36 +0000428 break;
429 case 2:
bellard2f275b82005-04-06 20:31:50 +0000430 DPRINTF("Chip reset (%2.2x)\n", val);
bellard6f7e9ae2005-03-13 09:43:36 +0000431 esp_reset(s);
432 break;
433 case 3:
bellard2f275b82005-04-06 20:31:50 +0000434 DPRINTF("Bus reset (%2.2x)\n", val);
bellard9e61bde2005-11-11 00:24:58 +0000435 s->rregs[5] = INTR_RST;
436 if (!(s->wregs[8] & 0x40)) {
bellard67e999b2006-09-03 16:09:07 +0000437 espdma_raise_irq(s->dma_opaque);
bellard9e61bde2005-11-11 00:24:58 +0000438 }
bellard2f275b82005-04-06 20:31:50 +0000439 break;
440 case 0x10:
441 handle_ti(s);
442 break;
443 case 0x11:
444 DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
pbrook0fc5c152006-05-26 21:53:41 +0000445 write_response(s);
bellard2f275b82005-04-06 20:31:50 +0000446 break;
447 case 0x12:
448 DPRINTF("Message Accepted (%2.2x)\n", val);
pbrook0fc5c152006-05-26 21:53:41 +0000449 write_response(s);
bellard2f275b82005-04-06 20:31:50 +0000450 s->rregs[5] = INTR_DC;
451 s->rregs[6] = 0;
bellard6f7e9ae2005-03-13 09:43:36 +0000452 break;
453 case 0x1a:
bellard2f275b82005-04-06 20:31:50 +0000454 DPRINTF("Set ATN (%2.2x)\n", val);
bellard6f7e9ae2005-03-13 09:43:36 +0000455 break;
456 case 0x42:
pbrook9f149aa2006-06-03 14:19:19 +0000457 DPRINTF("Set ATN (%2.2x)\n", val);
bellard2f275b82005-04-06 20:31:50 +0000458 handle_satn(s);
459 break;
460 case 0x43:
461 DPRINTF("Set ATN & stop (%2.2x)\n", val);
pbrook9f149aa2006-06-03 14:19:19 +0000462 handle_satn_stop(s);
bellard2f275b82005-04-06 20:31:50 +0000463 break;
464 default:
bellard4f6200f2005-10-30 17:24:05 +0000465 DPRINTF("Unhandled ESP command (%2.2x)\n", val);
bellard6f7e9ae2005-03-13 09:43:36 +0000466 break;
467 }
468 break;
469 case 4 ... 7:
bellard6f7e9ae2005-03-13 09:43:36 +0000470 break;
bellard4f6200f2005-10-30 17:24:05 +0000471 case 8:
472 s->rregs[saddr] = val;
473 break;
474 case 9 ... 10:
475 break;
bellard9e61bde2005-11-11 00:24:58 +0000476 case 11:
477 s->rregs[saddr] = val & 0x15;
478 break;
479 case 12 ... 15:
bellard4f6200f2005-10-30 17:24:05 +0000480 s->rregs[saddr] = val;
481 break;
bellard6f7e9ae2005-03-13 09:43:36 +0000482 default:
bellard6f7e9ae2005-03-13 09:43:36 +0000483 break;
484 }
bellard2f275b82005-04-06 20:31:50 +0000485 s->wregs[saddr] = val;
bellard6f7e9ae2005-03-13 09:43:36 +0000486}
487
488static CPUReadMemoryFunc *esp_mem_read[3] = {
489 esp_mem_readb,
490 esp_mem_readb,
491 esp_mem_readb,
492};
493
494static CPUWriteMemoryFunc *esp_mem_write[3] = {
495 esp_mem_writeb,
496 esp_mem_writeb,
497 esp_mem_writeb,
498};
499
bellard6f7e9ae2005-03-13 09:43:36 +0000500static void esp_save(QEMUFile *f, void *opaque)
501{
502 ESPState *s = opaque;
bellard2f275b82005-04-06 20:31:50 +0000503
504 qemu_put_buffer(f, s->rregs, ESP_MAXREG);
505 qemu_put_buffer(f, s->wregs, ESP_MAXREG);
bellard4f6200f2005-10-30 17:24:05 +0000506 qemu_put_be32s(f, &s->ti_size);
507 qemu_put_be32s(f, &s->ti_rptr);
508 qemu_put_be32s(f, &s->ti_wptr);
bellard4f6200f2005-10-30 17:24:05 +0000509 qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
510 qemu_put_be32s(f, &s->dma);
bellard6f7e9ae2005-03-13 09:43:36 +0000511}
512
513static int esp_load(QEMUFile *f, void *opaque, int version_id)
514{
515 ESPState *s = opaque;
516
bellard67e999b2006-09-03 16:09:07 +0000517 if (version_id != 2)
518 return -EINVAL; // Cannot emulate 1
bellard6f7e9ae2005-03-13 09:43:36 +0000519
bellard2f275b82005-04-06 20:31:50 +0000520 qemu_get_buffer(f, s->rregs, ESP_MAXREG);
521 qemu_get_buffer(f, s->wregs, ESP_MAXREG);
bellard4f6200f2005-10-30 17:24:05 +0000522 qemu_get_be32s(f, &s->ti_size);
523 qemu_get_be32s(f, &s->ti_rptr);
524 qemu_get_be32s(f, &s->ti_wptr);
bellard4f6200f2005-10-30 17:24:05 +0000525 qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
526 qemu_get_be32s(f, &s->dma);
bellard2f275b82005-04-06 20:31:50 +0000527
bellard6f7e9ae2005-03-13 09:43:36 +0000528 return 0;
529}
530
thsfa1fb142006-12-24 17:12:43 +0000531void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id)
532{
533 ESPState *s = (ESPState *)opaque;
534
535 if (id < 0) {
536 for (id = 0; id < ESP_MAX_DEVS; id++) {
537 if (s->scsi_dev[id] == NULL)
538 break;
539 }
540 }
541 if (id >= ESP_MAX_DEVS) {
542 DPRINTF("Bad Device ID %d\n", id);
543 return;
544 }
545 if (s->scsi_dev[id]) {
546 DPRINTF("Destroying device %d\n", id);
547 scsi_disk_destroy(s->scsi_dev[id]);
548 }
549 DPRINTF("Attaching block device %d\n", id);
550 /* Command queueing is not implemented. */
551 s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
552}
553
bellard67e999b2006-09-03 16:09:07 +0000554void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque)
bellard6f7e9ae2005-03-13 09:43:36 +0000555{
556 ESPState *s;
bellard67e999b2006-09-03 16:09:07 +0000557 int esp_io_memory;
bellard6f7e9ae2005-03-13 09:43:36 +0000558
559 s = qemu_mallocz(sizeof(ESPState));
560 if (!s)
bellard67e999b2006-09-03 16:09:07 +0000561 return NULL;
bellard6f7e9ae2005-03-13 09:43:36 +0000562
563 s->bd = bd;
bellard67e999b2006-09-03 16:09:07 +0000564 s->dma_opaque = dma_opaque;
bellard6f7e9ae2005-03-13 09:43:36 +0000565
566 esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
567 cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
568
bellard6f7e9ae2005-03-13 09:43:36 +0000569 esp_reset(s);
570
bellard67e999b2006-09-03 16:09:07 +0000571 register_savevm("esp", espaddr, 2, esp_save, esp_load, s);
bellard6f7e9ae2005-03-13 09:43:36 +0000572 qemu_register_reset(esp_reset, s);
bellard6f7e9ae2005-03-13 09:43:36 +0000573
bellard67e999b2006-09-03 16:09:07 +0000574 return s;
575}