Commit 2f275b8f9ff82864d389b5cfff1e3b65a7b78923

Authored by bellard
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  
... ...