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,8 +64,7 @@ struct ESPState { | ||
64 | int do_cmd; | 64 | int do_cmd; |
65 | 65 | ||
66 | uint32_t dma_left; | 66 | uint32_t dma_left; |
67 | - uint8_t async_buf[TARGET_PAGE_SIZE]; | ||
68 | - uint32_t async_ptr; | 67 | + uint8_t *async_buf; |
69 | uint32_t async_len; | 68 | uint32_t async_len; |
70 | }; | 69 | }; |
71 | 70 | ||
@@ -91,17 +90,16 @@ struct ESPState { | @@ -91,17 +90,16 @@ struct ESPState { | ||
91 | 90 | ||
92 | static int get_cmd(ESPState *s, uint8_t *buf) | 91 | static int get_cmd(ESPState *s, uint8_t *buf) |
93 | { | 92 | { |
94 | - uint32_t dmaptr, dmalen; | 93 | + uint32_t dmalen; |
95 | int target; | 94 | int target; |
96 | 95 | ||
97 | dmalen = s->wregs[0] | (s->wregs[1] << 8); | 96 | dmalen = s->wregs[0] | (s->wregs[1] << 8); |
98 | target = s->wregs[4] & 7; | 97 | target = s->wregs[4] & 7; |
99 | DPRINTF("get_cmd: len %d target %d\n", dmalen, target); | 98 | DPRINTF("get_cmd: len %d target %d\n", dmalen, target); |
100 | if (s->dma) { | 99 | if (s->dma) { |
101 | - dmaptr = iommu_translate(s->espdmaregs[1]); | ||
102 | DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", | 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 | } else { | 103 | } else { |
106 | buf[0] = 0; | 104 | buf[0] = 0; |
107 | memcpy(&buf[1], s->ti_buf, dmalen); | 105 | memcpy(&buf[1], s->ti_buf, dmalen); |
@@ -112,6 +110,12 @@ static int get_cmd(ESPState *s, uint8_t *buf) | @@ -112,6 +110,12 @@ static int get_cmd(ESPState *s, uint8_t *buf) | ||
112 | s->ti_rptr = 0; | 110 | s->ti_rptr = 0; |
113 | s->ti_wptr = 0; | 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 | if (target >= 4 || !s->scsi_dev[target]) { | 119 | if (target >= 4 || !s->scsi_dev[target]) { |
116 | // No such drive | 120 | // No such drive |
117 | s->rregs[4] = STAT_IN; | 121 | s->rregs[4] = STAT_IN; |
@@ -137,12 +141,15 @@ static void do_cmd(ESPState *s, uint8_t *buf) | @@ -137,12 +141,15 @@ static void do_cmd(ESPState *s, uint8_t *buf) | ||
137 | s->ti_size = 0; | 141 | s->ti_size = 0; |
138 | } else { | 142 | } else { |
139 | s->rregs[4] = STAT_IN | STAT_TC; | 143 | s->rregs[4] = STAT_IN | STAT_TC; |
144 | + s->dma_left = 0; | ||
140 | if (datalen > 0) { | 145 | if (datalen > 0) { |
141 | s->rregs[4] |= STAT_DI; | 146 | s->rregs[4] |= STAT_DI; |
142 | s->ti_size = datalen; | 147 | s->ti_size = datalen; |
148 | + scsi_read_data(s->current_dev, 0); | ||
143 | } else { | 149 | } else { |
144 | s->rregs[4] |= STAT_DO; | 150 | s->rregs[4] |= STAT_DO; |
145 | s->ti_size = -datalen; | 151 | s->ti_size = -datalen; |
152 | + scsi_write_data(s->current_dev, 0); | ||
146 | } | 153 | } |
147 | } | 154 | } |
148 | s->rregs[5] = INTR_BS | INTR_FC; | 155 | s->rregs[5] = INTR_BS | INTR_FC; |
@@ -178,16 +185,13 @@ static void handle_satn_stop(ESPState *s) | @@ -178,16 +185,13 @@ static void handle_satn_stop(ESPState *s) | ||
178 | 185 | ||
179 | static void write_response(ESPState *s) | 186 | static void write_response(ESPState *s) |
180 | { | 187 | { |
181 | - uint32_t dmaptr; | ||
182 | - | ||
183 | DPRINTF("Transfer status (sense=%d)\n", s->sense); | 188 | DPRINTF("Transfer status (sense=%d)\n", s->sense); |
184 | s->ti_buf[0] = s->sense; | 189 | s->ti_buf[0] = s->sense; |
185 | s->ti_buf[1] = 0; | 190 | s->ti_buf[1] = 0; |
186 | if (s->dma) { | 191 | if (s->dma) { |
187 | - dmaptr = iommu_translate(s->espdmaregs[1]); | ||
188 | DPRINTF("DMA Direction: %c\n", | 192 | DPRINTF("DMA Direction: %c\n", |
189 | s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); | 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 | s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; | 195 | s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; |
192 | s->rregs[5] = INTR_BS | INTR_FC; | 196 | s->rregs[5] = INTR_BS | INTR_FC; |
193 | s->rregs[6] = SEQ_CD; | 197 | s->rregs[6] = SEQ_CD; |
@@ -202,78 +206,89 @@ static void write_response(ESPState *s) | @@ -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 | static void esp_do_dma(ESPState *s) | 219 | static void esp_do_dma(ESPState *s) |
206 | { | 220 | { |
207 | - uint32_t dmaptr, minlen, len, from, to; | 221 | + uint32_t addr, len; |
208 | int to_device; | 222 | int to_device; |
223 | + | ||
209 | to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; | 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 | if (s->do_cmd) { | 228 | if (s->do_cmd) { |
221 | s->espdmaregs[1] += len; | 229 | s->espdmaregs[1] += len; |
222 | s->ti_size -= len; | 230 | s->ti_size -= len; |
223 | DPRINTF("command len %d + %d\n", s->cmdlen, len); | 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 | s->ti_size = 0; | 233 | s->ti_size = 0; |
226 | s->cmdlen = 0; | 234 | s->cmdlen = 0; |
227 | s->do_cmd = 0; | 235 | s->do_cmd = 0; |
228 | do_cmd(s, s->cmdbuf); | 236 | do_cmd(s, s->cmdbuf); |
229 | return; | 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 | } else { | 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 | if (to_device) { | 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 | } else { | 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 | ESPState *s = (ESPState *)opaque; | 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 | if (reason == SCSI_REASON_DONE) { | 273 | if (reason == SCSI_REASON_DONE) { |
254 | DPRINTF("SCSI Command complete\n"); | 274 | DPRINTF("SCSI Command complete\n"); |
255 | if (s->ti_size != 0) | 275 | if (s->ti_size != 0) |
256 | DPRINTF("SCSI command completed unexpectedly\n"); | 276 | DPRINTF("SCSI command completed unexpectedly\n"); |
257 | s->ti_size = 0; | 277 | s->ti_size = 0; |
258 | - if (sense) | 278 | + s->dma_left = 0; |
279 | + s->async_len = 0; | ||
280 | + if (arg) | ||
259 | DPRINTF("Command failed\n"); | 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 | } else { | 286 | } else { |
262 | DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); | 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,7 +348,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) | ||
333 | s->ti_size--; | 348 | s->ti_size--; |
334 | if ((s->rregs[4] & 6) == 0) { | 349 | if ((s->rregs[4] & 6) == 0) { |
335 | /* Data in/out. */ | 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 | } else { | 353 | } else { |
338 | s->rregs[2] = s->ti_buf[s->ti_rptr++]; | 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,7 +394,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | ||
378 | uint8_t buf; | 394 | uint8_t buf; |
379 | buf = val & 0xff; | 395 | buf = val & 0xff; |
380 | s->ti_size--; | 396 | s->ti_size--; |
381 | - scsi_write_data(s->current_dev, &buf, 0); | 397 | + fprintf(stderr, "esp: PIO data write not implemented\n"); |
382 | } else { | 398 | } else { |
383 | s->ti_size++; | 399 | s->ti_size++; |
384 | s->ti_buf[s->ti_wptr++] = val & 0xff; | 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,8 +606,9 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd | ||
590 | qemu_register_reset(esp_reset, s); | 606 | qemu_register_reset(esp_reset, s); |
591 | for (i = 0; i < MAX_DISKS; i++) { | 607 | for (i = 0; i < MAX_DISKS; i++) { |
592 | if (bs_table[i]) { | 608 | if (bs_table[i]) { |
609 | + /* Command queueing is not implemented. */ | ||
593 | s->scsi_dev[i] = | 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,21 +186,62 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { | ||
186 | iommu_mem_writew, | 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 | iopte = s->regs[1] << 4; | 193 | iopte = s->regs[1] << 4; |
195 | addr &= ~s->iostart; | 194 | addr &= ~s->iostart; |
196 | iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; | 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 | tmppte = pa; | 203 | tmppte = pa; |
199 | pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); | 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 | return pa; | 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 | static void iommu_save(QEMUFile *f, void *opaque) | 245 | static void iommu_save(QEMUFile *f, void *opaque) |
205 | { | 246 | { |
206 | IOMMUState *s = opaque; | 247 | IOMMUState *s = opaque; |
hw/lsi53c895a.c
@@ -19,11 +19,11 @@ | @@ -19,11 +19,11 @@ | ||
19 | #define DPRINTF(fmt, args...) \ | 19 | #define DPRINTF(fmt, args...) \ |
20 | do { printf("lsi_scsi: " fmt , ##args); } while (0) | 20 | do { printf("lsi_scsi: " fmt , ##args); } while (0) |
21 | #define BADF(fmt, args...) \ | 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 | #else | 23 | #else |
24 | #define DPRINTF(fmt, args...) do {} while(0) | 24 | #define DPRINTF(fmt, args...) do {} while(0) |
25 | #define BADF(fmt, args...) \ | 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 | #endif | 27 | #endif |
28 | 28 | ||
29 | #define LSI_SCNTL0_TRG 0x01 | 29 | #define LSI_SCNTL0_TRG 0x01 |
@@ -152,26 +152,46 @@ do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) | @@ -152,26 +152,46 @@ do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) | ||
152 | /* The HBA is ID 7, so for simplicitly limit to 7 devices. */ | 152 | /* The HBA is ID 7, so for simplicitly limit to 7 devices. */ |
153 | #define LSI_MAX_DEVS 7 | 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 | typedef struct { | 167 | typedef struct { |
159 | PCIDevice pci_dev; | 168 | PCIDevice pci_dev; |
160 | int mmio_io_addr; | 169 | int mmio_io_addr; |
161 | int ram_io_addr; | 170 | int ram_io_addr; |
162 | uint32_t script_ram_base; | 171 | uint32_t script_ram_base; |
163 | - uint32_t data_len; | ||
164 | 172 | ||
165 | int carry; /* ??? Should this be an a visible register somewhere? */ | 173 | int carry; /* ??? Should this be an a visible register somewhere? */ |
166 | int sense; | 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 | /* 0 if SCRIPTS are running or stopped. | 180 | /* 0 if SCRIPTS are running or stopped. |
169 | * 1 if a Wait Reselect instruction has been issued. | 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 | int waiting; | 184 | int waiting; |
172 | SCSIDevice *scsi_dev[LSI_MAX_DEVS]; | 185 | SCSIDevice *scsi_dev[LSI_MAX_DEVS]; |
173 | SCSIDevice *current_dev; | 186 | SCSIDevice *current_dev; |
174 | int current_lun; | 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 | uint32_t dsa; | 196 | uint32_t dsa; |
177 | uint32_t temp; | 197 | uint32_t temp; |
@@ -208,10 +228,12 @@ typedef struct { | @@ -208,10 +228,12 @@ typedef struct { | ||
208 | uint8_t sxfer; | 228 | uint8_t sxfer; |
209 | uint8_t socl; | 229 | uint8_t socl; |
210 | uint8_t sdid; | 230 | uint8_t sdid; |
231 | + uint8_t ssid; | ||
211 | uint8_t sfbr; | 232 | uint8_t sfbr; |
212 | uint8_t stest1; | 233 | uint8_t stest1; |
213 | uint8_t stest2; | 234 | uint8_t stest2; |
214 | uint8_t stest3; | 235 | uint8_t stest3; |
236 | + uint8_t sidl; | ||
215 | uint8_t stime0; | 237 | uint8_t stime0; |
216 | uint8_t respid0; | 238 | uint8_t respid0; |
217 | uint8_t respid1; | 239 | uint8_t respid1; |
@@ -231,7 +253,6 @@ typedef struct { | @@ -231,7 +253,6 @@ typedef struct { | ||
231 | uint32_t csbc; | 253 | uint32_t csbc; |
232 | uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ | 254 | uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ |
233 | 255 | ||
234 | - uint8_t dma_buf[LSI_DMA_BLOCK_SIZE]; | ||
235 | /* Script ram is stored as 32-bit words in host byteorder. */ | 256 | /* Script ram is stored as 32-bit words in host byteorder. */ |
236 | uint32_t script_ram[2048]; | 257 | uint32_t script_ram[2048]; |
237 | } LSIState; | 258 | } LSIState; |
@@ -280,6 +301,7 @@ static void lsi_soft_reset(LSIState *s) | @@ -280,6 +301,7 @@ static void lsi_soft_reset(LSIState *s) | ||
280 | s->stest1 = 0; | 301 | s->stest1 = 0; |
281 | s->stest2 = 0; | 302 | s->stest2 = 0; |
282 | s->stest3 = 0; | 303 | s->stest3 = 0; |
304 | + s->sidl = 0; | ||
283 | s->stime0 = 0; | 305 | s->stime0 = 0; |
284 | s->respid0 = 0x80; | 306 | s->respid0 = 0x80; |
285 | s->respid1 = 0; | 307 | s->respid1 = 0; |
@@ -409,68 +431,194 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase) | @@ -409,68 +431,194 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase) | ||
409 | lsi_set_phase(s, new_phase); | 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 | /* Initiate a SCSI layer data transfer. */ | 446 | /* Initiate a SCSI layer data transfer. */ |
413 | static void lsi_do_dma(LSIState *s, int out) | 447 | static void lsi_do_dma(LSIState *s, int out) |
414 | { | 448 | { |
415 | uint32_t count; | 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 | s->csbc += count; | 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 | /* ??? Set SFBR to first data byte. */ | 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 | } else { | 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 | /* Callback to indicate that the SCSI layer has completed a transfer. */ | 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 | LSIState *s = (LSIState *)opaque; | 593 | LSIState *s = (LSIState *)opaque; |
450 | - uint32_t count; | ||
451 | int out; | 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 | if (reason == SCSI_REASON_DONE) { | 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 | lsi_do_dma(s, out); | 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,27 +632,37 @@ static void lsi_do_command(LSIState *s) | ||
484 | s->dbc = 16; | 632 | s->dbc = 16; |
485 | cpu_physical_memory_read(s->dnad, buf, s->dbc); | 633 | cpu_physical_memory_read(s->dnad, buf, s->dbc); |
486 | s->sfbr = buf[0]; | 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 | if (n > 0) { | 636 | if (n > 0) { |
489 | - s->data_len = n; | ||
490 | lsi_set_phase(s, PHASE_DI); | 637 | lsi_set_phase(s, PHASE_DI); |
638 | + scsi_read_data(s->current_dev, s->current_tag); | ||
491 | } else if (n < 0) { | 639 | } else if (n < 0) { |
492 | - s->data_len = -n; | ||
493 | lsi_set_phase(s, PHASE_DO); | 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 | static void lsi_do_status(LSIState *s) | 653 | static void lsi_do_status(LSIState *s) |
498 | { | 654 | { |
655 | + uint8_t sense; | ||
499 | DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); | 656 | DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); |
500 | if (s->dbc != 1) | 657 | if (s->dbc != 1) |
501 | BADF("Bad Status move\n"); | 658 | BADF("Bad Status move\n"); |
502 | s->dbc = 1; | 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 | lsi_set_phase(s, PHASE_MI); | 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 | static void lsi_disconnect(LSIState *s) | 668 | static void lsi_disconnect(LSIState *s) |
@@ -515,55 +673,114 @@ static void lsi_disconnect(LSIState *s) | @@ -515,55 +673,114 @@ static void lsi_disconnect(LSIState *s) | ||
515 | 673 | ||
516 | static void lsi_do_msgin(LSIState *s) | 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 | } else { | 688 | } else { |
525 | /* ??? Check if ATN (not yet implemented) is asserted and maybe | 689 | /* ??? Check if ATN (not yet implemented) is asserted and maybe |
526 | switch to PHASE_MO. */ | 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 | static void lsi_do_msgout(LSIState *s) | 720 | static void lsi_do_msgout(LSIState *s) |
532 | { | 721 | { |
533 | uint8_t msg; | 722 | uint8_t msg; |
723 | + int len; | ||
534 | 724 | ||
535 | DPRINTF("MSG out len=%d\n", s->dbc); | 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 | /* Sign extend a 24-bit value. */ | 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,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 | static void lsi_execute_script(LSIState *s) | 825 | static void lsi_execute_script(LSIState *s) |
592 | { | 826 | { |
593 | uint32_t insn; | 827 | uint32_t insn; |
@@ -632,10 +866,16 @@ again: | @@ -632,10 +866,16 @@ again: | ||
632 | s->dnad = addr; | 866 | s->dnad = addr; |
633 | switch (s->sstat1 & 0x7) { | 867 | switch (s->sstat1 & 0x7) { |
634 | case PHASE_DO: | 868 | case PHASE_DO: |
869 | + s->waiting = 2; | ||
635 | lsi_do_dma(s, 1); | 870 | lsi_do_dma(s, 1); |
871 | + if (s->waiting) | ||
872 | + s->waiting = 3; | ||
636 | break; | 873 | break; |
637 | case PHASE_DI: | 874 | case PHASE_DI: |
875 | + s->waiting = 2; | ||
638 | lsi_do_dma(s, 0); | 876 | lsi_do_dma(s, 0); |
877 | + if (s->waiting) | ||
878 | + s->waiting = 3; | ||
639 | break; | 879 | break; |
640 | case PHASE_CMD: | 880 | case PHASE_CMD: |
641 | lsi_do_command(s); | 881 | lsi_do_command(s); |
@@ -679,9 +919,13 @@ again: | @@ -679,9 +919,13 @@ again: | ||
679 | s->dnad = addr; | 919 | s->dnad = addr; |
680 | switch (opcode) { | 920 | switch (opcode) { |
681 | case 0: /* Select */ | 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 | s->sstat0 |= LSI_SSTAT0_WOA; | 927 | s->sstat0 |= LSI_SSTAT0_WOA; |
683 | s->scntl1 &= ~LSI_SCNTL1_IARB; | 928 | s->scntl1 &= ~LSI_SCNTL1_IARB; |
684 | - s->sdid = id; | ||
685 | if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) { | 929 | if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) { |
686 | DPRINTF("Selected absent target %d\n", id); | 930 | DPRINTF("Selected absent target %d\n", id); |
687 | lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO); | 931 | lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO); |
@@ -694,6 +938,7 @@ again: | @@ -694,6 +938,7 @@ again: | ||
694 | it only applies in low-level mode (unimplemented). | 938 | it only applies in low-level mode (unimplemented). |
695 | lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ | 939 | lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ |
696 | s->current_dev = s->scsi_dev[id]; | 940 | s->current_dev = s->scsi_dev[id]; |
941 | + s->current_tag = id << 8; | ||
697 | s->scntl1 |= LSI_SCNTL1_CON; | 942 | s->scntl1 |= LSI_SCNTL1_CON; |
698 | if (insn & (1 << 3)) { | 943 | if (insn & (1 << 3)) { |
699 | s->socl |= LSI_SOCL_ATN; | 944 | s->socl |= LSI_SOCL_ATN; |
@@ -705,8 +950,7 @@ again: | @@ -705,8 +950,7 @@ again: | ||
705 | s->scntl1 &= ~LSI_SCNTL1_CON; | 950 | s->scntl1 &= ~LSI_SCNTL1_CON; |
706 | break; | 951 | break; |
707 | case 2: /* Wait Reselect */ | 952 | case 2: /* Wait Reselect */ |
708 | - DPRINTF("Wait Reselect\n"); | ||
709 | - s->waiting = 1; | 953 | + lsi_wait_reselect(s); |
710 | break; | 954 | break; |
711 | case 3: /* Set */ | 955 | case 3: /* Set */ |
712 | DPRINTF("Set%s%s%s%s\n", | 956 | DPRINTF("Set%s%s%s%s\n", |
@@ -755,9 +999,9 @@ again: | @@ -755,9 +999,9 @@ again: | ||
755 | data8 = (insn >> 8) & 0xff; | 999 | data8 = (insn >> 8) & 0xff; |
756 | opcode = (insn >> 27) & 7; | 1000 | opcode = (insn >> 27) & 7; |
757 | operator = (insn >> 24) & 7; | 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 | opcode_names[opcode - 5], reg, | 1003 | opcode_names[opcode - 5], reg, |
760 | - operator_names[operator], data8, | 1004 | + operator_names[operator], data8, s->sfbr, |
761 | (insn & (1 << 23)) ? " SFBR" : ""); | 1005 | (insn & (1 << 23)) ? " SFBR" : ""); |
762 | op0 = op1 = 0; | 1006 | op0 = op1 = 0; |
763 | switch (opcode) { | 1007 | switch (opcode) { |
@@ -923,8 +1167,9 @@ again: | @@ -923,8 +1167,9 @@ again: | ||
923 | n = (insn & 7); | 1167 | n = (insn & 7); |
924 | reg = (insn >> 16) & 0xff; | 1168 | reg = (insn >> 16) & 0xff; |
925 | if (insn & (1 << 24)) { | 1169 | if (insn & (1 << 24)) { |
926 | - DPRINTF("Load reg 0x%x size %d addr 0x%08x\n", reg, n, addr); | ||
927 | cpu_physical_memory_read(addr, data, n); | 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 | for (i = 0; i < n; i++) { | 1173 | for (i = 0; i < n; i++) { |
929 | lsi_reg_writeb(s, reg + i, data[i]); | 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,6 +1222,8 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) | ||
977 | return s->sdid; | 1222 | return s->sdid; |
978 | case 0x07: /* GPREG0 */ | 1223 | case 0x07: /* GPREG0 */ |
979 | return 0x7f; | 1224 | return 0x7f; |
1225 | + case 0xa: /* SSID */ | ||
1226 | + return s->ssid; | ||
980 | case 0xb: /* SBCL */ | 1227 | case 0xb: /* SBCL */ |
981 | /* ??? This is not correct. However it's (hopefully) only | 1228 | /* ??? This is not correct. However it's (hopefully) only |
982 | used for diagnostics, so should be ok. */ | 1229 | used for diagnostics, so should be ok. */ |
@@ -1065,13 +1312,22 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) | @@ -1065,13 +1312,22 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) | ||
1065 | return s->stest2; | 1312 | return s->stest2; |
1066 | case 0x4f: /* STEST3 */ | 1313 | case 0x4f: /* STEST3 */ |
1067 | return s->stest3; | 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 | case 0x52: /* STEST4 */ | 1319 | case 0x52: /* STEST4 */ |
1069 | return 0xe0; | 1320 | return 0xe0; |
1070 | case 0x56: /* CCNTL0 */ | 1321 | case 0x56: /* CCNTL0 */ |
1071 | return s->ccntl0; | 1322 | return s->ccntl0; |
1072 | case 0x57: /* CCNTL1 */ | 1323 | case 0x57: /* CCNTL1 */ |
1073 | return s->ccntl1; | 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 | return 0; | 1331 | return 0; |
1076 | CASE_GET_REG32(mmrs, 0xa0) | 1332 | CASE_GET_REG32(mmrs, 0xa0) |
1077 | CASE_GET_REG32(mmws, 0xa4) | 1333 | CASE_GET_REG32(mmws, 0xa4) |
@@ -1143,8 +1399,18 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) | @@ -1143,8 +1399,18 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) | ||
1143 | case 0x05: /* SXFER */ | 1399 | case 0x05: /* SXFER */ |
1144 | s->sxfer = val; | 1400 | s->sxfer = val; |
1145 | break; | 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 | case 0x07: /* GPREG0 */ | 1407 | case 0x07: /* GPREG0 */ |
1147 | break; | 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 | case 0x0c: case 0x0d: case 0x0e: case 0x0f: | 1414 | case 0x0c: case 0x0d: case 0x0e: case 0x0f: |
1149 | /* Linux writes to these readonly registers on startup. */ | 1415 | /* Linux writes to these readonly registers on startup. */ |
1150 | return; | 1416 | return; |
@@ -1555,7 +1821,7 @@ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id) | @@ -1555,7 +1821,7 @@ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id) | ||
1555 | scsi_disk_destroy(s->scsi_dev[id]); | 1821 | scsi_disk_destroy(s->scsi_dev[id]); |
1556 | } | 1822 | } |
1557 | DPRINTF("Attaching block device %d\n", id); | 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 | void *lsi_scsi_init(PCIBus *bus, int devfn) | 1827 | void *lsi_scsi_init(PCIBus *bus, int devfn) |
@@ -1587,6 +1853,9 @@ void *lsi_scsi_init(PCIBus *bus, int devfn) | @@ -1587,6 +1853,9 @@ void *lsi_scsi_init(PCIBus *bus, int devfn) | ||
1587 | PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc); | 1853 | PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc); |
1588 | pci_register_io_region((struct PCIDevice *)s, 2, 0x2000, | 1854 | pci_register_io_region((struct PCIDevice *)s, 2, 0x2000, |
1589 | PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc); | 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 | lsi_soft_reset(s); | 1860 | lsi_soft_reset(s); |
1592 | 1861 |
hw/scsi-disk.c
@@ -7,6 +7,10 @@ | @@ -7,6 +7,10 @@ | ||
7 | * Written by Paul Brook | 7 | * Written by Paul Brook |
8 | * | 8 | * |
9 | * This code is licenced under the LGPL. | 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 | //#define DEBUG_SCSI | 16 | //#define DEBUG_SCSI |
@@ -28,231 +32,241 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) | @@ -28,231 +32,241 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) | ||
28 | #define SENSE_HARDWARE_ERROR 4 | 32 | #define SENSE_HARDWARE_ERROR 4 |
29 | #define SENSE_ILLEGAL_REQUEST 5 | 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 | uint32_t tag; | 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 | /* ??? We should probably keep track of whether the data trasfer is | 40 | /* ??? We should probably keep track of whether the data trasfer is |
44 | a read or a write. Currently we rely on the host getting it right. */ | 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 | int sector; | 43 | int sector; |
46 | int sector_count; | 44 | int sector_count; |
47 | - int buf_pos; | 45 | + /* The amounnt of data in the buffer. */ |
48 | int buf_len; | 46 | int buf_len; |
49 | - int sense; | 47 | + uint8_t dma_buf[SCSI_DMA_BUF_SIZE]; |
50 | BlockDriverAIOCB *aiocb; | 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 | /* Completion functions may be called from either scsi_{read,write}_data | 61 | /* Completion functions may be called from either scsi_{read,write}_data |
56 | or from the AIO completion routines. */ | 62 | or from the AIO completion routines. */ |
57 | scsi_completionfn completion; | 63 | scsi_completionfn completion; |
58 | void *opaque; | 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 | /* Cancel a pending data transfer. */ | 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 | return; | 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 | uint32_t n; | 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 | static void scsi_write_complete(void * opaque, int ret) | 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 | if (ret) { | 208 | if (ret) { |
171 | fprintf(stderr, "scsi-disc: IO write error\n"); | 209 | fprintf(stderr, "scsi-disc: IO write error\n"); |
172 | exit(1); | 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 | /* Write data to a scsi device. Returns nonzero on failure. | 227 | /* Write data to a scsi device. Returns nonzero on failure. |
206 | The transfer may complete asynchronously. */ | 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 | uint32_t n; | 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 | return 1; | 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 | /* Execute a scsi command. Returns the length of the data expected by the | 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,15 +281,23 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
267 | uint32_t len; | 281 | uint32_t len; |
268 | int cmdlen; | 282 | int cmdlen; |
269 | int is_write; | 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 | is_write = 0; | 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 | case 0: | 301 | case 0: |
280 | lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16); | 302 | lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16); |
281 | len = buf[4]; | 303 | len = buf[4]; |
@@ -298,7 +320,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | @@ -298,7 +320,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
298 | cmdlen = 12; | 320 | cmdlen = 12; |
299 | break; | 321 | break; |
300 | default: | 322 | default: |
301 | - BADF("Unsupported command length, command %x\n", s->command); | 323 | + BADF("Unsupported command length, command %x\n", command); |
302 | goto fail; | 324 | goto fail; |
303 | } | 325 | } |
304 | #ifdef DEBUG_SCSI | 326 | #ifdef DEBUG_SCSI |
@@ -315,7 +337,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | @@ -315,7 +337,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
315 | DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); | 337 | DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); |
316 | goto fail; | 338 | goto fail; |
317 | } | 339 | } |
318 | - switch (s->command) { | 340 | + switch (command) { |
319 | case 0x0: | 341 | case 0x0: |
320 | DPRINTF("Test Unit Ready\n"); | 342 | DPRINTF("Test Unit Ready\n"); |
321 | break; | 343 | break; |
@@ -324,33 +346,35 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | @@ -324,33 +346,35 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
324 | if (len < 4) | 346 | if (len < 4) |
325 | goto fail; | 347 | goto fail; |
326 | memset(buf, 0, 4); | 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 | break; | 353 | break; |
332 | case 0x12: | 354 | case 0x12: |
333 | DPRINTF("Inquiry (len %d)\n", len); | 355 | DPRINTF("Inquiry (len %d)\n", len); |
334 | if (len < 36) { | 356 | if (len < 36) { |
335 | BADF("Inquiry buffer too small (%d)\n", len); | 357 | BADF("Inquiry buffer too small (%d)\n", len); |
336 | } | 358 | } |
337 | - memset(s->buf, 0, 36); | 359 | + memset(outbuf, 0, 36); |
338 | if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { | 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 | } else { | 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 | /* Identify device as SCSI-3 rev 1. | 370 | /* Identify device as SCSI-3 rev 1. |
349 | Some later commands are also implemented. */ | 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 | break; | 378 | break; |
355 | case 0x16: | 379 | case 0x16: |
356 | DPRINTF("Reserve(6)\n"); | 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,17 +389,17 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
365 | case 0x1a: | 389 | case 0x1a: |
366 | case 0x5a: | 390 | case 0x5a: |
367 | { | 391 | { |
368 | - char *p; | 392 | + uint8_t *p; |
369 | int page; | 393 | int page; |
370 | 394 | ||
371 | page = buf[2] & 0x3f; | 395 | page = buf[2] & 0x3f; |
372 | DPRINTF("Mode Sense (page %d, len %d)\n", page, len); | 396 | DPRINTF("Mode Sense (page %d, len %d)\n", page, len); |
373 | - p = s->buf; | 397 | + p = outbuf; |
374 | memset(p, 0, 4); | 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 | if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { | 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 | p += 4; | 404 | p += 4; |
381 | if ((page == 8 || page == 0x3f)) { | 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,10 +439,10 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
415 | p[21] = (16 * 176) & 0xff; | 439 | p[21] = (16 * 176) & 0xff; |
416 | p += 21; | 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 | break; | 447 | break; |
424 | case 0x1b: | 448 | case 0x1b: |
@@ -431,36 +455,36 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | @@ -431,36 +455,36 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
431 | case 0x25: | 455 | case 0x25: |
432 | DPRINTF("Read Capacity\n"); | 456 | DPRINTF("Read Capacity\n"); |
433 | /* The normal LEN field for this command is zero. */ | 457 | /* The normal LEN field for this command is zero. */ |
434 | - memset(s->buf, 0, 8); | 458 | + memset(outbuf, 0, 8); |
435 | bdrv_get_geometry(s->bdrv, &nb_sectors); | 459 | bdrv_get_geometry(s->bdrv, &nb_sectors); |
436 | /* Returned value is the address of the last sector. */ | 460 | /* Returned value is the address of the last sector. */ |
437 | if (nb_sectors) { | 461 | if (nb_sectors) { |
438 | nb_sectors--; | 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 | } else { | 472 | } else { |
449 | - scsi_command_complete(s, SENSE_NOT_READY); | 473 | + scsi_command_complete(r, SENSE_NOT_READY); |
450 | return 0; | 474 | return 0; |
451 | } | 475 | } |
452 | break; | 476 | break; |
453 | case 0x08: | 477 | case 0x08: |
454 | case 0x28: | 478 | case 0x28: |
455 | DPRINTF("Read (sector %d, count %d)\n", lba, len); | 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 | break; | 482 | break; |
459 | case 0x0a: | 483 | case 0x0a: |
460 | case 0x2a: | 484 | case 0x2a: |
461 | DPRINTF("Write (sector %d, count %d)\n", lba, len); | 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 | is_write = 1; | 488 | is_write = 1; |
465 | break; | 489 | break; |
466 | case 0x35: | 490 | case 0x35: |
@@ -478,18 +502,18 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | @@ -478,18 +502,18 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
478 | DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); | 502 | DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); |
479 | switch(format) { | 503 | switch(format) { |
480 | case 0: | 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 | break; | 506 | break; |
483 | case 1: | 507 | case 1: |
484 | /* multi session : only a single session defined */ | 508 | /* multi session : only a single session defined */ |
485 | toclen = 12; | 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 | break; | 514 | break; |
491 | case 2: | 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 | break; | 517 | break; |
494 | default: | 518 | default: |
495 | goto error_cmd; | 519 | goto error_cmd; |
@@ -497,7 +521,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | @@ -497,7 +521,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
497 | if (toclen > 0) { | 521 | if (toclen > 0) { |
498 | if (len > toclen) | 522 | if (len > toclen) |
499 | len = toclen; | 523 | len = toclen; |
500 | - s->buf_len = len; | 524 | + r->buf_len = len; |
501 | break; | 525 | break; |
502 | } | 526 | } |
503 | error_cmd: | 527 | error_cmd: |
@@ -506,11 +530,11 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | @@ -506,11 +530,11 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
506 | } | 530 | } |
507 | case 0x46: | 531 | case 0x46: |
508 | DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); | 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 | /* ??? This shoud probably return much more information. For now | 534 | /* ??? This shoud probably return much more information. For now |
511 | just return the basic header indicating the CD-ROM profile. */ | 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 | break; | 538 | break; |
515 | case 0x56: | 539 | case 0x56: |
516 | DPRINTF("Reserve(10)\n"); | 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,21 +550,27 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) | ||
526 | DPRINTF("Report LUNs (len %d)\n", len); | 550 | DPRINTF("Report LUNs (len %d)\n", len); |
527 | if (len < 16) | 551 | if (len < 16) |
528 | goto fail; | 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 | break; | 556 | break; |
533 | default: | 557 | default: |
534 | DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); | 558 | DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); |
535 | fail: | 559 | fail: |
536 | - scsi_command_complete(s, SENSE_ILLEGAL_REQUEST); | 560 | + scsi_command_complete(r, SENSE_ILLEGAL_REQUEST); |
537 | return 0; | 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 | void scsi_disk_destroy(SCSIDevice *s) | 576 | void scsi_disk_destroy(SCSIDevice *s) |
@@ -549,6 +579,7 @@ void scsi_disk_destroy(SCSIDevice *s) | @@ -549,6 +579,7 @@ void scsi_disk_destroy(SCSIDevice *s) | ||
549 | } | 579 | } |
550 | 580 | ||
551 | SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, | 581 | SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, |
582 | + int tcq, | ||
552 | scsi_completionfn completion, | 583 | scsi_completionfn completion, |
553 | void *opaque) | 584 | void *opaque) |
554 | { | 585 | { |
@@ -556,6 +587,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, | @@ -556,6 +587,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, | ||
556 | 587 | ||
557 | s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); | 588 | s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); |
558 | s->bdrv = bdrv; | 589 | s->bdrv = bdrv; |
590 | + s->tcq = tcq; | ||
559 | s->completion = completion; | 591 | s->completion = completion; |
560 | s->opaque = opaque; | 592 | s->opaque = opaque; |
561 | if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { | 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,6 +199,18 @@ uint32_t iommu_translate(uint32_t addr) | ||
199 | return iommu_translate_local(iommu, addr); | 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 | static void *slavio_misc; | 214 | static void *slavio_misc; |
203 | 215 | ||
204 | void qemu_system_powerdown(void) | 216 | void qemu_system_powerdown(void) |
hw/usb-msd.c
@@ -32,8 +32,12 @@ enum USBMSDMode { | @@ -32,8 +32,12 @@ enum USBMSDMode { | ||
32 | typedef struct { | 32 | typedef struct { |
33 | USBDevice dev; | 33 | USBDevice dev; |
34 | enum USBMSDMode mode; | 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 | uint32_t data_len; | 39 | uint32_t data_len; |
36 | - uint32_t transfer_len; | 40 | + uint32_t residue; |
37 | uint32_t tag; | 41 | uint32_t tag; |
38 | BlockDriverState *bs; | 42 | BlockDriverState *bs; |
39 | SCSIDevice *scsi_dev; | 43 | SCSIDevice *scsi_dev; |
@@ -42,6 +46,23 @@ typedef struct { | @@ -42,6 +46,23 @@ typedef struct { | ||
42 | USBPacket *packet; | 46 | USBPacket *packet; |
43 | } MSDState; | 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 | static const uint8_t qemu_msd_dev_descriptor[] = { | 66 | static const uint8_t qemu_msd_dev_descriptor[] = { |
46 | 0x12, /* u8 bLength; */ | 67 | 0x12, /* u8 bLength; */ |
47 | 0x01, /* u8 bDescriptorType; Device */ | 68 | 0x01, /* u8 bDescriptorType; Device */ |
@@ -107,26 +128,90 @@ static const uint8_t qemu_msd_config_descriptor[] = { | @@ -107,26 +128,90 @@ static const uint8_t qemu_msd_config_descriptor[] = { | ||
107 | 0x00 /* u8 ep_bInterval; */ | 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 | MSDState *s = (MSDState *)opaque; | 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 | if (reason == SCSI_REASON_DONE) { | 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,28 +336,12 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, | ||
251 | return ret; | 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 | static void usb_msd_cancel_io(USBPacket *p, void *opaque) | 339 | static void usb_msd_cancel_io(USBPacket *p, void *opaque) |
272 | { | 340 | { |
273 | MSDState *s = opaque; | 341 | MSDState *s = opaque; |
274 | - scsi_cancel_io(s->scsi_dev); | 342 | + scsi_cancel_io(s->scsi_dev, s->tag); |
275 | s->packet = NULL; | 343 | s->packet = NULL; |
344 | + s->scsi_len = 0; | ||
276 | } | 345 | } |
277 | 346 | ||
278 | static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) | 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,7 +349,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) | ||
280 | MSDState *s = (MSDState *)dev; | 349 | MSDState *s = (MSDState *)dev; |
281 | int ret = 0; | 350 | int ret = 0; |
282 | struct usb_msd_cbw cbw; | 351 | struct usb_msd_cbw cbw; |
283 | - struct usb_msd_csw csw; | ||
284 | uint8_t devep = p->devep; | 352 | uint8_t devep = p->devep; |
285 | uint8_t *data = p->data; | 353 | uint8_t *data = p->data; |
286 | int len = p->len; | 354 | int len = p->len; |
@@ -318,7 +386,17 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) | @@ -318,7 +386,17 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) | ||
318 | } | 386 | } |
319 | DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", | 387 | DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", |
320 | s->tag, cbw.flags, cbw.cmd_len, s->data_len); | 388 | s->tag, cbw.flags, cbw.cmd_len, s->data_len); |
389 | + s->residue = 0; | ||
321 | scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); | 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 | ret = len; | 400 | ret = len; |
323 | break; | 401 | break; |
324 | 402 | ||
@@ -327,17 +405,24 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) | @@ -327,17 +405,24 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) | ||
327 | if (len > s->data_len) | 405 | if (len > s->data_len) |
328 | goto fail; | 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 | DPRINTF("Deferring packet %p\n", p); | 420 | DPRINTF("Deferring packet %p\n", p); |
338 | usb_defer_packet(p, usb_msd_cancel_io, s); | 421 | usb_defer_packet(p, usb_msd_cancel_io, s); |
339 | s->packet = p; | 422 | s->packet = p; |
340 | ret = USB_RET_ASYNC; | 423 | ret = USB_RET_ASYNC; |
424 | + } else { | ||
425 | + ret = len; | ||
341 | } | 426 | } |
342 | break; | 427 | break; |
343 | 428 | ||
@@ -352,37 +437,51 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) | @@ -352,37 +437,51 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) | ||
352 | goto fail; | 437 | goto fail; |
353 | 438 | ||
354 | switch (s->mode) { | 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 | case USB_MSDM_CSW: | 449 | case USB_MSDM_CSW: |
356 | DPRINTF("Command status %d tag 0x%x, len %d\n", | 450 | DPRINTF("Command status %d tag 0x%x, len %d\n", |
357 | s->result, s->tag, len); | 451 | s->result, s->tag, len); |
358 | if (len < 13) | 452 | if (len < 13) |
359 | goto fail; | 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 | s->mode = USB_MSDM_CBW; | 458 | s->mode = USB_MSDM_CBW; |
459 | + ret = 13; | ||
368 | break; | 460 | break; |
369 | 461 | ||
370 | case USB_MSDM_DATAIN: | 462 | case USB_MSDM_DATAIN: |
371 | DPRINTF("Data in %d/%d\n", len, s->data_len); | 463 | DPRINTF("Data in %d/%d\n", len, s->data_len); |
372 | if (len > s->data_len) | 464 | if (len > s->data_len) |
373 | len = s->data_len; | 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 | DPRINTF("Deferring packet %p\n", p); | 479 | DPRINTF("Deferring packet %p\n", p); |
383 | usb_defer_packet(p, usb_msd_cancel_io, s); | 480 | usb_defer_packet(p, usb_msd_cancel_io, s); |
384 | s->packet = p; | 481 | s->packet = p; |
385 | ret = USB_RET_ASYNC; | 482 | ret = USB_RET_ASYNC; |
483 | + } else { | ||
484 | + ret = len; | ||
386 | } | 485 | } |
387 | break; | 486 | break; |
388 | 487 | ||
@@ -436,7 +535,7 @@ USBDevice *usb_msd_init(const char *filename) | @@ -436,7 +535,7 @@ USBDevice *usb_msd_init(const char *filename) | ||
436 | snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", | 535 | snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", |
437 | filename); | 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 | usb_msd_handle_reset((USBDevice *)s); | 539 | usb_msd_handle_reset((USBDevice *)s); |
441 | return (USBDevice *)s; | 540 | return (USBDevice *)s; |
442 | fail: | 541 | fail: |
vl.h
@@ -1025,12 +1025,20 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); | @@ -1025,12 +1025,20 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); | ||
1025 | 1025 | ||
1026 | /* sun4m.c */ | 1026 | /* sun4m.c */ |
1027 | extern QEMUMachine sun4m_machine; | 1027 | extern QEMUMachine sun4m_machine; |
1028 | -uint32_t iommu_translate(uint32_t addr); | ||
1029 | void pic_set_irq_cpu(int irq, int level, unsigned int cpu); | 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 | /* iommu.c */ | 1036 | /* iommu.c */ |
1032 | void *iommu_init(uint32_t addr); | 1037 | void *iommu_init(uint32_t addr); |
1038 | +/* ??? Remove iommu_translate_local. */ | ||
1033 | uint32_t iommu_translate_local(void *opaque, uint32_t addr); | 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 | /* lance.c */ | 1043 | /* lance.c */ |
1036 | void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr); | 1044 | void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr); |
@@ -1157,9 +1165,11 @@ enum scsi_reason { | @@ -1157,9 +1165,11 @@ enum scsi_reason { | ||
1157 | }; | 1165 | }; |
1158 | 1166 | ||
1159 | typedef struct SCSIDevice SCSIDevice; | 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 | SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, | 1171 | SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, |
1172 | + int tcq, | ||
1163 | scsi_completionfn completion, | 1173 | scsi_completionfn completion, |
1164 | void *opaque); | 1174 | void *opaque); |
1165 | void scsi_disk_destroy(SCSIDevice *s); | 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,9 +1178,10 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); | ||
1168 | /* SCSI data transfers are asynchrnonous. However, unlike the block IO | 1178 | /* SCSI data transfers are asynchrnonous. However, unlike the block IO |
1169 | layer the completion routine may be called directly by | 1179 | layer the completion routine may be called directly by |
1170 | scsi_{read,write}_data. */ | 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 | /* lsi53c895a.c */ | 1186 | /* lsi53c895a.c */ |
1176 | void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); | 1187 | void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); |