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 | 24 | #include "vl.h" |
| 25 | 25 | |
| 26 | 26 | /* debug ESP card */ |
| 27 | -#define DEBUG_ESP | |
| 27 | +//#define DEBUG_ESP | |
| 28 | 28 | |
| 29 | 29 | #ifdef DEBUG_ESP |
| 30 | 30 | #define DPRINTF(fmt, args...) \ |
| ... | ... | @@ -39,16 +39,178 @@ do { printf("ESP: " fmt , ##args); } while (0) |
| 39 | 39 | |
| 40 | 40 | typedef struct ESPState { |
| 41 | 41 | BlockDriverState **bd; |
| 42 | - uint8_t regs[ESP_MAXREG]; | |
| 42 | + uint8_t rregs[ESP_MAXREG]; | |
| 43 | + uint8_t wregs[ESP_MAXREG]; | |
| 43 | 44 | int irq; |
| 44 | 45 | uint32_t espdmaregs[ESPDMA_REGS]; |
| 46 | + uint32_t ti_size; | |
| 47 | + int ti_dir; | |
| 48 | + uint8_t ti_buf[65536]; | |
| 45 | 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 | 209 | static void esp_reset(void *opaque) |
| 48 | 210 | { |
| 49 | 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 | 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 | 224 | default: |
| 63 | 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 | 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 | 234 | uint32_t saddr; |
| 73 | 235 | |
| 74 | 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 | 238 | switch (saddr) { |
| 77 | 239 | case 3: |
| 78 | 240 | // Command |
| 79 | 241 | switch(val & 0x7f) { |
| 80 | 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 | 249 | break; |
| 83 | 250 | case 2: |
| 84 | - DPRINTF("esp: Chip reset (%2.2x)\n", val); | |
| 251 | + DPRINTF("Chip reset (%2.2x)\n", val); | |
| 85 | 252 | esp_reset(s); |
| 86 | 253 | break; |
| 87 | 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 | 269 | break; |
| 90 | 270 | case 0x1a: |
| 91 | - DPRINTF("esp: Set ATN (%2.2x)\n", val); | |
| 271 | + DPRINTF("Set ATN (%2.2x)\n", val); | |
| 92 | 272 | break; |
| 93 | 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 | 282 | break; |
| 100 | 283 | } |
| 101 | 284 | break; |
| ... | ... | @@ -103,9 +286,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
| 103 | 286 | case 9 ... 0xf: |
| 104 | 287 | break; |
| 105 | 288 | default: |
| 106 | - s->regs[saddr] = val; | |
| 107 | 289 | break; |
| 108 | 290 | } |
| 291 | + s->wregs[saddr] = val; | |
| 109 | 292 | } |
| 110 | 293 | |
| 111 | 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 | 309 | uint32_t saddr; |
| 127 | 310 | |
| 128 | 311 | saddr = (addr & ESPDMA_MAXADDR) >> 2; |
| 312 | + DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]); | |
| 129 | 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 | 319 | uint32_t saddr; |
| 136 | 320 | |
| 137 | 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 | 331 | s->espdmaregs[saddr] = val; |
| 139 | 332 | } |
| 140 | 333 | |
| ... | ... | @@ -153,16 +346,29 @@ static CPUWriteMemoryFunc *espdma_mem_write[3] = { |
| 153 | 346 | static void esp_save(QEMUFile *f, void *opaque) |
| 154 | 347 | { |
| 155 | 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 | 358 | static int esp_load(QEMUFile *f, void *opaque, int version_id) |
| 160 | 359 | { |
| 161 | 360 | ESPState *s = opaque; |
| 361 | + unsigned int i; | |
| 162 | 362 | |
| 163 | 363 | if (version_id != 1) |
| 164 | 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 | 372 | return 0; |
| 167 | 373 | } |
| 168 | 374 | ... | ... |