36 |
#define ESPDMA_REGS 4 |
#define ESPDMA_REGS 4 |
37 |
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) |
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) |
38 |
#define ESP_MAXREG 0x3f |
#define ESP_MAXREG 0x3f |
39 |
|
#define TI_BUFSZ 65536 |
40 |
|
#define DMA_VER 0xa0000000 |
41 |
|
#define DMA_LOADED 0x04000000 |
42 |
|
|
43 |
typedef struct ESPState { |
typedef struct ESPState { |
44 |
BlockDriverState **bd; |
BlockDriverState **bd; |
47 |
int irq; |
int irq; |
48 |
uint32_t espdmaregs[ESPDMA_REGS]; |
uint32_t espdmaregs[ESPDMA_REGS]; |
49 |
uint32_t ti_size; |
uint32_t ti_size; |
50 |
|
uint32_t ti_rptr, ti_wptr; |
51 |
int ti_dir; |
int ti_dir; |
52 |
uint8_t ti_buf[65536]; |
uint8_t ti_buf[TI_BUFSZ]; |
53 |
|
int dma; |
54 |
} ESPState; |
} ESPState; |
55 |
|
|
56 |
#define STAT_DO 0x00 |
#define STAT_DO 0x00 |
78 |
int64_t nb_sectors; |
int64_t nb_sectors; |
79 |
int target; |
int target; |
80 |
|
|
|
dmaptr = iommu_translate(s->espdmaregs[1]); |
|
81 |
dmalen = s->wregs[0] | (s->wregs[1] << 8); |
dmalen = s->wregs[0] | (s->wregs[1] << 8); |
82 |
DPRINTF("Select with ATN at %8.8x len %d\n", dmaptr, dmalen); |
target = s->wregs[4] & 7; |
83 |
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); |
DPRINTF("Select with ATN len %d target %d\n", dmalen, target); |
84 |
cpu_physical_memory_read(dmaptr, buf, dmalen); |
if (s->dma) { |
85 |
|
dmaptr = iommu_translate(s->espdmaregs[1]); |
86 |
|
DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); |
87 |
|
cpu_physical_memory_read(dmaptr, buf, dmalen); |
88 |
|
} else { |
89 |
|
buf[0] = 0; |
90 |
|
memcpy(&buf[1], s->ti_buf, dmalen); |
91 |
|
dmalen++; |
92 |
|
} |
93 |
for (i = 0; i < dmalen; i++) { |
for (i = 0; i < dmalen; i++) { |
94 |
DPRINTF("Command %2.2x\n", buf[i]); |
DPRINTF("Command %2.2x\n", buf[i]); |
95 |
} |
} |
96 |
s->ti_dir = 0; |
s->ti_dir = 0; |
97 |
s->ti_size = 0; |
s->ti_size = 0; |
98 |
target = s->wregs[4] & 7; |
s->ti_rptr = 0; |
99 |
|
s->ti_wptr = 0; |
100 |
|
|
101 |
if (target > 4 || !s->bd[target]) { // No such drive |
if (target > 4 || !s->bd[target]) { // No such drive |
102 |
s->rregs[4] = STAT_IN; |
s->rregs[4] = STAT_IN; |
139 |
s->ti_buf[3] = nb_sectors & 0xff; |
s->ti_buf[3] = nb_sectors & 0xff; |
140 |
s->ti_buf[4] = 0; |
s->ti_buf[4] = 0; |
141 |
s->ti_buf[5] = 0; |
s->ti_buf[5] = 0; |
142 |
s->ti_buf[6] = 2; |
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) |
143 |
|
s->ti_buf[6] = 8; // sector size 2048 |
144 |
|
else |
145 |
|
s->ti_buf[6] = 2; // sector size 512 |
146 |
s->ti_buf[7] = 0; |
s->ti_buf[7] = 0; |
147 |
s->ti_dir = 1; |
s->ti_dir = 1; |
148 |
s->ti_size = 8; |
s->ti_size = 8; |
151 |
{ |
{ |
152 |
int64_t offset, len; |
int64_t offset, len; |
153 |
|
|
154 |
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; |
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { |
155 |
len = (buf[8] << 8) | buf[9]; |
offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; |
156 |
|
len = ((buf[8] << 8) | buf[9]) * 4; |
157 |
|
s->ti_size = len * 2048; |
158 |
|
} else { |
159 |
|
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; |
160 |
|
len = (buf[8] << 8) | buf[9]; |
161 |
|
s->ti_size = len * 512; |
162 |
|
} |
163 |
DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); |
DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); |
164 |
bdrv_read(s->bd[target], offset, s->ti_buf, len); |
bdrv_read(s->bd[target], offset, s->ti_buf, len); |
165 |
|
// XXX error handling |
166 |
s->ti_dir = 1; |
s->ti_dir = 1; |
|
s->ti_size = len * 512; |
|
167 |
break; |
break; |
168 |
} |
} |
169 |
case 0x2a: |
case 0x2a: |
170 |
{ |
{ |
171 |
int64_t offset, len; |
int64_t offset, len; |
172 |
|
|
173 |
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; |
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { |
174 |
len = (buf[8] << 8) | buf[9]; |
offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; |
175 |
|
len = ((buf[8] << 8) | buf[9]) * 4; |
176 |
|
s->ti_size = len * 2048; |
177 |
|
} else { |
178 |
|
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; |
179 |
|
len = (buf[8] << 8) | buf[9]; |
180 |
|
s->ti_size = len * 512; |
181 |
|
} |
182 |
DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); |
DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); |
183 |
bdrv_write(s->bd[target], offset, s->ti_buf, len); |
bdrv_write(s->bd[target], offset, s->ti_buf, len); |
184 |
|
// XXX error handling |
185 |
s->ti_dir = 0; |
s->ti_dir = 0; |
|
s->ti_size = len * 512; |
|
186 |
break; |
break; |
187 |
} |
} |
188 |
default: |
default: |
189 |
DPRINTF("Unknown command (%2.2x)\n", buf[1]); |
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]); |
190 |
break; |
break; |
191 |
} |
} |
192 |
s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; |
s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; |
200 |
{ |
{ |
201 |
uint32_t dmaptr, dmalen; |
uint32_t dmaptr, dmalen; |
202 |
|
|
|
dmaptr = iommu_translate(s->espdmaregs[1]); |
|
203 |
dmalen = s->wregs[0] | (s->wregs[1] << 8); |
dmalen = s->wregs[0] | (s->wregs[1] << 8); |
204 |
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); |
DPRINTF("Transfer status len %d\n", dmalen); |
205 |
cpu_physical_memory_write(dmaptr, buf, len); |
if (s->dma) { |
206 |
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; |
dmaptr = iommu_translate(s->espdmaregs[1]); |
207 |
s->rregs[5] = INTR_BS | INTR_FC; |
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); |
208 |
s->rregs[6] = SEQ_CD; |
cpu_physical_memory_write(dmaptr, buf, len); |
209 |
s->espdmaregs[0] |= 1; |
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; |
210 |
|
s->rregs[5] = INTR_BS | INTR_FC; |
211 |
|
s->rregs[6] = SEQ_CD; |
212 |
|
s->espdmaregs[0] |= 1; |
213 |
|
} else { |
214 |
|
memcpy(s->ti_buf, buf, len); |
215 |
|
s->ti_size = dmalen; |
216 |
|
s->ti_rptr = 0; |
217 |
|
s->ti_wptr = 0; |
218 |
|
} |
219 |
pic_set_irq(s->irq, 1); |
pic_set_irq(s->irq, 1); |
220 |
|
|
221 |
} |
} |
222 |
|
|
223 |
static const uint8_t okbuf[] = {0, 0}; |
static const uint8_t okbuf[] = {0, 0}; |
224 |
|
|
225 |
static void handle_ti(ESPState *s) |
static void handle_ti(ESPState *s) |
227 |
uint32_t dmaptr, dmalen; |
uint32_t dmaptr, dmalen; |
228 |
unsigned int i; |
unsigned int i; |
229 |
|
|
|
dmaptr = iommu_translate(s->espdmaregs[1]); |
|
230 |
dmalen = s->wregs[0] | (s->wregs[1] << 8); |
dmalen = s->wregs[0] | (s->wregs[1] << 8); |
231 |
DPRINTF("Transfer Information at %8.8x len %d\n", dmaptr, dmalen); |
DPRINTF("Transfer Information len %d\n", dmalen); |
232 |
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); |
if (s->dma) { |
233 |
for (i = 0; i < s->ti_size; i++) { |
dmaptr = iommu_translate(s->espdmaregs[1]); |
234 |
dmaptr = iommu_translate(s->espdmaregs[1] + i); |
DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); |
235 |
if (s->ti_dir) |
for (i = 0; i < s->ti_size; i++) { |
236 |
cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); |
dmaptr = iommu_translate(s->espdmaregs[1] + i); |
237 |
else |
if (s->ti_dir) |
238 |
cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); |
cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); |
239 |
} |
else |
240 |
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; |
cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); |
241 |
s->rregs[5] = INTR_BS; |
} |
242 |
s->rregs[6] = 0; |
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; |
243 |
s->espdmaregs[0] |= 1; |
s->rregs[5] = INTR_BS; |
244 |
|
s->rregs[6] = 0; |
245 |
|
s->espdmaregs[0] |= 1; |
246 |
|
} else { |
247 |
|
s->ti_size = dmalen; |
248 |
|
s->ti_rptr = 0; |
249 |
|
s->ti_wptr = 0; |
250 |
|
} |
251 |
pic_set_irq(s->irq, 1); |
pic_set_irq(s->irq, 1); |
252 |
} |
} |
253 |
|
|
266 |
|
|
267 |
saddr = (addr & ESP_MAXREG) >> 2; |
saddr = (addr & ESP_MAXREG) >> 2; |
268 |
switch (saddr) { |
switch (saddr) { |
269 |
|
case 2: |
270 |
|
// FIFO |
271 |
|
if (s->ti_size > 0) { |
272 |
|
s->ti_size--; |
273 |
|
s->rregs[saddr] = s->ti_buf[s->ti_rptr++]; |
274 |
|
pic_set_irq(s->irq, 1); |
275 |
|
} |
276 |
|
if (s->ti_size == 0) { |
277 |
|
s->ti_rptr = 0; |
278 |
|
s->ti_wptr = 0; |
279 |
|
} |
280 |
|
break; |
281 |
default: |
default: |
282 |
break; |
break; |
283 |
} |
} |
284 |
DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); |
DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); |
285 |
|
|
286 |
return s->rregs[saddr]; |
return s->rregs[saddr]; |
287 |
} |
} |
288 |
|
|
294 |
saddr = (addr & ESP_MAXREG) >> 2; |
saddr = (addr & ESP_MAXREG) >> 2; |
295 |
DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); |
DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); |
296 |
switch (saddr) { |
switch (saddr) { |
297 |
|
case 0: |
298 |
|
case 1: |
299 |
|
s->rregs[saddr] = val; |
300 |
|
break; |
301 |
|
case 2: |
302 |
|
// FIFO |
303 |
|
s->ti_size++; |
304 |
|
s->ti_buf[s->ti_wptr++] = val & 0xff; |
305 |
|
break; |
306 |
case 3: |
case 3: |
307 |
|
s->rregs[saddr] = val; |
308 |
// Command |
// Command |
309 |
|
if (val & 0x80) { |
310 |
|
s->dma = 1; |
311 |
|
} else { |
312 |
|
s->dma = 0; |
313 |
|
} |
314 |
switch(val & 0x7f) { |
switch(val & 0x7f) { |
315 |
case 0: |
case 0: |
316 |
DPRINTF("NOP (%2.2x)\n", val); |
DPRINTF("NOP (%2.2x)\n", val); |
351 |
handle_satn(s); |
handle_satn(s); |
352 |
break; |
break; |
353 |
default: |
default: |
354 |
DPRINTF("Unhandled command (%2.2x)\n", val); |
DPRINTF("Unhandled ESP command (%2.2x)\n", val); |
355 |
break; |
break; |
356 |
} |
} |
357 |
break; |
break; |
358 |
case 4 ... 7: |
case 4 ... 7: |
|
case 9 ... 0xf: |
|
359 |
break; |
break; |
360 |
|
case 8: |
361 |
|
s->rregs[saddr] = val; |
362 |
|
break; |
363 |
|
case 9 ... 10: |
364 |
|
break; |
365 |
|
case 11 ... 15: |
366 |
|
s->rregs[saddr] = val; |
367 |
|
break; |
368 |
default: |
default: |
369 |
break; |
break; |
370 |
} |
} |
389 |
uint32_t saddr; |
uint32_t saddr; |
390 |
|
|
391 |
saddr = (addr & ESPDMA_MAXADDR) >> 2; |
saddr = (addr & ESPDMA_MAXADDR) >> 2; |
392 |
DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]); |
DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]); |
393 |
|
|
394 |
return s->espdmaregs[saddr]; |
return s->espdmaregs[saddr]; |
395 |
} |
} |
396 |
|
|
400 |
uint32_t saddr; |
uint32_t saddr; |
401 |
|
|
402 |
saddr = (addr & ESPDMA_MAXADDR) >> 2; |
saddr = (addr & ESPDMA_MAXADDR) >> 2; |
403 |
DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val); |
DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val); |
404 |
switch (saddr) { |
switch (saddr) { |
405 |
case 0: |
case 0: |
406 |
if (!(val & 0x10)) |
if (!(val & 0x10)) |
407 |
pic_set_irq(s->irq, 0); |
pic_set_irq(s->irq, 0); |
408 |
break; |
if (val & 0x80) { |
409 |
|
esp_reset(s); |
410 |
|
} else if (val & 0x40) { |
411 |
|
val &= ~0x40; |
412 |
|
} else if (val == 0) |
413 |
|
val = 0x40; |
414 |
|
val &= 0x0fffffff; |
415 |
|
val |= DMA_VER; |
416 |
|
break; |
417 |
|
case 1: |
418 |
|
s->espdmaregs[0] = DMA_LOADED; |
419 |
|
break; |
420 |
default: |
default: |
421 |
break; |
break; |
422 |
} |
} |
445 |
qemu_put_be32s(f, &s->irq); |
qemu_put_be32s(f, &s->irq); |
446 |
for (i = 0; i < ESPDMA_REGS; i++) |
for (i = 0; i < ESPDMA_REGS; i++) |
447 |
qemu_put_be32s(f, &s->espdmaregs[i]); |
qemu_put_be32s(f, &s->espdmaregs[i]); |
448 |
|
qemu_put_be32s(f, &s->ti_size); |
449 |
|
qemu_put_be32s(f, &s->ti_rptr); |
450 |
|
qemu_put_be32s(f, &s->ti_wptr); |
451 |
|
qemu_put_be32s(f, &s->ti_dir); |
452 |
|
qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); |
453 |
|
qemu_put_be32s(f, &s->dma); |
454 |
} |
} |
455 |
|
|
456 |
static int esp_load(QEMUFile *f, void *opaque, int version_id) |
static int esp_load(QEMUFile *f, void *opaque, int version_id) |
466 |
qemu_get_be32s(f, &s->irq); |
qemu_get_be32s(f, &s->irq); |
467 |
for (i = 0; i < ESPDMA_REGS; i++) |
for (i = 0; i < ESPDMA_REGS; i++) |
468 |
qemu_get_be32s(f, &s->espdmaregs[i]); |
qemu_get_be32s(f, &s->espdmaregs[i]); |
469 |
|
qemu_get_be32s(f, &s->ti_size); |
470 |
|
qemu_get_be32s(f, &s->ti_rptr); |
471 |
|
qemu_get_be32s(f, &s->ti_wptr); |
472 |
|
qemu_get_be32s(f, &s->ti_dir); |
473 |
|
qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); |
474 |
|
qemu_get_be32s(f, &s->dma); |
475 |
|
|
476 |
return 0; |
return 0; |
477 |
} |
} |