Statistics
| Branch: | Revision:

root / hw / esp.c @ a171fe39

History | View | Annotate | Download (14.8 kB)

1 6f7e9aec bellard
/*
2 67e999be bellard
 * QEMU ESP/NCR53C9x emulation
3 6f7e9aec bellard
 * 
4 4e9aec74 pbrook
 * Copyright (c) 2005-2006 Fabrice Bellard
5 6f7e9aec bellard
 * 
6 6f7e9aec bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 6f7e9aec bellard
 * of this software and associated documentation files (the "Software"), to deal
8 6f7e9aec bellard
 * in the Software without restriction, including without limitation the rights
9 6f7e9aec bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 6f7e9aec bellard
 * copies of the Software, and to permit persons to whom the Software is
11 6f7e9aec bellard
 * furnished to do so, subject to the following conditions:
12 6f7e9aec bellard
 *
13 6f7e9aec bellard
 * The above copyright notice and this permission notice shall be included in
14 6f7e9aec bellard
 * all copies or substantial portions of the Software.
15 6f7e9aec bellard
 *
16 6f7e9aec bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 6f7e9aec bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 6f7e9aec bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 6f7e9aec bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 6f7e9aec bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 6f7e9aec bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 6f7e9aec bellard
 * THE SOFTWARE.
23 6f7e9aec bellard
 */
24 6f7e9aec bellard
#include "vl.h"
25 6f7e9aec bellard
26 6f7e9aec bellard
/* debug ESP card */
27 2f275b8f bellard
//#define DEBUG_ESP
28 6f7e9aec bellard
29 67e999be bellard
/*
30 67e999be bellard
 * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), also
31 67e999be bellard
 * produced as NCR89C100. See
32 67e999be bellard
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
33 67e999be bellard
 * and
34 67e999be bellard
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
35 67e999be bellard
 */
36 67e999be bellard
37 6f7e9aec bellard
#ifdef DEBUG_ESP
38 6f7e9aec bellard
#define DPRINTF(fmt, args...) \
39 6f7e9aec bellard
do { printf("ESP: " fmt , ##args); } while (0)
40 6f7e9aec bellard
#else
41 6f7e9aec bellard
#define DPRINTF(fmt, args...)
42 6f7e9aec bellard
#endif
43 6f7e9aec bellard
44 6f7e9aec bellard
#define ESP_MAXREG 0x3f
45 2e5d83bb pbrook
#define TI_BUFSZ 32
46 fa1fb14c ths
/* The HBA is ID 7, so for simplicitly limit to 7 devices.  */
47 fa1fb14c ths
#define ESP_MAX_DEVS      7
48 67e999be bellard
49 4e9aec74 pbrook
typedef struct ESPState ESPState;
50 6f7e9aec bellard
51 4e9aec74 pbrook
struct ESPState {
52 6f7e9aec bellard
    BlockDriverState **bd;
53 2f275b8f bellard
    uint8_t rregs[ESP_MAXREG];
54 2f275b8f bellard
    uint8_t wregs[ESP_MAXREG];
55 67e999be bellard
    int32_t ti_size;
56 4f6200f0 bellard
    uint32_t ti_rptr, ti_wptr;
57 4f6200f0 bellard
    uint8_t ti_buf[TI_BUFSZ];
58 0fc5c15a pbrook
    int sense;
59 4f6200f0 bellard
    int dma;
60 2e5d83bb pbrook
    SCSIDevice *scsi_dev[MAX_DISKS];
61 2e5d83bb pbrook
    SCSIDevice *current_dev;
62 9f149aa9 pbrook
    uint8_t cmdbuf[TI_BUFSZ];
63 9f149aa9 pbrook
    int cmdlen;
64 9f149aa9 pbrook
    int do_cmd;
65 4d611c9a pbrook
66 6787f5fa pbrook
    /* The amount of data left in the current DMA transfer.  */
67 4d611c9a pbrook
    uint32_t dma_left;
68 6787f5fa pbrook
    /* The size of the current DMA transfer.  Zero if no transfer is in
69 6787f5fa pbrook
       progress.  */
70 6787f5fa pbrook
    uint32_t dma_counter;
71 a917d384 pbrook
    uint8_t *async_buf;
72 4d611c9a pbrook
    uint32_t async_len;
73 67e999be bellard
    void *dma_opaque;
74 4e9aec74 pbrook
};
75 6f7e9aec bellard
76 2f275b8f bellard
#define STAT_DO 0x00
77 2f275b8f bellard
#define STAT_DI 0x01
78 2f275b8f bellard
#define STAT_CD 0x02
79 2f275b8f bellard
#define STAT_ST 0x03
80 2f275b8f bellard
#define STAT_MI 0x06
81 2f275b8f bellard
#define STAT_MO 0x07
82 2f275b8f bellard
83 2f275b8f bellard
#define STAT_TC 0x10
84 4d611c9a pbrook
#define STAT_PE 0x20
85 4d611c9a pbrook
#define STAT_GE 0x40
86 2f275b8f bellard
#define STAT_IN 0x80
87 2f275b8f bellard
88 2f275b8f bellard
#define INTR_FC 0x08
89 2f275b8f bellard
#define INTR_BS 0x10
90 2f275b8f bellard
#define INTR_DC 0x20
91 9e61bde5 bellard
#define INTR_RST 0x80
92 2f275b8f bellard
93 2f275b8f bellard
#define SEQ_0 0x0
94 2f275b8f bellard
#define SEQ_CD 0x4
95 2f275b8f bellard
96 9f149aa9 pbrook
static int get_cmd(ESPState *s, uint8_t *buf)
97 2f275b8f bellard
{
98 a917d384 pbrook
    uint32_t dmalen;
99 2f275b8f bellard
    int target;
100 2f275b8f bellard
101 6787f5fa pbrook
    dmalen = s->rregs[0] | (s->rregs[1] << 8);
102 4f6200f0 bellard
    target = s->wregs[4] & 7;
103 9f149aa9 pbrook
    DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
104 4f6200f0 bellard
    if (s->dma) {
105 67e999be bellard
        espdma_memory_read(s->dma_opaque, buf, dmalen);
106 4f6200f0 bellard
    } else {
107 4f6200f0 bellard
        buf[0] = 0;
108 4f6200f0 bellard
        memcpy(&buf[1], s->ti_buf, dmalen);
109 4f6200f0 bellard
        dmalen++;
110 4f6200f0 bellard
    }
111 2e5d83bb pbrook
112 2f275b8f bellard
    s->ti_size = 0;
113 4f6200f0 bellard
    s->ti_rptr = 0;
114 4f6200f0 bellard
    s->ti_wptr = 0;
115 2f275b8f bellard
116 a917d384 pbrook
    if (s->current_dev) {
117 a917d384 pbrook
        /* Started a new command before the old one finished.  Cancel it.  */
118 a917d384 pbrook
        scsi_cancel_io(s->current_dev, 0);
119 a917d384 pbrook
        s->async_len = 0;
120 a917d384 pbrook
    }
121 a917d384 pbrook
122 67e999be bellard
    if (target >= MAX_DISKS || !s->scsi_dev[target]) {
123 2e5d83bb pbrook
        // No such drive
124 2f275b8f bellard
        s->rregs[4] = STAT_IN;
125 2f275b8f bellard
        s->rregs[5] = INTR_DC;
126 2f275b8f bellard
        s->rregs[6] = SEQ_0;
127 67e999be bellard
        espdma_raise_irq(s->dma_opaque);
128 9f149aa9 pbrook
        return 0;
129 2f275b8f bellard
    }
130 2e5d83bb pbrook
    s->current_dev = s->scsi_dev[target];
131 9f149aa9 pbrook
    return dmalen;
132 9f149aa9 pbrook
}
133 9f149aa9 pbrook
134 9f149aa9 pbrook
static void do_cmd(ESPState *s, uint8_t *buf)
135 9f149aa9 pbrook
{
136 9f149aa9 pbrook
    int32_t datalen;
137 9f149aa9 pbrook
    int lun;
138 9f149aa9 pbrook
139 9f149aa9 pbrook
    DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
140 9f149aa9 pbrook
    lun = buf[0] & 7;
141 0fc5c15a pbrook
    datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
142 67e999be bellard
    s->ti_size = datalen;
143 67e999be bellard
    if (datalen != 0) {
144 2e5d83bb pbrook
        s->rregs[4] = STAT_IN | STAT_TC;
145 a917d384 pbrook
        s->dma_left = 0;
146 6787f5fa pbrook
        s->dma_counter = 0;
147 2e5d83bb pbrook
        if (datalen > 0) {
148 2e5d83bb pbrook
            s->rregs[4] |= STAT_DI;
149 a917d384 pbrook
            scsi_read_data(s->current_dev, 0);
150 2e5d83bb pbrook
        } else {
151 2e5d83bb pbrook
            s->rregs[4] |= STAT_DO;
152 a917d384 pbrook
            scsi_write_data(s->current_dev, 0);
153 b9788fc4 bellard
        }
154 2f275b8f bellard
    }
155 2f275b8f bellard
    s->rregs[5] = INTR_BS | INTR_FC;
156 2f275b8f bellard
    s->rregs[6] = SEQ_CD;
157 67e999be bellard
    espdma_raise_irq(s->dma_opaque);
158 2f275b8f bellard
}
159 2f275b8f bellard
160 9f149aa9 pbrook
static void handle_satn(ESPState *s)
161 9f149aa9 pbrook
{
162 9f149aa9 pbrook
    uint8_t buf[32];
163 9f149aa9 pbrook
    int len;
164 9f149aa9 pbrook
165 9f149aa9 pbrook
    len = get_cmd(s, buf);
166 9f149aa9 pbrook
    if (len)
167 9f149aa9 pbrook
        do_cmd(s, buf);
168 9f149aa9 pbrook
}
169 9f149aa9 pbrook
170 9f149aa9 pbrook
static void handle_satn_stop(ESPState *s)
171 9f149aa9 pbrook
{
172 9f149aa9 pbrook
    s->cmdlen = get_cmd(s, s->cmdbuf);
173 9f149aa9 pbrook
    if (s->cmdlen) {
174 9f149aa9 pbrook
        DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
175 9f149aa9 pbrook
        s->do_cmd = 1;
176 9f149aa9 pbrook
        s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
177 9f149aa9 pbrook
        s->rregs[5] = INTR_BS | INTR_FC;
178 9f149aa9 pbrook
        s->rregs[6] = SEQ_CD;
179 67e999be bellard
        espdma_raise_irq(s->dma_opaque);
180 9f149aa9 pbrook
    }
181 9f149aa9 pbrook
}
182 9f149aa9 pbrook
183 0fc5c15a pbrook
static void write_response(ESPState *s)
184 2f275b8f bellard
{
185 0fc5c15a pbrook
    DPRINTF("Transfer status (sense=%d)\n", s->sense);
186 0fc5c15a pbrook
    s->ti_buf[0] = s->sense;
187 0fc5c15a pbrook
    s->ti_buf[1] = 0;
188 4f6200f0 bellard
    if (s->dma) {
189 67e999be bellard
        espdma_memory_write(s->dma_opaque, s->ti_buf, 2);
190 4f6200f0 bellard
        s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
191 4f6200f0 bellard
        s->rregs[5] = INTR_BS | INTR_FC;
192 4f6200f0 bellard
        s->rregs[6] = SEQ_CD;
193 4f6200f0 bellard
    } else {
194 0fc5c15a pbrook
        s->ti_size = 2;
195 4f6200f0 bellard
        s->ti_rptr = 0;
196 4f6200f0 bellard
        s->ti_wptr = 0;
197 0fc5c15a pbrook
        s->rregs[7] = 2;
198 4f6200f0 bellard
    }
199 67e999be bellard
    espdma_raise_irq(s->dma_opaque);
200 2f275b8f bellard
}
201 4f6200f0 bellard
202 a917d384 pbrook
static void esp_dma_done(ESPState *s)
203 a917d384 pbrook
{
204 a917d384 pbrook
    s->rregs[4] |= STAT_IN | STAT_TC;
205 a917d384 pbrook
    s->rregs[5] = INTR_BS;
206 a917d384 pbrook
    s->rregs[6] = 0;
207 a917d384 pbrook
    s->rregs[7] = 0;
208 6787f5fa pbrook
    s->rregs[0] = 0;
209 6787f5fa pbrook
    s->rregs[1] = 0;
210 67e999be bellard
    espdma_raise_irq(s->dma_opaque);
211 a917d384 pbrook
}
212 a917d384 pbrook
213 4d611c9a pbrook
static void esp_do_dma(ESPState *s)
214 4d611c9a pbrook
{
215 67e999be bellard
    uint32_t len;
216 4d611c9a pbrook
    int to_device;
217 a917d384 pbrook
218 67e999be bellard
    to_device = (s->ti_size < 0);
219 a917d384 pbrook
    len = s->dma_left;
220 4d611c9a pbrook
    if (s->do_cmd) {
221 4d611c9a pbrook
        DPRINTF("command len %d + %d\n", s->cmdlen, len);
222 67e999be bellard
        espdma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
223 4d611c9a pbrook
        s->ti_size = 0;
224 4d611c9a pbrook
        s->cmdlen = 0;
225 4d611c9a pbrook
        s->do_cmd = 0;
226 4d611c9a pbrook
        do_cmd(s, s->cmdbuf);
227 4d611c9a pbrook
        return;
228 a917d384 pbrook
    }
229 a917d384 pbrook
    if (s->async_len == 0) {
230 a917d384 pbrook
        /* Defer until data is available.  */
231 a917d384 pbrook
        return;
232 a917d384 pbrook
    }
233 a917d384 pbrook
    if (len > s->async_len) {
234 a917d384 pbrook
        len = s->async_len;
235 a917d384 pbrook
    }
236 a917d384 pbrook
    if (to_device) {
237 67e999be bellard
        espdma_memory_read(s->dma_opaque, s->async_buf, len);
238 4d611c9a pbrook
    } else {
239 67e999be bellard
        espdma_memory_write(s->dma_opaque, s->async_buf, len);
240 a917d384 pbrook
    }
241 a917d384 pbrook
    s->dma_left -= len;
242 a917d384 pbrook
    s->async_buf += len;
243 a917d384 pbrook
    s->async_len -= len;
244 6787f5fa pbrook
    if (to_device)
245 6787f5fa pbrook
        s->ti_size += len;
246 6787f5fa pbrook
    else
247 6787f5fa pbrook
        s->ti_size -= len;
248 a917d384 pbrook
    if (s->async_len == 0) {
249 4d611c9a pbrook
        if (to_device) {
250 67e999be bellard
            // ti_size is negative
251 a917d384 pbrook
            scsi_write_data(s->current_dev, 0);
252 4d611c9a pbrook
        } else {
253 a917d384 pbrook
            scsi_read_data(s->current_dev, 0);
254 6787f5fa pbrook
            /* If there is still data to be read from the device then
255 6787f5fa pbrook
               complete the DMA operation immeriately.  Otherwise defer
256 6787f5fa pbrook
               until the scsi layer has completed.  */
257 6787f5fa pbrook
            if (s->dma_left == 0 && s->ti_size > 0) {
258 6787f5fa pbrook
                esp_dma_done(s);
259 6787f5fa pbrook
            }
260 4d611c9a pbrook
        }
261 6787f5fa pbrook
    } else {
262 6787f5fa pbrook
        /* Partially filled a scsi buffer. Complete immediately.  */
263 a917d384 pbrook
        esp_dma_done(s);
264 a917d384 pbrook
    }
265 4d611c9a pbrook
}
266 4d611c9a pbrook
267 a917d384 pbrook
static void esp_command_complete(void *opaque, int reason, uint32_t tag,
268 a917d384 pbrook
                                 uint32_t arg)
269 2e5d83bb pbrook
{
270 2e5d83bb pbrook
    ESPState *s = (ESPState *)opaque;
271 2e5d83bb pbrook
272 4d611c9a pbrook
    if (reason == SCSI_REASON_DONE) {
273 4d611c9a pbrook
        DPRINTF("SCSI Command complete\n");
274 4d611c9a pbrook
        if (s->ti_size != 0)
275 4d611c9a pbrook
            DPRINTF("SCSI command completed unexpectedly\n");
276 4d611c9a pbrook
        s->ti_size = 0;
277 a917d384 pbrook
        s->dma_left = 0;
278 a917d384 pbrook
        s->async_len = 0;
279 a917d384 pbrook
        if (arg)
280 4d611c9a pbrook
            DPRINTF("Command failed\n");
281 a917d384 pbrook
        s->sense = arg;
282 a917d384 pbrook
        s->rregs[4] = STAT_ST;
283 a917d384 pbrook
        esp_dma_done(s);
284 a917d384 pbrook
        s->current_dev = NULL;
285 4d611c9a pbrook
    } else {
286 4d611c9a pbrook
        DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
287 a917d384 pbrook
        s->async_len = arg;
288 a917d384 pbrook
        s->async_buf = scsi_get_buf(s->current_dev, 0);
289 6787f5fa pbrook
        if (s->dma_left) {
290 a917d384 pbrook
            esp_do_dma(s);
291 6787f5fa pbrook
        } else if (s->dma_counter != 0 && s->ti_size <= 0) {
292 6787f5fa pbrook
            /* If this was the last part of a DMA transfer then the
293 6787f5fa pbrook
               completion interrupt is deferred to here.  */
294 6787f5fa pbrook
            esp_dma_done(s);
295 6787f5fa pbrook
        }
296 4d611c9a pbrook
    }
297 2e5d83bb pbrook
}
298 2e5d83bb pbrook
299 2f275b8f bellard
static void handle_ti(ESPState *s)
300 2f275b8f bellard
{
301 4d611c9a pbrook
    uint32_t dmalen, minlen;
302 2f275b8f bellard
303 6787f5fa pbrook
    dmalen = s->rregs[0] | (s->rregs[1] << 8);
304 db59203d pbrook
    if (dmalen==0) {
305 db59203d pbrook
      dmalen=0x10000;
306 db59203d pbrook
    }
307 6787f5fa pbrook
    s->dma_counter = dmalen;
308 db59203d pbrook
309 9f149aa9 pbrook
    if (s->do_cmd)
310 9f149aa9 pbrook
        minlen = (dmalen < 32) ? dmalen : 32;
311 67e999be bellard
    else if (s->ti_size < 0)
312 67e999be bellard
        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
313 9f149aa9 pbrook
    else
314 9f149aa9 pbrook
        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
315 db59203d pbrook
    DPRINTF("Transfer Information len %d\n", minlen);
316 4f6200f0 bellard
    if (s->dma) {
317 4d611c9a pbrook
        s->dma_left = minlen;
318 4d611c9a pbrook
        s->rregs[4] &= ~STAT_TC;
319 4d611c9a pbrook
        esp_do_dma(s);
320 9f149aa9 pbrook
    } else if (s->do_cmd) {
321 9f149aa9 pbrook
        DPRINTF("command len %d\n", s->cmdlen);
322 9f149aa9 pbrook
        s->ti_size = 0;
323 9f149aa9 pbrook
        s->cmdlen = 0;
324 9f149aa9 pbrook
        s->do_cmd = 0;
325 9f149aa9 pbrook
        do_cmd(s, s->cmdbuf);
326 9f149aa9 pbrook
        return;
327 9f149aa9 pbrook
    }
328 2f275b8f bellard
}
329 2f275b8f bellard
330 67e999be bellard
void esp_reset(void *opaque)
331 6f7e9aec bellard
{
332 6f7e9aec bellard
    ESPState *s = opaque;
333 67e999be bellard
334 2f275b8f bellard
    memset(s->rregs, 0, ESP_MAXREG);
335 4e9aec74 pbrook
    memset(s->wregs, 0, ESP_MAXREG);
336 2f275b8f bellard
    s->rregs[0x0e] = 0x4; // Indicate fas100a
337 4e9aec74 pbrook
    s->ti_size = 0;
338 4e9aec74 pbrook
    s->ti_rptr = 0;
339 4e9aec74 pbrook
    s->ti_wptr = 0;
340 4e9aec74 pbrook
    s->dma = 0;
341 9f149aa9 pbrook
    s->do_cmd = 0;
342 6f7e9aec bellard
}
343 6f7e9aec bellard
344 6f7e9aec bellard
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
345 6f7e9aec bellard
{
346 6f7e9aec bellard
    ESPState *s = opaque;
347 6f7e9aec bellard
    uint32_t saddr;
348 6f7e9aec bellard
349 6f7e9aec bellard
    saddr = (addr & ESP_MAXREG) >> 2;
350 9e61bde5 bellard
    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
351 6f7e9aec bellard
    switch (saddr) {
352 4f6200f0 bellard
    case 2:
353 4f6200f0 bellard
        // FIFO
354 4f6200f0 bellard
        if (s->ti_size > 0) {
355 4f6200f0 bellard
            s->ti_size--;
356 2e5d83bb pbrook
            if ((s->rregs[4] & 6) == 0) {
357 2e5d83bb pbrook
                /* Data in/out.  */
358 a917d384 pbrook
                fprintf(stderr, "esp: PIO data read not implemented\n");
359 a917d384 pbrook
                s->rregs[2] = 0;
360 2e5d83bb pbrook
            } else {
361 2e5d83bb pbrook
                s->rregs[2] = s->ti_buf[s->ti_rptr++];
362 2e5d83bb pbrook
            }
363 67e999be bellard
            espdma_raise_irq(s->dma_opaque);
364 4f6200f0 bellard
        }
365 4f6200f0 bellard
        if (s->ti_size == 0) {
366 4f6200f0 bellard
            s->ti_rptr = 0;
367 4f6200f0 bellard
            s->ti_wptr = 0;
368 4f6200f0 bellard
        }
369 4f6200f0 bellard
        break;
370 9e61bde5 bellard
    case 5:
371 9e61bde5 bellard
        // interrupt
372 4d611c9a pbrook
        // Clear interrupt/error status bits
373 4d611c9a pbrook
        s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE);
374 67e999be bellard
        espdma_clear_irq(s->dma_opaque);
375 9e61bde5 bellard
        break;
376 6f7e9aec bellard
    default:
377 6f7e9aec bellard
        break;
378 6f7e9aec bellard
    }
379 2f275b8f bellard
    return s->rregs[saddr];
380 6f7e9aec bellard
}
381 6f7e9aec bellard
382 6f7e9aec bellard
static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
383 6f7e9aec bellard
{
384 6f7e9aec bellard
    ESPState *s = opaque;
385 6f7e9aec bellard
    uint32_t saddr;
386 6f7e9aec bellard
387 6f7e9aec bellard
    saddr = (addr & ESP_MAXREG) >> 2;
388 2f275b8f bellard
    DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
389 6f7e9aec bellard
    switch (saddr) {
390 4f6200f0 bellard
    case 0:
391 4f6200f0 bellard
    case 1:
392 4d611c9a pbrook
        s->rregs[4] &= ~STAT_TC;
393 4f6200f0 bellard
        break;
394 4f6200f0 bellard
    case 2:
395 4f6200f0 bellard
        // FIFO
396 9f149aa9 pbrook
        if (s->do_cmd) {
397 9f149aa9 pbrook
            s->cmdbuf[s->cmdlen++] = val & 0xff;
398 9f149aa9 pbrook
        } else if ((s->rregs[4] & 6) == 0) {
399 2e5d83bb pbrook
            uint8_t buf;
400 2e5d83bb pbrook
            buf = val & 0xff;
401 2e5d83bb pbrook
            s->ti_size--;
402 a917d384 pbrook
            fprintf(stderr, "esp: PIO data write not implemented\n");
403 2e5d83bb pbrook
        } else {
404 2e5d83bb pbrook
            s->ti_size++;
405 2e5d83bb pbrook
            s->ti_buf[s->ti_wptr++] = val & 0xff;
406 2e5d83bb pbrook
        }
407 4f6200f0 bellard
        break;
408 6f7e9aec bellard
    case 3:
409 4f6200f0 bellard
        s->rregs[saddr] = val;
410 6f7e9aec bellard
        // Command
411 4f6200f0 bellard
        if (val & 0x80) {
412 4f6200f0 bellard
            s->dma = 1;
413 6787f5fa pbrook
            /* Reload DMA counter.  */
414 6787f5fa pbrook
            s->rregs[0] = s->wregs[0];
415 6787f5fa pbrook
            s->rregs[1] = s->wregs[1];
416 4f6200f0 bellard
        } else {
417 4f6200f0 bellard
            s->dma = 0;
418 4f6200f0 bellard
        }
419 6f7e9aec bellard
        switch(val & 0x7f) {
420 6f7e9aec bellard
        case 0:
421 2f275b8f bellard
            DPRINTF("NOP (%2.2x)\n", val);
422 2f275b8f bellard
            break;
423 2f275b8f bellard
        case 1:
424 2f275b8f bellard
            DPRINTF("Flush FIFO (%2.2x)\n", val);
425 9e61bde5 bellard
            //s->ti_size = 0;
426 2f275b8f bellard
            s->rregs[5] = INTR_FC;
427 9e61bde5 bellard
            s->rregs[6] = 0;
428 6f7e9aec bellard
            break;
429 6f7e9aec bellard
        case 2:
430 2f275b8f bellard
            DPRINTF("Chip reset (%2.2x)\n", val);
431 6f7e9aec bellard
            esp_reset(s);
432 6f7e9aec bellard
            break;
433 6f7e9aec bellard
        case 3:
434 2f275b8f bellard
            DPRINTF("Bus reset (%2.2x)\n", val);
435 9e61bde5 bellard
            s->rregs[5] = INTR_RST;
436 9e61bde5 bellard
            if (!(s->wregs[8] & 0x40)) {
437 67e999be bellard
                espdma_raise_irq(s->dma_opaque);
438 9e61bde5 bellard
            }
439 2f275b8f bellard
            break;
440 2f275b8f bellard
        case 0x10:
441 2f275b8f bellard
            handle_ti(s);
442 2f275b8f bellard
            break;
443 2f275b8f bellard
        case 0x11:
444 2f275b8f bellard
            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
445 0fc5c15a pbrook
            write_response(s);
446 2f275b8f bellard
            break;
447 2f275b8f bellard
        case 0x12:
448 2f275b8f bellard
            DPRINTF("Message Accepted (%2.2x)\n", val);
449 0fc5c15a pbrook
            write_response(s);
450 2f275b8f bellard
            s->rregs[5] = INTR_DC;
451 2f275b8f bellard
            s->rregs[6] = 0;
452 6f7e9aec bellard
            break;
453 6f7e9aec bellard
        case 0x1a:
454 2f275b8f bellard
            DPRINTF("Set ATN (%2.2x)\n", val);
455 6f7e9aec bellard
            break;
456 6f7e9aec bellard
        case 0x42:
457 9f149aa9 pbrook
            DPRINTF("Set ATN (%2.2x)\n", val);
458 2f275b8f bellard
            handle_satn(s);
459 2f275b8f bellard
            break;
460 2f275b8f bellard
        case 0x43:
461 2f275b8f bellard
            DPRINTF("Set ATN & stop (%2.2x)\n", val);
462 9f149aa9 pbrook
            handle_satn_stop(s);
463 2f275b8f bellard
            break;
464 2f275b8f bellard
        default:
465 4f6200f0 bellard
            DPRINTF("Unhandled ESP command (%2.2x)\n", val);
466 6f7e9aec bellard
            break;
467 6f7e9aec bellard
        }
468 6f7e9aec bellard
        break;
469 6f7e9aec bellard
    case 4 ... 7:
470 6f7e9aec bellard
        break;
471 4f6200f0 bellard
    case 8:
472 4f6200f0 bellard
        s->rregs[saddr] = val;
473 4f6200f0 bellard
        break;
474 4f6200f0 bellard
    case 9 ... 10:
475 4f6200f0 bellard
        break;
476 9e61bde5 bellard
    case 11:
477 9e61bde5 bellard
        s->rregs[saddr] = val & 0x15;
478 9e61bde5 bellard
        break;
479 9e61bde5 bellard
    case 12 ... 15:
480 4f6200f0 bellard
        s->rregs[saddr] = val;
481 4f6200f0 bellard
        break;
482 6f7e9aec bellard
    default:
483 6f7e9aec bellard
        break;
484 6f7e9aec bellard
    }
485 2f275b8f bellard
    s->wregs[saddr] = val;
486 6f7e9aec bellard
}
487 6f7e9aec bellard
488 6f7e9aec bellard
static CPUReadMemoryFunc *esp_mem_read[3] = {
489 6f7e9aec bellard
    esp_mem_readb,
490 6f7e9aec bellard
    esp_mem_readb,
491 6f7e9aec bellard
    esp_mem_readb,
492 6f7e9aec bellard
};
493 6f7e9aec bellard
494 6f7e9aec bellard
static CPUWriteMemoryFunc *esp_mem_write[3] = {
495 6f7e9aec bellard
    esp_mem_writeb,
496 6f7e9aec bellard
    esp_mem_writeb,
497 6f7e9aec bellard
    esp_mem_writeb,
498 6f7e9aec bellard
};
499 6f7e9aec bellard
500 6f7e9aec bellard
static void esp_save(QEMUFile *f, void *opaque)
501 6f7e9aec bellard
{
502 6f7e9aec bellard
    ESPState *s = opaque;
503 2f275b8f bellard
504 2f275b8f bellard
    qemu_put_buffer(f, s->rregs, ESP_MAXREG);
505 2f275b8f bellard
    qemu_put_buffer(f, s->wregs, ESP_MAXREG);
506 4f6200f0 bellard
    qemu_put_be32s(f, &s->ti_size);
507 4f6200f0 bellard
    qemu_put_be32s(f, &s->ti_rptr);
508 4f6200f0 bellard
    qemu_put_be32s(f, &s->ti_wptr);
509 4f6200f0 bellard
    qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
510 5425a216 blueswir1
    qemu_put_be32s(f, &s->sense);
511 4f6200f0 bellard
    qemu_put_be32s(f, &s->dma);
512 5425a216 blueswir1
    qemu_put_buffer(f, s->cmdbuf, TI_BUFSZ);
513 5425a216 blueswir1
    qemu_put_be32s(f, &s->cmdlen);
514 5425a216 blueswir1
    qemu_put_be32s(f, &s->do_cmd);
515 5425a216 blueswir1
    qemu_put_be32s(f, &s->dma_left);
516 5425a216 blueswir1
    // There should be no transfers in progress, so dma_counter is not saved
517 6f7e9aec bellard
}
518 6f7e9aec bellard
519 6f7e9aec bellard
static int esp_load(QEMUFile *f, void *opaque, int version_id)
520 6f7e9aec bellard
{
521 6f7e9aec bellard
    ESPState *s = opaque;
522 6f7e9aec bellard
    
523 5425a216 blueswir1
    if (version_id != 3)
524 5425a216 blueswir1
        return -EINVAL; // Cannot emulate 2
525 6f7e9aec bellard
526 2f275b8f bellard
    qemu_get_buffer(f, s->rregs, ESP_MAXREG);
527 2f275b8f bellard
    qemu_get_buffer(f, s->wregs, ESP_MAXREG);
528 4f6200f0 bellard
    qemu_get_be32s(f, &s->ti_size);
529 4f6200f0 bellard
    qemu_get_be32s(f, &s->ti_rptr);
530 4f6200f0 bellard
    qemu_get_be32s(f, &s->ti_wptr);
531 4f6200f0 bellard
    qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
532 5425a216 blueswir1
    qemu_get_be32s(f, &s->sense);
533 4f6200f0 bellard
    qemu_get_be32s(f, &s->dma);
534 5425a216 blueswir1
    qemu_get_buffer(f, s->cmdbuf, TI_BUFSZ);
535 5425a216 blueswir1
    qemu_get_be32s(f, &s->cmdlen);
536 5425a216 blueswir1
    qemu_get_be32s(f, &s->do_cmd);
537 5425a216 blueswir1
    qemu_get_be32s(f, &s->dma_left);
538 2f275b8f bellard
539 6f7e9aec bellard
    return 0;
540 6f7e9aec bellard
}
541 6f7e9aec bellard
542 fa1fb14c ths
void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id)
543 fa1fb14c ths
{
544 fa1fb14c ths
    ESPState *s = (ESPState *)opaque;
545 fa1fb14c ths
546 fa1fb14c ths
    if (id < 0) {
547 fa1fb14c ths
        for (id = 0; id < ESP_MAX_DEVS; id++) {
548 fa1fb14c ths
            if (s->scsi_dev[id] == NULL)
549 fa1fb14c ths
                break;
550 fa1fb14c ths
        }
551 fa1fb14c ths
    }
552 fa1fb14c ths
    if (id >= ESP_MAX_DEVS) {
553 fa1fb14c ths
        DPRINTF("Bad Device ID %d\n", id);
554 fa1fb14c ths
        return;
555 fa1fb14c ths
    }
556 fa1fb14c ths
    if (s->scsi_dev[id]) {
557 fa1fb14c ths
        DPRINTF("Destroying device %d\n", id);
558 fa1fb14c ths
        scsi_disk_destroy(s->scsi_dev[id]);
559 fa1fb14c ths
    }
560 fa1fb14c ths
    DPRINTF("Attaching block device %d\n", id);
561 fa1fb14c ths
    /* Command queueing is not implemented.  */
562 fa1fb14c ths
    s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
563 fa1fb14c ths
}
564 fa1fb14c ths
565 67e999be bellard
void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque)
566 6f7e9aec bellard
{
567 6f7e9aec bellard
    ESPState *s;
568 67e999be bellard
    int esp_io_memory;
569 6f7e9aec bellard
570 6f7e9aec bellard
    s = qemu_mallocz(sizeof(ESPState));
571 6f7e9aec bellard
    if (!s)
572 67e999be bellard
        return NULL;
573 6f7e9aec bellard
574 6f7e9aec bellard
    s->bd = bd;
575 67e999be bellard
    s->dma_opaque = dma_opaque;
576 6f7e9aec bellard
577 6f7e9aec bellard
    esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
578 6f7e9aec bellard
    cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
579 6f7e9aec bellard
580 6f7e9aec bellard
    esp_reset(s);
581 6f7e9aec bellard
582 5425a216 blueswir1
    register_savevm("esp", espaddr, 3, esp_save, esp_load, s);
583 6f7e9aec bellard
    qemu_register_reset(esp_reset, s);
584 6f7e9aec bellard
585 67e999be bellard
    return s;
586 67e999be bellard
}