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); |