diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/bt/hci-csr.c | 67 | ||||
| -rw-r--r-- | hw/char/escc.c | 30 | ||||
| -rw-r--r-- | hw/char/etraxfs_ser.c | 27 | ||||
| -rw-r--r-- | hw/char/lm32_juart.c | 17 | ||||
| -rw-r--r-- | hw/char/lm32_uart.c | 28 | ||||
| -rw-r--r-- | hw/char/milkymist-uart.c | 10 | ||||
| -rw-r--r-- | hw/cris/axis_dev88.c | 4 | ||||
| -rw-r--r-- | hw/lm32/lm32.h | 19 | ||||
| -rw-r--r-- | hw/lm32/lm32_boards.c | 9 | ||||
| -rw-r--r-- | hw/lm32/milkymist-hw.h | 4 | ||||
| -rw-r--r-- | hw/lm32/milkymist.c | 4 | ||||
| -rw-r--r-- | hw/misc/ivshmem.c | 5 | ||||
| -rw-r--r-- | hw/scsi/megasas.c | 6 | ||||
| -rw-r--r-- | hw/scsi/mptsas.c | 9 | ||||
| -rw-r--r-- | hw/scsi/scsi-disk.c | 415 | ||||
| -rw-r--r-- | hw/scsi/scsi-generic.c | 12 | ||||
| -rw-r--r-- | hw/scsi/vmw_pvscsi.c | 24 | ||||
| -rw-r--r-- | hw/virtio/vhost-user.c | 25 |
18 files changed, 495 insertions, 220 deletions
diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c index e6b8998253..d688372ca3 100644 --- a/hw/bt/hci-csr.c +++ b/hw/bt/hci-csr.c @@ -39,9 +39,14 @@ struct csrhci_s { int out_size; uint8_t outfifo[FIFO_LEN * 2]; uint8_t inpkt[FIFO_LEN]; + enum { + CSR_HDR_LEN, + CSR_DATA_LEN, + CSR_DATA + } in_state; int in_len; int in_hdr; - int in_data; + int in_needed; QEMUTimer *out_tm; int64_t baud_delay; @@ -296,38 +301,60 @@ static int csrhci_data_len(const uint8_t *pkt) exit(-1); } +static void csrhci_ready_for_next_inpkt(struct csrhci_s *s) +{ + s->in_state = CSR_HDR_LEN; + s->in_len = 0; + s->in_needed = 2; + s->in_hdr = INT_MAX; +} + static int csrhci_write(struct CharDriverState *chr, const uint8_t *buf, int len) { struct csrhci_s *s = (struct csrhci_s *) chr->opaque; - int plen = s->in_len; + int total = 0; if (!s->enable) return 0; - s->in_len += len; - memcpy(s->inpkt + plen, buf, len); + for (;;) { + int cnt = MIN(len, s->in_needed - s->in_len); + if (cnt) { + memcpy(s->inpkt + s->in_len, buf, cnt); + s->in_len += cnt; + buf += cnt; + len -= cnt; + total += cnt; + } + + if (s->in_len < s->in_needed) { + break; + } - while (1) { - if (s->in_len >= 2 && plen < 2) + if (s->in_state == CSR_HDR_LEN) { s->in_hdr = csrhci_header_len(s->inpkt) + 1; + assert(s->in_hdr >= s->in_needed); + s->in_needed = s->in_hdr; + s->in_state = CSR_DATA_LEN; + continue; + } - if (s->in_len >= s->in_hdr && plen < s->in_hdr) - s->in_data = csrhci_data_len(s->inpkt) + s->in_hdr; + if (s->in_state == CSR_DATA_LEN) { + s->in_needed += csrhci_data_len(s->inpkt); + /* hci_acl_hdr could specify more than 4096 bytes, so assert. */ + assert(s->in_needed <= sizeof(s->inpkt)); + s->in_state = CSR_DATA; + continue; + } - if (s->in_len >= s->in_data) { + if (s->in_state == CSR_DATA) { csrhci_in_packet(s, s->inpkt); - - memmove(s->inpkt, s->inpkt + s->in_len, s->in_len - s->in_data); - s->in_len -= s->in_data; - s->in_hdr = INT_MAX; - s->in_data = INT_MAX; - plen = 0; - } else - break; + csrhci_ready_for_next_inpkt(s); + } } - return len; + return total; } static void csrhci_out_hci_packet_event(void *opaque, @@ -389,11 +416,9 @@ static void csrhci_reset(struct csrhci_s *s) { s->out_len = 0; s->out_size = FIFO_LEN; - s->in_len = 0; + csrhci_ready_for_next_inpkt(s); s->baud_delay = NANOSECONDS_PER_SECOND; s->enable = 0; - s->in_hdr = INT_MAX; - s->in_data = INT_MAX; s->modem_state = 0; /* After a while... (but sooner than 10ms) */ diff --git a/hw/char/escc.c b/hw/char/escc.c index 7bf09a0077..8e6a7df465 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -983,9 +983,10 @@ void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq, sysbus_mmio_map(s, 0, base); } -static int escc_init1(SysBusDevice *dev) +static void escc_init1(Object *obj) { - ESCCState *s = ESCC(dev); + ESCCState *s = ESCC(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); unsigned int i; s->chn[0].disabled = s->disabled; @@ -994,17 +995,26 @@ static int escc_init1(SysBusDevice *dev) sysbus_init_irq(dev, &s->chn[i].irq); s->chn[i].chn = 1 - i; s->chn[i].clock = s->frequency / 2; - if (s->chn[i].chr) { - qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, - serial_receive1, serial_event, &s->chn[i]); - } } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; - memory_region_init_io(&s->mmio, OBJECT(s), &escc_mem_ops, s, "escc", + memory_region_init_io(&s->mmio, obj, &escc_mem_ops, s, "escc", ESCC_SIZE << s->it_shift); sysbus_init_mmio(dev, &s->mmio); +} + +static void escc_realize(DeviceState *dev, Error **errp) +{ + ESCCState *s = ESCC(dev); + unsigned int i; + + for (i = 0; i < 2; i++) { + if (s->chn[i].chr) { + qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, + serial_receive1, serial_event, &s->chn[i]); + } + } if (s->chn[0].type == mouse) { qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, @@ -1014,8 +1024,6 @@ static int escc_init1(SysBusDevice *dev) s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]), &sunkbd_handler); } - - return 0; } static Property escc_properties[] = { @@ -1032,10 +1040,9 @@ static Property escc_properties[] = { static void escc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = escc_init1; dc->reset = escc_reset; + dc->realize = escc_realize; dc->vmsd = &vmstate_escc; dc->props = escc_properties; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); @@ -1045,6 +1052,7 @@ static const TypeInfo escc_info = { .name = TYPE_ESCC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ESCCState), + .instance_init = escc_init1, .class_init = escc_class_init, }; diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c index 146b387e7e..04ca04fe2c 100644 --- a/hw/char/etraxfs_ser.c +++ b/hw/char/etraxfs_ser.c @@ -159,6 +159,11 @@ static const MemoryRegionOps ser_ops = { } }; +static Property etraxfs_ser_properties[] = { + DEFINE_PROP_CHR("chardev", ETRAXSerial, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void serial_receive(void *opaque, const uint8_t *buf, int size) { ETRAXSerial *s = opaque; @@ -209,40 +214,42 @@ static void etraxfs_ser_reset(DeviceState *d) } -static int etraxfs_ser_init(SysBusDevice *dev) +static void etraxfs_ser_init(Object *obj) { - ETRAXSerial *s = ETRAX_SERIAL(dev); + ETRAXSerial *s = ETRAX_SERIAL(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); sysbus_init_irq(dev, &s->irq); - memory_region_init_io(&s->mmio, OBJECT(s), &ser_ops, s, + memory_region_init_io(&s->mmio, obj, &ser_ops, s, "etraxfs-serial", R_MAX * 4); sysbus_init_mmio(dev, &s->mmio); +} + +static void etraxfs_ser_realize(DeviceState *dev, Error **errp) +{ + ETRAXSerial *s = ETRAX_SERIAL(dev); - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, serial_can_receive, serial_receive, serial_event, s); } - return 0; } static void etraxfs_ser_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = etraxfs_ser_init; dc->reset = etraxfs_ser_reset; - /* Reason: init() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; + dc->props = etraxfs_ser_properties; + dc->realize = etraxfs_ser_realize; } static const TypeInfo etraxfs_ser_info = { .name = TYPE_ETRAX_FS_SERIAL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ETRAXSerial), + .instance_init = etraxfs_ser_init, .class_init = etraxfs_ser_class_init, }; diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c index 5bf8acfe8f..28c2cf702d 100644 --- a/hw/char/lm32_juart.c +++ b/hw/char/lm32_juart.c @@ -114,17 +114,13 @@ static void juart_reset(DeviceState *d) s->jrx = 0; } -static int lm32_juart_init(SysBusDevice *dev) +static void lm32_juart_realize(DeviceState *dev, Error **errp) { LM32JuartState *s = LM32_JUART(dev); - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s); } - - return 0; } static const VMStateDescription vmstate_lm32_juart = { @@ -138,16 +134,19 @@ static const VMStateDescription vmstate_lm32_juart = { } }; +static Property lm32_juart_properties[] = { + DEFINE_PROP_CHR("chardev", LM32JuartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void lm32_juart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = lm32_juart_init; dc->reset = juart_reset; dc->vmsd = &vmstate_lm32_juart; - /* Reason: init() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; + dc->props = lm32_juart_properties; + dc->realize = lm32_juart_realize; } static const TypeInfo lm32_juart_info = { diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c index 036813d0f3..b5c760dda3 100644 --- a/hw/char/lm32_uart.c +++ b/hw/char/lm32_uart.c @@ -249,23 +249,25 @@ static void uart_reset(DeviceState *d) s->regs[R_LSR] = LSR_THRE | LSR_TEMT; } -static int lm32_uart_init(SysBusDevice *dev) +static void lm32_uart_init(Object *obj) { - LM32UartState *s = LM32_UART(dev); + LM32UartState *s = LM32_UART(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); sysbus_init_irq(dev, &s->irq); - memory_region_init_io(&s->iomem, OBJECT(s), &uart_ops, s, + memory_region_init_io(&s->iomem, obj, &uart_ops, s, "uart", R_MAX * 4); sysbus_init_mmio(dev, &s->iomem); +} + +static void lm32_uart_realize(DeviceState *dev, Error **errp) +{ + LM32UartState *s = LM32_UART(dev); - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } - - return 0; } static const VMStateDescription vmstate_lm32_uart = { @@ -278,22 +280,26 @@ static const VMStateDescription vmstate_lm32_uart = { } }; +static Property lm32_uart_properties[] = { + DEFINE_PROP_CHR("chardev", LM32UartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void lm32_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = lm32_uart_init; dc->reset = uart_reset; dc->vmsd = &vmstate_lm32_uart; - /* Reason: init() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; + dc->props = lm32_uart_properties; + dc->realize = lm32_uart_realize; } static const TypeInfo lm32_uart_info = { .name = TYPE_LM32_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32UartState), + .instance_init = lm32_uart_init, .class_init = lm32_uart_class_init, }; diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c index 03b36b2236..72f8484668 100644 --- a/hw/char/milkymist-uart.c +++ b/hw/char/milkymist-uart.c @@ -200,8 +200,6 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp) { MilkymistUartState *s = MILKYMIST_UART(dev); - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } @@ -229,6 +227,11 @@ static const VMStateDescription vmstate_milkymist_uart = { } }; +static Property milkymist_uart_properties[] = { + DEFINE_PROP_CHR("chardev", MilkymistUartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void milkymist_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -236,8 +239,7 @@ static void milkymist_uart_class_init(ObjectClass *klass, void *data) dc->realize = milkymist_uart_realize; dc->reset = milkymist_uart_reset; dc->vmsd = &vmstate_milkymist_uart; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; + dc->props = milkymist_uart_properties; } static const TypeInfo milkymist_uart_info = { diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c index 9f58658741..60df8877c1 100644 --- a/hw/cris/axis_dev88.c +++ b/hw/cris/axis_dev88.c @@ -37,6 +37,7 @@ #include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" +#include "sysemu/sysemu.h" #define D(x) #define DNAND(x) @@ -341,8 +342,7 @@ void axisdev88_init(MachineState *machine) sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL); for (i = 0; i < 4; i++) { - sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000, - irq[0x14 + i]); + etraxfs_ser_create(0x30026000 + i * 0x2000, irq[0x14 + i], serial_hds[i]); } if (kernel_filename) { diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h index 18aa6fdc15..e338bfeae5 100644 --- a/hw/lm32/lm32.h +++ b/hw/lm32/lm32.h @@ -16,14 +16,31 @@ static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq) return dev; } -static inline DeviceState *lm32_juart_init(void) +static inline DeviceState *lm32_juart_init(CharDriverState *chr) { DeviceState *dev; dev = qdev_create(NULL, TYPE_LM32_JUART); + qdev_prop_set_chr(dev, "chardev", chr); qdev_init_nofail(dev); return dev; } +static inline DeviceState *lm32_uart_create(hwaddr addr, + qemu_irq irq, + CharDriverState *chr) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "lm32-uart"); + s = SYS_BUS_DEVICE(dev); + qdev_prop_set_chr(dev, "chardev", chr); + qdev_init_nofail(dev); + sysbus_mmio_map(s, 0, addr); + sysbus_connect_irq(s, 0, irq); + return dev; +} + #endif diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c index c0290560fc..8f0c3079d6 100644 --- a/hw/lm32/lm32_boards.c +++ b/hw/lm32/lm32_boards.c @@ -31,6 +31,7 @@ #include "lm32_hwsetup.h" #include "lm32.h" #include "exec/address-spaces.h" +#include "sysemu/sysemu.h" typedef struct { LM32CPU *cpu; @@ -131,12 +132,12 @@ static void lm32_evr_init(MachineState *machine) irq[i] = qdev_get_gpio_in(env->pic_state, i); } - sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]); + lm32_uart_create(uart0_base, irq[uart0_irq], serial_hds[0]); sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(); + env->juart_state = lm32_juart_init(serial_hds[1]); reset_info->bootstrap_pc = flash_base; @@ -232,13 +233,13 @@ static void lm32_uclinux_init(MachineState *machine) irq[i] = qdev_get_gpio_in(env->pic_state, i); } - sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]); + lm32_uart_create(uart0_base, irq[uart0_irq], serial_hds[0]); sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]); /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(); + env->juart_state = lm32_juart_init(serial_hds[1]); reset_info->bootstrap_pc = flash_base; diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h index f857d2846f..eb6a3a2559 100644 --- a/hw/lm32/milkymist-hw.h +++ b/hw/lm32/milkymist-hw.h @@ -5,11 +5,13 @@ #include "net/net.h" static inline DeviceState *milkymist_uart_create(hwaddr base, - qemu_irq irq) + qemu_irq irq, + CharDriverState *chr) { DeviceState *dev; dev = qdev_create(NULL, "milkymist-uart"); + qdev_prop_set_chr(dev, "chardev", chr); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c index 1abdf6e2e6..5cae0f19dd 100644 --- a/hw/lm32/milkymist.c +++ b/hw/lm32/milkymist.c @@ -159,7 +159,7 @@ milkymist_init(MachineState *machine) } g_free(bios_filename); - milkymist_uart_create(0x60000000, irq[0]); + milkymist_uart_create(0x60000000, irq[0], serial_hds[0]); milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3], 80000000, 0x10014d31, 0x0000041f, 0x00000001); milkymist_hpdmc_create(0x60002000); @@ -175,7 +175,7 @@ milkymist_init(MachineState *machine) 0x20000000, 0x1000, 0x20020000, 0x2000); /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(); + env->juart_state = lm32_juart_init(serial_hds[1]); if (kernel_filename) { uint64_t entry; diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index e40f23bfc2..90be9f7617 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -33,7 +33,6 @@ #include "sysemu/hostmem.h" #include "sysemu/qtest.h" #include "qapi/visitor.h" -#include "exec/ram_addr.h" #include "hw/misc/ivshmem.h" @@ -533,7 +532,7 @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp) } memory_region_init_ram_ptr(&s->server_bar2, OBJECT(s), "ivshmem.bar2", size, ptr); - qemu_set_ram_fd(memory_region_get_ram_addr(&s->server_bar2), fd); + memory_region_set_fd(&s->server_bar2, fd); s->ivshmem_bar2 = &s->server_bar2; } @@ -940,7 +939,7 @@ static void ivshmem_exit(PCIDevice *dev) strerror(errno)); } - fd = qemu_get_ram_fd(memory_region_get_ram_addr(s->ivshmem_bar2)); + fd = memory_region_get_fd(s->ivshmem_bar2); close(fd); } diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index a63a581550..cc66d36186 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -650,7 +650,9 @@ static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd) pa_hi = le32_to_cpu(initq->pi_addr_hi); s->producer_pa = ((uint64_t) pa_hi << 32) | pa_lo; s->reply_queue_head = ldl_le_pci_dma(pcid, s->producer_pa); + s->reply_queue_head %= MEGASAS_MAX_FRAMES; s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa); + s->reply_queue_tail %= MEGASAS_MAX_FRAMES; flags = le32_to_cpu(initq->flags); if (flags & MFI_QUEUE_FLAG_CONTEXT64) { s->flags |= MEGASAS_MASK_USE_QUEUE64; @@ -1293,7 +1295,7 @@ static int megasas_dcmd_ld_get_info(MegasasState *s, MegasasCmd *cmd) static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd) { - uint8_t data[4096]; + uint8_t data[4096] = { 0 }; struct mfi_config_data *info; int num_pd_disks = 0, array_offset, ld_offset; BusChild *kid; @@ -1446,7 +1448,7 @@ static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd) dcmd_size); return MFI_STAT_INVALID_PARAMETER; } - dma_buf_write((uint8_t *)&info, cmd->iov_size, &cmd->qsg); + dma_buf_write((uint8_t *)&info, dcmd_size, &cmd->qsg); trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size); return MFI_STAT_OK; } diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 499c1465ae..be88e161a9 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -754,11 +754,6 @@ static void mptsas_fetch_request(MPTSASState *s) hwaddr addr; int size; - if (s->state != MPI_IOC_STATE_OPERATIONAL) { - mptsas_set_fault(s, MPI_IOCSTATUS_INVALID_STATE); - return; - } - /* Read the message header from the guest first. */ addr = s->host_mfa_high_addr | MPTSAS_FIFO_GET(s, request_post); pci_dma_read(pci, addr, req, sizeof(hdr)); @@ -789,6 +784,10 @@ static void mptsas_fetch_requests(void *opaque) { MPTSASState *s = opaque; + if (s->state != MPI_IOC_STATE_OPERATIONAL) { + mptsas_set_fault(s, MPI_IOCSTATUS_INVALID_STATE); + return; + } while (!MPTSAS_FIFO_EMPTY(s, request_post)) { mptsas_fetch_request(s); } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 8865da53e8..ace65e0720 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -53,7 +53,21 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define DEFAULT_MAX_UNMAP_SIZE (1 << 30) /* 1 GB */ #define DEFAULT_MAX_IO_SIZE INT_MAX /* 2 GB - 1 block */ -typedef struct SCSIDiskState SCSIDiskState; +#define TYPE_SCSI_DISK_BASE "scsi-disk-base" + +#define SCSI_DISK_BASE(obj) \ + OBJECT_CHECK(SCSIDiskState, (obj), TYPE_SCSI_DISK_BASE) +#define SCSI_DISK_BASE_CLASS(klass) \ + OBJECT_CLASS_CHECK(SCSIDiskClass, (klass), TYPE_SCSI_DISK_BASE) +#define SCSI_DISK_BASE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SCSIDiskClass, (obj), TYPE_SCSI_DISK_BASE) + +typedef struct SCSIDiskClass { + SCSIDeviceClass parent_class; + DMAIOFunc *dma_readv; + DMAIOFunc *dma_writev; + bool (*need_fua_emulation)(SCSICommand *cmd); +} SCSIDiskClass; typedef struct SCSIDiskReq { SCSIRequest req; @@ -62,16 +76,18 @@ typedef struct SCSIDiskReq { uint32_t sector_count; uint32_t buflen; bool started; + bool need_fua_emulation; struct iovec iov; QEMUIOVector qiov; BlockAcctCookie acct; + unsigned char *status; } SCSIDiskReq; #define SCSI_DISK_F_REMOVABLE 0 #define SCSI_DISK_F_DPOFUA 1 #define SCSI_DISK_F_NO_REMOVABLE_DEVOPS 2 -struct SCSIDiskState +typedef struct SCSIDiskState { SCSIDevice qdev; uint32_t features; @@ -88,7 +104,7 @@ struct SCSIDiskState char *product; bool tray_open; bool tray_locked; -}; +} SCSIDiskState; static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed); @@ -161,6 +177,29 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) qemu_iovec_init_external(&r->qiov, &r->iov, 1); } +static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) +{ + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); + return true; + } + + if (ret < 0) { + return scsi_handle_rw_error(r, -ret, acct_failed); + } + + if (r->status && *r->status) { + if (acct_failed) { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); + } + scsi_req_complete(&r->req, *r->status); + return true; + } + + return false; +} + static void scsi_aio_complete(void *opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; @@ -168,17 +207,10 @@ static void scsi_aio_complete(void *opaque, int ret) assert(r->req.aiocb != NULL); r->req.aiocb = NULL; - if (r->req.io_canceled) { - scsi_req_cancel_complete(&r->req); + if (scsi_disk_req_check_error(r, ret, true)) { goto done; } - if (ret < 0) { - if (scsi_handle_rw_error(r, -ret, true)) { - goto done; - } - } - block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct); scsi_req_complete(&r->req, GOOD); @@ -217,13 +249,9 @@ static void scsi_write_do_fua(SCSIDiskReq *r) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); assert(r->req.aiocb == NULL); + assert(!r->req.io_canceled); - if (r->req.io_canceled) { - scsi_req_cancel_complete(&r->req); - goto done; - } - - if (scsi_is_cmd_fua(&r->req.cmd)) { + if (r->need_fua_emulation) { block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0, BLOCK_ACCT_FLUSH); r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r); @@ -231,26 +259,16 @@ static void scsi_write_do_fua(SCSIDiskReq *r) } scsi_req_complete(&r->req, GOOD); - -done: scsi_req_unref(&r->req); } static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret) { assert(r->req.aiocb == NULL); - - if (r->req.io_canceled) { - scsi_req_cancel_complete(&r->req); + if (scsi_disk_req_check_error(r, ret, false)) { goto done; } - if (ret < 0) { - if (scsi_handle_rw_error(r, -ret, false)) { - goto done; - } - } - r->sector += r->sector_count; r->sector_count = 0; if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { @@ -288,17 +306,10 @@ static void scsi_read_complete(void * opaque, int ret) assert(r->req.aiocb != NULL); r->req.aiocb = NULL; - if (r->req.io_canceled) { - scsi_req_cancel_complete(&r->req); + if (scsi_disk_req_check_error(r, ret, true)) { goto done; } - if (ret < 0) { - if (scsi_handle_rw_error(r, -ret, true)) { - goto done; - } - } - block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct); DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size); @@ -315,36 +326,29 @@ done: static void scsi_do_read(SCSIDiskReq *r, int ret) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); assert (r->req.aiocb == NULL); - - if (r->req.io_canceled) { - scsi_req_cancel_complete(&r->req); + if (scsi_disk_req_check_error(r, ret, false)) { goto done; } - if (ret < 0) { - if (scsi_handle_rw_error(r, -ret, false)) { - goto done; - } - } - /* The request is used as the AIO opaque value, so add a ref. */ scsi_req_ref(&r->req); if (r->req.sg) { dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_READ); r->req.resid -= r->req.sg->size; - r->req.aiocb = dma_blk_read(s->qdev.conf.blk, r->req.sg, - r->sector << BDRV_SECTOR_BITS, - scsi_dma_complete, r); + r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk), + r->req.sg, r->sector << BDRV_SECTOR_BITS, + sdc->dma_readv, r, scsi_dma_complete, r, + DMA_DIRECTION_FROM_DEVICE); } else { scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, r->qiov.size, BLOCK_ACCT_READ); - r->req.aiocb = blk_aio_preadv(s->qdev.conf.blk, - r->sector << BDRV_SECTOR_BITS, &r->qiov, - 0, scsi_read_complete, r); + r->req.aiocb = sdc->dma_readv(r->sector, &r->qiov, + scsi_read_complete, r, r); } done: @@ -399,7 +403,7 @@ static void scsi_read_data(SCSIRequest *req) first = !r->started; r->started = true; - if (first && scsi_is_cmd_fua(&r->req.cmd)) { + if (first && r->need_fua_emulation) { block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0, BLOCK_ACCT_FLUSH); r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r); @@ -456,18 +460,10 @@ static void scsi_write_complete_noio(SCSIDiskReq *r, int ret) uint32_t n; assert (r->req.aiocb == NULL); - - if (r->req.io_canceled) { - scsi_req_cancel_complete(&r->req); + if (scsi_disk_req_check_error(r, ret, false)) { goto done; } - if (ret < 0) { - if (scsi_handle_rw_error(r, -ret, false)) { - goto done; - } - } - n = r->qiov.size / 512; r->sector += n; r->sector_count -= n; @@ -504,6 +500,7 @@ static void scsi_write_data(SCSIRequest *req) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); /* No data transfer may already be in progress */ assert(r->req.aiocb == NULL); @@ -540,15 +537,15 @@ static void scsi_write_data(SCSIRequest *req) if (r->req.sg) { dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_WRITE); r->req.resid -= r->req.sg->size; - r->req.aiocb = dma_blk_write(s->qdev.conf.blk, r->req.sg, - r->sector << BDRV_SECTOR_BITS, - scsi_dma_complete, r); + r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk), + r->req.sg, r->sector << BDRV_SECTOR_BITS, + sdc->dma_writev, r, scsi_dma_complete, r, + DMA_DIRECTION_TO_DEVICE); } else { block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, r->qiov.size, BLOCK_ACCT_WRITE); - r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk, - r->sector << BDRV_SECTOR_BITS, &r->qiov, - 0, scsi_write_complete, r); + r->req.aiocb = sdc->dma_writev(r->sector << BDRV_SECTOR_BITS, &r->qiov, + scsi_write_complete, r, r); } } @@ -1600,18 +1597,10 @@ static void scsi_unmap_complete_noio(UnmapCBData *data, int ret) uint32_t nb_sectors; assert(r->req.aiocb == NULL); - - if (r->req.io_canceled) { - scsi_req_cancel_complete(&r->req); + if (scsi_disk_req_check_error(r, ret, false)) { goto done; } - if (ret < 0) { - if (scsi_handle_rw_error(r, -ret, false)) { - goto done; - } - } - if (data->count > 0) { sector_num = ldq_be_p(&data->inbuf[0]); nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL; @@ -1711,17 +1700,10 @@ static void scsi_write_same_complete(void *opaque, int ret) assert(r->req.aiocb != NULL); r->req.aiocb = NULL; - if (r->req.io_canceled) { - scsi_req_cancel_complete(&r->req); + if (scsi_disk_req_check_error(r, ret, true)) { goto done; } - if (ret < 0) { - if (scsi_handle_rw_error(r, -ret, true)) { - goto done; - } - } - block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct); data->nb_sectors -= data->iov.iov_len / 512; @@ -2138,6 +2120,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); uint32_t len; uint8_t command; @@ -2196,6 +2179,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); return 0; } + r->need_fua_emulation = sdc->need_fua_emulation(&r->req.cmd); if (r->sector_count == 0) { scsi_req_complete(&r->req, GOOD); } @@ -2578,16 +2562,145 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) scsi_generic_read_device_identification(&s->qdev); } +typedef struct SCSIBlockReq { + SCSIDiskReq req; + sg_io_hdr_t io_header; + + /* Selected bytes of the original CDB, copied into our own CDB. */ + uint8_t cmd, cdb1, group_number; + + /* CDB passed to SG_IO. */ + uint8_t cdb[16]; +} SCSIBlockReq; + +static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req, + int64_t offset, QEMUIOVector *iov, + int direction, + BlockCompletionFunc *cb, void *opaque) +{ + sg_io_hdr_t *io_header = &req->io_header; + SCSIDiskReq *r = &req->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + int nb_logical_blocks; + uint64_t lba; + BlockAIOCB *aiocb; + + /* This is not supported yet. It can only happen if the guest does + * reads and writes that are not aligned to one logical sectors + * _and_ cover multiple MemoryRegions. + */ + assert(offset % s->qdev.blocksize == 0); + assert(iov->size % s->qdev.blocksize == 0); + + io_header->interface_id = 'S'; + + /* The data transfer comes from the QEMUIOVector. */ + io_header->dxfer_direction = direction; + io_header->dxfer_len = iov->size; + io_header->dxferp = (void *)iov->iov; + io_header->iovec_count = iov->niov; + assert(io_header->iovec_count == iov->niov); /* no overflow! */ + + /* Build a new CDB with the LBA and length patched in, in case + * DMA helpers split the transfer in multiple segments. Do not + * build a CDB smaller than what the guest wanted, and only build + * a larger one if strictly necessary. + */ + io_header->cmdp = req->cdb; + lba = offset / s->qdev.blocksize; + nb_logical_blocks = io_header->dxfer_len / s->qdev.blocksize; + + if ((req->cmd >> 5) == 0 && lba <= 0x1ffff) { + /* 6-byte CDB */ + stl_be_p(&req->cdb[0], lba | (req->cmd << 24)); + req->cdb[4] = nb_logical_blocks; + req->cdb[5] = 0; + io_header->cmd_len = 6; + } else if ((req->cmd >> 5) <= 1 && lba <= 0xffffffffULL) { + /* 10-byte CDB */ + req->cdb[0] = (req->cmd & 0x1f) | 0x20; + req->cdb[1] = req->cdb1; + stl_be_p(&req->cdb[2], lba); + req->cdb[6] = req->group_number; + stw_be_p(&req->cdb[7], nb_logical_blocks); + req->cdb[9] = 0; + io_header->cmd_len = 10; + } else if ((req->cmd >> 5) != 4 && lba <= 0xffffffffULL) { + /* 12-byte CDB */ + req->cdb[0] = (req->cmd & 0x1f) | 0xA0; + req->cdb[1] = req->cdb1; + stl_be_p(&req->cdb[2], lba); + stl_be_p(&req->cdb[6], nb_logical_blocks); + req->cdb[10] = req->group_number; + req->cdb[11] = 0; + io_header->cmd_len = 12; + } else { + /* 16-byte CDB */ + req->cdb[0] = (req->cmd & 0x1f) | 0x80; + req->cdb[1] = req->cdb1; + stq_be_p(&req->cdb[2], lba); + stl_be_p(&req->cdb[10], nb_logical_blocks); + req->cdb[14] = req->group_number; + req->cdb[15] = 0; + io_header->cmd_len = 16; + } + + /* The rest is as in scsi-generic.c. */ + io_header->mx_sb_len = sizeof(r->req.sense); + io_header->sbp = r->req.sense; + io_header->timeout = UINT_MAX; + io_header->usr_ptr = r; + io_header->flags |= SG_FLAG_DIRECT_IO; + + aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque); + assert(aiocb != NULL); + return aiocb; +} + +static bool scsi_block_no_fua(SCSICommand *cmd) +{ + return false; +} + +static BlockAIOCB *scsi_block_dma_readv(int64_t offset, + QEMUIOVector *iov, + BlockCompletionFunc *cb, void *cb_opaque, + void *opaque) +{ + SCSIBlockReq *r = opaque; + return scsi_block_do_sgio(r, offset, iov, + SG_DXFER_FROM_DEV, cb, cb_opaque); +} + +static BlockAIOCB *scsi_block_dma_writev(int64_t offset, + QEMUIOVector *iov, + BlockCompletionFunc *cb, void *cb_opaque, + void *opaque) +{ + SCSIBlockReq *r = opaque; + return scsi_block_do_sgio(r, offset, iov, + SG_DXFER_TO_DEV, cb, cb_opaque); +} + static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) { switch (buf[0]) { + case VERIFY_10: + case VERIFY_12: + case VERIFY_16: + /* Check if BYTCHK == 0x01 (data-out buffer contains data + * for the number of logical blocks specified in the length + * field). For other modes, do not use scatter/gather operation. + */ + if ((buf[1] & 6) != 2) { + return false; + } + break; + case READ_6: case READ_10: case READ_12: case READ_16: - case VERIFY_10: - case VERIFY_12: - case VERIFY_16: case WRITE_6: case WRITE_10: case WRITE_12: @@ -2595,21 +2708,8 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) case WRITE_VERIFY_10: case WRITE_VERIFY_12: case WRITE_VERIFY_16: - /* If we are not using O_DIRECT, we might read stale data from the - * host cache if writes were made using other commands than these - * ones (such as WRITE SAME or EXTENDED COPY, etc.). So, without - * O_DIRECT everything must go through SG_IO. - */ - if (!(blk_get_flags(s->qdev.conf.blk) & BDRV_O_NOCACHE)) { - break; - } - - /* MMC writing cannot be done via pread/pwrite, because it sometimes + /* MMC writing cannot be done via DMA helpers, because it sometimes * involves writing beyond the maximum LBA or to negative LBA (lead-in). - * And once you do these writes, reading from the block device is - * unreliable, too. It is even possible that reads deliver random data - * from the host page cache (this is probably a Linux bug). - * * We might use scsi_disk_dma_reqops as long as no writing commands are * seen, but performance usually isn't paramount on optical media. So, * just make scsi-block operate the same as scsi-generic for them. @@ -2627,6 +2727,54 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) } +static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf) +{ + SCSIBlockReq *r = (SCSIBlockReq *)req; + r->cmd = req->cmd.buf[0]; + switch (r->cmd >> 5) { + case 0: + /* 6-byte CDB. */ + r->cdb1 = r->group_number = 0; + break; + case 1: + /* 10-byte CDB. */ + r->cdb1 = req->cmd.buf[1]; + r->group_number = req->cmd.buf[6]; + case 4: + /* 12-byte CDB. */ + r->cdb1 = req->cmd.buf[1]; + r->group_number = req->cmd.buf[10]; + break; + case 5: + /* 16-byte CDB. */ + r->cdb1 = req->cmd.buf[1]; + r->group_number = req->cmd.buf[14]; + break; + default: + abort(); + } + + if (r->cdb1 & 0xe0) { + /* Protection information is not supported. */ + scsi_check_condition(&r->req, SENSE_CODE(INVALID_FIELD)); + return 0; + } + + r->req.status = &r->io_header.status; + return scsi_disk_dma_command(req, buf); +} + +static const SCSIReqOps scsi_block_dma_reqops = { + .size = sizeof(SCSIBlockReq), + .free_req = scsi_free_request, + .send_command = scsi_block_dma_command, + .read_data = scsi_read_data, + .write_data = scsi_write_data, + .get_buf = scsi_get_buf, + .load_request = scsi_disk_load_request, + .save_request = scsi_disk_save_request, +}; + static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, void *hba_private) @@ -2637,7 +2785,7 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun, hba_private); } else { - return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun, + return scsi_req_alloc(&scsi_block_dma_reqops, &s->qdev, tag, lun, hba_private); } } @@ -2656,6 +2804,46 @@ static int scsi_block_parse_cdb(SCSIDevice *d, SCSICommand *cmd, #endif +static +BlockAIOCB *scsi_dma_readv(int64_t offset, QEMUIOVector *iov, + BlockCompletionFunc *cb, void *cb_opaque, + void *opaque) +{ + SCSIDiskReq *r = opaque; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + return blk_aio_preadv(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque); +} + +static +BlockAIOCB *scsi_dma_writev(int64_t offset, QEMUIOVector *iov, + BlockCompletionFunc *cb, void *cb_opaque, + void *opaque) +{ + SCSIDiskReq *r = opaque; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque); +} + +static void scsi_disk_base_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SCSIDiskClass *sdc = SCSI_DISK_BASE_CLASS(klass); + + dc->fw_name = "disk"; + dc->reset = scsi_disk_reset; + sdc->dma_readv = scsi_dma_readv; + sdc->dma_writev = scsi_dma_writev; + sdc->need_fua_emulation = scsi_is_cmd_fua; +} + +static const TypeInfo scsi_disk_base_info = { + .name = TYPE_SCSI_DISK_BASE, + .parent = TYPE_SCSI_DEVICE, + .class_init = scsi_disk_base_class_initfn, + .instance_size = sizeof(SCSIDiskState), + .class_size = sizeof(SCSIDiskClass), +}; + #define DEFINE_SCSI_DISK_PROPERTIES() \ DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \ DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ @@ -2703,17 +2891,14 @@ static void scsi_hd_class_initfn(ObjectClass *klass, void *data) sc->realize = scsi_hd_realize; sc->alloc_req = scsi_new_request; sc->unit_attention_reported = scsi_disk_unit_attention_reported; - dc->fw_name = "disk"; dc->desc = "virtual SCSI disk"; - dc->reset = scsi_disk_reset; dc->props = scsi_hd_properties; dc->vmsd = &vmstate_scsi_disk_state; } static const TypeInfo scsi_hd_info = { .name = "scsi-hd", - .parent = TYPE_SCSI_DEVICE, - .instance_size = sizeof(SCSIDiskState), + .parent = TYPE_SCSI_DISK_BASE, .class_init = scsi_hd_class_initfn, }; @@ -2735,17 +2920,14 @@ static void scsi_cd_class_initfn(ObjectClass *klass, void *data) sc->realize = scsi_cd_realize; sc->alloc_req = scsi_new_request; sc->unit_attention_reported = scsi_disk_unit_attention_reported; - dc->fw_name = "disk"; dc->desc = "virtual SCSI CD-ROM"; - dc->reset = scsi_disk_reset; dc->props = scsi_cd_properties; dc->vmsd = &vmstate_scsi_disk_state; } static const TypeInfo scsi_cd_info = { .name = "scsi-cd", - .parent = TYPE_SCSI_DEVICE, - .instance_size = sizeof(SCSIDiskState), + .parent = TYPE_SCSI_DISK_BASE, .class_init = scsi_cd_class_initfn, }; @@ -2759,21 +2941,22 @@ static void scsi_block_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); + SCSIDiskClass *sdc = SCSI_DISK_BASE_CLASS(klass); sc->realize = scsi_block_realize; sc->alloc_req = scsi_block_new_request; sc->parse_cdb = scsi_block_parse_cdb; - dc->fw_name = "disk"; + sdc->dma_readv = scsi_block_dma_readv; + sdc->dma_writev = scsi_block_dma_writev; + sdc->need_fua_emulation = scsi_block_no_fua; dc->desc = "SCSI block device passthrough"; - dc->reset = scsi_disk_reset; dc->props = scsi_block_properties; dc->vmsd = &vmstate_scsi_disk_state; } static const TypeInfo scsi_block_info = { .name = "scsi-block", - .parent = TYPE_SCSI_DEVICE, - .instance_size = sizeof(SCSIDiskState), + .parent = TYPE_SCSI_DISK_BASE, .class_init = scsi_block_class_initfn, }; #endif @@ -2811,13 +2994,13 @@ static void scsi_disk_class_initfn(ObjectClass *klass, void *data) static const TypeInfo scsi_disk_info = { .name = "scsi-disk", - .parent = TYPE_SCSI_DEVICE, - .instance_size = sizeof(SCSIDiskState), + .parent = TYPE_SCSI_DISK_BASE, .class_init = scsi_disk_class_initfn, }; static void scsi_disk_register_types(void) { + type_register_static(&scsi_disk_base_info); type_register_static(&scsi_hd_info); type_register_static(&scsi_cd_info); #ifdef __linux__ diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 7459465f60..71372a8383 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -222,6 +222,18 @@ static void scsi_read_complete(void * opaque, int ret) r->buf[3] |= 0x80; } } + if (s->type == TYPE_DISK && + r->req.cmd.buf[0] == INQUIRY && + r->req.cmd.buf[2] == 0xb0) { + uint32_t max_xfer_len = blk_get_max_transfer_length(s->conf.blk); + if (max_xfer_len) { + stl_be_p(&r->buf[8], max_xfer_len); + /* Also take care of the opt xfer len. */ + if (ldl_be_p(&r->buf[12]) > max_xfer_len) { + stl_be_p(&r->buf[12], max_xfer_len); + } + } + } scsi_req_data(&r->req, len); scsi_req_unref(&r->req); } diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index f67b5bf7d3..2d7528d1dd 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -153,7 +153,7 @@ pvscsi_log2(uint32_t input) return log; } -static void +static int pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri) { int i; @@ -161,6 +161,10 @@ pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri) uint32_t req_ring_size, cmp_ring_size; m->rs_pa = ri->ringsStatePPN << VMW_PAGE_SHIFT; + if ((ri->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) + || (ri->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)) { + return -1; + } req_ring_size = ri->reqRingNumPages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; cmp_ring_size = ri->cmpRingNumPages * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE; txr_len_log2 = pvscsi_log2(req_ring_size - 1); @@ -192,15 +196,20 @@ pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri) /* Flush ring state page changes */ smp_wmb(); + + return 0; } -static void +static int pvscsi_ring_init_msg(PVSCSIRingInfo *m, PVSCSICmdDescSetupMsgRing *ri) { int i; uint32_t len_log2; uint32_t ring_size; + if (ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) { + return -1; + } ring_size = ri->numPages * PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE; len_log2 = pvscsi_log2(ring_size - 1); @@ -220,6 +229,8 @@ pvscsi_ring_init_msg(PVSCSIRingInfo *m, PVSCSICmdDescSetupMsgRing *ri) /* Flush ring state page changes */ smp_wmb(); + + return 0; } static void @@ -770,7 +781,10 @@ pvscsi_on_cmd_setup_rings(PVSCSIState *s) trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_RINGS"); pvscsi_dbg_dump_tx_rings_config(rc); - pvscsi_ring_init_data(&s->rings, rc); + if (pvscsi_ring_init_data(&s->rings, rc) < 0) { + return PVSCSI_COMMAND_PROCESSING_FAILED; + } + s->rings_info_valid = TRUE; return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; } @@ -850,7 +864,9 @@ pvscsi_on_cmd_setup_msg_ring(PVSCSIState *s) } if (s->rings_info_valid) { - pvscsi_ring_init_msg(&s->rings, rc); + if (pvscsi_ring_init_msg(&s->rings, rc) < 0) { + return PVSCSI_COMMAND_PROCESSING_FAILED; + } s->msg_ring_info_valid = TRUE; } return sizeof(PVSCSICmdDescSetupMsgRing) / sizeof(uint32_t); diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 5914e85107..495e09fd4e 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -17,7 +17,6 @@ #include "sysemu/kvm.h" #include "qemu/error-report.h" #include "qemu/sockets.h" -#include "exec/ram_addr.h" #include "migration/migration.h" #include <sys/ioctl.h> @@ -247,18 +246,18 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, for (i = 0; i < dev->mem->nregions; ++i) { struct vhost_memory_region *reg = dev->mem->regions + i; - ram_addr_t ram_addr; + ram_addr_t offset; + MemoryRegion *mr; assert((uintptr_t)reg->userspace_addr == reg->userspace_addr); - qemu_ram_addr_from_host((void *)(uintptr_t)reg->userspace_addr, - &ram_addr); - fd = qemu_get_ram_fd(ram_addr); + mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr, + &offset); + fd = memory_region_get_fd(mr); if (fd > 0) { msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr; msg.payload.memory.regions[fd_num].memory_size = reg->memory_size; msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr; - msg.payload.memory.regions[fd_num].mmap_offset = reg->userspace_addr - - (uintptr_t) qemu_get_ram_block_host_ptr(ram_addr); + msg.payload.memory.regions[fd_num].mmap_offset = offset; assert(fd_num < VHOST_MEMORY_MAX_NREGIONS); fds[fd_num++] = fd; } @@ -616,17 +615,15 @@ static bool vhost_user_can_merge(struct vhost_dev *dev, uint64_t start1, uint64_t size1, uint64_t start2, uint64_t size2) { - ram_addr_t ram_addr; + ram_addr_t offset; int mfd, rfd; MemoryRegion *mr; - mr = qemu_ram_addr_from_host((void *)(uintptr_t)start1, &ram_addr); - assert(mr); - mfd = qemu_get_ram_fd(ram_addr); + mr = memory_region_from_host((void *)(uintptr_t)start1, &offset); + mfd = memory_region_get_fd(mr); - mr = qemu_ram_addr_from_host((void *)(uintptr_t)start2, &ram_addr); - assert(mr); - rfd = qemu_get_ram_fd(ram_addr); + mr = memory_region_from_host((void *)(uintptr_t)start2, &offset); + rfd = memory_region_get_fd(mr); return mfd == rfd; } |