Commit 2f275b8f9ff82864d389b5cfff1e3b65a7b78923
1 parent
c3278b7b
SCSI support (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1344 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
224 additions
and
18 deletions
hw/esp.c
@@ -24,7 +24,7 @@ | @@ -24,7 +24,7 @@ | ||
24 | #include "vl.h" | 24 | #include "vl.h" |
25 | 25 | ||
26 | /* debug ESP card */ | 26 | /* debug ESP card */ |
27 | -#define DEBUG_ESP | 27 | +//#define DEBUG_ESP |
28 | 28 | ||
29 | #ifdef DEBUG_ESP | 29 | #ifdef DEBUG_ESP |
30 | #define DPRINTF(fmt, args...) \ | 30 | #define DPRINTF(fmt, args...) \ |
@@ -39,16 +39,178 @@ do { printf("ESP: " fmt , ##args); } while (0) | @@ -39,16 +39,178 @@ do { printf("ESP: " fmt , ##args); } while (0) | ||
39 | 39 | ||
40 | typedef struct ESPState { | 40 | typedef struct ESPState { |
41 | BlockDriverState **bd; | 41 | BlockDriverState **bd; |
42 | - uint8_t regs[ESP_MAXREG]; | 42 | + uint8_t rregs[ESP_MAXREG]; |
43 | + uint8_t wregs[ESP_MAXREG]; | ||
43 | int irq; | 44 | int irq; |
44 | uint32_t espdmaregs[ESPDMA_REGS]; | 45 | uint32_t espdmaregs[ESPDMA_REGS]; |
46 | + uint32_t ti_size; | ||
47 | + int ti_dir; | ||
48 | + uint8_t ti_buf[65536]; | ||
45 | } ESPState; | 49 | } ESPState; |
46 | 50 | ||
51 | +#define STAT_DO 0x00 | ||
52 | +#define STAT_DI 0x01 | ||
53 | +#define STAT_CD 0x02 | ||
54 | +#define STAT_ST 0x03 | ||
55 | +#define STAT_MI 0x06 | ||
56 | +#define STAT_MO 0x07 | ||
57 | + | ||
58 | +#define STAT_TC 0x10 | ||
59 | +#define STAT_IN 0x80 | ||
60 | + | ||
61 | +#define INTR_FC 0x08 | ||
62 | +#define INTR_BS 0x10 | ||
63 | +#define INTR_DC 0x20 | ||
64 | + | ||
65 | +#define SEQ_0 0x0 | ||
66 | +#define SEQ_CD 0x4 | ||
67 | + | ||
68 | +static void handle_satn(ESPState *s) | ||
69 | +{ | ||
70 | + uint8_t buf[32]; | ||
71 | + uint32_t dmaptr, dmalen; | ||
72 | + unsigned int i; | ||
73 | + int64_t nb_sectors; | ||
74 | + int target; | ||
75 | + | ||
76 | + dmaptr = iommu_translate(s->espdmaregs[1]); | ||
77 | + dmalen = s->wregs[0] | (s->wregs[1] << 8); | ||
78 | + DPRINTF("Select with ATN at %8.8x len %d\n", dmaptr, dmalen); | ||
79 | + DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); | ||
80 | + cpu_physical_memory_read(dmaptr, buf, dmalen); | ||
81 | + for (i = 0; i < dmalen; i++) { | ||
82 | + DPRINTF("Command %2.2x\n", buf[i]); | ||
83 | + } | ||
84 | + s->ti_dir = 0; | ||
85 | + s->ti_size = 0; | ||
86 | + target = s->wregs[4] & 7; | ||
87 | + | ||
88 | + if (target > 4 || !s->bd[target]) { // No such drive | ||
89 | + s->rregs[4] = STAT_IN; | ||
90 | + s->rregs[5] = INTR_DC; | ||
91 | + s->rregs[6] = SEQ_0; | ||
92 | + s->espdmaregs[0] |= 1; | ||
93 | + pic_set_irq(s->irq, 1); | ||
94 | + return; | ||
95 | + } | ||
96 | + switch (buf[1]) { | ||
97 | + case 0x0: | ||
98 | + DPRINTF("Test Unit Ready (len %d)\n", buf[5]); | ||
99 | + break; | ||
100 | + case 0x12: | ||
101 | + DPRINTF("Inquiry (len %d)\n", buf[5]); | ||
102 | + memset(s->ti_buf, 0, 36); | ||
103 | + if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { | ||
104 | + s->ti_buf[0] = 5; | ||
105 | + memcpy(&s->ti_buf[16], "QEMU CDROM ", 16); | ||
106 | + } else { | ||
107 | + s->ti_buf[0] = 0; | ||
108 | + memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16); | ||
109 | + } | ||
110 | + memcpy(&s->ti_buf[8], "QEMU ", 8); | ||
111 | + s->ti_buf[2] = 1; | ||
112 | + s->ti_buf[3] = 2; | ||
113 | + s->ti_dir = 1; | ||
114 | + s->ti_size = 36; | ||
115 | + break; | ||
116 | + case 0x1a: | ||
117 | + DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]); | ||
118 | + break; | ||
119 | + case 0x25: | ||
120 | + DPRINTF("Read Capacity (len %d)\n", buf[5]); | ||
121 | + memset(s->ti_buf, 0, 8); | ||
122 | + bdrv_get_geometry(s->bd[target], &nb_sectors); | ||
123 | + s->ti_buf[0] = (nb_sectors >> 24) & 0xff; | ||
124 | + s->ti_buf[1] = (nb_sectors >> 16) & 0xff; | ||
125 | + s->ti_buf[2] = (nb_sectors >> 8) & 0xff; | ||
126 | + s->ti_buf[3] = nb_sectors & 0xff; | ||
127 | + s->ti_buf[4] = 0; | ||
128 | + s->ti_buf[5] = 0; | ||
129 | + s->ti_buf[6] = 2; | ||
130 | + s->ti_buf[7] = 0; | ||
131 | + s->ti_dir = 1; | ||
132 | + s->ti_size = 8; | ||
133 | + break; | ||
134 | + case 0x28: | ||
135 | + { | ||
136 | + int64_t offset, len; | ||
137 | + | ||
138 | + offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; | ||
139 | + len = (buf[8] << 8) | buf[9]; | ||
140 | + DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); | ||
141 | + bdrv_read(s->bd[target], offset, s->ti_buf, len); | ||
142 | + s->ti_dir = 1; | ||
143 | + s->ti_size = len * 512; | ||
144 | + break; | ||
145 | + } | ||
146 | + case 0x2a: | ||
147 | + { | ||
148 | + int64_t offset, len; | ||
149 | + | ||
150 | + offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; | ||
151 | + len = (buf[8] << 8) | buf[9]; | ||
152 | + DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); | ||
153 | + bdrv_write(s->bd[target], offset, s->ti_buf, len); | ||
154 | + s->ti_dir = 0; | ||
155 | + s->ti_size = len * 512; | ||
156 | + break; | ||
157 | + } | ||
158 | + default: | ||
159 | + DPRINTF("Unknown command (%2.2x)\n", buf[1]); | ||
160 | + break; | ||
161 | + } | ||
162 | + s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; | ||
163 | + s->rregs[5] = INTR_BS | INTR_FC; | ||
164 | + s->rregs[6] = SEQ_CD; | ||
165 | + s->espdmaregs[0] |= 1; | ||
166 | + pic_set_irq(s->irq, 1); | ||
167 | +} | ||
168 | + | ||
169 | +static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) | ||
170 | +{ | ||
171 | + uint32_t dmaptr, dmalen; | ||
172 | + | ||
173 | + dmaptr = iommu_translate(s->espdmaregs[1]); | ||
174 | + dmalen = s->wregs[0] | (s->wregs[1] << 8); | ||
175 | + DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); | ||
176 | + cpu_physical_memory_write(dmaptr, buf, len); | ||
177 | + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; | ||
178 | + s->rregs[5] = INTR_BS | INTR_FC; | ||
179 | + s->rregs[6] = SEQ_CD; | ||
180 | + s->espdmaregs[0] |= 1; | ||
181 | + pic_set_irq(s->irq, 1); | ||
182 | + | ||
183 | +} | ||
184 | +static const uint8_t okbuf[] = {0, 0}; | ||
185 | + | ||
186 | +static void handle_ti(ESPState *s) | ||
187 | +{ | ||
188 | + uint32_t dmaptr, dmalen; | ||
189 | + unsigned int i; | ||
190 | + | ||
191 | + dmaptr = iommu_translate(s->espdmaregs[1]); | ||
192 | + dmalen = s->wregs[0] | (s->wregs[1] << 8); | ||
193 | + DPRINTF("Transfer Information at %8.8x len %d\n", dmaptr, dmalen); | ||
194 | + DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); | ||
195 | + for (i = 0; i < s->ti_size; i++) { | ||
196 | + dmaptr = iommu_translate(s->espdmaregs[1] + i); | ||
197 | + if (s->ti_dir) | ||
198 | + cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); | ||
199 | + else | ||
200 | + cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); | ||
201 | + } | ||
202 | + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; | ||
203 | + s->rregs[5] = INTR_BS; | ||
204 | + s->rregs[6] = 0; | ||
205 | + s->espdmaregs[0] |= 1; | ||
206 | + pic_set_irq(s->irq, 1); | ||
207 | +} | ||
208 | + | ||
47 | static void esp_reset(void *opaque) | 209 | static void esp_reset(void *opaque) |
48 | { | 210 | { |
49 | ESPState *s = opaque; | 211 | ESPState *s = opaque; |
50 | - memset(s->regs, 0, ESP_MAXREG); | ||
51 | - s->regs[0x0e] = 0x4; // Indicate fas100a | 212 | + memset(s->rregs, 0, ESP_MAXREG); |
213 | + s->rregs[0x0e] = 0x4; // Indicate fas100a | ||
52 | memset(s->espdmaregs, 0, ESPDMA_REGS * 4); | 214 | memset(s->espdmaregs, 0, ESPDMA_REGS * 4); |
53 | } | 215 | } |
54 | 216 | ||
@@ -62,8 +224,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) | @@ -62,8 +224,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) | ||
62 | default: | 224 | default: |
63 | break; | 225 | break; |
64 | } | 226 | } |
65 | - DPRINTF("esp: read reg[%d]: 0x%2.2x\n", saddr, s->regs[saddr]); | ||
66 | - return s->regs[saddr]; | 227 | + DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); |
228 | + return s->rregs[saddr]; | ||
67 | } | 229 | } |
68 | 230 | ||
69 | static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | 231 | static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
@@ -72,30 +234,51 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | @@ -72,30 +234,51 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | ||
72 | uint32_t saddr; | 234 | uint32_t saddr; |
73 | 235 | ||
74 | saddr = (addr & ESP_MAXREG) >> 2; | 236 | saddr = (addr & ESP_MAXREG) >> 2; |
75 | - DPRINTF("esp: write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->regs[saddr], val); | 237 | + DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); |
76 | switch (saddr) { | 238 | switch (saddr) { |
77 | case 3: | 239 | case 3: |
78 | // Command | 240 | // Command |
79 | switch(val & 0x7f) { | 241 | switch(val & 0x7f) { |
80 | case 0: | 242 | case 0: |
81 | - DPRINTF("esp: NOP (%2.2x)\n", val); | 243 | + DPRINTF("NOP (%2.2x)\n", val); |
244 | + break; | ||
245 | + case 1: | ||
246 | + DPRINTF("Flush FIFO (%2.2x)\n", val); | ||
247 | + s->rregs[6] = 0; | ||
248 | + s->rregs[5] = INTR_FC; | ||
82 | break; | 249 | break; |
83 | case 2: | 250 | case 2: |
84 | - DPRINTF("esp: Chip reset (%2.2x)\n", val); | 251 | + DPRINTF("Chip reset (%2.2x)\n", val); |
85 | esp_reset(s); | 252 | esp_reset(s); |
86 | break; | 253 | break; |
87 | case 3: | 254 | case 3: |
88 | - DPRINTF("esp: Bus reset (%2.2x)\n", val); | 255 | + DPRINTF("Bus reset (%2.2x)\n", val); |
256 | + break; | ||
257 | + case 0x10: | ||
258 | + handle_ti(s); | ||
259 | + break; | ||
260 | + case 0x11: | ||
261 | + DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); | ||
262 | + dma_write(s, okbuf, 2); | ||
263 | + break; | ||
264 | + case 0x12: | ||
265 | + DPRINTF("Message Accepted (%2.2x)\n", val); | ||
266 | + dma_write(s, okbuf, 2); | ||
267 | + s->rregs[5] = INTR_DC; | ||
268 | + s->rregs[6] = 0; | ||
89 | break; | 269 | break; |
90 | case 0x1a: | 270 | case 0x1a: |
91 | - DPRINTF("esp: Set ATN (%2.2x)\n", val); | 271 | + DPRINTF("Set ATN (%2.2x)\n", val); |
92 | break; | 272 | break; |
93 | case 0x42: | 273 | case 0x42: |
94 | - DPRINTF("esp: Select with ATN (%2.2x)\n", val); | ||
95 | - s->regs[4] = 0x1a; // Status: TCNT | TDONE | CMD | ||
96 | - s->regs[5] = 0x20; // Intr: Disconnect, nobody there | ||
97 | - s->regs[6] = 0x4; // Seq: Cmd done | ||
98 | - pic_set_irq(s->irq, 1); | 274 | + handle_satn(s); |
275 | + break; | ||
276 | + case 0x43: | ||
277 | + DPRINTF("Set ATN & stop (%2.2x)\n", val); | ||
278 | + handle_satn(s); | ||
279 | + break; | ||
280 | + default: | ||
281 | + DPRINTF("Unhandled command (%2.2x)\n", val); | ||
99 | break; | 282 | break; |
100 | } | 283 | } |
101 | break; | 284 | break; |
@@ -103,9 +286,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | @@ -103,9 +286,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | ||
103 | case 9 ... 0xf: | 286 | case 9 ... 0xf: |
104 | break; | 287 | break; |
105 | default: | 288 | default: |
106 | - s->regs[saddr] = val; | ||
107 | break; | 289 | break; |
108 | } | 290 | } |
291 | + s->wregs[saddr] = val; | ||
109 | } | 292 | } |
110 | 293 | ||
111 | static CPUReadMemoryFunc *esp_mem_read[3] = { | 294 | static CPUReadMemoryFunc *esp_mem_read[3] = { |
@@ -126,6 +309,7 @@ static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr) | @@ -126,6 +309,7 @@ static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr) | ||
126 | uint32_t saddr; | 309 | uint32_t saddr; |
127 | 310 | ||
128 | saddr = (addr & ESPDMA_MAXADDR) >> 2; | 311 | saddr = (addr & ESPDMA_MAXADDR) >> 2; |
312 | + DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]); | ||
129 | return s->espdmaregs[saddr]; | 313 | return s->espdmaregs[saddr]; |
130 | } | 314 | } |
131 | 315 | ||
@@ -135,6 +319,15 @@ static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va | @@ -135,6 +319,15 @@ static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va | ||
135 | uint32_t saddr; | 319 | uint32_t saddr; |
136 | 320 | ||
137 | saddr = (addr & ESPDMA_MAXADDR) >> 2; | 321 | saddr = (addr & ESPDMA_MAXADDR) >> 2; |
322 | + DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val); | ||
323 | + switch (saddr) { | ||
324 | + case 0: | ||
325 | + if (!(val & 0x10)) | ||
326 | + pic_set_irq(s->irq, 0); | ||
327 | + break; | ||
328 | + default: | ||
329 | + break; | ||
330 | + } | ||
138 | s->espdmaregs[saddr] = val; | 331 | s->espdmaregs[saddr] = val; |
139 | } | 332 | } |
140 | 333 | ||
@@ -153,16 +346,29 @@ static CPUWriteMemoryFunc *espdma_mem_write[3] = { | @@ -153,16 +346,29 @@ static CPUWriteMemoryFunc *espdma_mem_write[3] = { | ||
153 | static void esp_save(QEMUFile *f, void *opaque) | 346 | static void esp_save(QEMUFile *f, void *opaque) |
154 | { | 347 | { |
155 | ESPState *s = opaque; | 348 | ESPState *s = opaque; |
156 | - | 349 | + unsigned int i; |
350 | + | ||
351 | + qemu_put_buffer(f, s->rregs, ESP_MAXREG); | ||
352 | + qemu_put_buffer(f, s->wregs, ESP_MAXREG); | ||
353 | + qemu_put_be32s(f, &s->irq); | ||
354 | + for (i = 0; i < ESPDMA_REGS; i++) | ||
355 | + qemu_put_be32s(f, &s->espdmaregs[i]); | ||
157 | } | 356 | } |
158 | 357 | ||
159 | static int esp_load(QEMUFile *f, void *opaque, int version_id) | 358 | static int esp_load(QEMUFile *f, void *opaque, int version_id) |
160 | { | 359 | { |
161 | ESPState *s = opaque; | 360 | ESPState *s = opaque; |
361 | + unsigned int i; | ||
162 | 362 | ||
163 | if (version_id != 1) | 363 | if (version_id != 1) |
164 | return -EINVAL; | 364 | return -EINVAL; |
165 | 365 | ||
366 | + qemu_get_buffer(f, s->rregs, ESP_MAXREG); | ||
367 | + qemu_get_buffer(f, s->wregs, ESP_MAXREG); | ||
368 | + qemu_get_be32s(f, &s->irq); | ||
369 | + for (i = 0; i < ESPDMA_REGS; i++) | ||
370 | + qemu_get_be32s(f, &s->espdmaregs[i]); | ||
371 | + | ||
166 | return 0; | 372 | return 0; |
167 | } | 373 | } |
168 | 374 |