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