Commit a917d384ac0d09cd68266a6f2ca5c94212c8f81e
1 parent
508d92d0
SCSI TCQ support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2139 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
7 changed files
with
932 additions
and
451 deletions
hw/esp.c
... | ... | @@ -64,8 +64,7 @@ struct ESPState { |
64 | 64 | int do_cmd; |
65 | 65 | |
66 | 66 | uint32_t dma_left; |
67 | - uint8_t async_buf[TARGET_PAGE_SIZE]; | |
68 | - uint32_t async_ptr; | |
67 | + uint8_t *async_buf; | |
69 | 68 | uint32_t async_len; |
70 | 69 | }; |
71 | 70 | |
... | ... | @@ -91,17 +90,16 @@ struct ESPState { |
91 | 90 | |
92 | 91 | static int get_cmd(ESPState *s, uint8_t *buf) |
93 | 92 | { |
94 | - uint32_t dmaptr, dmalen; | |
93 | + uint32_t dmalen; | |
95 | 94 | int target; |
96 | 95 | |
97 | 96 | dmalen = s->wregs[0] | (s->wregs[1] << 8); |
98 | 97 | target = s->wregs[4] & 7; |
99 | 98 | DPRINTF("get_cmd: len %d target %d\n", dmalen, target); |
100 | 99 | if (s->dma) { |
101 | - dmaptr = iommu_translate(s->espdmaregs[1]); | |
102 | 100 | DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", |
103 | - s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr); | |
104 | - cpu_physical_memory_read(dmaptr, buf, dmalen); | |
101 | + s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->espdmaregs[1]); | |
102 | + sparc_iommu_memory_read(s->espdmaregs[1], buf, dmalen); | |
105 | 103 | } else { |
106 | 104 | buf[0] = 0; |
107 | 105 | memcpy(&buf[1], s->ti_buf, dmalen); |
... | ... | @@ -112,6 +110,12 @@ static int get_cmd(ESPState *s, uint8_t *buf) |
112 | 110 | s->ti_rptr = 0; |
113 | 111 | s->ti_wptr = 0; |
114 | 112 | |
113 | + if (s->current_dev) { | |
114 | + /* Started a new command before the old one finished. Cancel it. */ | |
115 | + scsi_cancel_io(s->current_dev, 0); | |
116 | + s->async_len = 0; | |
117 | + } | |
118 | + | |
115 | 119 | if (target >= 4 || !s->scsi_dev[target]) { |
116 | 120 | // No such drive |
117 | 121 | s->rregs[4] = STAT_IN; |
... | ... | @@ -137,12 +141,15 @@ static void do_cmd(ESPState *s, uint8_t *buf) |
137 | 141 | s->ti_size = 0; |
138 | 142 | } else { |
139 | 143 | s->rregs[4] = STAT_IN | STAT_TC; |
144 | + s->dma_left = 0; | |
140 | 145 | if (datalen > 0) { |
141 | 146 | s->rregs[4] |= STAT_DI; |
142 | 147 | s->ti_size = datalen; |
148 | + scsi_read_data(s->current_dev, 0); | |
143 | 149 | } else { |
144 | 150 | s->rregs[4] |= STAT_DO; |
145 | 151 | s->ti_size = -datalen; |
152 | + scsi_write_data(s->current_dev, 0); | |
146 | 153 | } |
147 | 154 | } |
148 | 155 | s->rregs[5] = INTR_BS | INTR_FC; |
... | ... | @@ -178,16 +185,13 @@ static void handle_satn_stop(ESPState *s) |
178 | 185 | |
179 | 186 | static void write_response(ESPState *s) |
180 | 187 | { |
181 | - uint32_t dmaptr; | |
182 | - | |
183 | 188 | DPRINTF("Transfer status (sense=%d)\n", s->sense); |
184 | 189 | s->ti_buf[0] = s->sense; |
185 | 190 | s->ti_buf[1] = 0; |
186 | 191 | if (s->dma) { |
187 | - dmaptr = iommu_translate(s->espdmaregs[1]); | |
188 | 192 | DPRINTF("DMA Direction: %c\n", |
189 | 193 | s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); |
190 | - cpu_physical_memory_write(dmaptr, s->ti_buf, 2); | |
194 | + sparc_iommu_memory_write(s->espdmaregs[1], s->ti_buf, 2); | |
191 | 195 | s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; |
192 | 196 | s->rregs[5] = INTR_BS | INTR_FC; |
193 | 197 | s->rregs[6] = SEQ_CD; |
... | ... | @@ -202,78 +206,89 @@ static void write_response(ESPState *s) |
202 | 206 | |
203 | 207 | } |
204 | 208 | |
209 | +static void esp_dma_done(ESPState *s) | |
210 | +{ | |
211 | + s->rregs[4] |= STAT_IN | STAT_TC; | |
212 | + s->rregs[5] = INTR_BS; | |
213 | + s->rregs[6] = 0; | |
214 | + s->rregs[7] = 0; | |
215 | + s->espdmaregs[0] |= DMA_INTR; | |
216 | + pic_set_irq(s->irq, 1); | |
217 | +} | |
218 | + | |
205 | 219 | static void esp_do_dma(ESPState *s) |
206 | 220 | { |
207 | - uint32_t dmaptr, minlen, len, from, to; | |
221 | + uint32_t addr, len; | |
208 | 222 | int to_device; |
223 | + | |
209 | 224 | to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; |
210 | - from = s->espdmaregs[1]; | |
211 | - minlen = s->dma_left; | |
212 | - to = from + minlen; | |
213 | - dmaptr = iommu_translate(s->espdmaregs[1]); | |
214 | - if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { | |
215 | - len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); | |
216 | - } else { | |
217 | - len = to - from; | |
218 | - } | |
219 | - DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1], len, from, to); | |
225 | + addr = s->espdmaregs[1]; | |
226 | + len = s->dma_left; | |
227 | + DPRINTF("DMA address %08x len %08x\n", addr, len); | |
220 | 228 | if (s->do_cmd) { |
221 | 229 | s->espdmaregs[1] += len; |
222 | 230 | s->ti_size -= len; |
223 | 231 | DPRINTF("command len %d + %d\n", s->cmdlen, len); |
224 | - cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); | |
232 | + sparc_iommu_memory_read(addr, &s->cmdbuf[s->cmdlen], len); | |
225 | 233 | s->ti_size = 0; |
226 | 234 | s->cmdlen = 0; |
227 | 235 | s->do_cmd = 0; |
228 | 236 | do_cmd(s, s->cmdbuf); |
229 | 237 | return; |
238 | + } | |
239 | + if (s->async_len == 0) { | |
240 | + /* Defer until data is available. */ | |
241 | + return; | |
242 | + } | |
243 | + if (len > s->async_len) { | |
244 | + len = s->async_len; | |
245 | + } | |
246 | + if (to_device) { | |
247 | + sparc_iommu_memory_read(addr, s->async_buf, len); | |
230 | 248 | } else { |
231 | - s->async_len = len; | |
232 | - s->dma_left -= len; | |
249 | + sparc_iommu_memory_write(addr, s->async_buf, len); | |
250 | + } | |
251 | + s->ti_size -= len; | |
252 | + s->dma_left -= len; | |
253 | + s->async_buf += len; | |
254 | + s->async_len -= len; | |
255 | + s->espdmaregs[1] += len; | |
256 | + if (s->async_len == 0) { | |
233 | 257 | if (to_device) { |
234 | - s->async_ptr = -1; | |
235 | - cpu_physical_memory_read(dmaptr, s->async_buf, len); | |
236 | - scsi_write_data(s->current_dev, s->async_buf, len); | |
258 | + scsi_write_data(s->current_dev, 0); | |
237 | 259 | } else { |
238 | - s->async_ptr = dmaptr; | |
239 | - scsi_read_data(s->current_dev, s->async_buf, len); | |
260 | + scsi_read_data(s->current_dev, 0); | |
240 | 261 | } |
241 | 262 | } |
263 | + if (s->dma_left == 0) { | |
264 | + esp_dma_done(s); | |
265 | + } | |
242 | 266 | } |
243 | 267 | |
244 | -static void esp_command_complete(void *opaque, uint32_t reason, int sense) | |
268 | +static void esp_command_complete(void *opaque, int reason, uint32_t tag, | |
269 | + uint32_t arg) | |
245 | 270 | { |
246 | 271 | ESPState *s = (ESPState *)opaque; |
247 | 272 | |
248 | - s->ti_size -= s->async_len; | |
249 | - s->espdmaregs[1] += s->async_len; | |
250 | - if (s->async_ptr != (uint32_t)-1) { | |
251 | - cpu_physical_memory_write(s->async_ptr, s->async_buf, s->async_len); | |
252 | - } | |
253 | 273 | if (reason == SCSI_REASON_DONE) { |
254 | 274 | DPRINTF("SCSI Command complete\n"); |
255 | 275 | if (s->ti_size != 0) |
256 | 276 | DPRINTF("SCSI command completed unexpectedly\n"); |
257 | 277 | s->ti_size = 0; |
258 | - if (sense) | |
278 | + s->dma_left = 0; | |
279 | + s->async_len = 0; | |
280 | + if (arg) | |
259 | 281 | DPRINTF("Command failed\n"); |
260 | - s->sense = sense; | |
282 | + s->sense = arg; | |
283 | + s->rregs[4] = STAT_ST; | |
284 | + esp_dma_done(s); | |
285 | + s->current_dev = NULL; | |
261 | 286 | } else { |
262 | 287 | DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); |
263 | - } | |
264 | - if (s->dma_left) { | |
265 | - esp_do_dma(s); | |
266 | - } else { | |
267 | - if (s->ti_size) { | |
268 | - s->rregs[4] |= STAT_IN | STAT_TC; | |
269 | - } else { | |
270 | - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; | |
271 | - } | |
272 | - s->rregs[5] = INTR_BS; | |
273 | - s->rregs[6] = 0; | |
274 | - s->rregs[7] = 0; | |
275 | - s->espdmaregs[0] |= DMA_INTR; | |
276 | - pic_set_irq(s->irq, 1); | |
288 | + s->async_len = arg; | |
289 | + s->async_buf = scsi_get_buf(s->current_dev, 0); | |
290 | + if (s->dma_left) | |
291 | + esp_do_dma(s); | |
277 | 292 | } |
278 | 293 | } |
279 | 294 | |
... | ... | @@ -333,7 +348,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) |
333 | 348 | s->ti_size--; |
334 | 349 | if ((s->rregs[4] & 6) == 0) { |
335 | 350 | /* Data in/out. */ |
336 | - scsi_read_data(s->current_dev, &s->rregs[2], 0); | |
351 | + fprintf(stderr, "esp: PIO data read not implemented\n"); | |
352 | + s->rregs[2] = 0; | |
337 | 353 | } else { |
338 | 354 | s->rregs[2] = s->ti_buf[s->ti_rptr++]; |
339 | 355 | } |
... | ... | @@ -378,7 +394,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
378 | 394 | uint8_t buf; |
379 | 395 | buf = val & 0xff; |
380 | 396 | s->ti_size--; |
381 | - scsi_write_data(s->current_dev, &buf, 0); | |
397 | + fprintf(stderr, "esp: PIO data write not implemented\n"); | |
382 | 398 | } else { |
383 | 399 | s->ti_size++; |
384 | 400 | s->ti_buf[s->ti_wptr++] = val & 0xff; |
... | ... | @@ -590,8 +606,9 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd |
590 | 606 | qemu_register_reset(esp_reset, s); |
591 | 607 | for (i = 0; i < MAX_DISKS; i++) { |
592 | 608 | if (bs_table[i]) { |
609 | + /* Command queueing is not implemented. */ | |
593 | 610 | s->scsi_dev[i] = |
594 | - scsi_disk_init(bs_table[i], esp_command_complete, s); | |
611 | + scsi_disk_init(bs_table[i], 0, esp_command_complete, s); | |
595 | 612 | } |
596 | 613 | } |
597 | 614 | } | ... | ... |
hw/iommu.c
... | ... | @@ -186,21 +186,62 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { |
186 | 186 | iommu_mem_writew, |
187 | 187 | }; |
188 | 188 | |
189 | -uint32_t iommu_translate_local(void *opaque, uint32_t addr) | |
189 | +static uint32_t iommu_page_get_flags(IOMMUState *s, uint32_t addr) | |
190 | 190 | { |
191 | - IOMMUState *s = opaque; | |
192 | - uint32_t iopte, pa, tmppte; | |
191 | + uint32_t iopte; | |
193 | 192 | |
194 | 193 | iopte = s->regs[1] << 4; |
195 | 194 | addr &= ~s->iostart; |
196 | 195 | iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; |
197 | - pa = ldl_phys(iopte); | |
196 | + return ldl_phys(iopte); | |
197 | +} | |
198 | + | |
199 | +static uint32_t iommu_translate_pa(IOMMUState *s, uint32_t addr, uint32_t pa) | |
200 | +{ | |
201 | + uint32_t tmppte; | |
202 | + | |
198 | 203 | tmppte = pa; |
199 | 204 | pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); |
200 | - DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte); | |
205 | + DPRINTF("xlate dva %x => pa %x (iopte = %x)\n", addr, pa, tmppte); | |
201 | 206 | return pa; |
202 | 207 | } |
203 | 208 | |
209 | +uint32_t iommu_translate_local(void *opaque, uint32_t addr) | |
210 | +{ | |
211 | + uint32_t flags; | |
212 | + flags = iommu_page_get_flags(opaque, addr); | |
213 | + return iommu_translate_pa(opaque, addr, flags); | |
214 | +} | |
215 | + | |
216 | +void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, | |
217 | + uint8_t *buf, int len, int is_write) | |
218 | +{ | |
219 | + int l, flags; | |
220 | + target_ulong page, phys_addr; | |
221 | + void * p; | |
222 | + | |
223 | + while (len > 0) { | |
224 | + page = addr & TARGET_PAGE_MASK; | |
225 | + l = (page + TARGET_PAGE_SIZE) - addr; | |
226 | + if (l > len) | |
227 | + l = len; | |
228 | + flags = iommu_page_get_flags(opaque, page); | |
229 | + if (!(flags & IOPTE_VALID)) | |
230 | + return; | |
231 | + phys_addr = iommu_translate_pa(opaque, addr, flags); | |
232 | + if (is_write) { | |
233 | + if (!(flags & IOPTE_WRITE)) | |
234 | + return; | |
235 | + cpu_physical_memory_write(phys_addr, buf, len); | |
236 | + } else { | |
237 | + cpu_physical_memory_read(phys_addr, buf, len); | |
238 | + } | |
239 | + len -= l; | |
240 | + buf += l; | |
241 | + addr += l; | |
242 | + } | |
243 | +} | |
244 | + | |
204 | 245 | static void iommu_save(QEMUFile *f, void *opaque) |
205 | 246 | { |
206 | 247 | IOMMUState *s = opaque; | ... | ... |
hw/lsi53c895a.c
... | ... | @@ -19,11 +19,11 @@ |
19 | 19 | #define DPRINTF(fmt, args...) \ |
20 | 20 | do { printf("lsi_scsi: " fmt , ##args); } while (0) |
21 | 21 | #define BADF(fmt, args...) \ |
22 | -do { fprintf(stderr, "lsi_scsi: " fmt , ##args); exit(1);} while (0) | |
22 | +do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args); exit(1);} while (0) | |
23 | 23 | #else |
24 | 24 | #define DPRINTF(fmt, args...) do {} while(0) |
25 | 25 | #define BADF(fmt, args...) \ |
26 | -do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) | |
26 | +do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args);} while (0) | |
27 | 27 | #endif |
28 | 28 | |
29 | 29 | #define LSI_SCNTL0_TRG 0x01 |
... | ... | @@ -152,26 +152,46 @@ do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) |
152 | 152 | /* The HBA is ID 7, so for simplicitly limit to 7 devices. */ |
153 | 153 | #define LSI_MAX_DEVS 7 |
154 | 154 | |
155 | -/* Size of internal DMA buffer for async IO requests. */ | |
156 | -#define LSI_DMA_BLOCK_SIZE 0x10000 | |
155 | +/* Maximum length of MSG IN data. */ | |
156 | +#define LSI_MAX_MSGIN_LEN 8 | |
157 | + | |
158 | +/* Flag set if this is a tagged command. */ | |
159 | +#define LSI_TAG_VALID (1 << 16) | |
160 | + | |
161 | +typedef struct { | |
162 | + uint32_t tag; | |
163 | + uint32_t pending; | |
164 | + int out; | |
165 | +} lsi_queue; | |
157 | 166 | |
158 | 167 | typedef struct { |
159 | 168 | PCIDevice pci_dev; |
160 | 169 | int mmio_io_addr; |
161 | 170 | int ram_io_addr; |
162 | 171 | uint32_t script_ram_base; |
163 | - uint32_t data_len; | |
164 | 172 | |
165 | 173 | int carry; /* ??? Should this be an a visible register somewhere? */ |
166 | 174 | int sense; |
167 | - uint8_t msg; | |
175 | + /* Action to take at the end of a MSG IN phase. | |
176 | + 0 = COMMAND, 1 = disconect, 2 = DATA OUT, 3 = DATA IN. */ | |
177 | + int msg_action; | |
178 | + int msg_len; | |
179 | + uint8_t msg[LSI_MAX_MSGIN_LEN]; | |
168 | 180 | /* 0 if SCRIPTS are running or stopped. |
169 | 181 | * 1 if a Wait Reselect instruction has been issued. |
170 | - * 2 if a DMA operation is in progress. */ | |
182 | + * 2 if processing DMA from lsi_execute_script. | |
183 | + * 3 if a DMA operation is in progress. */ | |
171 | 184 | int waiting; |
172 | 185 | SCSIDevice *scsi_dev[LSI_MAX_DEVS]; |
173 | 186 | SCSIDevice *current_dev; |
174 | 187 | int current_lun; |
188 | + /* The tag is a combination of the device ID and the SCSI tag. */ | |
189 | + uint32_t current_tag; | |
190 | + uint32_t current_dma_len; | |
191 | + uint8_t *dma_buf; | |
192 | + lsi_queue *queue; | |
193 | + int queue_len; | |
194 | + int active_commands; | |
175 | 195 | |
176 | 196 | uint32_t dsa; |
177 | 197 | uint32_t temp; |
... | ... | @@ -208,10 +228,12 @@ typedef struct { |
208 | 228 | uint8_t sxfer; |
209 | 229 | uint8_t socl; |
210 | 230 | uint8_t sdid; |
231 | + uint8_t ssid; | |
211 | 232 | uint8_t sfbr; |
212 | 233 | uint8_t stest1; |
213 | 234 | uint8_t stest2; |
214 | 235 | uint8_t stest3; |
236 | + uint8_t sidl; | |
215 | 237 | uint8_t stime0; |
216 | 238 | uint8_t respid0; |
217 | 239 | uint8_t respid1; |
... | ... | @@ -231,7 +253,6 @@ typedef struct { |
231 | 253 | uint32_t csbc; |
232 | 254 | uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ |
233 | 255 | |
234 | - uint8_t dma_buf[LSI_DMA_BLOCK_SIZE]; | |
235 | 256 | /* Script ram is stored as 32-bit words in host byteorder. */ |
236 | 257 | uint32_t script_ram[2048]; |
237 | 258 | } LSIState; |
... | ... | @@ -280,6 +301,7 @@ static void lsi_soft_reset(LSIState *s) |
280 | 301 | s->stest1 = 0; |
281 | 302 | s->stest2 = 0; |
282 | 303 | s->stest3 = 0; |
304 | + s->sidl = 0; | |
283 | 305 | s->stime0 = 0; |
284 | 306 | s->respid0 = 0x80; |
285 | 307 | s->respid1 = 0; |
... | ... | @@ -409,68 +431,194 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase) |
409 | 431 | lsi_set_phase(s, new_phase); |
410 | 432 | } |
411 | 433 | |
434 | + | |
435 | +/* Resume SCRIPTS execution after a DMA operation. */ | |
436 | +static void lsi_resume_script(LSIState *s) | |
437 | +{ | |
438 | + if (s->waiting != 2) { | |
439 | + s->waiting = 0; | |
440 | + lsi_execute_script(s); | |
441 | + } else { | |
442 | + s->waiting = 0; | |
443 | + } | |
444 | +} | |
445 | + | |
412 | 446 | /* Initiate a SCSI layer data transfer. */ |
413 | 447 | static void lsi_do_dma(LSIState *s, int out) |
414 | 448 | { |
415 | 449 | uint32_t count; |
450 | + uint32_t addr; | |
416 | 451 | |
417 | - count = s->dbc; | |
418 | - if (count > LSI_DMA_BLOCK_SIZE) | |
419 | - count = LSI_DMA_BLOCK_SIZE; | |
420 | - DPRINTF("DMA addr=0x%08x len=%d avail=%d\n", | |
421 | - addr, count, s->data_len); | |
422 | - /* ??? Too long transfers are truncated. Don't know if this is the | |
423 | - correct behavior. */ | |
424 | - if (count > s->data_len) { | |
425 | - /* If the DMA length is greater than the device data length then | |
426 | - a phase mismatch will occur. */ | |
427 | - count = s->data_len; | |
428 | - s->dbc = count; | |
429 | - lsi_bad_phase(s, out, PHASE_ST); | |
452 | + if (!s->current_dma_len) { | |
453 | + /* Wait until data is available. */ | |
454 | + DPRINTF("DMA no data available\n"); | |
455 | + return; | |
430 | 456 | } |
431 | 457 | |
458 | + count = s->dbc; | |
459 | + if (count > s->current_dma_len) | |
460 | + count = s->current_dma_len; | |
461 | + DPRINTF("DMA addr=0x%08x len=%d\n", s->dnad, count); | |
462 | + | |
463 | + addr = s->dnad; | |
432 | 464 | s->csbc += count; |
465 | + s->dnad += count; | |
466 | + s->dbc -= count; | |
467 | + | |
468 | + if (s->dma_buf == NULL) { | |
469 | + s->dma_buf = scsi_get_buf(s->current_dev, s->current_tag); | |
470 | + } | |
433 | 471 | |
434 | 472 | /* ??? Set SFBR to first data byte. */ |
435 | - if ((s->sstat1 & PHASE_MASK) == PHASE_DO) { | |
436 | - cpu_physical_memory_read(s->dnad, s->dma_buf, count); | |
437 | - scsi_write_data(s->current_dev, s->dma_buf, count); | |
473 | + if (out) { | |
474 | + cpu_physical_memory_read(addr, s->dma_buf, count); | |
475 | + } else { | |
476 | + cpu_physical_memory_write(addr, s->dma_buf, count); | |
477 | + } | |
478 | + s->current_dma_len -= count; | |
479 | + if (s->current_dma_len == 0) { | |
480 | + s->dma_buf = NULL; | |
481 | + if (out) { | |
482 | + /* Write the data. */ | |
483 | + scsi_write_data(s->current_dev, s->current_tag); | |
484 | + } else { | |
485 | + /* Request any remaining data. */ | |
486 | + scsi_read_data(s->current_dev, s->current_tag); | |
487 | + } | |
488 | + } else { | |
489 | + s->dma_buf += count; | |
490 | + lsi_resume_script(s); | |
491 | + } | |
492 | +} | |
493 | + | |
494 | + | |
495 | +/* Add a command to the queue. */ | |
496 | +static void lsi_queue_command(LSIState *s) | |
497 | +{ | |
498 | + lsi_queue *p; | |
499 | + | |
500 | + DPRINTF("Queueing tag=0x%x\n", s->current_tag); | |
501 | + if (s->queue_len == s->active_commands) { | |
502 | + s->queue_len++; | |
503 | + s->queue = realloc(s->queue, s->queue_len * sizeof(lsi_queue)); | |
504 | + } | |
505 | + p = &s->queue[s->active_commands++]; | |
506 | + p->tag = s->current_tag; | |
507 | + p->pending = 0; | |
508 | + p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO; | |
509 | +} | |
510 | + | |
511 | +/* Queue a byte for a MSG IN phase. */ | |
512 | +static void lsi_add_msg_byte(LSIState *s, uint8_t data) | |
513 | +{ | |
514 | + if (s->msg_len >= LSI_MAX_MSGIN_LEN) { | |
515 | + BADF("MSG IN data too long\n"); | |
438 | 516 | } else { |
439 | - scsi_read_data(s->current_dev, s->dma_buf, count); | |
517 | + DPRINTF("MSG IN 0x%02x\n", data); | |
518 | + s->msg[s->msg_len++] = data; | |
440 | 519 | } |
441 | - /* If the DMA did not complete then suspend execution. */ | |
442 | - if (s->dbc) | |
443 | - s->waiting = 2; | |
520 | +} | |
521 | + | |
522 | +/* Perform reselection to continue a command. */ | |
523 | +static void lsi_reselect(LSIState *s, uint32_t tag) | |
524 | +{ | |
525 | + lsi_queue *p; | |
526 | + int n; | |
527 | + int id; | |
528 | + | |
529 | + p = NULL; | |
530 | + for (n = 0; n < s->active_commands; n++) { | |
531 | + p = &s->queue[n]; | |
532 | + if (p->tag == tag) | |
533 | + break; | |
534 | + } | |
535 | + if (n == s->active_commands) { | |
536 | + BADF("Reselected non-existant command tag=0x%x\n", tag); | |
537 | + return; | |
538 | + } | |
539 | + id = (tag >> 8) & 0xf; | |
540 | + s->ssid = id | 0x80; | |
541 | + DPRINTF("Reselected target %d\n", id); | |
542 | + s->current_dev = s->scsi_dev[id]; | |
543 | + s->current_tag = tag; | |
544 | + s->scntl1 |= LSI_SCNTL1_CON; | |
545 | + lsi_set_phase(s, PHASE_MI); | |
546 | + s->msg_action = p->out ? 2 : 3; | |
547 | + s->current_dma_len = p->pending; | |
548 | + s->dma_buf = NULL; | |
549 | + lsi_add_msg_byte(s, 0x80); | |
550 | + if (s->current_tag & LSI_TAG_VALID) { | |
551 | + lsi_add_msg_byte(s, 0x20); | |
552 | + lsi_add_msg_byte(s, tag & 0xff); | |
553 | + } | |
554 | + | |
555 | + s->active_commands--; | |
556 | + if (n != s->active_commands) { | |
557 | + s->queue[n] = s->queue[s->active_commands]; | |
558 | + } | |
559 | +} | |
560 | + | |
561 | +/* Record that data is available for a queued command. Returns zero if | |
562 | + the device was reselected, nonzero if the IO is deferred. */ | |
563 | +static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) | |
564 | +{ | |
565 | + lsi_queue *p; | |
566 | + int i; | |
567 | + for (i = 0; i < s->active_commands; i++) { | |
568 | + p = &s->queue[i]; | |
569 | + if (p->tag == tag) { | |
570 | + if (p->pending) { | |
571 | + BADF("Multiple IO pending for tag %d\n", tag); | |
572 | + } | |
573 | + p->pending = arg; | |
574 | + if (s->waiting == 1) { | |
575 | + /* Reselect device. */ | |
576 | + lsi_reselect(s, tag); | |
577 | + return 0; | |
578 | + } else { | |
579 | + DPRINTF("Queueing IO tag=0x%x\n", tag); | |
580 | + p->pending = arg; | |
581 | + return 1; | |
582 | + } | |
583 | + } | |
584 | + } | |
585 | + BADF("IO with unknown tag %d\n", tag); | |
586 | + return 1; | |
444 | 587 | } |
445 | 588 | |
446 | 589 | /* Callback to indicate that the SCSI layer has completed a transfer. */ |
447 | -static void lsi_command_complete(void *opaque, uint32_t reason, int sense) | |
590 | +static void lsi_command_complete(void *opaque, int reason, uint32_t tag, | |
591 | + uint32_t arg) | |
448 | 592 | { |
449 | 593 | LSIState *s = (LSIState *)opaque; |
450 | - uint32_t count; | |
451 | 594 | int out; |
452 | 595 | |
453 | - out = ((s->sstat1 & PHASE_MASK) == PHASE_DO); | |
454 | - count = s->dbc; | |
455 | - if (count > LSI_DMA_BLOCK_SIZE) | |
456 | - count = LSI_DMA_BLOCK_SIZE; | |
457 | - if (!out) | |
458 | - cpu_physical_memory_write(s->dnad, s->dma_buf, count); | |
459 | - s->dnad += count; | |
460 | - s->dbc -= count; | |
461 | - | |
596 | + out = (s->sstat1 & PHASE_MASK) == PHASE_DO; | |
462 | 597 | if (reason == SCSI_REASON_DONE) { |
463 | - DPRINTF("Command complete sense=%d\n", sense); | |
464 | - s->sense = sense; | |
465 | - lsi_set_phase(s, PHASE_ST); | |
598 | + DPRINTF("Command complete sense=%d\n", (int)arg); | |
599 | + s->sense = arg; | |
600 | + if (s->waiting && s->dbc != 0) { | |
601 | + /* Raise phase mismatch for short transfers. */ | |
602 | + lsi_bad_phase(s, out, PHASE_ST); | |
603 | + } else { | |
604 | + lsi_set_phase(s, PHASE_ST); | |
605 | + } | |
606 | + lsi_resume_script(s); | |
607 | + return; | |
466 | 608 | } |
467 | 609 | |
468 | - if (s->dbc) { | |
610 | + if (s->waiting == 1 || tag != s->current_tag) { | |
611 | + if (lsi_queue_tag(s, tag, arg)) | |
612 | + return; | |
613 | + } | |
614 | + DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg); | |
615 | + s->current_dma_len = arg; | |
616 | + if (!s->waiting) | |
617 | + return; | |
618 | + if (s->waiting == 1 || s->dbc == 0) { | |
619 | + lsi_resume_script(s); | |
620 | + } else { | |
469 | 621 | lsi_do_dma(s, out); |
470 | - } else if (s->waiting == 2) { | |
471 | - /* Restart SCRIPTS execution. */ | |
472 | - s->waiting = 0; | |
473 | - lsi_execute_script(s); | |
474 | 622 | } |
475 | 623 | } |
476 | 624 | |
... | ... | @@ -484,27 +632,37 @@ static void lsi_do_command(LSIState *s) |
484 | 632 | s->dbc = 16; |
485 | 633 | cpu_physical_memory_read(s->dnad, buf, s->dbc); |
486 | 634 | s->sfbr = buf[0]; |
487 | - n = scsi_send_command(s->current_dev, 0, buf, s->current_lun); | |
635 | + n = scsi_send_command(s->current_dev, s->current_tag, buf, s->current_lun); | |
488 | 636 | if (n > 0) { |
489 | - s->data_len = n; | |
490 | 637 | lsi_set_phase(s, PHASE_DI); |
638 | + scsi_read_data(s->current_dev, s->current_tag); | |
491 | 639 | } else if (n < 0) { |
492 | - s->data_len = -n; | |
493 | 640 | lsi_set_phase(s, PHASE_DO); |
641 | + scsi_write_data(s->current_dev, s->current_tag); | |
642 | + } | |
643 | + if (n && s->current_dma_len == 0) { | |
644 | + /* Command did not complete immediately so disconnect. */ | |
645 | + lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */ | |
646 | + lsi_add_msg_byte(s, 4); /* DISCONNECT */ | |
647 | + lsi_set_phase(s, PHASE_MI); | |
648 | + s->msg_action = 1; | |
649 | + lsi_queue_command(s); | |
494 | 650 | } |
495 | 651 | } |
496 | 652 | |
497 | 653 | static void lsi_do_status(LSIState *s) |
498 | 654 | { |
655 | + uint8_t sense; | |
499 | 656 | DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); |
500 | 657 | if (s->dbc != 1) |
501 | 658 | BADF("Bad Status move\n"); |
502 | 659 | s->dbc = 1; |
503 | - s->msg = s->sense; | |
504 | - cpu_physical_memory_write(s->dnad, &s->msg, 1); | |
505 | - s->sfbr = s->msg; | |
660 | + sense = s->sense; | |
661 | + s->sfbr = sense; | |
662 | + cpu_physical_memory_write(s->dnad, &sense, 1); | |
506 | 663 | lsi_set_phase(s, PHASE_MI); |
507 | - s->msg = 0; /* COMMAND COMPLETE */ | |
664 | + s->msg_action = 1; | |
665 | + lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */ | |
508 | 666 | } |
509 | 667 | |
510 | 668 | static void lsi_disconnect(LSIState *s) |
... | ... | @@ -515,55 +673,114 @@ static void lsi_disconnect(LSIState *s) |
515 | 673 | |
516 | 674 | static void lsi_do_msgin(LSIState *s) |
517 | 675 | { |
518 | - DPRINTF("Message in len=%d\n", s->dbc); | |
519 | - s->dbc = 1; | |
520 | - s->sfbr = s->msg; | |
521 | - cpu_physical_memory_write(s->dnad, &s->msg, 1); | |
522 | - if (s->msg == 0) { | |
523 | - lsi_disconnect(s); | |
676 | + int len; | |
677 | + DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len); | |
678 | + s->sfbr = s->msg[0]; | |
679 | + len = s->msg_len; | |
680 | + if (len > s->dbc) | |
681 | + len = s->dbc; | |
682 | + cpu_physical_memory_write(s->dnad, s->msg, len); | |
683 | + /* Linux drivers rely on the last byte being in the SIDL. */ | |
684 | + s->sidl = s->msg[len - 1]; | |
685 | + s->msg_len -= len; | |
686 | + if (s->msg_len) { | |
687 | + memmove(s->msg, s->msg + len, s->msg_len); | |
524 | 688 | } else { |
525 | 689 | /* ??? Check if ATN (not yet implemented) is asserted and maybe |
526 | 690 | switch to PHASE_MO. */ |
527 | - lsi_set_phase(s, PHASE_CMD); | |
691 | + switch (s->msg_action) { | |
692 | + case 0: | |
693 | + lsi_set_phase(s, PHASE_CMD); | |
694 | + break; | |
695 | + case 1: | |
696 | + lsi_disconnect(s); | |
697 | + break; | |
698 | + case 2: | |
699 | + lsi_set_phase(s, PHASE_DO); | |
700 | + break; | |
701 | + case 3: | |
702 | + lsi_set_phase(s, PHASE_DI); | |
703 | + break; | |
704 | + default: | |
705 | + abort(); | |
706 | + } | |
528 | 707 | } |
529 | 708 | } |
530 | 709 | |
710 | +/* Read the next byte during a MSGOUT phase. */ | |
711 | +static uint8_t lsi_get_msgbyte(LSIState *s) | |
712 | +{ | |
713 | + uint8_t data; | |
714 | + cpu_physical_memory_read(s->dnad, &data, 1); | |
715 | + s->dnad++; | |
716 | + s->dbc--; | |
717 | + return data; | |
718 | +} | |
719 | + | |
531 | 720 | static void lsi_do_msgout(LSIState *s) |
532 | 721 | { |
533 | 722 | uint8_t msg; |
723 | + int len; | |
534 | 724 | |
535 | 725 | DPRINTF("MSG out len=%d\n", s->dbc); |
536 | - if (s->dbc != 1) { | |
537 | - /* Multibyte messages not implemented. */ | |
538 | - s->msg = 7; /* MESSAGE REJECT */ | |
539 | - //s->dbc = 1; | |
540 | - //lsi_bad_phase(s, 1, PHASE_MI); | |
541 | - lsi_set_phase(s, PHASE_MI); | |
542 | - return; | |
543 | - } | |
544 | - cpu_physical_memory_read(s->dnad, &msg, 1); | |
545 | - s->sfbr = msg; | |
546 | - s->dnad++; | |
547 | - | |
548 | - switch (msg) { | |
549 | - case 0x00: | |
550 | - DPRINTF("Got Disconnect\n"); | |
551 | - lsi_disconnect(s); | |
552 | - return; | |
553 | - case 0x08: | |
554 | - DPRINTF("Got No Operation\n"); | |
555 | - lsi_set_phase(s, PHASE_CMD); | |
556 | - return; | |
557 | - } | |
558 | - if ((msg & 0x80) == 0) { | |
559 | - DPRINTF("Unimplemented message 0x%d\n", msg); | |
560 | - s->msg = 7; /* MESSAGE REJECT */ | |
561 | - lsi_bad_phase(s, 1, PHASE_MI); | |
562 | - return; | |
726 | + while (s->dbc) { | |
727 | + msg = lsi_get_msgbyte(s); | |
728 | + s->sfbr = msg; | |
729 | + | |
730 | + switch (msg) { | |
731 | + case 0x00: | |
732 | + DPRINTF("MSG: Disconnect\n"); | |
733 | + lsi_disconnect(s); | |
734 | + break; | |
735 | + case 0x08: | |
736 | + DPRINTF("MSG: No Operation\n"); | |
737 | + lsi_set_phase(s, PHASE_CMD); | |
738 | + break; | |
739 | + case 0x01: | |
740 | + len = lsi_get_msgbyte(s); | |
741 | + msg = lsi_get_msgbyte(s); | |
742 | + DPRINTF("Extended message 0x%x (len %d)\n", msg, len); | |
743 | + switch (msg) { | |
744 | + case 1: | |
745 | + DPRINTF("SDTR (ignored)\n"); | |
746 | + s->dbc -= 2; | |
747 | + break; | |
748 | + case 3: | |
749 | + DPRINTF("WDTR (ignored)\n"); | |
750 | + s->dbc -= 1; | |
751 | + break; | |
752 | + default: | |
753 | + goto bad; | |
754 | + } | |
755 | + break; | |
756 | + case 0x20: /* SIMPLE queue */ | |
757 | + s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; | |
758 | + DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff); | |
759 | + break; | |
760 | + case 0x21: /* HEAD of queue */ | |
761 | + BADF("HEAD queue not implemented\n"); | |
762 | + s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; | |
763 | + break; | |
764 | + case 0x22: /* ORDERED queue */ | |
765 | + BADF("ORDERED queue not implemented\n"); | |
766 | + s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; | |
767 | + break; | |
768 | + default: | |
769 | + if ((msg & 0x80) == 0) { | |
770 | + goto bad; | |
771 | + } | |
772 | + s->current_lun = msg & 7; | |
773 | + DPRINTF("Select LUN %d\n", s->current_lun); | |
774 | + lsi_set_phase(s, PHASE_CMD); | |
775 | + break; | |
776 | + } | |
563 | 777 | } |
564 | - s->current_lun = msg & 7; | |
565 | - DPRINTF("Select LUN %d\n", s->current_lun); | |
566 | - lsi_set_phase(s, PHASE_CMD); | |
778 | + return; | |
779 | +bad: | |
780 | + BADF("Unimplemented message 0x%02x\n", msg); | |
781 | + lsi_set_phase(s, PHASE_MI); | |
782 | + lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */ | |
783 | + s->msg_action = 0; | |
567 | 784 | } |
568 | 785 | |
569 | 786 | /* Sign extend a 24-bit value. */ |
... | ... | @@ -588,6 +805,23 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) |
588 | 805 | } |
589 | 806 | } |
590 | 807 | |
808 | +static void lsi_wait_reselect(LSIState *s) | |
809 | +{ | |
810 | + int i; | |
811 | + DPRINTF("Wait Reselect\n"); | |
812 | + if (s->current_dma_len) | |
813 | + BADF("Reselect with pending DMA\n"); | |
814 | + for (i = 0; i < s->active_commands; i++) { | |
815 | + if (s->queue[i].pending) { | |
816 | + lsi_reselect(s, s->queue[i].tag); | |
817 | + break; | |
818 | + } | |
819 | + } | |
820 | + if (s->current_dma_len == 0) { | |
821 | + s->waiting = 1; | |
822 | + } | |
823 | +} | |
824 | + | |
591 | 825 | static void lsi_execute_script(LSIState *s) |
592 | 826 | { |
593 | 827 | uint32_t insn; |
... | ... | @@ -632,10 +866,16 @@ again: |
632 | 866 | s->dnad = addr; |
633 | 867 | switch (s->sstat1 & 0x7) { |
634 | 868 | case PHASE_DO: |
869 | + s->waiting = 2; | |
635 | 870 | lsi_do_dma(s, 1); |
871 | + if (s->waiting) | |
872 | + s->waiting = 3; | |
636 | 873 | break; |
637 | 874 | case PHASE_DI: |
875 | + s->waiting = 2; | |
638 | 876 | lsi_do_dma(s, 0); |
877 | + if (s->waiting) | |
878 | + s->waiting = 3; | |
639 | 879 | break; |
640 | 880 | case PHASE_CMD: |
641 | 881 | lsi_do_command(s); |
... | ... | @@ -679,9 +919,13 @@ again: |
679 | 919 | s->dnad = addr; |
680 | 920 | switch (opcode) { |
681 | 921 | case 0: /* Select */ |
922 | + s->sdid = id; | |
923 | + if (s->current_dma_len && (s->ssid & 0xf) == id) { | |
924 | + DPRINTF("Already reselected by target %d\n", id); | |
925 | + break; | |
926 | + } | |
682 | 927 | s->sstat0 |= LSI_SSTAT0_WOA; |
683 | 928 | s->scntl1 &= ~LSI_SCNTL1_IARB; |
684 | - s->sdid = id; | |
685 | 929 | if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) { |
686 | 930 | DPRINTF("Selected absent target %d\n", id); |
687 | 931 | lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO); |
... | ... | @@ -694,6 +938,7 @@ again: |
694 | 938 | it only applies in low-level mode (unimplemented). |
695 | 939 | lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ |
696 | 940 | s->current_dev = s->scsi_dev[id]; |
941 | + s->current_tag = id << 8; | |
697 | 942 | s->scntl1 |= LSI_SCNTL1_CON; |
698 | 943 | if (insn & (1 << 3)) { |
699 | 944 | s->socl |= LSI_SOCL_ATN; |
... | ... | @@ -705,8 +950,7 @@ again: |
705 | 950 | s->scntl1 &= ~LSI_SCNTL1_CON; |
706 | 951 | break; |
707 | 952 | case 2: /* Wait Reselect */ |
708 | - DPRINTF("Wait Reselect\n"); | |
709 | - s->waiting = 1; | |
953 | + lsi_wait_reselect(s); | |
710 | 954 | break; |
711 | 955 | case 3: /* Set */ |
712 | 956 | DPRINTF("Set%s%s%s%s\n", |
... | ... | @@ -755,9 +999,9 @@ again: |
755 | 999 | data8 = (insn >> 8) & 0xff; |
756 | 1000 | opcode = (insn >> 27) & 7; |
757 | 1001 | operator = (insn >> 24) & 7; |
758 | - DPRINTF("%s reg 0x%x %s data8 %d%s\n", | |
1002 | + DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n", | |
759 | 1003 | opcode_names[opcode - 5], reg, |
760 | - operator_names[operator], data8, | |
1004 | + operator_names[operator], data8, s->sfbr, | |
761 | 1005 | (insn & (1 << 23)) ? " SFBR" : ""); |
762 | 1006 | op0 = op1 = 0; |
763 | 1007 | switch (opcode) { |
... | ... | @@ -923,8 +1167,9 @@ again: |
923 | 1167 | n = (insn & 7); |
924 | 1168 | reg = (insn >> 16) & 0xff; |
925 | 1169 | if (insn & (1 << 24)) { |
926 | - DPRINTF("Load reg 0x%x size %d addr 0x%08x\n", reg, n, addr); | |
927 | 1170 | cpu_physical_memory_read(addr, data, n); |
1171 | + DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n, | |
1172 | + addr, *(int *)data); | |
928 | 1173 | for (i = 0; i < n; i++) { |
929 | 1174 | lsi_reg_writeb(s, reg + i, data[i]); |
930 | 1175 | } |
... | ... | @@ -977,6 +1222,8 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) |
977 | 1222 | return s->sdid; |
978 | 1223 | case 0x07: /* GPREG0 */ |
979 | 1224 | return 0x7f; |
1225 | + case 0xa: /* SSID */ | |
1226 | + return s->ssid; | |
980 | 1227 | case 0xb: /* SBCL */ |
981 | 1228 | /* ??? This is not correct. However it's (hopefully) only |
982 | 1229 | used for diagnostics, so should be ok. */ |
... | ... | @@ -1065,13 +1312,22 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) |
1065 | 1312 | return s->stest2; |
1066 | 1313 | case 0x4f: /* STEST3 */ |
1067 | 1314 | return s->stest3; |
1315 | + case 0x50: /* SIDL */ | |
1316 | + /* This is needed by the linux drivers. We currently only update it | |
1317 | + during the MSG IN phase. */ | |
1318 | + return s->sidl; | |
1068 | 1319 | case 0x52: /* STEST4 */ |
1069 | 1320 | return 0xe0; |
1070 | 1321 | case 0x56: /* CCNTL0 */ |
1071 | 1322 | return s->ccntl0; |
1072 | 1323 | case 0x57: /* CCNTL1 */ |
1073 | 1324 | return s->ccntl1; |
1074 | - case 0x58: case 0x59: /* SBDL */ | |
1325 | + case 0x58: /* SBDL */ | |
1326 | + /* Some drivers peek at the data bus during the MSG IN phase. */ | |
1327 | + if ((s->sstat1 & PHASE_MASK) == PHASE_MI) | |
1328 | + return s->msg[0]; | |
1329 | + return 0; | |
1330 | + case 0x59: /* SBDL high */ | |
1075 | 1331 | return 0; |
1076 | 1332 | CASE_GET_REG32(mmrs, 0xa0) |
1077 | 1333 | CASE_GET_REG32(mmws, 0xa4) |
... | ... | @@ -1143,8 +1399,18 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) |
1143 | 1399 | case 0x05: /* SXFER */ |
1144 | 1400 | s->sxfer = val; |
1145 | 1401 | break; |
1402 | + case 0x06: /* SDID */ | |
1403 | + if ((val & 0xf) != (s->ssid & 0xf)) | |
1404 | + BADF("Destination ID does not match SSID\n"); | |
1405 | + s->sdid = val & 0xf; | |
1406 | + break; | |
1146 | 1407 | case 0x07: /* GPREG0 */ |
1147 | 1408 | break; |
1409 | + case 0x08: /* SFBR */ | |
1410 | + /* The CPU is not allowed to write to this register. However the | |
1411 | + SCRIPTS register move instructions are. */ | |
1412 | + s->sfbr = val; | |
1413 | + break; | |
1148 | 1414 | case 0x0c: case 0x0d: case 0x0e: case 0x0f: |
1149 | 1415 | /* Linux writes to these readonly registers on startup. */ |
1150 | 1416 | return; |
... | ... | @@ -1555,7 +1821,7 @@ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id) |
1555 | 1821 | scsi_disk_destroy(s->scsi_dev[id]); |
1556 | 1822 | } |
1557 | 1823 | DPRINTF("Attaching block device %d\n", id); |
1558 | - s->scsi_dev[id] = scsi_disk_init(bd, lsi_command_complete, s); | |
1824 | + s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s); | |
1559 | 1825 | } |
1560 | 1826 | |
1561 | 1827 | void *lsi_scsi_init(PCIBus *bus, int devfn) |
... | ... | @@ -1587,6 +1853,9 @@ void *lsi_scsi_init(PCIBus *bus, int devfn) |
1587 | 1853 | PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc); |
1588 | 1854 | pci_register_io_region((struct PCIDevice *)s, 2, 0x2000, |
1589 | 1855 | PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc); |
1856 | + s->queue = qemu_malloc(sizeof(lsi_queue)); | |
1857 | + s->queue_len = 1; | |
1858 | + s->active_commands = 0; | |
1590 | 1859 | |
1591 | 1860 | lsi_soft_reset(s); |
1592 | 1861 | ... | ... |
hw/scsi-disk.c
... | ... | @@ -7,6 +7,10 @@ |
7 | 7 | * Written by Paul Brook |
8 | 8 | * |
9 | 9 | * This code is licenced under the LGPL. |
10 | + * | |
11 | + * Note that this file only handles the SCSI architecture model and device | |
12 | + * commands. Emultion of interface/link layer protocols is handled by | |
13 | + * the host adapter emulation. | |
10 | 14 | */ |
11 | 15 | |
12 | 16 | //#define DEBUG_SCSI |
... | ... | @@ -28,231 +32,241 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) |
28 | 32 | #define SENSE_HARDWARE_ERROR 4 |
29 | 33 | #define SENSE_ILLEGAL_REQUEST 5 |
30 | 34 | |
31 | -struct SCSIDevice | |
32 | -{ | |
33 | - int command; | |
35 | +#define SCSI_DMA_BUF_SIZE 65536 | |
36 | + | |
37 | +typedef struct SCSIRequest { | |
38 | + SCSIDevice *dev; | |
34 | 39 | uint32_t tag; |
35 | - BlockDriverState *bdrv; | |
36 | - /* The qemu block layer uses a fixed 512 byte sector size. | |
37 | - This is the number of 512 byte blocks in a single scsi sector. */ | |
38 | - int cluster_size; | |
39 | - /* When transfering data buf_pos and buf_len contain a partially | |
40 | - transferred block of data (or response to a command), and | |
41 | - sector/sector_count identify any remaining sectors. | |
42 | - Both sector and sector_count are in terms of qemu 512 byte blocks. */ | |
43 | 40 | /* ??? We should probably keep track of whether the data trasfer is |
44 | 41 | a read or a write. Currently we rely on the host getting it right. */ |
42 | + /* Both sector and sector_count are in terms of qemu 512 byte blocks. */ | |
45 | 43 | int sector; |
46 | 44 | int sector_count; |
47 | - int buf_pos; | |
45 | + /* The amounnt of data in the buffer. */ | |
48 | 46 | int buf_len; |
49 | - int sense; | |
47 | + uint8_t dma_buf[SCSI_DMA_BUF_SIZE]; | |
50 | 48 | BlockDriverAIOCB *aiocb; |
51 | - /* Data still to be transfered after this request completes. */ | |
52 | - uint8_t *aiodata; | |
53 | - uint32_t aiolen; | |
54 | - char buf[512]; | |
49 | + struct SCSIRequest *next; | |
50 | +} SCSIRequest; | |
51 | + | |
52 | +struct SCSIDevice | |
53 | +{ | |
54 | + BlockDriverState *bdrv; | |
55 | + SCSIRequest *requests; | |
56 | + /* The qemu block layer uses a fixed 512 byte sector size. | |
57 | + This is the number of 512 byte blocks in a single scsi sector. */ | |
58 | + int cluster_size; | |
59 | + int sense; | |
60 | + int tcq; | |
55 | 61 | /* Completion functions may be called from either scsi_{read,write}_data |
56 | 62 | or from the AIO completion routines. */ |
57 | 63 | scsi_completionfn completion; |
58 | 64 | void *opaque; |
59 | 65 | }; |
60 | 66 | |
61 | -static void scsi_command_complete(SCSIDevice *s, int sense) | |
67 | +/* Global pool of SCSIRequest structures. */ | |
68 | +static SCSIRequest *free_requests = NULL; | |
69 | + | |
70 | +static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag) | |
62 | 71 | { |
63 | - s->sense = sense; | |
64 | - s->completion(s->opaque, SCSI_REASON_DONE, sense); | |
72 | + SCSIRequest *r; | |
73 | + | |
74 | + if (free_requests) { | |
75 | + r = free_requests; | |
76 | + free_requests = r->next; | |
77 | + } else { | |
78 | + r = qemu_malloc(sizeof(SCSIRequest)); | |
79 | + } | |
80 | + r->dev = s; | |
81 | + r->tag = tag; | |
82 | + r->sector_count = 0; | |
83 | + r->buf_len = 0; | |
84 | + r->aiocb = NULL; | |
85 | + | |
86 | + r->next = s->requests; | |
87 | + s->requests = r; | |
88 | + return r; | |
65 | 89 | } |
66 | 90 | |
67 | -static void scsi_transfer_complete(SCSIDevice *s) | |
91 | +static void scsi_remove_request(SCSIRequest *r) | |
68 | 92 | { |
69 | - s->completion(s->opaque, SCSI_REASON_DATA, 0); | |
70 | - s->aiocb = NULL; | |
93 | + SCSIRequest *last; | |
94 | + SCSIDevice *s = r->dev; | |
95 | + | |
96 | + if (s->requests == r) { | |
97 | + s->requests = r->next; | |
98 | + } else { | |
99 | + last = s->requests; | |
100 | + while (last && last->next != r) | |
101 | + last = last->next; | |
102 | + if (last) { | |
103 | + last->next = r->next; | |
104 | + } else { | |
105 | + BADF("Orphaned request\n"); | |
106 | + } | |
107 | + } | |
108 | + r->next = free_requests; | |
109 | + free_requests = r; | |
71 | 110 | } |
72 | 111 | |
73 | -static void scsi_read_complete(void * opaque, int ret) | |
112 | +static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag) | |
74 | 113 | { |
75 | - SCSIDevice *s = (SCSIDevice *)opaque; | |
114 | + SCSIRequest *r; | |
76 | 115 | |
77 | - if (ret) { | |
78 | - DPRINTF("IO error\n"); | |
79 | - scsi_command_complete(s, SENSE_HARDWARE_ERROR); | |
80 | - } | |
116 | + r = s->requests; | |
117 | + while (r && r->tag != tag) | |
118 | + r = r->next; | |
81 | 119 | |
82 | - if (s->aiolen) { | |
83 | - /* Read the remaining data. Full and partial sectors are transferred | |
84 | - separately. */ | |
85 | - scsi_read_data(s, s->aiodata, s->aiolen); | |
86 | - } else { | |
87 | - if (s->buf_len == 0 && s->sector_count == 0) | |
88 | - scsi_command_complete(s, SENSE_NO_SENSE); | |
89 | - else | |
90 | - scsi_transfer_complete(s); | |
91 | - } | |
120 | + return r; | |
121 | +} | |
122 | + | |
123 | +/* Helper function for command completion. */ | |
124 | +static void scsi_command_complete(SCSIRequest *r, int sense) | |
125 | +{ | |
126 | + SCSIDevice *s = r->dev; | |
127 | + uint32_t tag; | |
128 | + DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense); | |
129 | + s->sense = sense; | |
130 | + tag = r->tag; | |
131 | + scsi_remove_request(r); | |
132 | + s->completion(s->opaque, SCSI_REASON_DONE, tag, sense); | |
92 | 133 | } |
93 | 134 | |
94 | 135 | /* Cancel a pending data transfer. */ |
95 | -void scsi_cancel_io(SCSIDevice *s) | |
136 | +void scsi_cancel_io(SCSIDevice *s, uint32_t tag) | |
96 | 137 | { |
97 | - if (!s->aiocb) { | |
98 | - BADF("Cancel with no pending IO\n"); | |
138 | + SCSIRequest *r; | |
139 | + DPRINTF("Cancel tag=0x%x\n", tag); | |
140 | + r = scsi_find_request(s, tag); | |
141 | + if (r) { | |
142 | + if (r->aiocb) | |
143 | + bdrv_aio_cancel(r->aiocb); | |
144 | + r->aiocb = NULL; | |
145 | + scsi_remove_request(r); | |
146 | + } | |
147 | +} | |
148 | + | |
149 | +static void scsi_read_complete(void * opaque, int ret) | |
150 | +{ | |
151 | + SCSIRequest *r = (SCSIRequest *)opaque; | |
152 | + SCSIDevice *s = r->dev; | |
153 | + | |
154 | + if (ret) { | |
155 | + DPRINTF("IO error\n"); | |
156 | + scsi_command_complete(r, SENSE_HARDWARE_ERROR); | |
99 | 157 | return; |
100 | 158 | } |
101 | - bdrv_aio_cancel(s->aiocb); | |
102 | - s->aiocb = NULL; | |
159 | + DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->buf_len); | |
160 | + | |
161 | + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len); | |
103 | 162 | } |
104 | 163 | |
105 | -/* Read data from a scsi device. Returns nonzero on failure. | |
106 | - The transfer may complete asynchronously. */ | |
107 | -int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) | |
164 | +/* Read more data from scsi device into buffer. */ | |
165 | +void scsi_read_data(SCSIDevice *s, uint32_t tag) | |
108 | 166 | { |
167 | + SCSIRequest *r; | |
109 | 168 | uint32_t n; |
110 | 169 | |
111 | - DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count); | |
112 | - if (s->buf_len == 0 && s->sector_count == 0) | |
113 | - return 1; | |
114 | - | |
115 | - if (s->buf_len) { | |
116 | - n = s->buf_len; | |
117 | - if (n > len) | |
118 | - n = len; | |
119 | - memcpy(data, s->buf + s->buf_pos, n); | |
120 | - s->buf_pos += n; | |
121 | - s->buf_len -= n; | |
122 | - data += n; | |
123 | - len -= n; | |
124 | - if (s->buf_len == 0) | |
125 | - s->buf_pos = 0; | |
170 | + r = scsi_find_request(s, tag); | |
171 | + if (!r) { | |
172 | + BADF("Bad read tag 0x%x\n", tag); | |
173 | + /* ??? This is the wrong error. */ | |
174 | + scsi_command_complete(r, SENSE_HARDWARE_ERROR); | |
175 | + return; | |
126 | 176 | } |
127 | - | |
128 | - n = len / 512; | |
129 | - if (n > s->sector_count) | |
130 | - n = s->sector_count; | |
131 | - | |
132 | - if (n != 0) { | |
133 | - s->aiolen = len - n * 512; | |
134 | - s->aiodata = data + n * 512; | |
135 | - s->aiocb = bdrv_aio_read(s->bdrv, s->sector, data, n, | |
136 | - scsi_read_complete, s); | |
137 | - if (s->aiocb == NULL) | |
138 | - scsi_command_complete(s, SENSE_HARDWARE_ERROR); | |
139 | - s->sector += n; | |
140 | - s->sector_count -= n; | |
141 | - return 0; | |
177 | + if (r->sector_count == (uint32_t)-1) { | |
178 | + DPRINTF("Read buf_len=%d\n", r->buf_len); | |
179 | + r->sector_count = 0; | |
180 | + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len); | |
181 | + return; | |
142 | 182 | } |
143 | - | |
144 | - if (len && s->sector_count) { | |
145 | - /* TODO: Make this use AIO. */ | |
146 | - bdrv_read(s->bdrv, s->sector, s->buf, 1); | |
147 | - s->sector++; | |
148 | - s->sector_count--; | |
149 | - s->buf_pos = 0; | |
150 | - s->buf_len = 512; | |
151 | - /* Recurse to complete the partial read. */ | |
152 | - return scsi_read_data(s, data, len); | |
183 | + DPRINTF("Read sector_count=%d\n", r->sector_count); | |
184 | + if (r->sector_count == 0) { | |
185 | + scsi_command_complete(r, SENSE_NO_SENSE); | |
186 | + return; | |
153 | 187 | } |
154 | 188 | |
155 | - if (len != 0) | |
156 | - return 1; | |
157 | - | |
158 | - if (s->buf_len == 0 && s->sector_count == 0) | |
159 | - scsi_command_complete(s, SENSE_NO_SENSE); | |
160 | - else | |
161 | - scsi_transfer_complete(s); | |
162 | - | |
163 | - return 0; | |
189 | + n = r->sector_count; | |
190 | + if (n > SCSI_DMA_BUF_SIZE / 512) | |
191 | + n = SCSI_DMA_BUF_SIZE / 512; | |
192 | + | |
193 | + r->buf_len = n * 512; | |
194 | + r->aiocb = bdrv_aio_read(s->bdrv, r->sector, r->dma_buf, n, | |
195 | + scsi_read_complete, r); | |
196 | + if (r->aiocb == NULL) | |
197 | + scsi_command_complete(r, SENSE_HARDWARE_ERROR); | |
198 | + r->sector += n; | |
199 | + r->sector_count -= n; | |
164 | 200 | } |
165 | 201 | |
166 | 202 | static void scsi_write_complete(void * opaque, int ret) |
167 | 203 | { |
168 | - SCSIDevice *s = (SCSIDevice *)opaque; | |
204 | + SCSIRequest *r = (SCSIRequest *)opaque; | |
205 | + SCSIDevice *s = r->dev; | |
206 | + uint32_t len; | |
169 | 207 | |
170 | 208 | if (ret) { |
171 | 209 | fprintf(stderr, "scsi-disc: IO write error\n"); |
172 | 210 | exit(1); |
173 | 211 | } |
174 | 212 | |
175 | - if (s->sector_count == 0) | |
176 | - scsi_command_complete(s, SENSE_NO_SENSE); | |
177 | - else | |
178 | - scsi_transfer_complete(s); | |
179 | -} | |
180 | - | |
181 | -static uint32_t scsi_write_partial_sector(SCSIDevice *s, uint8_t *data, | |
182 | - uint32_t len) | |
183 | -{ | |
184 | - int n; | |
185 | - | |
186 | - n = 512 - s->buf_len; | |
187 | - if (n > len) | |
188 | - n = len; | |
189 | - | |
190 | - memcpy(s->buf + s->buf_len, data, n); | |
191 | - data += n; | |
192 | - s->buf_len += n; | |
193 | - len -= n; | |
194 | - if (s->buf_len == 512) { | |
195 | - /* A full sector has been accumulated. Write it to disk. */ | |
196 | - /* TODO: Make this use async IO. */ | |
197 | - bdrv_write(s->bdrv, s->sector, s->buf, 1); | |
198 | - s->buf_len = 0; | |
199 | - s->sector++; | |
200 | - s->sector_count--; | |
213 | + r->aiocb = NULL; | |
214 | + if (r->sector_count == 0) { | |
215 | + scsi_command_complete(r, SENSE_NO_SENSE); | |
216 | + } else { | |
217 | + len = r->sector_count * 512; | |
218 | + if (len > SCSI_DMA_BUF_SIZE) { | |
219 | + len = SCSI_DMA_BUF_SIZE; | |
220 | + } | |
221 | + r->buf_len = len; | |
222 | + DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len); | |
223 | + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len); | |
201 | 224 | } |
202 | - return n; | |
203 | 225 | } |
204 | 226 | |
205 | 227 | /* Write data to a scsi device. Returns nonzero on failure. |
206 | 228 | The transfer may complete asynchronously. */ |
207 | -int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) | |
229 | +int scsi_write_data(SCSIDevice *s, uint32_t tag) | |
208 | 230 | { |
231 | + SCSIRequest *r; | |
209 | 232 | uint32_t n; |
210 | 233 | |
211 | - DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count); | |
212 | - if (s->buf_pos != 0) { | |
213 | - BADF("Bad state on write\n"); | |
234 | + DPRINTF("Write data tag=0x%x\n", tag); | |
235 | + r = scsi_find_request(s, tag); | |
236 | + if (!r) { | |
237 | + BADF("Bad write tag 0x%x\n", tag); | |
238 | + scsi_command_complete(r, SENSE_HARDWARE_ERROR); | |
214 | 239 | return 1; |
215 | 240 | } |
216 | - | |
217 | - if (s->sector_count == 0) | |
218 | - return 1; | |
219 | - | |
220 | - if (s->buf_len != 0 || len < 512) { | |
221 | - n = scsi_write_partial_sector(s, data, len); | |
222 | - len -= n; | |
223 | - data += n; | |
241 | + if (r->aiocb) | |
242 | + BADF("Data transfer already in progress\n"); | |
243 | + n = r->buf_len / 512; | |
244 | + if (n) { | |
245 | + r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n, | |
246 | + scsi_write_complete, r); | |
247 | + if (r->aiocb == NULL) | |
248 | + scsi_command_complete(r, SENSE_HARDWARE_ERROR); | |
249 | + r->sector += n; | |
250 | + r->sector_count -= n; | |
251 | + } else { | |
252 | + /* Invoke completion routine to fetch data from host. */ | |
253 | + scsi_write_complete(r, 0); | |
224 | 254 | } |
225 | 255 | |
226 | - n = len / 512; | |
227 | - if (n > s->sector_count) | |
228 | - return 1; | |
256 | + return 0; | |
257 | +} | |
229 | 258 | |
230 | - if (n != 0) { | |
231 | - s->aiocb = bdrv_aio_write(s->bdrv, s->sector, data, n, | |
232 | - scsi_write_complete, s); | |
233 | - if (s->aiocb == NULL) | |
234 | - scsi_command_complete(s, SENSE_HARDWARE_ERROR); | |
235 | - data += n * 512; | |
236 | - len -= n * 512; | |
237 | - s->sector += n; | |
238 | - s->sector_count -= n; | |
239 | - } | |
259 | +/* Return a pointer to the data buffer. */ | |
260 | +uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag) | |
261 | +{ | |
262 | + SCSIRequest *r; | |
240 | 263 | |
241 | - if (len) { | |
242 | - if (s->sector_count == 0) | |
243 | - return 1; | |
244 | - /* Complete a partial write. */ | |
245 | - scsi_write_partial_sector(s, data, len); | |
264 | + r = scsi_find_request(s, tag); | |
265 | + if (!r) { | |
266 | + BADF("Bad buffer tag 0x%x\n", tag); | |
267 | + return NULL; | |
246 | 268 | } |
247 | - if (n == 0) { | |
248 | - /* Transfer completes immediately. */ | |
249 | - if (s->sector_count == 0) | |
250 | - scsi_command_complete(s, SENSE_NO_SENSE); | |
251 | - else | |
252 | - scsi_transfer_complete(s); | |
253 | - } | |
254 | - | |
255 | - return 0; | |
269 | + return r->dma_buf; | |
256 | 270 | } |
257 | 271 | |
258 | 272 | /* Execute a scsi command. Returns the length of the data expected by the |
... | ... | @@ -267,15 +281,23 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
267 | 281 | uint32_t len; |
268 | 282 | int cmdlen; |
269 | 283 | int is_write; |
270 | - | |
271 | - s->command = buf[0]; | |
272 | - s->tag = tag; | |
273 | - s->sector_count = 0; | |
274 | - s->buf_pos = 0; | |
275 | - s->buf_len = 0; | |
284 | + uint8_t command; | |
285 | + uint8_t *outbuf; | |
286 | + SCSIRequest *r; | |
287 | + | |
288 | + command = buf[0]; | |
289 | + r = scsi_find_request(s, tag); | |
290 | + if (r) { | |
291 | + BADF("Tag 0x%x already in use\n", tag); | |
292 | + scsi_cancel_io(s, tag); | |
293 | + } | |
294 | + /* ??? Tags are not unique for different luns. We only implement a | |
295 | + single lun, so this should not matter. */ | |
296 | + r = scsi_new_request(s, tag); | |
297 | + outbuf = r->dma_buf; | |
276 | 298 | is_write = 0; |
277 | - DPRINTF("Command: 0x%02x", buf[0]); | |
278 | - switch (s->command >> 5) { | |
299 | + DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); | |
300 | + switch (command >> 5) { | |
279 | 301 | case 0: |
280 | 302 | lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16); |
281 | 303 | len = buf[4]; |
... | ... | @@ -298,7 +320,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
298 | 320 | cmdlen = 12; |
299 | 321 | break; |
300 | 322 | default: |
301 | - BADF("Unsupported command length, command %x\n", s->command); | |
323 | + BADF("Unsupported command length, command %x\n", command); | |
302 | 324 | goto fail; |
303 | 325 | } |
304 | 326 | #ifdef DEBUG_SCSI |
... | ... | @@ -315,7 +337,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
315 | 337 | DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); |
316 | 338 | goto fail; |
317 | 339 | } |
318 | - switch (s->command) { | |
340 | + switch (command) { | |
319 | 341 | case 0x0: |
320 | 342 | DPRINTF("Test Unit Ready\n"); |
321 | 343 | break; |
... | ... | @@ -324,33 +346,35 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
324 | 346 | if (len < 4) |
325 | 347 | goto fail; |
326 | 348 | memset(buf, 0, 4); |
327 | - s->buf[0] = 0xf0; | |
328 | - s->buf[1] = 0; | |
329 | - s->buf[2] = s->sense; | |
330 | - s->buf_len = 4; | |
349 | + outbuf[0] = 0xf0; | |
350 | + outbuf[1] = 0; | |
351 | + outbuf[2] = s->sense; | |
352 | + r->buf_len = 4; | |
331 | 353 | break; |
332 | 354 | case 0x12: |
333 | 355 | DPRINTF("Inquiry (len %d)\n", len); |
334 | 356 | if (len < 36) { |
335 | 357 | BADF("Inquiry buffer too small (%d)\n", len); |
336 | 358 | } |
337 | - memset(s->buf, 0, 36); | |
359 | + memset(outbuf, 0, 36); | |
338 | 360 | if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
339 | - s->buf[0] = 5; | |
340 | - s->buf[1] = 0x80; | |
341 | - memcpy(&s->buf[16], "QEMU CD-ROM ", 16); | |
361 | + outbuf[0] = 5; | |
362 | + outbuf[1] = 0x80; | |
363 | + memcpy(&outbuf[16], "QEMU CD-ROM ", 16); | |
342 | 364 | } else { |
343 | - s->buf[0] = 0; | |
344 | - memcpy(&s->buf[16], "QEMU HARDDISK ", 16); | |
365 | + outbuf[0] = 0; | |
366 | + memcpy(&outbuf[16], "QEMU HARDDISK ", 16); | |
345 | 367 | } |
346 | - memcpy(&s->buf[8], "QEMU ", 8); | |
347 | - memcpy(&s->buf[32], QEMU_VERSION, 4); | |
368 | + memcpy(&outbuf[8], "QEMU ", 8); | |
369 | + memcpy(&outbuf[32], QEMU_VERSION, 4); | |
348 | 370 | /* Identify device as SCSI-3 rev 1. |
349 | 371 | Some later commands are also implemented. */ |
350 | - s->buf[2] = 3; | |
351 | - s->buf[3] = 2; /* Format 2 */ | |
352 | - s->buf[4] = 32; | |
353 | - s->buf_len = 36; | |
372 | + outbuf[2] = 3; | |
373 | + outbuf[3] = 2; /* Format 2 */ | |
374 | + outbuf[4] = 32; | |
375 | + /* Sync data transfer and TCQ. */ | |
376 | + outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0); | |
377 | + r->buf_len = 36; | |
354 | 378 | break; |
355 | 379 | case 0x16: |
356 | 380 | DPRINTF("Reserve(6)\n"); |
... | ... | @@ -365,17 +389,17 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
365 | 389 | case 0x1a: |
366 | 390 | case 0x5a: |
367 | 391 | { |
368 | - char *p; | |
392 | + uint8_t *p; | |
369 | 393 | int page; |
370 | 394 | |
371 | 395 | page = buf[2] & 0x3f; |
372 | 396 | DPRINTF("Mode Sense (page %d, len %d)\n", page, len); |
373 | - p = s->buf; | |
397 | + p = outbuf; | |
374 | 398 | memset(p, 0, 4); |
375 | - s->buf[1] = 0; /* Default media type. */ | |
376 | - s->buf[3] = 0; /* Block descriptor length. */ | |
399 | + outbuf[1] = 0; /* Default media type. */ | |
400 | + outbuf[3] = 0; /* Block descriptor length. */ | |
377 | 401 | if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
378 | - s->buf[2] = 0x80; /* Readonly. */ | |
402 | + outbuf[2] = 0x80; /* Readonly. */ | |
379 | 403 | } |
380 | 404 | p += 4; |
381 | 405 | if ((page == 8 || page == 0x3f)) { |
... | ... | @@ -415,10 +439,10 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
415 | 439 | p[21] = (16 * 176) & 0xff; |
416 | 440 | p += 21; |
417 | 441 | } |
418 | - s->buf_len = p - s->buf; | |
419 | - s->buf[0] = s->buf_len - 4; | |
420 | - if (s->buf_len > len) | |
421 | - s->buf_len = len; | |
442 | + r->buf_len = p - outbuf; | |
443 | + outbuf[0] = r->buf_len - 4; | |
444 | + if (r->buf_len > len) | |
445 | + r->buf_len = len; | |
422 | 446 | } |
423 | 447 | break; |
424 | 448 | case 0x1b: |
... | ... | @@ -431,36 +455,36 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
431 | 455 | case 0x25: |
432 | 456 | DPRINTF("Read Capacity\n"); |
433 | 457 | /* The normal LEN field for this command is zero. */ |
434 | - memset(s->buf, 0, 8); | |
458 | + memset(outbuf, 0, 8); | |
435 | 459 | bdrv_get_geometry(s->bdrv, &nb_sectors); |
436 | 460 | /* Returned value is the address of the last sector. */ |
437 | 461 | if (nb_sectors) { |
438 | 462 | nb_sectors--; |
439 | - s->buf[0] = (nb_sectors >> 24) & 0xff; | |
440 | - s->buf[1] = (nb_sectors >> 16) & 0xff; | |
441 | - s->buf[2] = (nb_sectors >> 8) & 0xff; | |
442 | - s->buf[3] = nb_sectors & 0xff; | |
443 | - s->buf[4] = 0; | |
444 | - s->buf[5] = 0; | |
445 | - s->buf[6] = s->cluster_size * 2; | |
446 | - s->buf[7] = 0; | |
447 | - s->buf_len = 8; | |
463 | + outbuf[0] = (nb_sectors >> 24) & 0xff; | |
464 | + outbuf[1] = (nb_sectors >> 16) & 0xff; | |
465 | + outbuf[2] = (nb_sectors >> 8) & 0xff; | |
466 | + outbuf[3] = nb_sectors & 0xff; | |
467 | + outbuf[4] = 0; | |
468 | + outbuf[5] = 0; | |
469 | + outbuf[6] = s->cluster_size * 2; | |
470 | + outbuf[7] = 0; | |
471 | + r->buf_len = 8; | |
448 | 472 | } else { |
449 | - scsi_command_complete(s, SENSE_NOT_READY); | |
473 | + scsi_command_complete(r, SENSE_NOT_READY); | |
450 | 474 | return 0; |
451 | 475 | } |
452 | 476 | break; |
453 | 477 | case 0x08: |
454 | 478 | case 0x28: |
455 | 479 | DPRINTF("Read (sector %d, count %d)\n", lba, len); |
456 | - s->sector = lba * s->cluster_size; | |
457 | - s->sector_count = len * s->cluster_size; | |
480 | + r->sector = lba * s->cluster_size; | |
481 | + r->sector_count = len * s->cluster_size; | |
458 | 482 | break; |
459 | 483 | case 0x0a: |
460 | 484 | case 0x2a: |
461 | 485 | DPRINTF("Write (sector %d, count %d)\n", lba, len); |
462 | - s->sector = lba * s->cluster_size; | |
463 | - s->sector_count = len * s->cluster_size; | |
486 | + r->sector = lba * s->cluster_size; | |
487 | + r->sector_count = len * s->cluster_size; | |
464 | 488 | is_write = 1; |
465 | 489 | break; |
466 | 490 | case 0x35: |
... | ... | @@ -478,18 +502,18 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
478 | 502 | DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); |
479 | 503 | switch(format) { |
480 | 504 | case 0: |
481 | - toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track); | |
505 | + toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track); | |
482 | 506 | break; |
483 | 507 | case 1: |
484 | 508 | /* multi session : only a single session defined */ |
485 | 509 | toclen = 12; |
486 | - memset(s->buf, 0, 12); | |
487 | - s->buf[1] = 0x0a; | |
488 | - s->buf[2] = 0x01; | |
489 | - s->buf[3] = 0x01; | |
510 | + memset(outbuf, 0, 12); | |
511 | + outbuf[1] = 0x0a; | |
512 | + outbuf[2] = 0x01; | |
513 | + outbuf[3] = 0x01; | |
490 | 514 | break; |
491 | 515 | case 2: |
492 | - toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track); | |
516 | + toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track); | |
493 | 517 | break; |
494 | 518 | default: |
495 | 519 | goto error_cmd; |
... | ... | @@ -497,7 +521,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
497 | 521 | if (toclen > 0) { |
498 | 522 | if (len > toclen) |
499 | 523 | len = toclen; |
500 | - s->buf_len = len; | |
524 | + r->buf_len = len; | |
501 | 525 | break; |
502 | 526 | } |
503 | 527 | error_cmd: |
... | ... | @@ -506,11 +530,11 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
506 | 530 | } |
507 | 531 | case 0x46: |
508 | 532 | DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); |
509 | - memset(s->buf, 0, 8); | |
533 | + memset(outbuf, 0, 8); | |
510 | 534 | /* ??? This shoud probably return much more information. For now |
511 | 535 | just return the basic header indicating the CD-ROM profile. */ |
512 | - s->buf[7] = 8; // CD-ROM | |
513 | - s->buf_len = 8; | |
536 | + outbuf[7] = 8; // CD-ROM | |
537 | + r->buf_len = 8; | |
514 | 538 | break; |
515 | 539 | case 0x56: |
516 | 540 | DPRINTF("Reserve(10)\n"); |
... | ... | @@ -526,21 +550,27 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) |
526 | 550 | DPRINTF("Report LUNs (len %d)\n", len); |
527 | 551 | if (len < 16) |
528 | 552 | goto fail; |
529 | - memset(s->buf, 0, 16); | |
530 | - s->buf[3] = 8; | |
531 | - s->buf_len = 16; | |
553 | + memset(outbuf, 0, 16); | |
554 | + outbuf[3] = 8; | |
555 | + r->buf_len = 16; | |
532 | 556 | break; |
533 | 557 | default: |
534 | 558 | DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); |
535 | 559 | fail: |
536 | - scsi_command_complete(s, SENSE_ILLEGAL_REQUEST); | |
560 | + scsi_command_complete(r, SENSE_ILLEGAL_REQUEST); | |
537 | 561 | return 0; |
538 | 562 | } |
539 | - if (s->sector_count == 0 && s->buf_len == 0) { | |
540 | - scsi_command_complete(s, SENSE_NO_SENSE); | |
563 | + if (r->sector_count == 0 && r->buf_len == 0) { | |
564 | + scsi_command_complete(r, SENSE_NO_SENSE); | |
565 | + } | |
566 | + len = r->sector_count * 512 + r->buf_len; | |
567 | + if (is_write) { | |
568 | + return -len; | |
569 | + } else { | |
570 | + if (!r->sector_count) | |
571 | + r->sector_count = -1; | |
572 | + return len; | |
541 | 573 | } |
542 | - len = s->sector_count * 512 + s->buf_len; | |
543 | - return is_write ? -len : len; | |
544 | 574 | } |
545 | 575 | |
546 | 576 | void scsi_disk_destroy(SCSIDevice *s) |
... | ... | @@ -549,6 +579,7 @@ void scsi_disk_destroy(SCSIDevice *s) |
549 | 579 | } |
550 | 580 | |
551 | 581 | SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, |
582 | + int tcq, | |
552 | 583 | scsi_completionfn completion, |
553 | 584 | void *opaque) |
554 | 585 | { |
... | ... | @@ -556,6 +587,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, |
556 | 587 | |
557 | 588 | s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); |
558 | 589 | s->bdrv = bdrv; |
590 | + s->tcq = tcq; | |
559 | 591 | s->completion = completion; |
560 | 592 | s->opaque = opaque; |
561 | 593 | if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { | ... | ... |
hw/sun4m.c
... | ... | @@ -199,6 +199,18 @@ uint32_t iommu_translate(uint32_t addr) |
199 | 199 | return iommu_translate_local(iommu, addr); |
200 | 200 | } |
201 | 201 | |
202 | +void sparc_iommu_memory_read(target_phys_addr_t addr, | |
203 | + uint8_t *buf, int len) | |
204 | +{ | |
205 | + return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 0); | |
206 | +} | |
207 | + | |
208 | +void sparc_iommu_memory_write(target_phys_addr_t addr, | |
209 | + uint8_t *buf, int len) | |
210 | +{ | |
211 | + return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 1); | |
212 | +} | |
213 | + | |
202 | 214 | static void *slavio_misc; |
203 | 215 | |
204 | 216 | void qemu_system_powerdown(void) | ... | ... |
hw/usb-msd.c
... | ... | @@ -32,8 +32,12 @@ enum USBMSDMode { |
32 | 32 | typedef struct { |
33 | 33 | USBDevice dev; |
34 | 34 | enum USBMSDMode mode; |
35 | + uint32_t scsi_len; | |
36 | + uint8_t *scsi_buf; | |
37 | + uint32_t usb_len; | |
38 | + uint8_t *usb_buf; | |
35 | 39 | uint32_t data_len; |
36 | - uint32_t transfer_len; | |
40 | + uint32_t residue; | |
37 | 41 | uint32_t tag; |
38 | 42 | BlockDriverState *bs; |
39 | 43 | SCSIDevice *scsi_dev; |
... | ... | @@ -42,6 +46,23 @@ typedef struct { |
42 | 46 | USBPacket *packet; |
43 | 47 | } MSDState; |
44 | 48 | |
49 | +struct usb_msd_cbw { | |
50 | + uint32_t sig; | |
51 | + uint32_t tag; | |
52 | + uint32_t data_len; | |
53 | + uint8_t flags; | |
54 | + uint8_t lun; | |
55 | + uint8_t cmd_len; | |
56 | + uint8_t cmd[16]; | |
57 | +}; | |
58 | + | |
59 | +struct usb_msd_csw { | |
60 | + uint32_t sig; | |
61 | + uint32_t tag; | |
62 | + uint32_t residue; | |
63 | + uint8_t status; | |
64 | +}; | |
65 | + | |
45 | 66 | static const uint8_t qemu_msd_dev_descriptor[] = { |
46 | 67 | 0x12, /* u8 bLength; */ |
47 | 68 | 0x01, /* u8 bDescriptorType; Device */ |
... | ... | @@ -107,26 +128,90 @@ static const uint8_t qemu_msd_config_descriptor[] = { |
107 | 128 | 0x00 /* u8 ep_bInterval; */ |
108 | 129 | }; |
109 | 130 | |
110 | -static void usb_msd_command_complete(void *opaque, uint32_t reason, int fail) | |
131 | +static void usb_msd_copy_data(MSDState *s) | |
132 | +{ | |
133 | + uint32_t len; | |
134 | + len = s->usb_len; | |
135 | + if (len > s->scsi_len) | |
136 | + len = s->scsi_len; | |
137 | + if (s->mode == USB_MSDM_DATAIN) { | |
138 | + memcpy(s->usb_buf, s->scsi_buf, len); | |
139 | + } else { | |
140 | + memcpy(s->scsi_buf, s->usb_buf, len); | |
141 | + } | |
142 | + s->usb_len -= len; | |
143 | + s->scsi_len -= len; | |
144 | + s->usb_buf += len; | |
145 | + s->scsi_buf += len; | |
146 | + s->data_len -= len; | |
147 | + if (s->scsi_len == 0) { | |
148 | + if (s->mode == USB_MSDM_DATAIN) { | |
149 | + scsi_read_data(s->scsi_dev, s->tag); | |
150 | + } else if (s->mode == USB_MSDM_DATAOUT) { | |
151 | + scsi_write_data(s->scsi_dev, s->tag); | |
152 | + } | |
153 | + } | |
154 | +} | |
155 | + | |
156 | +static void usb_msd_send_status(MSDState *s) | |
157 | +{ | |
158 | + struct usb_msd_csw csw; | |
159 | + | |
160 | + csw.sig = cpu_to_le32(0x53425355); | |
161 | + csw.tag = cpu_to_le32(s->tag); | |
162 | + csw.residue = s->residue; | |
163 | + csw.status = s->result; | |
164 | + memcpy(s->usb_buf, &csw, 13); | |
165 | +} | |
166 | + | |
167 | +static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag, | |
168 | + uint32_t arg) | |
111 | 169 | { |
112 | 170 | MSDState *s = (MSDState *)opaque; |
113 | - USBPacket *p; | |
171 | + USBPacket *p = s->packet; | |
114 | 172 | |
115 | - s->data_len -= s->transfer_len; | |
116 | - s->transfer_len = 0; | |
173 | + if (tag != s->tag) { | |
174 | + fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", tag); | |
175 | + } | |
117 | 176 | if (reason == SCSI_REASON_DONE) { |
118 | - DPRINTF("Command complete %d\n", fail); | |
119 | - s->result = fail; | |
120 | - s->mode = USB_MSDM_CSW; | |
177 | + DPRINTF("Command complete %d\n", arg); | |
178 | + s->residue = s->data_len; | |
179 | + s->result = arg != 0; | |
180 | + if (s->packet) { | |
181 | + if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) { | |
182 | + /* A deferred packet with no write data remaining must be | |
183 | + the status read packet. */ | |
184 | + usb_msd_send_status(s); | |
185 | + s->mode = USB_MSDM_CBW; | |
186 | + } else { | |
187 | + if (s->data_len) { | |
188 | + s->data_len -= s->usb_len; | |
189 | + if (s->mode == USB_MSDM_DATAIN) | |
190 | + memset(s->usb_buf, 0, s->usb_len); | |
191 | + s->usb_len = 0; | |
192 | + } | |
193 | + if (s->data_len == 0) | |
194 | + s->mode = USB_MSDM_CSW; | |
195 | + } | |
196 | + s->packet = NULL; | |
197 | + usb_packet_complete(p); | |
198 | + } else if (s->data_len == 0) { | |
199 | + s->mode = USB_MSDM_CSW; | |
200 | + } | |
201 | + return; | |
121 | 202 | } |
122 | - if (s->packet) { | |
123 | - /* Set s->packet to NULL before calling usb_packet_complete because | |
124 | - annother request may be issues before usb_packet_complete returns. | |
125 | - */ | |
126 | - DPRINTF("Packet complete %p\n", p); | |
127 | - p = s->packet; | |
128 | - s->packet = NULL; | |
129 | - usb_packet_complete(p); | |
203 | + s->scsi_len = arg; | |
204 | + s->scsi_buf = scsi_get_buf(s->scsi_dev, tag); | |
205 | + if (p) { | |
206 | + usb_msd_copy_data(s); | |
207 | + if (s->usb_len == 0) { | |
208 | + /* Set s->packet to NULL before calling usb_packet_complete | |
209 | + because annother request may be issued before | |
210 | + usb_packet_complete returns. */ | |
211 | + DPRINTF("Packet complete %p\n", p); | |
212 | + s->packet = NULL; | |
213 | + usb_packet_complete(p); | |
214 | + } | |
130 | 215 | } |
131 | 216 | } |
132 | 217 | |
... | ... | @@ -251,28 +336,12 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, |
251 | 336 | return ret; |
252 | 337 | } |
253 | 338 | |
254 | -struct usb_msd_cbw { | |
255 | - uint32_t sig; | |
256 | - uint32_t tag; | |
257 | - uint32_t data_len; | |
258 | - uint8_t flags; | |
259 | - uint8_t lun; | |
260 | - uint8_t cmd_len; | |
261 | - uint8_t cmd[16]; | |
262 | -}; | |
263 | - | |
264 | -struct usb_msd_csw { | |
265 | - uint32_t sig; | |
266 | - uint32_t tag; | |
267 | - uint32_t residue; | |
268 | - uint8_t status; | |
269 | -}; | |
270 | - | |
271 | 339 | static void usb_msd_cancel_io(USBPacket *p, void *opaque) |
272 | 340 | { |
273 | 341 | MSDState *s = opaque; |
274 | - scsi_cancel_io(s->scsi_dev); | |
342 | + scsi_cancel_io(s->scsi_dev, s->tag); | |
275 | 343 | s->packet = NULL; |
344 | + s->scsi_len = 0; | |
276 | 345 | } |
277 | 346 | |
278 | 347 | static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) |
... | ... | @@ -280,7 +349,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) |
280 | 349 | MSDState *s = (MSDState *)dev; |
281 | 350 | int ret = 0; |
282 | 351 | struct usb_msd_cbw cbw; |
283 | - struct usb_msd_csw csw; | |
284 | 352 | uint8_t devep = p->devep; |
285 | 353 | uint8_t *data = p->data; |
286 | 354 | int len = p->len; |
... | ... | @@ -318,7 +386,17 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) |
318 | 386 | } |
319 | 387 | DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", |
320 | 388 | s->tag, cbw.flags, cbw.cmd_len, s->data_len); |
389 | + s->residue = 0; | |
321 | 390 | scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); |
391 | + /* ??? Should check that USB and SCSI data transfer | |
392 | + directions match. */ | |
393 | + if (s->residue == 0) { | |
394 | + if (s->mode == USB_MSDM_DATAIN) { | |
395 | + scsi_read_data(s->scsi_dev, s->tag); | |
396 | + } else if (s->mode == USB_MSDM_DATAOUT) { | |
397 | + scsi_write_data(s->scsi_dev, s->tag); | |
398 | + } | |
399 | + } | |
322 | 400 | ret = len; |
323 | 401 | break; |
324 | 402 | |
... | ... | @@ -327,17 +405,24 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) |
327 | 405 | if (len > s->data_len) |
328 | 406 | goto fail; |
329 | 407 | |
330 | - s->transfer_len = len; | |
331 | - if (scsi_write_data(s->scsi_dev, data, len)) | |
332 | - goto fail; | |
333 | - | |
334 | - if (s->transfer_len == 0) { | |
335 | - ret = len; | |
336 | - } else { | |
408 | + s->usb_buf = data; | |
409 | + s->usb_len = len; | |
410 | + if (s->scsi_len) { | |
411 | + usb_msd_copy_data(s); | |
412 | + } | |
413 | + if (s->residue && s->usb_len) { | |
414 | + s->data_len -= s->usb_len; | |
415 | + if (s->data_len == 0) | |
416 | + s->mode = USB_MSDM_CSW; | |
417 | + s->usb_len = 0; | |
418 | + } | |
419 | + if (s->usb_len) { | |
337 | 420 | DPRINTF("Deferring packet %p\n", p); |
338 | 421 | usb_defer_packet(p, usb_msd_cancel_io, s); |
339 | 422 | s->packet = p; |
340 | 423 | ret = USB_RET_ASYNC; |
424 | + } else { | |
425 | + ret = len; | |
341 | 426 | } |
342 | 427 | break; |
343 | 428 | |
... | ... | @@ -352,37 +437,51 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) |
352 | 437 | goto fail; |
353 | 438 | |
354 | 439 | switch (s->mode) { |
440 | + case USB_MSDM_DATAOUT: | |
441 | + if (s->data_len != 0 || len < 13) | |
442 | + goto fail; | |
443 | + /* Waiting for SCSI write to complete. */ | |
444 | + usb_defer_packet(p, usb_msd_cancel_io, s); | |
445 | + s->packet = p; | |
446 | + ret = USB_RET_ASYNC; | |
447 | + break; | |
448 | + | |
355 | 449 | case USB_MSDM_CSW: |
356 | 450 | DPRINTF("Command status %d tag 0x%x, len %d\n", |
357 | 451 | s->result, s->tag, len); |
358 | 452 | if (len < 13) |
359 | 453 | goto fail; |
360 | 454 | |
361 | - csw.sig = cpu_to_le32(0x53425355); | |
362 | - csw.tag = cpu_to_le32(s->tag); | |
363 | - csw.residue = 0; | |
364 | - csw.status = s->result; | |
365 | - memcpy(data, &csw, 13); | |
366 | - ret = 13; | |
455 | + s->usb_len = len; | |
456 | + s->usb_buf = data; | |
457 | + usb_msd_send_status(s); | |
367 | 458 | s->mode = USB_MSDM_CBW; |
459 | + ret = 13; | |
368 | 460 | break; |
369 | 461 | |
370 | 462 | case USB_MSDM_DATAIN: |
371 | 463 | DPRINTF("Data in %d/%d\n", len, s->data_len); |
372 | 464 | if (len > s->data_len) |
373 | 465 | len = s->data_len; |
374 | - | |
375 | - s->transfer_len = len; | |
376 | - if (scsi_read_data(s->scsi_dev, data, len)) | |
377 | - goto fail; | |
378 | - | |
379 | - if (s->transfer_len == 0) { | |
380 | - ret = len; | |
381 | - } else { | |
466 | + s->usb_buf = data; | |
467 | + s->usb_len = len; | |
468 | + if (s->scsi_len) { | |
469 | + usb_msd_copy_data(s); | |
470 | + } | |
471 | + if (s->residue && s->usb_len) { | |
472 | + s->data_len -= s->usb_len; | |
473 | + memset(s->usb_buf, 0, s->usb_len); | |
474 | + if (s->data_len == 0) | |
475 | + s->mode = USB_MSDM_CSW; | |
476 | + s->usb_len = 0; | |
477 | + } | |
478 | + if (s->usb_len) { | |
382 | 479 | DPRINTF("Deferring packet %p\n", p); |
383 | 480 | usb_defer_packet(p, usb_msd_cancel_io, s); |
384 | 481 | s->packet = p; |
385 | 482 | ret = USB_RET_ASYNC; |
483 | + } else { | |
484 | + ret = len; | |
386 | 485 | } |
387 | 486 | break; |
388 | 487 | |
... | ... | @@ -436,7 +535,7 @@ USBDevice *usb_msd_init(const char *filename) |
436 | 535 | snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", |
437 | 536 | filename); |
438 | 537 | |
439 | - s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s); | |
538 | + s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s); | |
440 | 539 | usb_msd_handle_reset((USBDevice *)s); |
441 | 540 | return (USBDevice *)s; |
442 | 541 | fail: | ... | ... |
vl.h
... | ... | @@ -1025,12 +1025,20 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); |
1025 | 1025 | |
1026 | 1026 | /* sun4m.c */ |
1027 | 1027 | extern QEMUMachine sun4m_machine; |
1028 | -uint32_t iommu_translate(uint32_t addr); | |
1029 | 1028 | void pic_set_irq_cpu(int irq, int level, unsigned int cpu); |
1029 | +/* ??? Remove iommu_translate once lance emulation has been converted. */ | |
1030 | +uint32_t iommu_translate(uint32_t addr); | |
1031 | +void sparc_iommu_memory_read(target_phys_addr_t addr, | |
1032 | + uint8_t *buf, int len); | |
1033 | +void sparc_iommu_memory_write(target_phys_addr_t addr, | |
1034 | + uint8_t *buf, int len); | |
1030 | 1035 | |
1031 | 1036 | /* iommu.c */ |
1032 | 1037 | void *iommu_init(uint32_t addr); |
1038 | +/* ??? Remove iommu_translate_local. */ | |
1033 | 1039 | uint32_t iommu_translate_local(void *opaque, uint32_t addr); |
1040 | +void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, | |
1041 | + uint8_t *buf, int len, int is_write); | |
1034 | 1042 | |
1035 | 1043 | /* lance.c */ |
1036 | 1044 | void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr); |
... | ... | @@ -1157,9 +1165,11 @@ enum scsi_reason { |
1157 | 1165 | }; |
1158 | 1166 | |
1159 | 1167 | typedef struct SCSIDevice SCSIDevice; |
1160 | -typedef void (*scsi_completionfn)(void *, uint32_t, int); | |
1168 | +typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag, | |
1169 | + uint32_t arg); | |
1161 | 1170 | |
1162 | 1171 | SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, |
1172 | + int tcq, | |
1163 | 1173 | scsi_completionfn completion, |
1164 | 1174 | void *opaque); |
1165 | 1175 | void scsi_disk_destroy(SCSIDevice *s); |
... | ... | @@ -1168,9 +1178,10 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); |
1168 | 1178 | /* SCSI data transfers are asynchrnonous. However, unlike the block IO |
1169 | 1179 | layer the completion routine may be called directly by |
1170 | 1180 | scsi_{read,write}_data. */ |
1171 | -int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len); | |
1172 | -int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len); | |
1173 | -void scsi_cancel_io(SCSIDevice *s); | |
1181 | +void scsi_read_data(SCSIDevice *s, uint32_t tag); | |
1182 | +int scsi_write_data(SCSIDevice *s, uint32_t tag); | |
1183 | +void scsi_cancel_io(SCSIDevice *s, uint32_t tag); | |
1184 | +uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); | |
1174 | 1185 | |
1175 | 1186 | /* lsi53c895a.c */ |
1176 | 1187 | void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); | ... | ... |