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 |