From 2d38853239ac17984e81fee169d80384784c6401 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 28 Oct 2014 16:47:54 +0800 Subject: [PATCH 01/35] rules.mak: Allow .mo-objs and .mo-cflags in -y variables Expand %.mo-objs in -y nested objects, so that we can write combined object -cflags rules like what will be done in the coming patch. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- rules.mak | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rules.mak b/rules.mak index cf76b88d26..f500fefdd1 100644 --- a/rules.mak +++ b/rules.mak @@ -362,4 +362,9 @@ define unnest-vars # Include all the .d files $(eval -include $(addsuffix *.d, $(sort $(dir $($v))))) $(eval $v := $(filter-out %/,$($v)))) + + # For all %.mo objects that are directly added into -y, expand them to %.mo-objs + $(foreach v,$2, + $(eval $v := $(foreach o,$($v),$(if $($o-objs),$($o-objs),$o)))) + endef From 98001e7b085b19b2b03ca5fdf44d063c204cc325 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 28 Oct 2014 16:47:55 +0800 Subject: [PATCH 02/35] ui: Use the new ".mo-cflags" rule syntax for SDL_CFLAGS Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- ui/Makefile.objs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 6afb52a93c..801cba2675 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -10,12 +10,13 @@ vnc-obj-y += vnc-jobs.o common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o common-obj-y += input.o input-keymap.o input-legacy.o common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o -common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o sdl2.o +common-obj-$(CONFIG_SDL) += sdl.mo x_keymap.o common-obj-$(CONFIG_COCOA) += cocoa.o common-obj-$(CONFIG_CURSES) += curses.o common-obj-$(CONFIG_VNC) += $(vnc-obj-y) common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o -$(obj)/sdl.o $(obj)/sdl_zoom.o $(obj)/sdl2.o: QEMU_CFLAGS += $(SDL_CFLAGS) +sdl.mo-objs := sdl.o sdl_zoom.o sdl2.o +sdl.mo-cflags := $(SDL_CFLAGS) gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) From 1894df02811f6b79ea3ffbf1084599d96f316173 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:04 +0100 Subject: [PATCH 03/35] scsi: Rename scsi_*_length() to scsi_*_xfer(), add scsi_cdb_length() scsi_cdb_length() does not return the length of the cdb, but the transfersize encoded in the cdb. So rename it to scsi_cdb_xfer() and also rename all other related functions to end with _xfer. We can then add a new scsi_cdb_length() which actually does return the length of the cdb. With that DEBUG_SCSI can now display the correct CDB buffer. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 73 +++++++++++++++++++++++------------------- hw/scsi/scsi-disk.c | 6 ++-- include/hw/scsi/scsi.h | 5 +-- 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index af7707cf27..6fce8471d4 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -826,7 +826,7 @@ static int ata_passthrough_xfer_unit(SCSIDevice *dev, uint8_t *buf) return xfer_unit; } -static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf) +static int ata_passthrough_12_xfer(SCSIDevice *dev, uint8_t *buf) { int length = buf[2] & 0x3; int xfer; @@ -849,7 +849,7 @@ static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf) return xfer * unit; } -static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf) +static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf) { int extend = buf[1] & 0x1; int length = buf[2] & 0x3; @@ -875,16 +875,16 @@ static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf) return xfer * unit; } -uint32_t scsi_data_cdb_length(uint8_t *buf) +uint32_t scsi_data_cdb_xfer(uint8_t *buf) { if ((buf[0] >> 5) == 0 && buf[4] == 0) { return 256; } else { - return scsi_cdb_length(buf); + return scsi_cdb_xfer(buf); } } -uint32_t scsi_cdb_length(uint8_t *buf) +uint32_t scsi_cdb_xfer(uint8_t *buf) { switch (buf[0] >> 5) { case 0: @@ -905,9 +905,9 @@ uint32_t scsi_cdb_length(uint8_t *buf) } } -static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) { - cmd->xfer = scsi_cdb_length(buf); + cmd->xfer = scsi_cdb_xfer(buf); switch (buf[0]) { case TEST_UNIT_READY: case REWIND: @@ -1038,17 +1038,17 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) /* BLANK command of MMC */ cmd->xfer = 0; } else { - cmd->xfer = ata_passthrough_12_xfer_size(dev, buf); + cmd->xfer = ata_passthrough_12_xfer(dev, buf); } break; case ATA_PASSTHROUGH_16: - cmd->xfer = ata_passthrough_16_xfer_size(dev, buf); + cmd->xfer = ata_passthrough_16_xfer(dev, buf); break; } return 0; } -static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +static int scsi_req_stream_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) { switch (buf[0]) { /* stream commands */ @@ -1103,12 +1103,12 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu break; /* generic commands */ default: - return scsi_req_length(cmd, dev, buf); + return scsi_req_xfer(cmd, dev, buf); } return 0; } -static int scsi_req_medium_changer_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +static int scsi_req_medium_changer_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) { switch (buf[0]) { /* medium changer commands */ @@ -1125,7 +1125,7 @@ static int scsi_req_medium_changer_length(SCSICommand *cmd, SCSIDevice *dev, uin /* generic commands */ default: - return scsi_req_length(cmd, dev, buf); + return scsi_req_xfer(cmd, dev, buf); } return 0; } @@ -1214,38 +1214,45 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd) return lba; } +int scsi_cdb_length(uint8_t *buf) { + int cdb_len; + + switch (buf[0] >> 5) { + case 0: + cdb_len = 6; + break; + case 1: + case 2: + cdb_len = 10; + break; + case 4: + cdb_len = 16; + break; + case 5: + cdb_len = 12; + break; + default: + cdb_len = -1; + } + return cdb_len; +} + int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf) { int rc; cmd->lba = -1; - switch (buf[0] >> 5) { - case 0: - cmd->len = 6; - break; - case 1: - case 2: - cmd->len = 10; - break; - case 4: - cmd->len = 16; - break; - case 5: - cmd->len = 12; - break; - default: - return -1; - } + cmd->len = scsi_cdb_length(buf); switch (dev->type) { case TYPE_TAPE: - rc = scsi_req_stream_length(cmd, dev, buf); + rc = scsi_req_stream_xfer(cmd, dev, buf); break; case TYPE_MEDIUM_CHANGER: - rc = scsi_req_medium_changer_length(cmd, dev, buf); + rc = scsi_req_medium_changer_xfer(cmd, dev, buf); break; default: - rc = scsi_req_length(cmd, dev, buf); + rc = scsi_req_xfer(cmd, dev, buf); break; } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 010eefd443..7b58488b0e 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1666,7 +1666,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) { SCSIRequest *req = &r->req; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); - uint32_t nb_sectors = scsi_data_cdb_length(r->req.cmd.buf); + uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf); WriteSameCBData *data; uint8_t *buf; int i; @@ -2061,7 +2061,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) return 0; } - len = scsi_data_cdb_length(r->req.cmd.buf); + len = scsi_data_cdb_xfer(r->req.cmd.buf); switch (command) { case READ_6: case READ_10: @@ -2396,7 +2396,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); { int i; - for (i = 1; i < req->cmd.len; i++) { + for (i = 1; i < scsi_cdb_length(buf); i++) { printf(" 0x%02x", buf[i]); } printf("\n"); diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 6bc841ab8b..fd48177fa6 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -239,8 +239,9 @@ extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED; #define SENSE_CODE(x) sense_code_ ## x -uint32_t scsi_data_cdb_length(uint8_t *buf); -uint32_t scsi_cdb_length(uint8_t *buf); +uint32_t scsi_data_cdb_xfer(uint8_t *buf); +uint32_t scsi_cdb_xfer(uint8_t *buf); +int scsi_cdb_length(uint8_t *buf); int scsi_sense_valid(SCSISense sense); int scsi_build_sense(uint8_t *in_buf, int in_len, uint8_t *buf, int len, bool fixed); From d97ae3684863960d12633c845f648d50ce767273 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:05 +0100 Subject: [PATCH 04/35] megasas: fixup MFI_DCMD_LD_LIST_QUERY The MFI_DCMD_LD_LIST_QUERY function is using a different format than MFI_DCMD_LD_LIST, so we need to implement it differently. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 37 ++++++++++++++++++++++++++++++++++--- hw/scsi/mfi.h | 7 +++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 36a04f31bb..562c35bede 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -1123,15 +1123,46 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd) { uint16_t flags; + struct mfi_ld_targetid_list info; + size_t dcmd_size = sizeof(info), resid; + uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns; + BusChild *kid; /* mbox0 contains flags */ flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]); trace_megasas_dcmd_ld_list_query(cmd->index, flags); - if (flags == MR_LD_QUERY_TYPE_ALL || - flags == MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) { - return megasas_dcmd_ld_get_list(s, cmd); + if (flags != MR_LD_QUERY_TYPE_ALL && + flags != MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) { + max_ld_disks = 0; } + memset(&info, 0, dcmd_size); + if (cmd->iov_size < 12) { + trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, + dcmd_size); + return MFI_STAT_INVALID_PARAMETER; + } + dcmd_size = sizeof(uint32_t) * 2 + 3; + + if (megasas_is_jbod(s)) { + max_ld_disks = 0; + } + QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { + SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); + + if (num_ld_disks >= max_ld_disks) { + break; + } + info.targetid[num_ld_disks] = sdev->lun; + num_ld_disks++; + dcmd_size++; + } + info.ld_count = cpu_to_le32(num_ld_disks); + info.size = dcmd_size; + trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks); + + resid = dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg); + cmd->iov_size = dcmd_size - resid; return MFI_STAT_OK; } diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h index a3034f6239..5050ce4732 100644 --- a/hw/scsi/mfi.h +++ b/hw/scsi/mfi.h @@ -1111,6 +1111,13 @@ struct mfi_ld_list { } ld_list[MFI_MAX_LD]; } QEMU_PACKED; +struct mfi_ld_targetid_list { + uint32_t size; + uint32_t ld_count; + uint8_t pad[3]; + uint8_t targetid[MFI_MAX_LD]; +} QEMU_PACKED; + enum mfi_ld_access { MFI_LD_ACCESS_RW = 0, MFI_LD_ACCSSS_RO = 2, From 7bd908491c4e62767fa959959f3560fb54e34c19 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:06 +0100 Subject: [PATCH 05/35] megasas: simplify trace event messages The trace events already contain the function name, so the actual message doesn't need to contain any of these informations. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- trace-events | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/trace-events b/trace-events index 6c3a4003c1..c5ebfc8a03 100644 --- a/trace-events +++ b/trace-events @@ -698,34 +698,34 @@ megasas_init_firmware(uint64_t pa) "pa %" PRIx64 " " megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at %" PRIx64 " len %d head %" PRIx64 " tail %" PRIx64 " flags %x" megasas_initq_map_failed(int frame) "scmd %d: failed to map queue" megasas_initq_mismatch(int queue_len, int fw_cmds) "queue size %d max fw cmds %d" -megasas_qf_found(unsigned int index, uint64_t pa) "found mapped frame %x pa %" PRIx64 "" +megasas_qf_found(unsigned int index, uint64_t pa) "mapped frame %x pa %" PRIx64 "" megasas_qf_new(unsigned int index, void *cmd) "return new frame %x cmd %p" megasas_qf_failed(unsigned long pa) "all frames busy for frame %lx" megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int tail, int busy) "enqueue frame %x count %d context %" PRIx64 " tail %x busy %d" -megasas_qf_update(unsigned int head, unsigned int busy) "update reply queue head %x busy %d" +megasas_qf_update(unsigned int head, unsigned int busy) "reply queue head %x busy %d" megasas_qf_map_failed(int cmd, unsigned long frame) "scmd %d: frame %lu" megasas_qf_complete_noirq(uint64_t context) "context %" PRIx64 " " megasas_qf_complete(uint64_t context, unsigned int tail, unsigned int offset, int busy, unsigned int doorbell) "context %" PRIx64 " tail %x offset %d busy %d doorbell %x" megasas_frame_busy(uint64_t addr) "frame %" PRIx64 " busy" -megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: Unhandled MFI cmd %x" +megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: MFI cmd %x" megasas_handle_scsi(const char *frame, int bus, int dev, int lun, void *sdev, unsigned long size) "%s dev %x/%x/%x sdev %p xfer %lu" -megasas_scsi_target_not_present(const char *frame, int bus, int dev, int lun) "%s dev %x/%x/%x target not present" +megasas_scsi_target_not_present(const char *frame, int bus, int dev, int lun) "%s dev %x/%x/%x" megasas_scsi_invalid_cdb_len(const char *frame, int bus, int dev, int lun, int len) "%s dev %x/%x/%x invalid cdb len %d" megasas_iov_read_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes" megasas_iov_write_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes" megasas_iov_read_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes" megasas_iov_write_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes" -megasas_scsi_req_alloc_failed(const char *frame, int dev, int lun) "%s dev %x/%x req allocation failed" +megasas_scsi_req_alloc_failed(const char *frame, int dev, int lun) "%s dev %x/%x" megasas_scsi_read_start(int cmd, int len) "scmd %d: transfer %d bytes of data" megasas_scsi_write_start(int cmd, int len) "scmd %d: transfer %d bytes of data" megasas_scsi_nodata(int cmd) "scmd %d: no data to be transferred" -megasas_scsi_complete(int cmd, uint32_t status, int len, int xfer) "scmd %d: finished with status %x, len %u/%u" -megasas_command_complete(int cmd, uint32_t status, uint32_t resid) "scmd %d: command completed, status %x, residual %d" +megasas_scsi_complete(int cmd, uint32_t status, int len, int xfer) "scmd %d: status %x, len %u/%u" +megasas_command_complete(int cmd, uint32_t status, uint32_t resid) "scmd %d: status %x, residual %d" megasas_handle_io(int cmd, const char *frame, int dev, int lun, unsigned long lba, unsigned long count) "scmd %d: %s dev %x/%x lba %lx count %lu" megasas_io_target_not_present(int cmd, const char *frame, int dev, int lun) "scmd %d: %s dev 1/%x/%x LUN not present" megasas_io_read_start(int cmd, unsigned long lba, unsigned long count, unsigned long len) "scmd %d: start LBA %lx %lu blocks (%lu bytes)" megasas_io_write_start(int cmd, unsigned long lba, unsigned long count, unsigned long len) "scmd %d: start LBA %lx %lu blocks (%lu bytes)" -megasas_io_complete(int cmd, uint32_t len) "scmd %d: %d bytes completed" +megasas_io_complete(int cmd, uint32_t len) "scmd %d: %d bytes" megasas_iovec_sgl_overflow(int cmd, int index, int limit) "scmd %d: iovec count %d limit %d" megasas_iovec_sgl_underflow(int cmd, int index) "scmd %d: iovec count %d" megasas_iovec_sgl_invalid(int cmd, int index, uint64_t pa, uint32_t len) "scmd %d: element %d pa %" PRIx64 " len %u" @@ -733,25 +733,25 @@ megasas_iovec_overflow(int cmd, int len, int limit) "scmd %d: len %d limit %d" megasas_iovec_underflow(int cmd, int len, int limit) "scmd %d: len %d limit %d" megasas_handle_dcmd(int cmd, int opcode) "scmd %d: MFI DCMD opcode %x" megasas_finish_dcmd(int cmd, int size) "scmd %d: MFI DCMD wrote %d bytes" -megasas_dcmd_req_alloc_failed(int cmd, const char *desc) "scmd %d: %s alloc failed" +megasas_dcmd_req_alloc_failed(int cmd, const char *desc) "scmd %d: %s" megasas_dcmd_internal_submit(int cmd, const char *desc, int dev) "scmd %d: %s to dev %d" -megasas_dcmd_internal_finish(int cmd, int opcode, int lun) "scmd %d: DCMD finish internal cmd %x lun %d" -megasas_dcmd_internal_invalid(int cmd, int opcode) "scmd %d: Invalid internal DCMD %x" +megasas_dcmd_internal_finish(int cmd, int opcode, int lun) "scmd %d: cmd %x lun %d" +megasas_dcmd_internal_invalid(int cmd, int opcode) "scmd %d: DCMD %x" megasas_dcmd_unhandled(int cmd, int opcode, int len) "scmd %d: opcode %x, len %d" megasas_dcmd_zero_sge(int cmd) "scmd %d: zero DCMD sge count" -megasas_dcmd_invalid_sge(int cmd, int count) "scmd %d: invalid DCMD sge count %d" -megasas_dcmd_invalid_xfer_len(int cmd, unsigned long size, unsigned long max) "scmd %d: invalid xfer len %ld, max %ld" +megasas_dcmd_invalid_sge(int cmd, int count) "scmd %d: DCMD sge count %d" +megasas_dcmd_invalid_xfer_len(int cmd, unsigned long size, unsigned long max) "scmd %d: xfer len %ld, max %ld" megasas_dcmd_enter(int cmd, const char *dcmd, int len) "scmd %d: DCMD %s len %d" -megasas_dcmd_dummy(int cmd, unsigned long size) "scmd %d: DCMD dummy xfer len %ld" +megasas_dcmd_dummy(int cmd, unsigned long size) "scmd %d: xfer len %ld" megasas_dcmd_set_fw_time(int cmd, unsigned long time) "scmd %d: Set FW time %lx" megasas_dcmd_pd_get_list(int cmd, int num, int max, int offset) "scmd %d: DCMD PD get list: %d / %d PDs, size %d" megasas_dcmd_ld_get_list(int cmd, int num, int max) "scmd %d: DCMD LD get list: found %d / %d LDs" -megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: DCMD LD get info for dev %d" -megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: DCMD PD get info for dev %d" -megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: DCMD PD list query flags %x" -megasas_dcmd_ld_list_query(int cmd, int flags) "scmd %d: DCMD LD list query flags %x" +megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: dev %d" +megasas_dcmd_ld_list_query(int cmd, int flags) "scmd %d: query flags %x" +megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: dev %d" +megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: query flags %x" megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld" -megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: aborting frame %x" +megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: frame %x" megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 "" megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x" megasas_reset(void) "Reset" From 3f2cd4dd47719497540fb0e0aa0635e127f2838f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:07 +0100 Subject: [PATCH 06/35] megasas: fixup device mapping Logical drives can only be addressed with the 'target_id' number; LUN numbers cannot be selected. Physical drives can be selected with both, target and LUN id. So we should disallow LUN numbers not equal to 0 when in RAID mode. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 95 ++++++++++++++++++++++++++++++----------------- hw/scsi/mfi.h | 2 +- 2 files changed, 61 insertions(+), 36 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 562c35bede..3a7e85e75e 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -689,8 +689,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) struct mfi_ctrl_info info; size_t dcmd_size = sizeof(info); BusChild *kid; - int num_ld_disks = 0; - uint16_t sdev_id; + int num_pd_disks = 0; memset(&info, 0x0, cmd->iov_size); if (cmd->iov_size < dcmd_size) { @@ -719,13 +718,14 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) info.device.port_count = 8; QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); + uint16_t pd_id; - if (num_ld_disks < 8) { - sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF); - info.device.port_addr[num_ld_disks] = - cpu_to_le64(megasas_get_sata_addr(sdev_id)); + if (num_pd_disks < 8) { + pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF); + info.device.port_addr[num_pd_disks] = + cpu_to_le64(megasas_get_sata_addr(pd_id)); } - num_ld_disks++; + num_pd_disks++; } memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20); @@ -751,13 +751,14 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) info.max_arms = 32; info.max_spans = 8; info.max_arrays = MEGASAS_MAX_ARRAYS; - info.max_lds = s->fw_luns; + info.max_lds = MFI_MAX_LD; info.max_cmds = cpu_to_le16(s->fw_cmds); info.max_sg_elements = cpu_to_le16(s->fw_sge); info.max_request_size = cpu_to_le32(MEGASAS_MAX_SECTORS); - info.lds_present = cpu_to_le16(num_ld_disks); - info.pd_present = cpu_to_le16(num_ld_disks); - info.pd_disks_present = cpu_to_le16(num_ld_disks); + if (!megasas_is_jbod(s)) + info.lds_present = cpu_to_le16(num_pd_disks); + info.pd_present = cpu_to_le16(num_pd_disks); + info.pd_disks_present = cpu_to_le16(num_pd_disks); info.hw_present = cpu_to_le32(MFI_INFO_HW_NVRAM | MFI_INFO_HW_MEM | MFI_INFO_HW_FLASH); @@ -916,7 +917,6 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd) size_t dcmd_size = sizeof(info); BusChild *kid; uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks; - uint16_t sdev_id; memset(&info, 0, dcmd_size); offset = 8; @@ -928,22 +928,25 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd) } max_pd_disks = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address); - if (max_pd_disks > s->fw_luns) { - max_pd_disks = s->fw_luns; + if (max_pd_disks > MFI_MAX_SYS_PDS) { + max_pd_disks = MFI_MAX_SYS_PDS; } - QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); + uint16_t pd_id; - sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF); - info.addr[num_pd_disks].device_id = cpu_to_le16(sdev_id); + if (num_pd_disks >= max_pd_disks) + break; + + pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF); + info.addr[num_pd_disks].device_id = cpu_to_le16(pd_id); info.addr[num_pd_disks].encl_device_id = 0xFFFF; info.addr[num_pd_disks].encl_index = 0; - info.addr[num_pd_disks].slot_number = (sdev->id & 0xFF); + info.addr[num_pd_disks].slot_number = sdev->id & 0xFF; info.addr[num_pd_disks].scsi_dev_type = sdev->type; info.addr[num_pd_disks].connect_port_bitmap = 0x1; info.addr[num_pd_disks].sas_addr[0] = - cpu_to_le64(megasas_get_sata_addr(sdev_id)); + cpu_to_le64(megasas_get_sata_addr(pd_id)); num_pd_disks++; offset += sizeof(struct mfi_pd_address); } @@ -978,7 +981,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, struct mfi_pd_info *info = cmd->iov_buf; size_t dcmd_size = sizeof(struct mfi_pd_info); uint64_t pd_size; - uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF); + uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF); uint8_t cmdbuf[6]; SCSIRequest *req; size_t len, resid; @@ -1034,7 +1037,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, info->fw_state = cpu_to_le16(MFI_PD_STATE_OFFLINE); } - info->ref.v.device_id = cpu_to_le16(sdev_id); + info->ref.v.device_id = cpu_to_le16(pd_id); info->state.ddf.pd_type = cpu_to_le16(MFI_PD_DDF_TYPE_IN_VD| MFI_PD_DDF_TYPE_INTF_SAS); blk_get_geometry(sdev->conf.blk, &pd_size); @@ -1045,7 +1048,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, info->slot_number = (sdev->id & 0xFF); info->path_info.count = 1; info->path_info.sas_addr[0] = - cpu_to_le64(megasas_get_sata_addr(sdev_id)); + cpu_to_le64(megasas_get_sata_addr(pd_id)); info->connected_port_bitmap = 0x1; info->device_speed = 1; info->link_speed = 1; @@ -1060,6 +1063,7 @@ static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd) { size_t dcmd_size = sizeof(struct mfi_pd_info); uint16_t pd_id; + uint8_t target_id, lun_id; SCSIDevice *sdev = NULL; int retval = MFI_STAT_DEVICE_NOT_FOUND; @@ -1069,7 +1073,9 @@ static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd) /* mbox0 has the ID */ pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]); - sdev = scsi_device_find(&s->bus, 0, pd_id, 0); + target_id = (pd_id >> 8) & 0xFF; + lun_id = pd_id & 0xFF; + sdev = scsi_device_find(&s->bus, 0, target_id, lun_id); trace_megasas_dcmd_pd_get_info(cmd->index, pd_id); if (sdev) { @@ -1084,7 +1090,7 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) { struct mfi_ld_list info; size_t dcmd_size = sizeof(info), resid; - uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns; + uint32_t num_ld_disks = 0, max_ld_disks; uint64_t ld_size; BusChild *kid; @@ -1095,9 +1101,13 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) return MFI_STAT_INVALID_PARAMETER; } + max_ld_disks = (cmd->iov_size - 8) / 16; if (megasas_is_jbod(s)) { max_ld_disks = 0; } + if (max_ld_disks > MFI_MAX_LD) { + max_ld_disks = MFI_MAX_LD; + } QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); @@ -1107,7 +1117,6 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) /* Logical device size is in blocks */ blk_get_geometry(sdev->conf.blk, &ld_size); info.ld_list[num_ld_disks].ld.v.target_id = sdev->id; - info.ld_list[num_ld_disks].ld.v.lun_id = sdev->lun; info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL; info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size); num_ld_disks++; @@ -1143,10 +1152,13 @@ static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd) return MFI_STAT_INVALID_PARAMETER; } dcmd_size = sizeof(uint32_t) * 2 + 3; - + max_ld_disks = cmd->iov_size - dcmd_size; if (megasas_is_jbod(s)) { max_ld_disks = 0; } + if (max_ld_disks > MFI_MAX_LD) { + max_ld_disks = MFI_MAX_LD; + } QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); @@ -1174,7 +1186,7 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, uint8_t cdb[6]; SCSIRequest *req; ssize_t len, resid; - uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF); + uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF); uint64_t ld_size; if (!cmd->iov_buf) { @@ -1290,7 +1302,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd) QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); - uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF); + uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF); struct mfi_array *array; struct mfi_ld_config *ld; uint64_t pd_size; @@ -1316,7 +1328,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd) array_offset += sizeof(struct mfi_array); ld = (struct mfi_ld_config *)(data + ld_offset); memset(ld, 0, sizeof(struct mfi_ld_config)); - ld->properties.ld.v.target_id = (sdev->id & 0xFF); + ld->properties.ld.v.target_id = sdev->id; ld->properties.default_cache_policy = MR_LD_CACHE_READ_AHEAD | MR_LD_CACHE_READ_ADAPTIVE; ld->properties.current_cache_policy = MR_LD_CACHE_READ_AHEAD | @@ -1603,10 +1615,18 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, cdb = cmd->frame->pass.cdb; - if (cmd->frame->header.target_id < s->fw_luns) { - sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id, - cmd->frame->header.lun_id); + if (is_logical) { + if (cmd->frame->header.target_id >= MFI_MAX_LD || + cmd->frame->header.lun_id != 0) { + trace_megasas_scsi_target_not_present( + mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical, + cmd->frame->header.target_id, cmd->frame->header.lun_id); + return MFI_STAT_DEVICE_NOT_FOUND; + } } + sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id, + cmd->frame->header.lun_id); + cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len); trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical, cmd->frame->header.target_id, @@ -1677,7 +1697,8 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd) lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi); lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo; - if (cmd->frame->header.target_id < s->fw_luns) { + if (cmd->frame->header.target_id < MFI_MAX_LD && + cmd->frame->header.lun_id == 0) { sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id, cmd->frame->header.lun_id); } @@ -2233,8 +2254,12 @@ static int megasas_scsi_init(PCIDevice *dev) } trace_megasas_init(s->fw_sge, s->fw_cmds, megasas_is_jbod(s) ? "jbod" : "raid"); - s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ? - MAX_SCSI_DEVS : MFI_MAX_LD; + + if (megasas_is_jbod(s)) { + s->fw_luns = MFI_MAX_SYS_PDS; + } else { + s->fw_luns = MFI_MAX_LD; + } s->producer_pa = 0; s->consumer_pa = 0; for (i = 0; i < s->fw_cmds; i++) { diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h index 5050ce4732..455c96b782 100644 --- a/hw/scsi/mfi.h +++ b/hw/scsi/mfi.h @@ -1094,7 +1094,7 @@ struct mfi_pd_list { union mfi_ld_ref { struct { uint8_t target_id; - uint8_t lun_id; + uint8_t reserved; uint16_t seq; } v; uint32_t ref; From e23d04984a78490d8aaa5c45724a3a334933331f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:08 +0100 Subject: [PATCH 07/35] megasas: add MegaRAID SAS 2108 emulation The 2108 chip supports MSI and MSI-X, so update the emulation to support both chips. Signed-off-by: Hannes Reinecke [Make VMStateDescription const. - Paolo] Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 218 ++++++++++++++++++++++++++++++++++----- hw/scsi/mfi.h | 7 ++ include/hw/pci/pci_ids.h | 1 + 3 files changed, 201 insertions(+), 25 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 3a7e85e75e..7401b6b778 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -31,9 +31,11 @@ #include "mfi.h" -#define MEGASAS_VERSION "1.70" +#define MEGASAS_VERSION_GEN1 "1.70" +#define MEGASAS_VERSION_GEN2 "1.80" #define MEGASAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */ #define MEGASAS_DEFAULT_FRAMES 1000 /* Windows requires this */ +#define MEGASAS_GEN2_DEFAULT_FRAMES 1008 /* Windows requires this */ #define MEGASAS_MAX_SGE 128 /* Firmware limit */ #define MEGASAS_DEFAULT_SGE 80 #define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */ @@ -91,6 +93,8 @@ typedef struct MegasasState { int intr_mask; int doorbell; int busy; + int diag; + int adp_reset; MegasasCmd *event_cmd; int event_locale; @@ -115,10 +119,26 @@ typedef struct MegasasState { SCSIBus bus; } MegasasState; -#define TYPE_MEGASAS "megasas" +typedef struct MegasasBaseClass { + PCIDeviceClass parent_class; + const char *product_name; + const char *product_version; + int mmio_bar; + int ioport_bar; + int osts; +} MegasasBaseClass; + +#define TYPE_MEGASAS_BASE "megasas-base" +#define TYPE_MEGASAS_GEN1 "megasas" +#define TYPE_MEGASAS_GEN2 "megasas-gen2" #define MEGASAS(obj) \ - OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS) + OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS_BASE) + +#define MEGASAS_DEVICE_CLASS(oc) \ + OBJECT_CLASS_CHECK(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE) +#define MEGASAS_DEVICE_GET_CLASS(oc) \ + OBJECT_GET_CLASS(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE) #define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF @@ -686,6 +706,8 @@ static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size) static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) { PCIDevice *pci_dev = PCI_DEVICE(s); + PCIDeviceClass *pci_class = PCI_DEVICE_GET_CLASS(pci_dev); + MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s); struct mfi_ctrl_info info; size_t dcmd_size = sizeof(info); BusChild *kid; @@ -698,10 +720,10 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) return MFI_STAT_INVALID_PARAMETER; } - info.pci.vendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC); - info.pci.device = cpu_to_le16(PCI_DEVICE_ID_LSI_SAS1078); - info.pci.subvendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC); - info.pci.subdevice = cpu_to_le16(0x1013); + info.pci.vendor = cpu_to_le16(pci_class->vendor_id); + info.pci.device = cpu_to_le16(pci_class->device_id); + info.pci.subvendor = cpu_to_le16(pci_class->subsystem_vendor_id); + info.pci.subdevice = cpu_to_le16(pci_class->subsystem_id); /* * For some reason the firmware supports @@ -728,11 +750,12 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) num_pd_disks++; } - memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20); + memcpy(info.product_name, base_class->product_name, 24); snprintf(info.serial_number, 32, "%s", s->hba_serial); snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION); memcpy(info.image_component[0].name, "APP", 3); - memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9); + snprintf(info.image_component[0].version, 10, "%s-QEMU", + base_class->product_version); memcpy(info.image_component[0].build_date, "Apr 1 2014", 11); memcpy(info.image_component[0].build_time, "12:34:56", 8); info.image_component_count = 1; @@ -1960,6 +1983,8 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, unsigned size) { MegasasState *s = opaque; + PCIDevice *pci_dev = PCI_DEVICE(s); + MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s); uint32_t retval = 0; switch (addr) { @@ -1968,14 +1993,14 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, break; case MFI_OMSG0: case MFI_OSP0: - retval = (megasas_use_msix(s) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) | + retval = (msix_present(pci_dev) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) | (s->fw_state & MFI_FWSTATE_MASK) | ((s->fw_sge & 0xff) << 16) | (s->fw_cmds & 0xFFFF); break; case MFI_OSTS: if (megasas_intr_enabled(s) && s->doorbell) { - retval = MFI_1078_RM | 1; + retval = base_class->osts; } break; case MFI_OMSK: @@ -1984,6 +2009,12 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, case MFI_ODCR0: retval = s->doorbell; break; + case MFI_DIAG: + retval = s->diag; + break; + case MFI_OSP1: + retval = 15; + break; default: trace_megasas_mmio_invalid_readl(addr); break; @@ -1992,6 +2023,8 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, return retval; } +static int adp_reset_seq[] = {0x00, 0x04, 0x0b, 0x02, 0x07, 0x0d}; + static void megasas_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { @@ -2017,6 +2050,10 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, if (val & MFI_FWINIT_MFIMODE) { /* discard MFIs */ } + if (val & MFI_FWINIT_STOP_ADP) { + /* Terminal error, stop processing */ + s->fw_state = MFI_FWSTATE_FAULT; + } break; case MFI_OMSK: s->intr_mask = val; @@ -2036,6 +2073,7 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, } } else { trace_megasas_intr_disabled(); + megasas_soft_reset(s); } break; case MFI_ODCR0: @@ -2057,8 +2095,9 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, break; case MFI_IQPL: /* Received low 32 bits of a 64 bit MFI frame address */ + /* Fallthrough */ case MFI_IQP: - /* Received 32 bit MFI frame address */ + /* Received 64 bit MFI frame address */ frame_addr = (val & ~0x1F); /* Add possible 64 bit offset */ frame_addr |= ((uint64_t)s->frame_hi << 32); @@ -2066,6 +2105,28 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, frame_count = (val >> 1) & 0xF; megasas_handle_frame(s, frame_addr, frame_count); break; + case MFI_SEQ: + /* Magic sequence to start ADP reset */ + if (adp_reset_seq[s->adp_reset] == val) { + s->adp_reset++; + } else { + s->adp_reset = 0; + s->diag = 0; + } + if (s->adp_reset == 6) { + s->diag = MFI_DIAG_WRITE_ENABLE; + } + break; + case MFI_DIAG: + /* ADP reset */ + if ((s->diag & MFI_DIAG_WRITE_ENABLE) && + (val & MFI_DIAG_RESET_ADP)) { + s->diag |= MFI_DIAG_RESET_ADP; + megasas_soft_reset(s); + s->adp_reset = 0; + s->diag = 0; + } + break; default: trace_megasas_mmio_invalid_writel(addr, val); break; @@ -2150,7 +2211,7 @@ static void megasas_scsi_reset(DeviceState *dev) megasas_soft_reset(s); } -static const VMStateDescription vmstate_megasas = { +static const VMStateDescription vmstate_megasas_gen1 = { .name = "megasas", .version_id = 0, .minimum_version_id = 0, @@ -2168,6 +2229,25 @@ static const VMStateDescription vmstate_megasas = { } }; +static const VMStateDescription vmstate_megasas_gen2 = { + .name = "megasas-gen2", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_PCIE_DEVICE(parent_obj, MegasasState), + VMSTATE_MSIX(parent_obj, MegasasState), + + VMSTATE_INT32(fw_state, MegasasState), + VMSTATE_INT32(intr_mask, MegasasState), + VMSTATE_INT32(doorbell, MegasasState), + VMSTATE_UINT64(reply_queue_pa, MegasasState), + VMSTATE_UINT64(consumer_pa, MegasasState), + VMSTATE_UINT64(producer_pa, MegasasState), + VMSTATE_END_OF_LIST() + } +}; + static void megasas_scsi_uninit(PCIDevice *d) { MegasasState *s = MEGASAS(d); @@ -2195,6 +2275,7 @@ static int megasas_scsi_init(PCIDevice *dev) { DeviceState *d = DEVICE(dev); MegasasState *s = MEGASAS(dev); + MegasasBaseClass *b = MEGASAS_DEVICE_GET_CLASS(s); uint8_t *pci_conf; int i, bar_type; Error *err = NULL; @@ -2218,14 +2299,18 @@ static int megasas_scsi_init(PCIDevice *dev) s->flags &= ~MEGASAS_MASK_USE_MSI; } if (megasas_use_msix(s) && - msix_init(dev, 15, &s->mmio_io, 0, 0x2000, - &s->mmio_io, 0, 0x3800, 0x68)) { + msix_init(dev, 15, &s->mmio_io, b->mmio_bar, 0x2000, + &s->mmio_io, b->mmio_bar, 0x3800, 0x68)) { s->flags &= ~MEGASAS_MASK_USE_MSIX; } + if (pci_is_express(dev)) { + pcie_endpoint_cap_init(dev, 0xa0); + } bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64; - pci_register_bar(dev, 0, bar_type, &s->mmio_io); - pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io); + pci_register_bar(dev, b->ioport_bar, + PCI_BASE_ADDRESS_SPACE_IO, &s->port_io); + pci_register_bar(dev, b->mmio_bar, bar_type, &s->mmio_io); pci_register_bar(dev, 3, bar_type, &s->queue_io); if (megasas_use_msix(s)) { @@ -2288,7 +2373,7 @@ megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len) msi_write_config(pci, addr, val, len); } -static Property megasas_properties[] = { +static Property megasas_properties_gen1[] = { DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge, MEGASAS_DEFAULT_SGE), DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds, @@ -2304,36 +2389,119 @@ static Property megasas_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static Property megasas_properties_gen2[] = { + DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge, + MEGASAS_DEFAULT_SGE), + DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds, + MEGASAS_GEN2_DEFAULT_FRAMES), + DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial), + DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0), + DEFINE_PROP_BIT("use_msi", MegasasState, flags, + MEGASAS_FLAG_USE_MSI, true), + DEFINE_PROP_BIT("use_msix", MegasasState, flags, + MEGASAS_FLAG_USE_MSIX, true), + DEFINE_PROP_BIT("use_jbod", MegasasState, flags, + MEGASAS_FLAG_USE_JBOD, false), + DEFINE_PROP_END_OF_LIST(), +}; + +typedef struct MegasasInfo { + const char *name; + const char *desc; + const char *product_name; + const char *product_version; + uint16_t device_id; + uint16_t subsystem_id; + int ioport_bar; + int mmio_bar; + bool is_express; + int osts; + const VMStateDescription *vmsd; + Property *props; +} MegasasInfo; + +static struct MegasasInfo megasas_devices[] = { + { + .name = TYPE_MEGASAS_GEN1, + .desc = "LSI MegaRAID SAS 1078", + .product_name = "LSI MegaRAID SAS 8708EM2", + .product_version = MEGASAS_VERSION_GEN1, + .device_id = PCI_DEVICE_ID_LSI_SAS1078, + .subsystem_id = 0x1013, + .ioport_bar = 2, + .mmio_bar = 0, + .osts = MFI_1078_RM | 1, + .is_express = false, + .vmsd = &vmstate_megasas_gen1, + .props = megasas_properties_gen1, + },{ + .name = TYPE_MEGASAS_GEN2, + .desc = "LSI MegaRAID SAS 2108", + .product_name = "LSI MegaRAID SAS 9260-8i", + .product_version = MEGASAS_VERSION_GEN2, + .device_id = PCI_DEVICE_ID_LSI_SAS0079, + .subsystem_id = 0x9261, + .ioport_bar = 0, + .mmio_bar = 1, + .osts = MFI_GEN2_RM, + .is_express = true, + .vmsd = &vmstate_megasas_gen2, + .props = megasas_properties_gen2, + } +}; + static void megasas_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); + MegasasBaseClass *e = MEGASAS_DEVICE_CLASS(oc); + const MegasasInfo *info = data; pc->init = megasas_scsi_init; pc->exit = megasas_scsi_uninit; pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC; - pc->device_id = PCI_DEVICE_ID_LSI_SAS1078; + pc->device_id = info->device_id; pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC; - pc->subsystem_id = 0x1013; + pc->subsystem_id = info->subsystem_id; pc->class_id = PCI_CLASS_STORAGE_RAID; - dc->props = megasas_properties; + pc->is_express = info->is_express; + e->mmio_bar = info->mmio_bar; + e->ioport_bar = info->ioport_bar; + e->osts = info->osts; + e->product_name = info->product_name; + e->product_version = info->product_version; + dc->props = info->props; dc->reset = megasas_scsi_reset; - dc->vmsd = &vmstate_megasas; + dc->vmsd = info->vmsd; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->desc = "LSI MegaRAID SAS 1078"; + dc->desc = info->desc; pc->config_write = megasas_write_config; } static const TypeInfo megasas_info = { - .name = TYPE_MEGASAS, + .name = TYPE_MEGASAS_BASE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MegasasState), - .class_init = megasas_class_init, + .class_size = sizeof(MegasasBaseClass), + .abstract = true, }; static void megasas_register_types(void) { + int i; + type_register_static(&megasas_info); + for (i = 0; i < ARRAY_SIZE(megasas_devices); i++) { + const MegasasInfo *info = &megasas_devices[i]; + TypeInfo type_info = {}; + + type_info.name = info->name; + type_info.parent = TYPE_MEGASAS_BASE; + type_info.class_data = (void *)info; + type_info.class_init = megasas_class_init; + + type_register(&type_info); + } } type_init(megasas_register_types) diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h index 455c96b782..29d41775d4 100644 --- a/hw/scsi/mfi.h +++ b/hw/scsi/mfi.h @@ -60,6 +60,7 @@ #define MFI_ODR0 0x9c /* outbound doorbell register0 */ #define MFI_ODCR0 0xa0 /* outbound doorbell clear register0 */ #define MFI_OSP0 0xb0 /* outbound scratch pad0 */ +#define MFI_OSP1 0xb4 /* outbound scratch pad1 */ #define MFI_IQPL 0xc0 /* Inbound queue port (low bytes) */ #define MFI_IQPH 0xc4 /* Inbound queue port (high bytes) */ #define MFI_DIAG 0xf8 /* Host diag */ @@ -116,6 +117,12 @@ #define MFI_FWINIT_STOP_ADP 0x00000020 /* Move to operational, stop */ #define MFI_FWINIT_ADP_RESET 0x00000040 /* Reset ADP */ +/* + * Control bits for the DIAG register + */ +#define MFI_DIAG_WRITE_ENABLE 0x00000080 +#define MFI_DIAG_RESET_ADP 0x00000004 + /* MFI Commands */ typedef enum { MFI_CMD_INIT = 0x00, diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index e597070ab8..321d622b78 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -56,6 +56,7 @@ #define PCI_DEVICE_ID_LSI_53C810 0x0001 #define PCI_DEVICE_ID_LSI_53C895A 0x0012 #define PCI_DEVICE_ID_LSI_SAS1078 0x0060 +#define PCI_DEVICE_ID_LSI_SAS0079 0x0079 #define PCI_VENDOR_ID_DEC 0x1011 #define PCI_DEVICE_ID_DEC_21154 0x0026 From e74a43154d17ff771bb591e780f64eac0cb2e452 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:09 +0100 Subject: [PATCH 08/35] megasas: Fix typo in megasas_dcmd_ld_get_list() The check for a valid command buffer size was inverted. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 7401b6b778..acc9d30772 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -1118,7 +1118,7 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) BusChild *kid; memset(&info, 0, dcmd_size); - if (cmd->iov_size < dcmd_size) { + if (cmd->iov_size > dcmd_size) { trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size, dcmd_size); return MFI_STAT_INVALID_PARAMETER; From 77bb6b171043d03f7e4f5212beaa4e6cb3fd6528 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:10 +0100 Subject: [PATCH 09/35] megasas: Decode register names To ease debugging we should be decoding the register names. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 23 ++++++++++++++++++++--- trace-events | 4 ++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index acc9d30772..58e29aed71 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -1990,6 +1990,7 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, switch (addr) { case MFI_IDB: retval = 0; + trace_megasas_mmio_readl("MFI_IDB", retval); break; case MFI_OMSG0: case MFI_OSP0: @@ -1997,29 +1998,35 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, (s->fw_state & MFI_FWSTATE_MASK) | ((s->fw_sge & 0xff) << 16) | (s->fw_cmds & 0xFFFF); + trace_megasas_mmio_readl(addr == MFI_OMSG0 ? "MFI_OMSG0" : "MFI_OSP0", + retval); break; case MFI_OSTS: if (megasas_intr_enabled(s) && s->doorbell) { retval = base_class->osts; } + trace_megasas_mmio_readl("MFI_OSTS", retval); break; case MFI_OMSK: retval = s->intr_mask; + trace_megasas_mmio_readl("MFI_OMSK", retval); break; case MFI_ODCR0: retval = s->doorbell; + trace_megasas_mmio_readl("MFI_ODCR0", retval); break; case MFI_DIAG: retval = s->diag; + trace_megasas_mmio_readl("MFI_DIAG", retval); break; case MFI_OSP1: retval = 15; + trace_megasas_mmio_readl("MFI_OSP1", retval); break; default: trace_megasas_mmio_invalid_readl(addr); break; } - trace_megasas_mmio_readl(addr, retval); return retval; } @@ -2034,9 +2041,9 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, uint32_t frame_count; int i; - trace_megasas_mmio_writel(addr, val); switch (addr) { case MFI_IDB: + trace_megasas_mmio_writel("MFI_IDB", val); if (val & MFI_FWINIT_ABORT) { /* Abort all pending cmds */ for (i = 0; i < s->fw_cmds; i++) { @@ -2056,6 +2063,7 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, } break; case MFI_OMSK: + trace_megasas_mmio_writel("MFI_OMSK", val); s->intr_mask = val; if (!megasas_intr_enabled(s) && !msi_enabled(pci_dev) && @@ -2077,6 +2085,7 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, } break; case MFI_ODCR0: + trace_megasas_mmio_writel("MFI_ODCR0", val); s->doorbell = 0; if (s->producer_pa && megasas_intr_enabled(s)) { /* Update reply queue pointer */ @@ -2090,14 +2099,20 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, } break; case MFI_IQPH: + trace_megasas_mmio_writel("MFI_IQPH", val); /* Received high 32 bits of a 64 bit MFI frame address */ s->frame_hi = val; break; case MFI_IQPL: + trace_megasas_mmio_writel("MFI_IQPL", val); /* Received low 32 bits of a 64 bit MFI frame address */ /* Fallthrough */ case MFI_IQP: - /* Received 64 bit MFI frame address */ + if (addr == MFI_IQP) { + trace_megasas_mmio_writel("MFI_IQP", val); + /* Received 64 bit MFI frame address */ + s->frame_hi = 0; + } frame_addr = (val & ~0x1F); /* Add possible 64 bit offset */ frame_addr |= ((uint64_t)s->frame_hi << 32); @@ -2106,6 +2121,7 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, megasas_handle_frame(s, frame_addr, frame_count); break; case MFI_SEQ: + trace_megasas_mmio_writel("MFI_SEQ", val); /* Magic sequence to start ADP reset */ if (adp_reset_seq[s->adp_reset] == val) { s->adp_reset++; @@ -2118,6 +2134,7 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, } break; case MFI_DIAG: + trace_megasas_mmio_writel("MFI_DIAG", val); /* ADP reset */ if ((s->diag & MFI_DIAG_WRITE_ENABLE) && (val & MFI_DIAG_RESET_ADP)) { diff --git a/trace-events b/trace-events index c5ebfc8a03..cd149cb3f7 100644 --- a/trace-events +++ b/trace-events @@ -764,9 +764,9 @@ megasas_intr_enabled(void) "Interrupts enabled" megasas_intr_disabled(void) "Interrupts disabled" megasas_msix_enabled(int vector) "vector %d" megasas_msi_enabled(int vector) "vector %d" -megasas_mmio_readl(unsigned long addr, uint32_t val) "addr 0x%lx: 0x%x" +megasas_mmio_readl(const char *reg, uint32_t val) "reg %s: 0x%x" megasas_mmio_invalid_readl(unsigned long addr) "addr 0x%lx" -megasas_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x" +megasas_mmio_writel(const char *reg, uint32_t val) "reg %s: 0x%x" megasas_mmio_invalid_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x" # hw/audio/milkymist-ac97.c From 8d72db68fe7b45c7e01f815c4ac3e6c7ac0e26c1 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:11 +0100 Subject: [PATCH 10/35] megasas: Clear unit attention on initial reset The EFI firmware doesn't handle unit attentions properly, so we need to clear the Power On/Reset unit attention upon initial reset. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 18 +++++++++++++++++- hw/scsi/scsi-bus.c | 2 +- include/hw/scsi/scsi.h | 1 + trace-events | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 58e29aed71..57d52885b7 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2202,11 +2202,26 @@ static void megasas_soft_reset(MegasasState *s) int i; MegasasCmd *cmd; - trace_megasas_reset(); + trace_megasas_reset(s->fw_state); for (i = 0; i < s->fw_cmds; i++) { cmd = &s->frames[i]; megasas_abort_command(cmd); } + if (s->fw_state == MFI_FWSTATE_READY) { + BusChild *kid; + + /* + * The EFI firmware doesn't handle UA, + * so we need to clear the Power On/Reset UA + * after the initial reset. + */ + QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { + SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); + + sdev->unit_attention = SENSE_CODE(NO_SENSE); + scsi_device_unit_attention_reported(sdev); + } + } megasas_reset_frames(s); s->reply_queue_len = s->fw_cmds; s->reply_queue_pa = 0; @@ -2334,6 +2349,7 @@ static int megasas_scsi_init(PCIDevice *dev) msix_vector_use(dev, 0); } + s->fw_state = MFI_FWSTATE_READY; if (!s->sas_addr) { s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) | IEEE_COMPANY_LOCALLY_ASSIGNED) << 36; diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 6fce8471d4..6376b88722 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -84,7 +84,7 @@ static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t return NULL; } -static void scsi_device_unit_attention_reported(SCSIDevice *s) +void scsi_device_unit_attention_reported(SCSIDevice *s) { SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s); if (sc->unit_attention_reported) { diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index fd48177fa6..f4aabfd0e7 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -272,6 +272,7 @@ void scsi_req_retry(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense); void scsi_device_report_change(SCSIDevice *dev, SCSISense sense); +void scsi_device_unit_attention_reported(SCSIDevice *dev); int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun); diff --git a/trace-events b/trace-events index cd149cb3f7..2ceb8e426c 100644 --- a/trace-events +++ b/trace-events @@ -754,7 +754,7 @@ megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties l megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: frame %x" megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 "" megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x" -megasas_reset(void) "Reset" +megasas_reset(int fw_state) "firmware state %x" megasas_init(int sges, int cmds, const char *mode) "Using %d sges, %d cmds, %s mode" megasas_msix_raise(int vector) "vector %d" megasas_msi_raise(int vector) "vector %d" From 96f8f23a1e900796494a54e8b56610e1a7db2a89 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:12 +0100 Subject: [PATCH 11/35] megasas: Ignore duplicate init_firmware commands The windows driver is sending several init_firmware commands when in MSI-X mode. It is, however, using only the first queue. So disregard any additional init_firmware commands until the HBA is reset. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 9 ++++++--- trace-events | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 57d52885b7..ed4cc1b398 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -610,16 +610,19 @@ static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd) { PCIDevice *pcid = PCI_DEVICE(s); uint32_t pa_hi, pa_lo; - hwaddr iq_pa, initq_size; - struct mfi_init_qinfo *initq; + hwaddr iq_pa, initq_size = sizeof(struct mfi_init_qinfo); + struct mfi_init_qinfo *initq = NULL; uint32_t flags; int ret = MFI_STAT_OK; + if (s->reply_queue_pa) { + trace_megasas_initq_mapped(s->reply_queue_pa); + goto out; + } pa_lo = le32_to_cpu(cmd->frame->init.qinfo_new_addr_lo); pa_hi = le32_to_cpu(cmd->frame->init.qinfo_new_addr_hi); iq_pa = (((uint64_t) pa_hi << 32) | pa_lo); trace_megasas_init_firmware((uint64_t)iq_pa); - initq_size = sizeof(*initq); initq = pci_dma_map(pcid, iq_pa, &initq_size, 0); if (!initq || initq_size != sizeof(*initq)) { trace_megasas_initq_map_failed(cmd->index); diff --git a/trace-events b/trace-events index 2ceb8e426c..a8b25a1524 100644 --- a/trace-events +++ b/trace-events @@ -697,6 +697,7 @@ lm32_uart_irq_state(int level) "irq state %d" megasas_init_firmware(uint64_t pa) "pa %" PRIx64 " " megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at %" PRIx64 " len %d head %" PRIx64 " tail %" PRIx64 " flags %x" megasas_initq_map_failed(int frame) "scmd %d: failed to map queue" +megasas_initq_mapped(uint64_t pa) "queue already mapped at %" PRIx64 "" megasas_initq_mismatch(int queue_len, int fw_cmds) "queue size %d max fw cmds %d" megasas_qf_found(unsigned int index, uint64_t pa) "mapped frame %x pa %" PRIx64 "" megasas_qf_new(unsigned int index, void *cmd) "return new frame %x cmd %p" From 200b6966cdd393045ef042f0777faf660115ab22 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:13 +0100 Subject: [PATCH 12/35] megasas: Implement DCMD_CLUSTER_RESET_LD Some implementations use DCMD_CLUSTER_RESET_LD to simulate a device reset. Signed-off-by: Hannes Reinecke [Compare against id, not lun. - Paolo] Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index ed4cc1b398..dcfef6384a 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -1416,9 +1416,23 @@ static int megasas_ctrl_shutdown(MegasasState *s, MegasasCmd *cmd) return MFI_STAT_OK; } +/* Some implementations use CLUSTER RESET LD to simulate a device reset */ static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd) { - return MFI_STAT_INVALID_DCMD; + uint16_t target_id; + int i; + + /* mbox0 contains the device index */ + target_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]); + trace_megasas_dcmd_reset_ld(cmd->index, target_id); + for (i = 0; i < s->fw_cmds; i++) { + MegasasCmd *tmp_cmd = &s->frames[i]; + if (tmp_cmd->req && tmp_cmd->req->dev->id == target_id) { + SCSIDevice *d = tmp_cmd->req->dev; + qdev_reset_all(&d->qdev); + } + } + return MFI_STAT_OK; } static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd) From aaf2a859b6758ad9b3a6fa242b0453bd7d8b7615 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:14 +0100 Subject: [PATCH 13/35] megasas: Update queue logging Improve queue logging by displaying head and tail pointer of the completion queue. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 26 +++++++++++++++++--------- trace-events | 7 ++++--- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index dcfef6384a..3107445e4b 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -527,8 +527,12 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s, cmd->count = count; s->busy++; + if (s->consumer_pa) { + s->reply_queue_tail = ldl_le_phys(&address_space_memory, + s->consumer_pa); + } trace_megasas_qf_enqueue(cmd->index, cmd->count, cmd->context, - s->reply_queue_head, s->busy); + s->reply_queue_head, s->reply_queue_tail, s->busy); return cmd; } @@ -558,8 +562,10 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) s->reply_queue_pa + queue_offset, context); } s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds); - trace_megasas_qf_complete(context, tail, queue_offset, - s->busy, s->doorbell); + s->reply_queue_tail = ldl_le_phys(&address_space_memory, + s->consumer_pa); + trace_megasas_qf_complete(context, s->reply_queue_head, + s->reply_queue_tail, s->busy, s->doorbell); } if (megasas_intr_enabled(s)) { @@ -1649,7 +1655,6 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, bool is_logical) { uint8_t *cdb; - int len; bool is_write; struct SCSIDevice *sdev = NULL; @@ -1710,16 +1715,16 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, } is_write = (cmd->req->cmd.mode == SCSI_XFER_TO_DEV); - len = megasas_enqueue_req(cmd, is_write); - if (len > 0) { + if (cmd->iov_size) { if (is_write) { - trace_megasas_scsi_write_start(cmd->index, len); + trace_megasas_scsi_write_start(cmd->index, cmd->iov_size); } else { - trace_megasas_scsi_read_start(cmd->index, len); + trace_megasas_scsi_read_start(cmd->index, cmd->iov_size); } } else { trace_megasas_scsi_nodata(cmd->index); } + megasas_enqueue_req(cmd, is_write); return MFI_STAT_INVALID_STATUS; } @@ -2106,7 +2111,10 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, s->doorbell = 0; if (s->producer_pa && megasas_intr_enabled(s)) { /* Update reply queue pointer */ - trace_megasas_qf_update(s->reply_queue_head, s->busy); + s->reply_queue_tail = ldl_le_phys(&address_space_memory, + s->consumer_pa); + trace_megasas_qf_update(s->reply_queue_head, s->reply_queue_tail, + s->busy); stl_le_phys(&address_space_memory, s->producer_pa, s->reply_queue_head); if (!msix_enabled(pci_dev)) { diff --git a/trace-events b/trace-events index a8b25a1524..3399219bac 100644 --- a/trace-events +++ b/trace-events @@ -702,11 +702,11 @@ megasas_initq_mismatch(int queue_len, int fw_cmds) "queue size %d max fw cmds %d megasas_qf_found(unsigned int index, uint64_t pa) "mapped frame %x pa %" PRIx64 "" megasas_qf_new(unsigned int index, void *cmd) "return new frame %x cmd %p" megasas_qf_failed(unsigned long pa) "all frames busy for frame %lx" -megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int tail, int busy) "enqueue frame %x count %d context %" PRIx64 " tail %x busy %d" -megasas_qf_update(unsigned int head, unsigned int busy) "reply queue head %x busy %d" +megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int head, unsigned int tail, int busy) "frame %x count %d context %" PRIx64 " head %x tail %x busy %d" +megasas_qf_update(unsigned int head, unsigned int tail, unsigned int busy) "head %x tail %x busy %d" megasas_qf_map_failed(int cmd, unsigned long frame) "scmd %d: frame %lu" megasas_qf_complete_noirq(uint64_t context) "context %" PRIx64 " " -megasas_qf_complete(uint64_t context, unsigned int tail, unsigned int offset, int busy, unsigned int doorbell) "context %" PRIx64 " tail %x offset %d busy %d doorbell %x" +megasas_qf_complete(uint64_t context, unsigned int head, unsigned int tail, int busy, unsigned int doorbell) "context %" PRIx64 " head %x tail %x busy %d doorbell %x" megasas_frame_busy(uint64_t addr) "frame %" PRIx64 " busy" megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: MFI cmd %x" megasas_handle_scsi(const char *frame, int bus, int dev, int lun, void *sdev, unsigned long size) "%s dev %x/%x/%x sdev %p xfer %lu" @@ -751,6 +751,7 @@ megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: dev %d" megasas_dcmd_ld_list_query(int cmd, int flags) "scmd %d: query flags %x" megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: dev %d" megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: query flags %x" +megasas_dcmd_reset_ld(int cmd, int target_id) "scmd %d: dev %d" megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld" megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: frame %x" megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 "" From 6df5718bd3ec56225c44cf96440c723c1b611b87 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:15 +0100 Subject: [PATCH 14/35] megasas: Rework frame queueing algorithm Windows requires the frames to be unmapped, otherwise we run into a race condition where the updated frame data is not visible to the guest. With that we can simplify the queue algorithm and use a bitmap for tracking free frames. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 96 ++++++++++++++++++++++------------------------- trace-events | 6 +-- 2 files changed, 48 insertions(+), 54 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 3107445e4b..c0d8215100 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -115,7 +115,7 @@ typedef struct MegasasState { uint64_t producer_pa; MegasasCmd frames[MEGASAS_MAX_FRAMES]; - + DECLARE_BITMAP(frame_map, MEGASAS_MAX_FRAMES); SCSIBus bus; } MegasasState; @@ -463,34 +463,20 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s, return cmd; } -static MegasasCmd *megasas_next_frame(MegasasState *s, - hwaddr frame) +static void megasas_unmap_frame(MegasasState *s, MegasasCmd *cmd) { - MegasasCmd *cmd = NULL; - int num = 0, index; + PCIDevice *p = PCI_DEVICE(s); - cmd = megasas_lookup_frame(s, frame); - if (cmd) { - trace_megasas_qf_found(cmd->index, cmd->pa); - return cmd; - } - index = s->reply_queue_head; - num = 0; - while (num < s->fw_cmds) { - if (!s->frames[index].pa) { - cmd = &s->frames[index]; - break; - } - index = megasas_next_index(s, index, s->fw_cmds); - num++; - } - if (!cmd) { - trace_megasas_qf_failed(frame); - } - trace_megasas_qf_new(index, cmd); - return cmd; + pci_dma_unmap(p, cmd->frame, cmd->pa_size, 0, 0); + cmd->frame = NULL; + cmd->pa = 0; + clear_bit(cmd->index, s->frame_map); } +/* + * This absolutely needs to be locked if + * qemu ever goes multithreaded. + */ static MegasasCmd *megasas_enqueue_frame(MegasasState *s, hwaddr frame, uint64_t context, int count) { @@ -498,31 +484,40 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s, MegasasCmd *cmd = NULL; int frame_size = MFI_FRAME_SIZE * 16; hwaddr frame_size_p = frame_size; + unsigned long index; - cmd = megasas_next_frame(s, frame); - /* All frames busy */ - if (!cmd) { + index = 0; + while (index < s->fw_cmds) { + index = find_next_zero_bit(s->frame_map, s->fw_cmds, index); + if (!s->frames[index].pa) + break; + /* Busy frame found */ + trace_megasas_qf_mapped(index); + } + if (index >= s->fw_cmds) { + /* All frames busy */ + trace_megasas_qf_busy(frame); return NULL; } - if (!cmd->pa) { - cmd->pa = frame; - /* Map all possible frames */ - cmd->frame = pci_dma_map(pcid, frame, &frame_size_p, 0); - if (frame_size_p != frame_size) { - trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame); - if (cmd->frame) { - pci_dma_unmap(pcid, cmd->frame, frame_size_p, 0, 0); - cmd->frame = NULL; - cmd->pa = 0; - } - s->event_count++; - return NULL; - } - cmd->pa_size = frame_size_p; - cmd->context = context; - if (!megasas_use_queue64(s)) { - cmd->context &= (uint64_t)0xFFFFFFFF; + cmd = &s->frames[index]; + set_bit(index, s->frame_map); + trace_megasas_qf_new(index, frame); + + cmd->pa = frame; + /* Map all possible frames */ + cmd->frame = pci_dma_map(pcid, frame, &frame_size_p, 0); + if (frame_size_p != frame_size) { + trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame); + if (cmd->frame) { + megasas_unmap_frame(s, cmd); } + s->event_count++; + return NULL; + } + cmd->pa_size = frame_size_p; + cmd->context = context; + if (!megasas_use_queue64(s)) { + cmd->context &= (uint64_t)0xFFFFFFFF; } cmd->count = count; s->busy++; @@ -544,7 +539,6 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) /* Decrement busy count */ s->busy--; - if (s->reply_queue_pa) { /* * Put command on the reply queue. @@ -590,18 +584,16 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) static void megasas_reset_frames(MegasasState *s) { - PCIDevice *pcid = PCI_DEVICE(s); int i; MegasasCmd *cmd; for (i = 0; i < s->fw_cmds; i++) { cmd = &s->frames[i]; if (cmd->pa) { - pci_dma_unmap(pcid, cmd->frame, cmd->pa_size, 0, 0); - cmd->frame = NULL; - cmd->pa = 0; + megasas_unmap_frame(s, cmd); } } + bitmap_zero(s->frame_map, MEGASAS_MAX_FRAMES); } static void megasas_abort_command(MegasasCmd *cmd) @@ -1894,6 +1886,7 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status, cmd->req = NULL; } cmd->frame->header.cmd_status = cmd_status; + megasas_unmap_frame(cmd->state, cmd); megasas_complete_frame(cmd->state, cmd->context); } @@ -1997,6 +1990,7 @@ static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr, } else { megasas_frame_set_cmd_status(frame_addr, frame_status); } + megasas_unmap_frame(s, cmd); megasas_complete_frame(s, cmd->context); } } diff --git a/trace-events b/trace-events index 3399219bac..24df190c88 100644 --- a/trace-events +++ b/trace-events @@ -699,9 +699,9 @@ megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tai megasas_initq_map_failed(int frame) "scmd %d: failed to map queue" megasas_initq_mapped(uint64_t pa) "queue already mapped at %" PRIx64 "" megasas_initq_mismatch(int queue_len, int fw_cmds) "queue size %d max fw cmds %d" -megasas_qf_found(unsigned int index, uint64_t pa) "mapped frame %x pa %" PRIx64 "" -megasas_qf_new(unsigned int index, void *cmd) "return new frame %x cmd %p" -megasas_qf_failed(unsigned long pa) "all frames busy for frame %lx" +megasas_qf_mapped(unsigned int index) "skip mapped frame %x" +megasas_qf_new(unsigned int index, uint64_t frame) "frame %x addr %" PRIx64 "" +megasas_qf_busy(unsigned long pa) "all frames busy for frame %lx" megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int head, unsigned int tail, int busy) "frame %x count %d context %" PRIx64 " head %x tail %x busy %d" megasas_qf_update(unsigned int head, unsigned int tail, unsigned int busy) "head %x tail %x busy %d" megasas_qf_map_failed(int cmd, unsigned long frame) "scmd %d: frame %lu" From 7957ee71c7733ca20178a49ba7de2b84bbc53d29 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 29 Oct 2014 13:00:16 +0100 Subject: [PATCH 15/35] megasas: Fixup MSI-X handling MSI-X works slightly different than INTx; the doorbell registers are not necessarily used as MSI-X interrupts are directed anyway. So the head pointer on the reply queue needs to be updated as soon as a frame is completed, and we can set the doorbell only when in INTx mode. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 48 +++++++++++++++++++++++------------------------ trace-events | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index c0d8215100..604252a198 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -545,34 +545,41 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) * Context is opaque, but emulation is running in * little endian. So convert it. */ - tail = s->reply_queue_head; if (megasas_use_queue64(s)) { - queue_offset = tail * sizeof(uint64_t); + queue_offset = s->reply_queue_head * sizeof(uint64_t); stq_le_phys(&address_space_memory, s->reply_queue_pa + queue_offset, context); } else { - queue_offset = tail * sizeof(uint32_t); + queue_offset = s->reply_queue_head * sizeof(uint32_t); stl_le_phys(&address_space_memory, s->reply_queue_pa + queue_offset, context); } - s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds); s->reply_queue_tail = ldl_le_phys(&address_space_memory, s->consumer_pa); trace_megasas_qf_complete(context, s->reply_queue_head, - s->reply_queue_tail, s->busy, s->doorbell); + s->reply_queue_tail, s->busy); } if (megasas_intr_enabled(s)) { + /* Update reply queue pointer */ + s->reply_queue_tail = ldl_le_phys(&address_space_memory, + s->consumer_pa); + tail = s->reply_queue_head; + s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds); + trace_megasas_qf_update(s->reply_queue_head, s->reply_queue_tail, + s->busy); + stl_le_phys(&address_space_memory, + s->producer_pa, s->reply_queue_head); /* Notify HBA */ - s->doorbell++; - if (s->doorbell == 1) { - if (msix_enabled(pci_dev)) { - trace_megasas_msix_raise(0); - msix_notify(pci_dev, 0); - } else if (msi_enabled(pci_dev)) { - trace_megasas_msi_raise(0); - msi_notify(pci_dev, 0); - } else { + if (msix_enabled(pci_dev)) { + trace_megasas_msix_raise(0); + msix_notify(pci_dev, 0); + } else if (msi_enabled(pci_dev)) { + trace_megasas_msi_raise(0); + msi_notify(pci_dev, 0); + } else { + s->doorbell++; + if (s->doorbell == 1) { trace_megasas_irq_raise(); pci_irq_assert(pci_dev); } @@ -2028,7 +2035,7 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, trace_megasas_mmio_readl("MFI_OMSK", retval); break; case MFI_ODCR0: - retval = s->doorbell; + retval = s->doorbell ? 1 : 0; trace_megasas_mmio_readl("MFI_ODCR0", retval); break; case MFI_DIAG: @@ -2103,15 +2110,8 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, case MFI_ODCR0: trace_megasas_mmio_writel("MFI_ODCR0", val); s->doorbell = 0; - if (s->producer_pa && megasas_intr_enabled(s)) { - /* Update reply queue pointer */ - s->reply_queue_tail = ldl_le_phys(&address_space_memory, - s->consumer_pa); - trace_megasas_qf_update(s->reply_queue_head, s->reply_queue_tail, - s->busy); - stl_le_phys(&address_space_memory, - s->producer_pa, s->reply_queue_head); - if (!msix_enabled(pci_dev)) { + if (megasas_intr_enabled(s)) { + if (!msix_enabled(pci_dev) && !msi_enabled(pci_dev)) { trace_megasas_irq_lower(); pci_irq_deassert(pci_dev); } diff --git a/trace-events b/trace-events index 24df190c88..b5722ea8ae 100644 --- a/trace-events +++ b/trace-events @@ -706,7 +706,7 @@ megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, uns megasas_qf_update(unsigned int head, unsigned int tail, unsigned int busy) "head %x tail %x busy %d" megasas_qf_map_failed(int cmd, unsigned long frame) "scmd %d: frame %lu" megasas_qf_complete_noirq(uint64_t context) "context %" PRIx64 " " -megasas_qf_complete(uint64_t context, unsigned int head, unsigned int tail, int busy, unsigned int doorbell) "context %" PRIx64 " head %x tail %x busy %d doorbell %x" +megasas_qf_complete(uint64_t context, unsigned int head, unsigned int tail, int busy) "context %" PRIx64 " head %x tail %x busy %d" megasas_frame_busy(uint64_t addr) "frame %" PRIx64 " busy" megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: MFI cmd %x" megasas_handle_scsi(const char *frame, int bus, int dev, int lun, void *sdev, unsigned long size) "%s dev %x/%x/%x sdev %p xfer %lu" From b154537ad07598377ebf98252fb7d2aff127983b Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 3 Oct 2014 17:33:37 -0400 Subject: [PATCH 16/35] -machine vmport=off: Allow disabling of VMWare ioport emulation This is a pc & q35 only machine opt. VMWare apparently doesn't like running under QEMU due to our incomplete emulation of it's special IO Port. This adds a pc & q35 property to allow it to be turned off. Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Don Slutz Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 19 +++++++++++++++++++ hw/i386/pc_piix.c | 4 ++-- hw/i386/pc_q35.c | 3 ++- include/hw/i386/pc.h | 2 ++ qemu-options.hx | 3 +++ vl.c | 4 ++++ 6 files changed, 32 insertions(+), 3 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 61aba9fc54..889e888c6a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1688,6 +1688,20 @@ static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v, pcms->max_ram_below_4g = value; } +static bool pc_machine_get_vmport(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->vmport; +} + +static void pc_machine_set_vmport(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->vmport = value; +} + static void pc_machine_initfn(Object *obj) { PCMachineState *pcms = PC_MACHINE(obj); @@ -1700,6 +1714,11 @@ static void pc_machine_initfn(Object *obj) pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g, NULL, NULL, NULL); + pcms->vmport = !xen_enabled(); + object_property_add_bool(obj, PC_MACHINE_VMPORT, + pc_machine_get_vmport, + pc_machine_set_vmport, + NULL); } static void pc_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 91a20cb8f4..1cda5dd068 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -234,8 +234,8 @@ static void pc_init1(MachineState *machine, pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL); /* init basic PC hardware */ - pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled(), - 0x4); + pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, + !pc_machine->vmport, 0x4); pc_nic_init(isa_bus, pci_bus); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index e225c6d110..4d9e3cd69d 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -242,7 +242,8 @@ static void pc_q35_init(MachineState *machine) pc_register_ferr_irq(gsi[13]); /* init basic PC hardware */ - pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false, 0xff0104); + pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, + !pc_machine->vmport, 0xff0104); /* connect pm stuff to lpc */ ich9_lpc_pm_init(lpc); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index c4ee520e20..2545268a6c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -35,11 +35,13 @@ struct PCMachineState { HotplugHandler *acpi_dev; uint64_t max_ram_below_4g; + bool vmport; }; #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" #define PC_MACHINE_MEMHP_REGION_SIZE "hotplug-memory-region-size" #define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g" +#define PC_MACHINE_VMPORT "vmport" /** * PCMachineClass: diff --git a/qemu-options.hx b/qemu-options.hx index 1e7d5b8362..da9851d483 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -33,6 +33,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ " property accel=accel1[:accel2[:...]] selects accelerator\n" " supported accelerators are kvm, xen, tcg (default: tcg)\n" " kernel_irqchip=on|off controls accelerated irqchip support\n" + " vmport=on|off controls emulation of vmport (default: on)\n" " kvm_shadow_mem=size of KVM shadow MMU\n" " dump-guest-core=on|off include guest memory in a core dump (default=on)\n" " mem-merge=on|off controls memory merge support (default: on)\n" @@ -51,6 +52,8 @@ than one accelerator specified, the next one is used if the previous one fails to initialize. @item kernel_irqchip=on|off Enables in-kernel irqchip support for the chosen accelerator when available. +@item vmport=on|off +Enables emulation of VMWare IO port, for vmmouse etc. (enabled by default) @item kvm_shadow_mem=size Defines the size of the KVM shadow MMU. @item dump-guest-core=on|off diff --git a/vl.c b/vl.c index f6b3546942..f5721d1f25 100644 --- a/vl.c +++ b/vl.c @@ -376,6 +376,10 @@ static QemuOptsList qemu_machine_opts = { .name = PC_MACHINE_MAX_RAM_BELOW_4G, .type = QEMU_OPT_SIZE, .help = "maximum ram below the 4G boundary (32bit boundary)", + }, { + .name = PC_MACHINE_VMPORT, + .type = QEMU_OPT_BOOL, + .help = "Enable vmport (pc & q35)", },{ .name = "iommu", .type = QEMU_OPT_BOOL, From e4dc3f5909ab90520bc1a27b381c3017ff65ed68 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 15 Sep 2014 09:28:23 +0530 Subject: [PATCH 17/35] Add skip_dump flag to ignore memory region during dump The PCI MMIO might be disabled or the device in the reset state. Make sure we do not dump these memory regions. Signed-off-by: Nikunj A Dadhania Acked-by: Alex Williamson CC: Paolo Bonzini Signed-off-by: Paolo Bonzini --- hw/misc/vfio.c | 1 + include/exec/memory.h | 19 +++++++++++++++++++ memory.c | 10 ++++++++++ memory_mapping.c | 3 ++- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c index b5e798173b..fd318a122d 100644 --- a/hw/misc/vfio.c +++ b/hw/misc/vfio.c @@ -2911,6 +2911,7 @@ static int vfio_mmap_bar(VFIODevice *vdev, VFIOBAR *bar, } memory_region_init_ram_ptr(submem, OBJECT(vdev), name, size, *map); + memory_region_set_skip_dump(submem); } else { empty_region: /* Create a zero sized sub-region to make cleanup easy. */ diff --git a/include/exec/memory.h b/include/exec/memory.h index 072aad2239..74a58b4883 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -150,6 +150,7 @@ struct MemoryRegion { bool terminates; bool romd_mode; bool ram; + bool skip_dump; bool readonly; /* For RAM regions */ bool enabled; bool rom_device; @@ -456,6 +457,24 @@ uint64_t memory_region_size(MemoryRegion *mr); */ bool memory_region_is_ram(MemoryRegion *mr); +/** + * memory_region_is_skip_dump: check whether a memory region should not be + * dumped + * + * Returns %true is a memory region should not be dumped(e.g. VFIO BAR MMAP). + * + * @mr: the memory region being queried + */ +bool memory_region_is_skip_dump(MemoryRegion *mr); + +/** + * memory_region_set_skip_dump: Set skip_dump flag, dump will ignore this memory + * region + * + * @mr: the memory region being queried + */ +void memory_region_set_skip_dump(MemoryRegion *mr); + /** * memory_region_is_romd: check whether a memory region is in ROMD mode * diff --git a/memory.c b/memory.c index 30f77b2a6a..0f4fdc7db7 100644 --- a/memory.c +++ b/memory.c @@ -1185,6 +1185,11 @@ void memory_region_init_ram_ptr(MemoryRegion *mr, mr->ram_addr = qemu_ram_alloc_from_ptr(size, ptr, mr, &error_abort); } +void memory_region_set_skip_dump(MemoryRegion *mr) +{ + mr->skip_dump = true; +} + void memory_region_init_alias(MemoryRegion *mr, Object *owner, const char *name, @@ -1306,6 +1311,11 @@ bool memory_region_is_ram(MemoryRegion *mr) return mr->ram; } +bool memory_region_is_skip_dump(MemoryRegion *mr) +{ + return mr->skip_dump; +} + bool memory_region_is_logging(MemoryRegion *mr) { return mr->dirty_log_mask; diff --git a/memory_mapping.c b/memory_mapping.c index 87a6ed5c8e..7b69801cb8 100644 --- a/memory_mapping.c +++ b/memory_mapping.c @@ -203,7 +203,8 @@ static void guest_phys_blocks_region_add(MemoryListener *listener, GuestPhysBlock *predecessor; /* we only care about RAM */ - if (!memory_region_is_ram(section->mr)) { + if (!memory_region_is_ram(section->mr) || + memory_region_is_skip_dump(section->mr)) { return; } From 522abf69995ca20680ab048cad003796be36ef77 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Wed, 29 Oct 2014 20:49:43 +0800 Subject: [PATCH 18/35] vl.c: Fix Coverity complaining for vmstate_dump_file commit abfd9ce3(migration: dump vmstate info as a json file for static analysis) introduce a new command, '-dump-vmstate', that takes a filename as an argument. When executed, QEMU will dump the vmstate information for the machine type it's invoked with to the file, and quit. However, only one instance of the -dump-vmstate option is supported. If more were given, the vmstate_dump_file variable would be overwritten. This fix also helps silence a Coverity error. Signed-off-by: Gonglei Signed-off-by: Paolo Bonzini --- vl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vl.c b/vl.c index f5721d1f25..f070c90826 100644 --- a/vl.c +++ b/vl.c @@ -3750,6 +3750,11 @@ int main(int argc, char **argv, char **envp) configure_msg(opts); break; case QEMU_OPTION_dump_vmstate: + if (vmstate_dump_file) { + fprintf(stderr, "qemu: only one '-dump-vmstate' " + "option may be given\n"); + exit(1); + } vmstate_dump_file = fopen(optarg, "w"); if (vmstate_dump_file == NULL) { fprintf(stderr, "open %s: %s\n", optarg, strerror(errno)); From 076893d3d06fe8642b8912591b9222bcb81f85aa Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Thu, 30 Oct 2014 12:31:00 +0300 Subject: [PATCH 19/35] kvmvapic: patch_instruction fix When QEMU works in icount mode cpu_restore_state function performs two actions: restoring the program counter and updating icount to the correct value. kvmvapic's patch_instruction function is called by cpu_report_tpr_access function which also invokes cpu_restore_state. It results to calling cpu_restore_state twice - in cpu_report_tpr_access and in patch_instruction. When icount is disabled second call is safe. But when icount is enabled, cpu_restore_state modifies instructions counter twice, which leads to incorrect behavior. This patch removes useless cpu_restore_state call from kvmvapic. Signed-off-by: Pavel Dovgalyuk Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- hw/i386/kvmvapic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index 2dc362b88f..c6d34b2546 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -405,7 +405,6 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip) } if (!kvm_enabled()) { - cpu_restore_state(cs, cs->mem_io_pc); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); } From c1d4096b0f033d0a52c542f0948403783c3682e9 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 30 Oct 2014 19:23:46 +0800 Subject: [PATCH 20/35] iscsi: Refuse to open as writable if the LUN is write protected Before, when a write protected iSCSI target is attached as scsi-disk with BDRV_O_RDWR, we report it as writable, while in fact all writes will fail. One way to improve this is to report write protect flag as true to guest, but a even better way is to refuse using a write protected LUN to guest. Target write protect flag is checked with a mode sense query. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- block/iscsi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index 233f46285c..3485d622ec 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1219,6 +1219,40 @@ static void iscsi_attach_aio_context(BlockDriverState *bs, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); } +static bool iscsi_is_write_protected(IscsiLun *iscsilun) +{ + struct scsi_task *task; + struct scsi_mode_sense *ms = NULL; + bool wrprotected = false; + + task = iscsi_modesense6_sync(iscsilun->iscsi, iscsilun->lun, + 1, SCSI_MODESENSE_PC_CURRENT, + 0x3F, 0, 255); + if (task == NULL) { + error_report("iSCSI: Failed to send MODE_SENSE(6) command: %s", + iscsi_get_error(iscsilun->iscsi)); + goto out; + } + + if (task->status != SCSI_STATUS_GOOD) { + error_report("iSCSI: Failed MODE_SENSE(6), LUN assumed writable"); + goto out; + } + ms = scsi_datain_unmarshall(task); + if (!ms) { + error_report("iSCSI: Failed to unmarshall MODE_SENSE(6) data: %s", + iscsi_get_error(iscsilun->iscsi)); + goto out; + } + wrprotected = ms->device_specific_parameter & 0x80; + +out: + if (task) { + scsi_free_scsi_task(task); + } + return wrprotected; +} + /* * We support iscsi url's on the form * iscsi://[%@][:]// @@ -1339,6 +1373,14 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, scsi_free_scsi_task(task); task = NULL; + /* Check the write protect flag of the LUN if we want to write */ + if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) && + iscsi_is_write_protected(iscsilun)) { + error_setg(errp, "Cannot open a write protected LUN as read-write"); + ret = -EACCES; + goto out; + } + iscsi_readcapacity_sync(iscsilun, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); From 93bd49aff9081bbe9440192db9da3676941f77a3 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 30 Oct 2014 19:50:26 +0800 Subject: [PATCH 21/35] virtio-scsi: Fix memory leak when realize failed Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 7d40eccb0c..235c2053da 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -808,6 +808,7 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, error_setg(errp, "Invalid number of queues (= %" PRId32 "), " "must be a positive integer less than %d.", s->conf.num_queues, VIRTIO_PCI_QUEUE_MAX); + virtio_cleanup(vdev); return; } s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *)); From fb7b5c0df6e3c501973ce4d57eb2b1d4344a519d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 17 Sep 2013 15:09:15 +0200 Subject: [PATCH 22/35] scsi: devirtualize unrealize of SCSI devices All implementations are the same. Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 12 +++--------- hw/scsi/scsi-disk.c | 12 ------------ hw/scsi/scsi-generic.c | 7 ------- include/hw/scsi/scsi.h | 1 - 4 files changed, 3 insertions(+), 29 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 6376b88722..24f7b74ae8 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -51,14 +51,6 @@ static void scsi_device_realize(SCSIDevice *s, Error **errp) } } -static void scsi_device_unrealize(SCSIDevice *s, Error **errp) -{ - SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s); - if (sc->unrealize) { - sc->unrealize(s, errp); - } -} - int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, void *hba_private) { @@ -218,7 +210,9 @@ static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp) if (dev->vmsentry) { qemu_del_vm_change_state_handler(dev->vmsentry); } - scsi_device_unrealize(dev, errp); + + scsi_device_purge_requests(dev, SENSE_CODE(NO_SENSE)); + blockdev_mark_auto_del(dev->conf.blk); } /* handle legacy '-drive if=scsi,...' cmd line args */ diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 7b58488b0e..2f75d7d51c 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2138,14 +2138,6 @@ static void scsi_disk_reset(DeviceState *dev) s->tray_open = 0; } -static void scsi_unrealize(SCSIDevice *dev, Error **errp) -{ - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); - - scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE)); - blockdev_mark_auto_del(s->qdev.conf.blk); -} - static void scsi_disk_resize_cb(void *opaque) { SCSIDiskState *s = opaque; @@ -2612,7 +2604,6 @@ static void scsi_hd_class_initfn(ObjectClass *klass, void *data) SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); sc->realize = scsi_hd_realize; - sc->unrealize = scsi_unrealize; sc->alloc_req = scsi_new_request; sc->unit_attention_reported = scsi_disk_unit_attention_reported; dc->fw_name = "disk"; @@ -2643,7 +2634,6 @@ static void scsi_cd_class_initfn(ObjectClass *klass, void *data) SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); sc->realize = scsi_cd_realize; - sc->unrealize = scsi_unrealize; sc->alloc_req = scsi_new_request; sc->unit_attention_reported = scsi_disk_unit_attention_reported; dc->fw_name = "disk"; @@ -2672,7 +2662,6 @@ static void scsi_block_class_initfn(ObjectClass *klass, void *data) SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); sc->realize = scsi_block_realize; - sc->unrealize = scsi_unrealize; sc->alloc_req = scsi_block_new_request; sc->parse_cdb = scsi_block_parse_cdb; dc->fw_name = "disk"; @@ -2710,7 +2699,6 @@ static void scsi_disk_class_initfn(ObjectClass *klass, void *data) SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); sc->realize = scsi_disk_realize; - sc->unrealize = scsi_unrealize; sc->alloc_req = scsi_new_request; sc->unit_attention_reported = scsi_disk_unit_attention_reported; dc->fw_name = "disk"; diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index f2e53afd09..6b9e4e1ef9 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -368,12 +368,6 @@ static void scsi_generic_reset(DeviceState *dev) scsi_device_purge_requests(s, SENSE_CODE(RESET)); } -static void scsi_unrealize(SCSIDevice *s, Error **errp) -{ - scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE)); - blockdev_mark_auto_del(s->conf.blk); -} - static void scsi_generic_realize(SCSIDevice *s, Error **errp) { int rc; @@ -478,7 +472,6 @@ static void scsi_generic_class_initfn(ObjectClass *klass, void *data) SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); sc->realize = scsi_generic_realize; - sc->unrealize = scsi_unrealize; sc->alloc_req = scsi_new_request; sc->parse_cdb = scsi_generic_parse_cdb; dc->fw_name = "disk"; diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index f4aabfd0e7..cdaf0f8eb7 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -84,7 +84,6 @@ struct SCSIRequest { typedef struct SCSIDeviceClass { DeviceClass parent_class; void (*realize)(SCSIDevice *dev, Error **errp); - void (*unrealize)(SCSIDevice *dev, Error **errp); int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, void *hba_private); SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun, From 0ba1f53191221b541b938df86a39eeccfb87f996 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Fri, 31 Oct 2014 11:04:31 +0800 Subject: [PATCH 23/35] virtio-scsi: Fix num_queue input validation We need to count the ctrlq and eventq, and also cleanup before returning. Besides, the format string should be unsigned. The number could never be less than zero. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 235c2053da..fdcacfd79a 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -804,10 +804,11 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI, sizeof(VirtIOSCSIConfig)); - if (s->conf.num_queues <= 0 || s->conf.num_queues > VIRTIO_PCI_QUEUE_MAX) { - error_setg(errp, "Invalid number of queues (= %" PRId32 "), " + if (s->conf.num_queues == 0 || + s->conf.num_queues > VIRTIO_PCI_QUEUE_MAX - 2) { + error_setg(errp, "Invalid number of queues (= %" PRIu32 "), " "must be a positive integer less than %d.", - s->conf.num_queues, VIRTIO_PCI_QUEUE_MAX); + s->conf.num_queues, VIRTIO_PCI_QUEUE_MAX - 2); virtio_cleanup(vdev); return; } From 763952d08b9c89726151a72f90bca90d0828302d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 17 Jun 2014 17:54:30 +1000 Subject: [PATCH 24/35] kvm_stat: Only consider online cpus In kvm_stat we grovel through /sys to find out how many cpus are in the system. However if a cpu is offline it will still be present in /sys, and the perf_event_open() will fail. Modify the logic to only return online cpus. We need to be careful on systems which don't support cpu hotplug, the online file will not be present at all. Signed-off-by: Michael Ellerman Signed-off-by: Paolo Bonzini --- scripts/kvm/kvm_stat | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index d7e97e7488..2a788bc34c 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -311,18 +311,30 @@ class TracepointProvider(object): self.select(fields) def fields(self): return self._fields + + def _online_cpus(self): + l = [] + pattern = r'cpu([0-9]+)' + basedir = '/sys/devices/system/cpu' + for entry in os.listdir(basedir): + match = re.match(pattern, entry) + if not match: + continue + path = os.path.join(basedir, entry, 'online') + if os.path.exists(path) and open(path).read().strip() != '1': + continue + l.append(int(match.group(1))) + return l + def _setup(self, _fields): self._fields = _fields - cpure = r'cpu([0-9]+)' - self.cpus = [int(re.match(cpure, x).group(1)) - for x in os.listdir('/sys/devices/system/cpu') - if re.match(cpure, x)] + cpus = self._online_cpus() import resource - nfiles = len(self.cpus) * 1000 + nfiles = len(cpus) * 1000 resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles)) events = [] self.group_leaders = [] - for cpu in self.cpus: + for cpu in cpus: group = Group(cpu) for name in _fields: tracepoint = name From 27d318a88583b2bb263292a4d35931a3bc8d2b7a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 17 Jun 2014 17:54:31 +1000 Subject: [PATCH 25/35] kvm_stat: Fix the non-x86 exit reasons In kvm_stat we have a dictionary of exit reasons for s390. Firstly these are not s390 specific, they are the generic exit reasons. So rename the dictionary to reflect that, and add it separately to filters[]. Secondly, the values are defined using hex, but in the kernel header they are decimal. That means values above 9 in kvm_stat are incorrect. While we're there, fix the whitespace to match the rest of the file. Signed-off-by: Michael Ellerman Signed-off-by: Paolo Bonzini --- scripts/kvm/kvm_stat | 57 +++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index 2a788bc34c..4ec1fa5b63 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -141,33 +141,37 @@ svm_exit_reasons = { 0x400: 'NPF', } -s390_exit_reasons = { - 0x000: 'UNKNOWN', - 0x001: 'EXCEPTION', - 0x002: 'IO', - 0x003: 'HYPERCALL', - 0x004: 'DEBUG', - 0x005: 'HLT', - 0x006: 'MMIO', - 0x007: 'IRQ_WINDOW_OPEN', - 0x008: 'SHUTDOWN', - 0x009: 'FAIL_ENTRY', - 0x010: 'INTR', - 0x011: 'SET_TPR', - 0x012: 'TPR_ACCESS', - 0x013: 'S390_SIEIC', - 0x014: 'S390_RESET', - 0x015: 'DCR', - 0x016: 'NMI', - 0x017: 'INTERNAL_ERROR', - 0x018: 'OSI', - 0x019: 'PAPR_HCALL', +# From include/uapi/linux/kvm.h, KVM_EXIT_xxx +userspace_exit_reasons = { + 0: 'UNKNOWN', + 1: 'EXCEPTION', + 2: 'IO', + 3: 'HYPERCALL', + 4: 'DEBUG', + 5: 'HLT', + 6: 'MMIO', + 7: 'IRQ_WINDOW_OPEN', + 8: 'SHUTDOWN', + 9: 'FAIL_ENTRY', + 10: 'INTR', + 11: 'SET_TPR', + 12: 'TPR_ACCESS', + 13: 'S390_SIEIC', + 14: 'S390_RESET', + 15: 'DCR', + 16: 'NMI', + 17: 'INTERNAL_ERROR', + 18: 'OSI', + 19: 'PAPR_HCALL', + 20: 'S390_UCONTROL', + 21: 'WATCHDOG', + 22: 'S390_TSCH', + 23: 'EPR', } vendor_exit_reasons = { 'vmx': vmx_exit_reasons, 'svm': svm_exit_reasons, - 'IBM/S390': s390_exit_reasons, } syscall_numbers = { @@ -185,15 +189,14 @@ for line in file('/proc/cpuinfo').readlines(): exit_reasons = vendor_exit_reasons[flag] if flag in syscall_numbers: sc_perf_evt_open = syscall_numbers[flag] -filters = { - 'kvm_exit': ('exit_reason', exit_reasons) -} def invert(d): return dict((x[1], x[0]) for x in d.iteritems()) -for f in filters: - filters[f] = (filters[f][0], invert(filters[f][1])) +filters = {} +filters['kvm_userspace_exit'] = ('reason', invert(userspace_exit_reasons)) +if exit_reasons: + filters['kvm_exit'] = ('exit_reason', invert(exit_reasons)) import ctypes, struct, array From 4d4103ff32ee4c88857727515b5e596a1debc227 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 17 Jun 2014 17:54:32 +1000 Subject: [PATCH 26/35] kvm_stat: Rework platform detection The current platform detection is a little bit messy. We look for lines in /proc/cpuinfo starting with 'flags' OR 'vendor-id', and scan both for values we know will only occur in one or the other. We also keep scanning once we've found a value, which could be a feature, but isn't in this case. We'd also like to add another platform, powerpc, which will just make it worse. So clean it up in preparation. Signed-off-by: Michael Ellerman Signed-off-by: Paolo Bonzini --- scripts/kvm/kvm_stat | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index 4ec1fa5b63..00d4c5dffa 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -169,26 +169,39 @@ userspace_exit_reasons = { 23: 'EPR', } -vendor_exit_reasons = { +x86_exit_reasons = { 'vmx': vmx_exit_reasons, 'svm': svm_exit_reasons, } -syscall_numbers = { - 'IBM/S390': 331, -} - -sc_perf_evt_open = 298 - +sc_perf_evt_open = None exit_reasons = None -for line in file('/proc/cpuinfo').readlines(): - if line.startswith('flags') or line.startswith('vendor_id'): - for flag in line.split(): - if flag in vendor_exit_reasons: - exit_reasons = vendor_exit_reasons[flag] - if flag in syscall_numbers: - sc_perf_evt_open = syscall_numbers[flag] +def x86_init(flag): + globals().update({ + 'sc_perf_evt_open' : 298, + 'exit_reasons' : x86_exit_reasons[flag], + }) + +def s390_init(): + globals().update({ + 'sc_perf_evt_open' : 331 + }) + +def detect_platform(): + for line in file('/proc/cpuinfo').readlines(): + if line.startswith('flags'): + for flag in line.split(): + if flag in x86_exit_reasons: + x86_init(flag) + return + elif line.startswith('vendor_id'): + for flag in line.split(): + if flag == 'IBM/S390': + s390_init() + return + +detect_platform() def invert(d): return dict((x[1], x[0]) for x in d.iteritems()) From a15d5642a03a0b6c6cf327e497e688d1ba4c676d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 17 Jun 2014 17:54:34 +1000 Subject: [PATCH 27/35] kvm_stat: Abstract ioctl numbers Unfortunately ioctl numbers are platform specific, so abstract them out of the code so they can be overridden. As it happens x86 and s390 share the same values, so nothing needs to change yet. Signed-off-by: Michael Ellerman Signed-off-by: Paolo Bonzini --- scripts/kvm/kvm_stat | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index 00d4c5dffa..a65d0a364d 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -177,6 +177,12 @@ x86_exit_reasons = { sc_perf_evt_open = None exit_reasons = None +ioctl_numbers = { + 'SET_FILTER' : 0x40082406, + 'ENABLE' : 0x00002400, + 'DISABLE' : 0x00002401, +} + def x86_init(flag): globals().update({ 'sc_perf_evt_open' : 298, @@ -301,14 +307,14 @@ class Event(object): raise Exception('perf_event_open failed') if filter: import fcntl - fcntl.ioctl(fd, 0x40082406, filter) + fcntl.ioctl(fd, ioctl_numbers['SET_FILTER'], filter) self.fd = fd def enable(self): import fcntl - fcntl.ioctl(self.fd, 0x00002400, 0) + fcntl.ioctl(self.fd, ioctl_numbers['ENABLE'], 0) def disable(self): import fcntl - fcntl.ioctl(self.fd, 0x00002401, 0) + fcntl.ioctl(self.fd, ioctl_numbers['DISABLE'], 0) class TracepointProvider(object): def __init__(self): From 4725398f9309d05936fec2eaaa6e97e01e25545e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 17 Jun 2014 17:54:35 +1000 Subject: [PATCH 28/35] kvm_stat: Add powerpc support Add support for powerpc platforms. We use uname -m, which allows us to detect ppc, ppc64 and ppc64le/el. Signed-off-by: Michael Ellerman Signed-off-by: Paolo Bonzini --- scripts/kvm/kvm_stat | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index a65d0a364d..7b1437ca21 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -12,7 +12,7 @@ # the COPYING file in the top-level directory. import curses -import sys, os, time, optparse +import sys, os, time, optparse, ctypes class DebugfsProvider(object): def __init__(self): @@ -194,7 +194,21 @@ def s390_init(): 'sc_perf_evt_open' : 331 }) +def ppc_init(): + globals().update({ + 'sc_perf_evt_open' : 319, + 'ioctl_numbers' : { + 'SET_FILTER' : 0x80002406 | (ctypes.sizeof(ctypes.c_char_p) << 16), + 'ENABLE' : 0x20002400, + 'DISABLE' : 0x20002401, + } + }) + def detect_platform(): + if os.uname()[4].startswith('ppc'): + ppc_init() + return + for line in file('/proc/cpuinfo').readlines(): if line.startswith('flags'): for flag in line.split(): @@ -217,7 +231,7 @@ filters['kvm_userspace_exit'] = ('reason', invert(userspace_exit_reasons)) if exit_reasons: filters['kvm_exit'] = ('exit_reason', invert(exit_reasons)) -import ctypes, struct, array +import struct, array libc = ctypes.CDLL('libc.so.6') syscall = libc.syscall From e64e353590c2584b41cd1db925f67042a05f4250 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Wed, 22 Oct 2014 15:38:31 +0400 Subject: [PATCH 29/35] i386: fix breakpoints handling in icount mode This patch fixes instructions counting when execution is stopped on breakpoint (e.g. set from gdb). Without a patch extra instruction is translated and icount is incremented by invalid value (which equals to number of executed instructions + 1). Signed-off-by: Pavel Dovgalyuk Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- target-i386/translate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 418173e0ea..782f7d2666 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7987,7 +7987,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu, if (bp->pc == pc_ptr && !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) { gen_debug(dc, pc_ptr - dc->cs_base); - break; + goto done_generating; } } } @@ -8038,6 +8038,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu, } if (tb->cflags & CF_LAST_IO) gen_io_end(); +done_generating: gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; /* we don't forget to fill the last values */ From a2e9011b4164894594bf0b2a2a59e9c55c58c17b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 15 Sep 2014 18:40:05 +0200 Subject: [PATCH 30/35] ivshmem: Check ivshmem_read() size argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The third argument to the fd_read() callback implemented by ivshmem_read() is the number of bytes, not a flags field. Fix this and check we received enough bytes before accessing the buffer pointer. Cc: Cam Macdonell Reported-by: Sebastian Krahmer Signed-off-by: Stefan Hajnoczi [AF: Handle partial reads via FIFO] Reported-by: Peter Maydell Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber Reviewed-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/misc/ivshmem.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index bd9d7182af..caeee1ebf5 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -24,6 +24,7 @@ #include "migration/migration.h" #include "qapi/qmp/qerror.h" #include "qemu/event_notifier.h" +#include "qemu/fifo8.h" #include "sysemu/char.h" #include @@ -73,6 +74,7 @@ typedef struct IVShmemState { CharDriverState **eventfd_chr; CharDriverState *server_chr; + Fifo8 incoming_fifo; MemoryRegion ivshmem_mmio; /* We might need to register the BAR before we actually have the memory. @@ -424,14 +426,35 @@ static void increase_dynamic_storage(IVShmemState *s, int new_min_size) { } } -static void ivshmem_read(void *opaque, const uint8_t * buf, int flags) +static void ivshmem_read(void *opaque, const uint8_t *buf, int size) { IVShmemState *s = opaque; int incoming_fd, tmp_fd; int guest_max_eventfd; long incoming_posn; - memcpy(&incoming_posn, buf, sizeof(long)); + if (fifo8_is_empty(&s->incoming_fifo) && size == sizeof(incoming_posn)) { + memcpy(&incoming_posn, buf, size); + } else { + const uint8_t *p; + uint32_t num; + + IVSHMEM_DPRINTF("short read of %d bytes\n", size); + num = MAX(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo)); + fifo8_push_all(&s->incoming_fifo, buf, num); + if (fifo8_num_used(&s->incoming_fifo) < sizeof(incoming_posn)) { + return; + } + size -= num; + buf += num; + p = fifo8_pop_buf(&s->incoming_fifo, sizeof(incoming_posn), &num); + g_assert(num == sizeof(incoming_posn)); + memcpy(&incoming_posn, p, sizeof(incoming_posn)); + if (size > 0) { + fifo8_push_all(&s->incoming_fifo, buf, size); + } + } + /* pick off s->server_chr->msgfd and store it, posn should accompany msg */ tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr); IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd); @@ -663,6 +686,8 @@ static int pci_ivshmem_init(PCIDevice *dev) s->ivshmem_size = ivshmem_get_size(s); } + fifo8_create(&s->incoming_fifo, sizeof(long)); + register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load, dev); @@ -796,6 +821,7 @@ static void pci_ivshmem_uninit(PCIDevice *dev) memory_region_del_subregion(&s->bar, &s->ivshmem); vmstate_unregister_ram(&s->ivshmem, DEVICE(dev)); unregister_savevm(DEVICE(dev), "ivshmem", s); + fifo8_destroy(&s->incoming_fifo); } static Property ivshmem_properties[] = { From 363ba1c72fed4425e7917afc36722584aaeaad8a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 15 Sep 2014 18:40:06 +0200 Subject: [PATCH 31/35] ivshmem: validate incoming_posn value from server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check incoming_posn to avoid out-of-bounds array accesses if the ivshmem server on the host sends invalid values. Cc: Cam Macdonell Reported-by: Sebastian Krahmer Signed-off-by: Stefan Hajnoczi [AF: Tighten upper bound check for posn in close_guest_eventfds()] Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber Reviewed-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/misc/ivshmem.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index caeee1ebf5..24f74f6f58 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -389,6 +389,9 @@ static void close_guest_eventfds(IVShmemState *s, int posn) if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) { return; } + if (posn < 0 || posn >= s->nb_peers) { + return; + } guest_curr_max = s->peers[posn].nb_eventfds; @@ -455,6 +458,11 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size) } } + if (incoming_posn < -1) { + IVSHMEM_DPRINTF("invalid incoming_posn %ld\n", incoming_posn); + return; + } + /* pick off s->server_chr->msgfd and store it, posn should accompany msg */ tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr); IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd); From 34bc07c5282a631c2663ae1ded0a186f46f64612 Mon Sep 17 00:00:00 2001 From: Sebastian Krahmer Date: Mon, 15 Sep 2014 18:40:07 +0200 Subject: [PATCH 32/35] ivshmem: Fix potential OOB r/w access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix OOB access via malformed incoming_posn parameters and check that requested memory is actually alloc'ed. Signed-off-by: Sebastian Krahmer [AF: Rebased, cleanups, avoid fd leak] Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber Reviewed-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/misc/ivshmem.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 24f74f6f58..ecef82a423 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -29,6 +29,7 @@ #include #include +#include #define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET #define PCI_DEVICE_ID_IVSHMEM 0x1110 @@ -410,14 +411,24 @@ static void close_guest_eventfds(IVShmemState *s, int posn) /* this function increase the dynamic storage need to store data about other * guests */ -static void increase_dynamic_storage(IVShmemState *s, int new_min_size) { +static int increase_dynamic_storage(IVShmemState *s, int new_min_size) +{ int j, old_nb_alloc; + /* check for integer overflow */ + if (new_min_size >= INT_MAX / sizeof(Peer) - 1 || new_min_size <= 0) { + return -1; + } + old_nb_alloc = s->nb_peers; - while (new_min_size >= s->nb_peers) - s->nb_peers = s->nb_peers * 2; + if (new_min_size >= s->nb_peers) { + /* +1 because #new_min_size is used as last array index */ + s->nb_peers = new_min_size + 1; + } else { + return 0; + } IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers); s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer)); @@ -427,6 +438,8 @@ static void increase_dynamic_storage(IVShmemState *s, int new_min_size) { s->peers[j].eventfds = NULL; s->peers[j].nb_eventfds = 0; } + + return 0; } static void ivshmem_read(void *opaque, const uint8_t *buf, int size) @@ -469,7 +482,13 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size) /* make sure we have enough space for this guest */ if (incoming_posn >= s->nb_peers) { - increase_dynamic_storage(s, incoming_posn); + if (increase_dynamic_storage(s, incoming_posn) < 0) { + error_report("increase_dynamic_storage() failed"); + if (tmp_fd != -1) { + close(tmp_fd); + } + return; + } } if (tmp_fd == -1) { From 3a31cff11203bf62ebafa6d74b1fcf2aba345eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 15 Sep 2014 18:40:08 +0200 Subject: [PATCH 33/35] ivshmem: Fix fd leak on error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Stefan Hajnoczi Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber Reviewed-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/misc/ivshmem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index ecef82a423..bf585b7691 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -512,6 +512,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size) if (incoming_fd == -1) { fprintf(stderr, "could not allocate file descriptor %s\n", strerror(errno)); + close(tmp_fd); return; } From dbc464d401f989bbca7812b068c3aded1d834f79 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 7 Oct 2014 13:24:02 +0200 Subject: [PATCH 34/35] ivshmem: use error_report Replace all the fprintf(stderr, ...) calls with error_report. Also make sure exit() consistently uses the error code 1. A few calls used -1. While at it cleanup some indentation in the printf argument lists. Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- hw/misc/ivshmem.c | 52 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index bf585b7691..5d272c84e9 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -133,7 +133,7 @@ static void ivshmem_update_irq(IVShmemState *s, int val) /* don't print ISR resets */ if (isr) { IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n", - isr ? 1 : 0, s->intrstatus, s->intrmask); + isr ? 1 : 0, s->intrstatus, s->intrmask); } pci_set_irq(d, (isr != 0)); @@ -300,8 +300,8 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier * chr = qemu_chr_open_eventfd(eventfd); if (chr == NULL) { - fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd); - exit(-1); + error_report("creating eventfd for eventfd %d failed", eventfd); + exit(1); } qemu_chr_fe_claim_no_fail(chr); @@ -328,16 +328,15 @@ static int check_shm_size(IVShmemState *s, int fd) { struct stat buf; if (fstat(fd, &buf) < 0) { - fprintf(stderr, "ivshmem: exiting: fstat on fd %d failed: %s\n", - fd, strerror(errno)); + error_report("exiting: fstat on fd %d failed: %s", + fd, strerror(errno)); return -1; } if (s->ivshmem_size > buf.st_size) { - fprintf(stderr, - "IVSHMEM ERROR: Requested memory size greater" - " than shared object size (%" PRIu64 " > %" PRIu64")\n", - s->ivshmem_size, (uint64_t)buf.st_size); + error_report("Requested memory size greater" + " than shared object size (%" PRIu64 " > %" PRIu64")", + s->ivshmem_size, (uint64_t)buf.st_size); return -1; } else { return 0; @@ -510,8 +509,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size) incoming_fd = dup(tmp_fd); if (incoming_fd == -1) { - fprintf(stderr, "could not allocate file descriptor %s\n", - strerror(errno)); + error_report("could not allocate file descriptor %s", strerror(errno)); close(tmp_fd); return; } @@ -524,7 +522,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size) s->max_peer = 0; if (check_shm_size(s, incoming_fd) == -1) { - exit(-1); + exit(1); } /* mmap the region and map into the BAR2 */ @@ -535,7 +533,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size) vmstate_register_ram(&s->ivshmem, DEVICE(s)); IVSHMEM_DPRINTF("guest h/w addr = %p, size = %" PRIu64 "\n", - map_ptr, s->ivshmem_size); + map_ptr, s->ivshmem_size); memory_region_add_subregion(&s->bar, 0, &s->ivshmem); @@ -556,7 +554,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size) /* this is an eventfd for a particular guest VM */ IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn, - guest_max_eventfd, incoming_fd); + guest_max_eventfd, incoming_fd); event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd], incoming_fd); @@ -618,13 +616,13 @@ static uint64_t ivshmem_get_size(IVShmemState * s) { value <<= 30; break; default: - fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg); + error_report("invalid ram size: %s", s->sizearg); exit(1); } /* BARs must be a power of 2 */ if (!is_power_of_two(value)) { - fprintf(stderr, "ivshmem: size must be power of 2\n"); + error_report("size must be power of 2"); exit(1); } @@ -676,7 +674,7 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id) } if (proxy->role_val == IVSHMEM_PEER) { - fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n"); + error_report("'peer' devices are not migratable"); return -EINVAL; } @@ -722,7 +720,7 @@ static int pci_ivshmem_init(PCIDevice *dev) /* IRQFD requires MSI */ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) && !ivshmem_has_feature(s, IVSHMEM_MSI)) { - fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n"); + error_report("ioeventfd/irqfd requires MSI"); exit(1); } @@ -733,7 +731,7 @@ static int pci_ivshmem_init(PCIDevice *dev) } else if (strncmp(s->role, "master", 7) == 0) { s->role_val = IVSHMEM_MASTER; } else { - fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n"); + error_report("'role' must be 'peer' or 'master'"); exit(1); } } else { @@ -773,12 +771,12 @@ static int pci_ivshmem_init(PCIDevice *dev) * to the ivshmem server to receive the memory region */ if (s->shmobj != NULL) { - fprintf(stderr, "WARNING: do not specify both 'chardev' " - "and 'shm' with ivshmem\n"); + error_report("WARNING: do not specify both 'chardev' " + "and 'shm' with ivshmem"); } IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", - s->server_chr->filename); + s->server_chr->filename); if (ivshmem_has_feature(s, IVSHMEM_MSI)) { ivshmem_setup_msi(s); @@ -802,7 +800,7 @@ static int pci_ivshmem_init(PCIDevice *dev) int fd; if (s->shmobj == NULL) { - fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n"); + error_report("Must specify 'chardev' or 'shm' to ivshmem"); exit(1); } @@ -814,18 +812,18 @@ static int pci_ivshmem_init(PCIDevice *dev) S_IRWXU|S_IRWXG|S_IRWXO)) > 0) { /* truncate file to length PCI device's memory */ if (ftruncate(fd, s->ivshmem_size) != 0) { - fprintf(stderr, "ivshmem: could not truncate shared file\n"); + error_report("could not truncate shared file"); } } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO)) < 0) { - fprintf(stderr, "ivshmem: could not open shared file\n"); - exit(-1); + error_report("could not open shared file"); + exit(1); } if (check_shm_size(s, fd) == -1) { - exit(-1); + exit(1); } create_shared_memory_BAR(s, fd); From ace386b4e0e088ed1d42fba697fbb68219aceee6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 31 Oct 2014 17:38:04 +0100 Subject: [PATCH 35/35] virtio-scsi: fix dataplane Commit 361dcc7 (virtio-scsi: dataplane: fail setup gracefully, 2014-10-15) actually broke successful dataplane setup in a not-so-graceful manner: qemu-system-x86_64: .../util/rfifolock.c:71: rfifolock_unlock: Assertion `r->nesting > 0' failed. due to a missing return statement. Fixes: 361dcc790db8c87b2e46ab610739191ced894c44 Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi-dataplane.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 3097d544b4..9651e6f274 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -241,9 +241,10 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s) } } - aio_context_release(s->ctx); s->dataplane_starting = false; s->dataplane_started = true; + aio_context_release(s->ctx); + return; fail_vrings: virtio_scsi_clear_aio(s);