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,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