aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/char/escc.c233
-rw-r--r--hw/input/ps2.c166
-rw-r--r--hw/scsi/megasas.c81
-rw-r--r--hw/scsi/mfi.h9
-rw-r--r--hw/scsi/scsi-disk.c16
-rw-r--r--hw/scsi/scsi-generic.c8
6 files changed, 407 insertions, 106 deletions
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 6397f6f282..d9a20aa931 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -27,6 +27,7 @@
#include "hw/char/escc.h"
#include "sysemu/char.h"
#include "ui/console.h"
+#include "ui/input.h"
#include "trace.h"
/*
@@ -94,6 +95,7 @@ typedef struct ChannelState {
ChnID chn; // this channel, A (base+4) or B (base+0)
ChnType type;
uint8_t rx, tx;
+ QemuInputHandlerState *hs;
} ChannelState;
#define ESCC(obj) OBJECT_CHECK(ESCCState, (obj), TYPE_ESCC)
@@ -714,71 +716,181 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
return &d->mmio;
}
-static const uint8_t keycodes[128] = {
- 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
- 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
- 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
- 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
- 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
- 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
+static const uint8_t qcode_to_keycode[Q_KEY_CODE_MAX] = {
+ [Q_KEY_CODE_SHIFT] = 99,
+ [Q_KEY_CODE_SHIFT_R] = 110,
+ [Q_KEY_CODE_ALT] = 19,
+ [Q_KEY_CODE_ALT_R] = 13,
+ [Q_KEY_CODE_ALTGR] = 13,
+ [Q_KEY_CODE_CTRL] = 76,
+ [Q_KEY_CODE_CTRL_R] = 76,
+ [Q_KEY_CODE_ESC] = 29,
+ [Q_KEY_CODE_1] = 30,
+ [Q_KEY_CODE_2] = 31,
+ [Q_KEY_CODE_3] = 32,
+ [Q_KEY_CODE_4] = 33,
+ [Q_KEY_CODE_5] = 34,
+ [Q_KEY_CODE_6] = 35,
+ [Q_KEY_CODE_7] = 36,
+ [Q_KEY_CODE_8] = 37,
+ [Q_KEY_CODE_9] = 38,
+ [Q_KEY_CODE_0] = 39,
+ [Q_KEY_CODE_MINUS] = 40,
+ [Q_KEY_CODE_EQUAL] = 41,
+ [Q_KEY_CODE_BACKSPACE] = 43,
+ [Q_KEY_CODE_TAB] = 53,
+ [Q_KEY_CODE_Q] = 54,
+ [Q_KEY_CODE_W] = 55,
+ [Q_KEY_CODE_E] = 56,
+ [Q_KEY_CODE_R] = 57,
+ [Q_KEY_CODE_T] = 58,
+ [Q_KEY_CODE_Y] = 59,
+ [Q_KEY_CODE_U] = 60,
+ [Q_KEY_CODE_I] = 61,
+ [Q_KEY_CODE_O] = 62,
+ [Q_KEY_CODE_P] = 63,
+ [Q_KEY_CODE_BRACKET_LEFT] = 64,
+ [Q_KEY_CODE_BRACKET_RIGHT] = 65,
+ [Q_KEY_CODE_RET] = 89,
+ [Q_KEY_CODE_A] = 77,
+ [Q_KEY_CODE_S] = 78,
+ [Q_KEY_CODE_D] = 79,
+ [Q_KEY_CODE_F] = 80,
+ [Q_KEY_CODE_G] = 81,
+ [Q_KEY_CODE_H] = 82,
+ [Q_KEY_CODE_J] = 83,
+ [Q_KEY_CODE_K] = 84,
+ [Q_KEY_CODE_L] = 85,
+ [Q_KEY_CODE_SEMICOLON] = 86,
+ [Q_KEY_CODE_APOSTROPHE] = 87,
+ [Q_KEY_CODE_GRAVE_ACCENT] = 42,
+ [Q_KEY_CODE_BACKSLASH] = 88,
+ [Q_KEY_CODE_Z] = 100,
+ [Q_KEY_CODE_X] = 101,
+ [Q_KEY_CODE_C] = 102,
+ [Q_KEY_CODE_V] = 103,
+ [Q_KEY_CODE_B] = 104,
+ [Q_KEY_CODE_N] = 105,
+ [Q_KEY_CODE_M] = 106,
+ [Q_KEY_CODE_COMMA] = 107,
+ [Q_KEY_CODE_DOT] = 108,
+ [Q_KEY_CODE_SLASH] = 109,
+ [Q_KEY_CODE_ASTERISK] = 47,
+ [Q_KEY_CODE_SPC] = 121,
+ [Q_KEY_CODE_CAPS_LOCK] = 119,
+ [Q_KEY_CODE_F1] = 5,
+ [Q_KEY_CODE_F2] = 6,
+ [Q_KEY_CODE_F3] = 8,
+ [Q_KEY_CODE_F4] = 10,
+ [Q_KEY_CODE_F5] = 12,
+ [Q_KEY_CODE_F6] = 14,
+ [Q_KEY_CODE_F7] = 16,
+ [Q_KEY_CODE_F8] = 17,
+ [Q_KEY_CODE_F9] = 18,
+ [Q_KEY_CODE_F10] = 7,
+ [Q_KEY_CODE_NUM_LOCK] = 98,
+ [Q_KEY_CODE_SCROLL_LOCK] = 23,
+ [Q_KEY_CODE_KP_DIVIDE] = 46,
+ [Q_KEY_CODE_KP_MULTIPLY] = 47,
+ [Q_KEY_CODE_KP_SUBTRACT] = 71,
+ [Q_KEY_CODE_KP_ADD] = 125,
+ [Q_KEY_CODE_KP_ENTER] = 90,
+ [Q_KEY_CODE_KP_DECIMAL] = 50,
+ [Q_KEY_CODE_KP_0] = 94,
+ [Q_KEY_CODE_KP_1] = 112,
+ [Q_KEY_CODE_KP_2] = 113,
+ [Q_KEY_CODE_KP_3] = 114,
+ [Q_KEY_CODE_KP_4] = 91,
+ [Q_KEY_CODE_KP_5] = 92,
+ [Q_KEY_CODE_KP_6] = 93,
+ [Q_KEY_CODE_KP_7] = 68,
+ [Q_KEY_CODE_KP_8] = 69,
+ [Q_KEY_CODE_KP_9] = 70,
+ [Q_KEY_CODE_LESS] = 124,
+ [Q_KEY_CODE_F11] = 9,
+ [Q_KEY_CODE_F12] = 11,
+ [Q_KEY_CODE_HOME] = 52,
+ [Q_KEY_CODE_PGUP] = 96,
+ [Q_KEY_CODE_PGDN] = 123,
+ [Q_KEY_CODE_END] = 74,
+ [Q_KEY_CODE_LEFT] = 24,
+ [Q_KEY_CODE_UP] = 20,
+ [Q_KEY_CODE_DOWN] = 27,
+ [Q_KEY_CODE_RIGHT] = 28,
+ [Q_KEY_CODE_INSERT] = 44,
+ [Q_KEY_CODE_DELETE] = 66,
+ [Q_KEY_CODE_STOP] = 1,
+ [Q_KEY_CODE_AGAIN] = 3,
+ [Q_KEY_CODE_PROPS] = 25,
+ [Q_KEY_CODE_UNDO] = 26,
+ [Q_KEY_CODE_FRONT] = 49,
+ [Q_KEY_CODE_COPY] = 51,
+ [Q_KEY_CODE_OPEN] = 72,
+ [Q_KEY_CODE_PASTE] = 73,
+ [Q_KEY_CODE_FIND] = 95,
+ [Q_KEY_CODE_CUT] = 97,
+ [Q_KEY_CODE_LF] = 111,
+ [Q_KEY_CODE_HELP] = 118,
+ [Q_KEY_CODE_META_L] = 120,
+ [Q_KEY_CODE_META_R] = 122,
+ [Q_KEY_CODE_COMPOSE] = 67,
+ [Q_KEY_CODE_PRINT] = 22,
+ [Q_KEY_CODE_SYSRQ] = 21,
};
-static const uint8_t e0_keycodes[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
- 113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
-};
-
-static void sunkbd_event(void *opaque, int ch)
+static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
{
- ChannelState *s = opaque;
- int release = ch & 0x80;
-
- trace_escc_sunkbd_event_in(ch);
- switch (ch) {
- case 58: // Caps lock press
- s->caps_lock_mode ^= 1;
- if (s->caps_lock_mode == 2)
- return; // Drop second press
- break;
- case 69: // Num lock press
- s->num_lock_mode ^= 1;
- if (s->num_lock_mode == 2)
- return; // Drop second press
- break;
- case 186: // Caps lock release
- s->caps_lock_mode ^= 2;
- if (s->caps_lock_mode == 3)
- return; // Drop first release
- break;
- case 197: // Num lock release
- s->num_lock_mode ^= 2;
- if (s->num_lock_mode == 3)
- return; // Drop first release
- break;
- case 0xe0:
- s->e0_mode = 1;
- return;
- default:
- break;
+ ChannelState *s = (ChannelState *)dev;
+ int qcode, keycode;
+
+ assert(evt->kind == INPUT_EVENT_KIND_KEY);
+ qcode = qemu_input_key_value_to_qcode(evt->key->key);
+ trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode],
+ evt->key->down);
+
+ if (qcode == Q_KEY_CODE_CAPS_LOCK) {
+ if (evt->key->down) {
+ s->caps_lock_mode ^= 1;
+ if (s->caps_lock_mode == 2) {
+ return; /* Drop second press */
+ }
+ } else {
+ s->caps_lock_mode ^= 2;
+ if (s->caps_lock_mode == 3) {
+ return; /* Drop first release */
+ }
+ }
}
- if (s->e0_mode) {
- s->e0_mode = 0;
- ch = e0_keycodes[ch & 0x7f];
- } else {
- ch = keycodes[ch & 0x7f];
+
+ if (qcode == Q_KEY_CODE_NUM_LOCK) {
+ if (evt->key->down) {
+ s->num_lock_mode ^= 1;
+ if (s->num_lock_mode == 2) {
+ return; /* Drop second press */
+ }
+ } else {
+ s->num_lock_mode ^= 2;
+ if (s->num_lock_mode == 3) {
+ return; /* Drop first release */
+ }
+ }
+ }
+
+ keycode = qcode_to_keycode[qcode];
+ if (!evt->key->down) {
+ keycode |= 0x80;
}
- trace_escc_sunkbd_event_out(ch);
- put_queue(s, ch | release);
+ trace_escc_sunkbd_event_out(keycode);
+ put_queue(s, keycode);
}
+static QemuInputHandler sunkbd_handler = {
+ .name = "sun keyboard",
+ .mask = INPUT_EVENT_MASK_KEY,
+ .event = sunkbd_handle_event,
+};
+
static void handle_kbd_command(ChannelState *s, int val)
{
trace_escc_kbd_command(val);
@@ -800,7 +912,7 @@ static void handle_kbd_command(ChannelState *s, int val)
case 0xf:
clear_queue(s);
put_queue(s, 0xfe);
- put_queue(s, 0); // XXX, layout?
+ put_queue(s, 0x21); /* en-us layout */
break;
default:
break;
@@ -898,7 +1010,8 @@ static int escc_init1(SysBusDevice *dev)
"QEMU Sun Mouse");
}
if (s->chn[1].type == kbd) {
- qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
+ s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]),
+ &sunkbd_handler);
}
return 0;
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 34120796b1..22b77dfe5c 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -24,6 +24,7 @@
#include "hw/hw.h"
#include "hw/input/ps2.h"
#include "ui/console.h"
+#include "ui/input.h"
#include "sysemu/sysemu.h"
/* debug PC keyboard */
@@ -71,10 +72,12 @@
#define MOUSE_STATUS_ENABLED 0x20
#define MOUSE_STATUS_SCALE21 0x10
-#define PS2_QUEUE_SIZE 256
+#define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */
typedef struct {
- uint8_t data[PS2_QUEUE_SIZE];
+ /* Keep the data array 256 bytes long, which compatibility
+ with older qemu versions. */
+ uint8_t data[256];
int rptr, wptr, count;
} PS2Queue;
@@ -137,7 +140,7 @@ void ps2_queue(void *opaque, int b)
PS2State *s = (PS2State *)opaque;
PS2Queue *q = &s->queue;
- if (q->count >= PS2_QUEUE_SIZE)
+ if (q->count >= PS2_QUEUE_SIZE - 1)
return;
q->data[q->wptr] = b;
if (++q->wptr == PS2_QUEUE_SIZE)
@@ -170,6 +173,21 @@ static void ps2_put_keycode(void *opaque, int keycode)
ps2_queue(&s->common, keycode);
}
+static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
+{
+ PS2KbdState *s = (PS2KbdState *)dev;
+ int scancodes[3], i, count;
+
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ count = qemu_input_key_value_to_scancode(evt->key->key,
+ evt->key->down,
+ scancodes);
+ for (i = 0; i < count; i++) {
+ ps2_put_keycode(s, scancodes[i]);
+ }
+}
+
uint32_t ps2_read_data(void *opaque)
{
PS2State *s = (PS2State *)opaque;
@@ -352,31 +370,57 @@ static void ps2_mouse_send_packet(PS2MouseState *s)
s->mouse_dz -= dz1;
}
-static void ps2_mouse_event(void *opaque,
- int dx, int dy, int dz, int buttons_state)
+static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
{
- PS2MouseState *s = opaque;
+ static const int bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
+ [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
+ [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
+ };
+ PS2MouseState *s = (PS2MouseState *)dev;
/* check if deltas are recorded when disabled */
if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
return;
- s->mouse_dx += dx;
- s->mouse_dy -= dy;
- s->mouse_dz += dz;
- /* XXX: SDL sometimes generates nul events: we delete them */
- if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
- s->mouse_buttons == buttons_state)
- return;
- s->mouse_buttons = buttons_state;
+ switch (evt->kind) {
+ case INPUT_EVENT_KIND_REL:
+ if (evt->rel->axis == INPUT_AXIS_X) {
+ s->mouse_dx += evt->rel->value;
+ } else if (evt->rel->axis == INPUT_AXIS_Y) {
+ s->mouse_dy -= evt->rel->value;
+ }
+ break;
- if (buttons_state) {
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ case INPUT_EVENT_KIND_BTN:
+ if (evt->btn->down) {
+ s->mouse_buttons |= bmap[evt->btn->button];
+ if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
+ s->mouse_dz--;
+ } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+ s->mouse_dz++;
+ }
+ } else {
+ s->mouse_buttons &= ~bmap[evt->btn->button];
+ }
+ break;
+
+ default:
+ /* keep gcc happy */
+ break;
}
+}
- if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
- (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
- for(;;) {
+static void ps2_mouse_sync(DeviceState *dev)
+{
+ PS2MouseState *s = (PS2MouseState *)dev;
+
+ if (s->mouse_buttons) {
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ }
+ if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
+ while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
/* if not remote, send event. Multiple events are sent if
too big deltas */
ps2_mouse_send_packet(s);
@@ -388,7 +432,9 @@ static void ps2_mouse_event(void *opaque,
void ps2_mouse_fake_event(void *opaque)
{
- ps2_mouse_event(opaque, 1, 0, 0, 0);
+ PS2MouseState *s = opaque;
+ s->mouse_dx++;
+ ps2_mouse_sync(opaque);
}
void ps2_write_mouse(void *opaque, int val)
@@ -528,6 +574,34 @@ static void ps2_common_reset(PS2State *s)
s->update_irq(s->update_arg, 0);
}
+static void ps2_common_post_load(PS2State *s)
+{
+ PS2Queue *q = &s->queue;
+ int size;
+ int i;
+ int tmp_data[PS2_QUEUE_SIZE];
+
+ /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
+ size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
+
+ /* move the queue elements to the start of data array */
+ if (size > 0) {
+ for (i = 0; i < size; i++) {
+ /* move the queue elements to the temporary buffer */
+ tmp_data[i] = q->data[q->rptr];
+ if (++q->rptr == 256) {
+ q->rptr = 0;
+ }
+ }
+ memcpy(q->data, tmp_data, size);
+ }
+ /* reset rptr/wptr/count */
+ q->rptr = 0;
+ q->wptr = size;
+ q->count = size;
+ s->update_irq(s->update_arg, q->count != 0);
+}
+
static void ps2_kbd_reset(void *opaque)
{
PS2KbdState *s = (PS2KbdState *) opaque;
@@ -600,18 +674,31 @@ static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
static int ps2_kbd_post_load(void* opaque, int version_id)
{
PS2KbdState *s = (PS2KbdState*)opaque;
+ PS2State *ps2 = &s->common;
if (version_id == 2)
s->scancode_set=2;
+
+ ps2_common_post_load(ps2);
+
return 0;
}
+static void ps2_kbd_pre_save(void *opaque)
+{
+ PS2KbdState *s = (PS2KbdState *)opaque;
+ PS2State *ps2 = &s->common;
+
+ ps2_common_post_load(ps2);
+}
+
static const VMStateDescription vmstate_ps2_keyboard = {
.name = "ps2kbd",
.version_id = 3,
.minimum_version_id = 2,
.minimum_version_id_old = 2,
.post_load = ps2_kbd_post_load,
+ .pre_save = ps2_kbd_pre_save,
.fields = (VMStateField []) {
VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
VMSTATE_INT32(scan_enabled, PS2KbdState),
@@ -629,11 +716,31 @@ static const VMStateDescription vmstate_ps2_keyboard = {
}
};
+static int ps2_mouse_post_load(void *opaque, int version_id)
+{
+ PS2MouseState *s = (PS2MouseState *)opaque;
+ PS2State *ps2 = &s->common;
+
+ ps2_common_post_load(ps2);
+
+ return 0;
+}
+
+static void ps2_mouse_pre_save(void *opaque)
+{
+ PS2MouseState *s = (PS2MouseState *)opaque;
+ PS2State *ps2 = &s->common;
+
+ ps2_common_post_load(ps2);
+}
+
static const VMStateDescription vmstate_ps2_mouse = {
.name = "ps2mouse",
.version_id = 2,
.minimum_version_id = 2,
.minimum_version_id_old = 2,
+ .post_load = ps2_mouse_post_load,
+ .pre_save = ps2_mouse_pre_save,
.fields = (VMStateField []) {
VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
VMSTATE_UINT8(mouse_status, PS2MouseState),
@@ -650,6 +757,12 @@ static const VMStateDescription vmstate_ps2_mouse = {
}
};
+static QemuInputHandler ps2_keyboard_handler = {
+ .name = "QEMU PS/2 Keyboard",
+ .mask = INPUT_EVENT_MASK_KEY,
+ .event = ps2_keyboard_event,
+};
+
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
{
PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
@@ -658,11 +771,19 @@ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
s->common.update_arg = update_arg;
s->scancode_set = 2;
vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
- qemu_add_kbd_event_handler(ps2_put_keycode, s);
+ qemu_input_handler_register((DeviceState *)s,
+ &ps2_keyboard_handler);
qemu_register_reset(ps2_kbd_reset, s);
return s;
}
+static QemuInputHandler ps2_mouse_handler = {
+ .name = "QEMU PS/2 Mouse",
+ .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+ .event = ps2_mouse_event,
+ .sync = ps2_mouse_sync,
+};
+
void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
{
PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
@@ -670,7 +791,8 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
s->common.update_irq = update_irq;
s->common.update_arg = update_arg;
vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
- qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
+ qemu_input_handler_register((DeviceState *)s,
+ &ps2_mouse_handler);
qemu_register_reset(ps2_mouse_reset, s);
return s;
}
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index e6e1ffd1bb..baee46f981 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -21,6 +21,7 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "sysemu/dma.h"
+#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "qemu/iov.h"
#include "hw/scsi/scsi.h"
@@ -43,9 +44,11 @@
#define MEGASAS_FLAG_USE_JBOD 0
#define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD)
-#define MEGASAS_FLAG_USE_MSIX 1
+#define MEGASAS_FLAG_USE_MSI 1
+#define MEGASAS_MASK_USE_MSI (1 << MEGASAS_FLAG_USE_MSI)
+#define MEGASAS_FLAG_USE_MSIX 2
#define MEGASAS_MASK_USE_MSIX (1 << MEGASAS_FLAG_USE_MSIX)
-#define MEGASAS_FLAG_USE_QUEUE64 2
+#define MEGASAS_FLAG_USE_QUEUE64 3
#define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64)
static const char *mfi_frame_desc[] = {
@@ -132,6 +135,11 @@ static bool megasas_use_queue64(MegasasState *s)
return s->flags & MEGASAS_MASK_USE_QUEUE64;
}
+static bool megasas_use_msi(MegasasState *s)
+{
+ return s->flags & MEGASAS_MASK_USE_MSI;
+}
+
static bool megasas_use_msix(MegasasState *s)
{
return s->flags & MEGASAS_MASK_USE_MSIX;
@@ -538,6 +546,9 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context)
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 {
trace_megasas_irq_raise();
pci_irq_assert(pci_dev);
@@ -1106,6 +1117,21 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
return MFI_STAT_OK;
}
+static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd)
+{
+ uint16_t flags;
+
+ /* 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);
+ }
+
+ return MFI_STAT_OK;
+}
+
static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
MegasasCmd *cmd)
{
@@ -1409,6 +1435,8 @@ static const struct dcmd_cmd_tbl_t {
megasas_dcmd_dummy },
{ MFI_DCMD_LD_GET_LIST, "LD_GET_LIST",
megasas_dcmd_ld_get_list},
+ { MFI_DCMD_LD_LIST_QUERY, "LD_LIST_QUERY",
+ megasas_dcmd_ld_list_query },
{ MFI_DCMD_LD_GET_INFO, "LD_GET_INFO",
megasas_dcmd_ld_get_info },
{ MFI_DCMD_LD_GET_PROP, "LD_GET_PROP",
@@ -1939,12 +1967,20 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
break;
case MFI_OMSK:
s->intr_mask = val;
- if (!megasas_intr_enabled(s) && !msix_enabled(pci_dev)) {
+ if (!megasas_intr_enabled(s) &&
+ !msi_enabled(pci_dev) &&
+ !msix_enabled(pci_dev)) {
trace_megasas_irq_lower();
pci_irq_deassert(pci_dev);
}
if (megasas_intr_enabled(s)) {
- trace_megasas_intr_enabled();
+ if (msix_enabled(pci_dev)) {
+ trace_megasas_msix_enabled(0);
+ } else if (msi_enabled(pci_dev)) {
+ trace_megasas_msi_enabled(0);
+ } else {
+ trace_megasas_intr_enabled();
+ }
} else {
trace_megasas_intr_disabled();
}
@@ -2068,6 +2104,7 @@ static const VMStateDescription vmstate_megasas = {
.minimum_version_id_old = 0,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, MegasasState),
+ VMSTATE_MSIX(parent_obj, MegasasState),
VMSTATE_INT32(fw_state, MegasasState),
VMSTATE_INT32(intr_mask, MegasasState),
@@ -2083,9 +2120,12 @@ static void megasas_scsi_uninit(PCIDevice *d)
{
MegasasState *s = MEGASAS(d);
-#ifdef USE_MSIX
- msix_uninit(d, &s->mmio_io);
-#endif
+ if (megasas_use_msix(s)) {
+ msix_uninit(d, &s->mmio_io, &s->mmio_io);
+ }
+ if (megasas_use_msi(s)) {
+ msi_uninit(d);
+ }
memory_region_destroy(&s->mmio_io);
memory_region_destroy(&s->port_io);
memory_region_destroy(&s->queue_io);
@@ -2124,15 +2164,15 @@ static int megasas_scsi_init(PCIDevice *dev)
memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s,
"megasas-queue", 0x40000);
-#ifdef USE_MSIX
- /* MSI-X support is currently broken */
+ if (megasas_use_msi(s) &&
+ msi_init(dev, 0x50, 1, true, false)) {
+ s->flags &= ~MEGASAS_MASK_USE_MSI;
+ }
if (megasas_use_msix(s) &&
- msix_init(dev, 15, &s->mmio_io, 0, 0x2000)) {
+ msix_init(dev, 15, &s->mmio_io, 0, 0x2000,
+ &s->mmio_io, 0, 0x3800, 0x68)) {
s->flags &= ~MEGASAS_MASK_USE_MSIX;
}
-#else
- s->flags &= ~MEGASAS_MASK_USE_MSIX;
-#endif
bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64;
pci_register_bar(dev, 0, bar_type, &s->mmio_io);
@@ -2151,7 +2191,7 @@ static int megasas_scsi_init(PCIDevice *dev)
s->sas_addr |= PCI_FUNC(dev->devfn);
}
if (!s->hba_serial) {
- s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
+ s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
}
if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
@@ -2164,7 +2204,6 @@ static int megasas_scsi_init(PCIDevice *dev)
s->fw_cmds = MEGASAS_MAX_FRAMES;
}
trace_megasas_init(s->fw_sge, s->fw_cmds,
- megasas_use_msix(s) ? "MSI-X" : "INTx",
megasas_is_jbod(s) ? "jbod" : "raid");
s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ?
MAX_SCSI_DEVS : MFI_MAX_LD;
@@ -2189,6 +2228,13 @@ static int megasas_scsi_init(PCIDevice *dev)
return 0;
}
+static void
+megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len)
+{
+ pci_default_write_config(pci, addr, val, len);
+ msi_write_config(pci, addr, val, len);
+}
+
static Property megasas_properties[] = {
DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
MEGASAS_DEFAULT_SGE),
@@ -2196,10 +2242,10 @@ static Property megasas_properties[] = {
MEGASAS_DEFAULT_FRAMES),
DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0),
-#ifdef USE_MSIX
+ DEFINE_PROP_BIT("use_msi", MegasasState, flags,
+ MEGASAS_FLAG_USE_MSI, false),
DEFINE_PROP_BIT("use_msix", MegasasState, flags,
MEGASAS_FLAG_USE_MSIX, false),
-#endif
DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
MEGASAS_FLAG_USE_JBOD, false),
DEFINE_PROP_END_OF_LIST(),
@@ -2222,6 +2268,7 @@ static void megasas_class_init(ObjectClass *oc, void *data)
dc->vmsd = &vmstate_megasas;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->desc = "LSI MegaRAID SAS 1078";
+ pc->config_write = megasas_write_config;
}
static const TypeInfo megasas_info = {
diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h
index cd8355badf..a3034f6239 100644
--- a/hw/scsi/mfi.h
+++ b/hw/scsi/mfi.h
@@ -164,6 +164,7 @@ typedef enum {
MFI_DCMD_PD_BLINK = 0x02070100,
MFI_DCMD_PD_UNBLINK = 0x02070200,
MFI_DCMD_LD_GET_LIST = 0x03010000,
+ MFI_DCMD_LD_LIST_QUERY = 0x03010100,
MFI_DCMD_LD_GET_INFO = 0x03020000,
MFI_DCMD_LD_GET_PROP = 0x03030000,
MFI_DCMD_LD_SET_PROP = 0x03040000,
@@ -411,6 +412,14 @@ typedef enum {
MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, /*query for system drives */
} mfi_pd_query_type;
+typedef enum {
+ MR_LD_QUERY_TYPE_ALL = 0,
+ MR_LD_QUERY_TYPE_EXPOSED_TO_HOST = 1,
+ MR_LD_QUERY_TYPE_USED_TGT_IDS = 2,
+ MR_LD_QUERY_TYPE_CLUSTER_ACCESS = 3,
+ MR_LD_QUERY_TYPE_CLUSTER_LOCALE = 4,
+} mfi_ld_query_type;
+
/*
* Other propertities and definitions
*/
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 48a28ae199..4bcef551a6 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2458,21 +2458,27 @@ static int scsi_block_initfn(SCSIDevice *dev)
int rc;
if (!s->qdev.conf.bs) {
- error_report("scsi-block: drive property not set");
+ error_report("drive property not set");
return -1;
}
/* check we are using a driver managing SG_IO (version 3 and after) */
- if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
- sg_version < 30000) {
- error_report("scsi-block: scsi generic interface too old");
+ rc = bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version);
+ if (rc < 0) {
+ error_report("cannot get SG_IO version number: %s. "
+ "Is this a SCSI device?",
+ strerror(-rc));
+ return -1;
+ }
+ if (sg_version < 30000) {
+ error_report("scsi generic interface too old");
return -1;
}
/* get device type from INQUIRY data */
rc = get_device_type(s);
if (rc < 0) {
- error_report("scsi-block: INQUIRY failed");
+ error_report("INQUIRY failed");
return -1;
}
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 8d92e0da15..3733d2c36c 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -394,6 +394,7 @@ static void scsi_destroy(SCSIDevice *s)
static int scsi_generic_initfn(SCSIDevice *s)
{
+ int rc;
int sg_version;
struct sg_scsi_id scsiid;
@@ -412,8 +413,11 @@ static int scsi_generic_initfn(SCSIDevice *s)
}
/* check we are using a driver managing SG_IO (version 3 and after */
- if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) {
- error_report("scsi generic interface not supported");
+ rc = bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version);
+ if (rc < 0) {
+ error_report("cannot get SG_IO version number: %s. "
+ "Is this a SCSI device?",
+ strerror(-rc));
return -1;
}
if (sg_version < 30000) {