From 5e23f480df7a451dab6f82c4f13520b089daaf0e Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Nov 2009 22:59:02 -0200 Subject: QMP: Allow 'query-' commands The 'info' command makes sense for the user protocol, but for QMP it doesn't, as its return data is not well defined. That is, it can return anything. To fix this Avi proposes having 'query-' commands when in protocol mode. For example, 'info balloon' would become 'query-balloon'. The right way of supporting this would probably be to move all info handlers to qemu-monitor.hx, add a flags field to mon_cmd_t to identify them and then modify do_info() to do its search based on that flag. Unfortunately, this would require a big change in the Monitor. To make things simpler for now, this commit takes a different approach: a check for commands starting with "query-" is added to toplevel QMP code, if it's true we setup things so that do_info() is called with the appropriate arguments. This is a hack, but is a temporary one and guarantees that query- commands will work from the first day. Also note that 'info' is not allowed in protocol mode. Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- monitor.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index 845e40547..beaff6425 100644 --- a/monitor.c +++ b/monitor.c @@ -3728,9 +3728,9 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) int err; QObject *obj; QDict *input, *args; - const char *cmd_name; const mon_cmd_t *cmd; Monitor *mon = cur_mon; + const char *cmd_name, *info_item; args = NULL; qemu_errors_to_mon(mon); @@ -3761,10 +3761,24 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) } cmd_name = qstring_get_str(qobject_to_qstring(obj)); - cmd = monitor_find_command(cmd_name); - if (!cmd) { + + /* + * XXX: We need this special case until we get info handlers + * converted into 'query-' commands + */ + if (compare_cmd(cmd_name, "info")) { qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_input; + } else if (strstart(cmd_name, "query-", &info_item)) { + cmd = monitor_find_command("info"); + qdict_put_obj(input, "arguments", + qobject_from_jsonf("{ 'item': %s }", info_item)); + } else { + cmd = monitor_find_command(cmd_name); + if (!cmd) { + qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name); + goto err_input; + } } obj = qdict_get(input, "arguments"); -- cgit v1.2.3-65-gdbad From 0d1ea871b09fc74b4a2085150980b43bd1973744 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Nov 2009 22:59:03 -0200 Subject: QMP: Asynchronous events infrastructure Asynchronous events are generated with a call to monitor_protocol_event(). This function builds the right data-type and emit the event right away. The emitted data is always a JSON object and its format is as follows: { "event": json-string, "timestamp": { "seconds": json-number, "microseconds": json-number }, "data": json-value } This design is based on ideas by Amit Shah . Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- monitor.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ monitor.h | 6 ++++++ qemu-tool.c | 4 ++++ 3 files changed, 60 insertions(+) diff --git a/monitor.c b/monitor.c index beaff6425..68b63cacc 100644 --- a/monitor.c +++ b/monitor.c @@ -307,6 +307,56 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data) QDECREF(qmp); } +static void timestamp_put(QDict *qdict) +{ + int err; + QObject *obj; + struct timeval tv; + + err = gettimeofday(&tv, NULL); + if (err < 0) + return; + + obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", " + "'microseconds': %" PRId64 " }", + (int64_t) tv.tv_sec, (int64_t) tv.tv_usec); + assert(obj != NULL); + + qdict_put_obj(qdict, "timestamp", obj); +} + +/** + * monitor_protocol_event(): Generate a Monitor event + * + * Event-specific data can be emitted through the (optional) 'data' parameter. + */ +void monitor_protocol_event(MonitorEvent event, QObject *data) +{ + QDict *qmp; + const char *event_name; + Monitor *mon = cur_mon; + + assert(event < EVENT_MAX); + + if (!monitor_ctrl_mode(mon)) + return; + + switch (event) { + default: + abort(); + break; + } + + qmp = qdict_new(); + timestamp_put(qmp); + qdict_put(qmp, "event", qstring_from_str(event_name)); + if (data) + qdict_put_obj(qmp, "data", data); + + monitor_json_emitter(mon, QOBJECT(qmp)); + QDECREF(qmp); +} + static int compare_cmd(const char *name, const char *list) { const char *p, *pstart; diff --git a/monitor.h b/monitor.h index 556507ce8..a1d8b7a5f 100644 --- a/monitor.h +++ b/monitor.h @@ -13,6 +13,12 @@ extern Monitor *cur_mon; #define MONITOR_USE_READLINE 0x02 #define MONITOR_USE_CONTROL 0x04 +/* QMP events */ +typedef enum MonitorEvent { + EVENT_MAX, +} MonitorEvent; + +void monitor_protocol_event(MonitorEvent event, QObject *data); const char *monitor_cmdline_parse(const char *cmdline, int *flags); void monitor_init(CharDriverState *chr, int flags); diff --git a/qemu-tool.c b/qemu-tool.c index b35ea8e1c..18b48af31 100644 --- a/qemu-tool.c +++ b/qemu-tool.c @@ -56,6 +56,10 @@ int get_async_context_id(void) return 0; } +void monitor_protocol_event(MonitorEvent event, QObject *data) +{ +} + QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) { QEMUBH *bh; -- cgit v1.2.3-65-gdbad From b1a15e7eaafba8f26e2263b1a9b6e6d40e585e72 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Nov 2009 22:59:04 -0200 Subject: QMP: Introduce basic asynchronous events Debug, shutdown, reset, powerdown and stop are all basic events, as they are very simple they can be added in the same commit. Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- monitor.c | 15 +++++++++++++++ monitor.h | 5 +++++ vl.c | 11 +++++++++-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/monitor.c b/monitor.c index 68b63cacc..cd2f19c19 100644 --- a/monitor.c +++ b/monitor.c @@ -342,6 +342,21 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) return; switch (event) { + case EVENT_DEBUG: + event_name = "DEBUG"; + break; + case EVENT_SHUTDOWN: + event_name = "SHUTDOWN"; + break; + case EVENT_RESET: + event_name = "RESET"; + break; + case EVENT_POWERDOWN: + event_name = "POWERDOWN"; + break; + case EVENT_STOP: + event_name = "STOP"; + break; default: abort(); break; diff --git a/monitor.h b/monitor.h index a1d8b7a5f..851fd3366 100644 --- a/monitor.h +++ b/monitor.h @@ -15,6 +15,11 @@ extern Monitor *cur_mon; /* QMP events */ typedef enum MonitorEvent { + EVENT_DEBUG, + EVENT_SHUTDOWN, + EVENT_RESET, + EVENT_POWERDOWN, + EVENT_STOP, EVENT_MAX, } MonitorEvent; diff --git a/vl.c b/vl.c index 2e0fb3966..e6fcccf20 100644 --- a/vl.c +++ b/vl.c @@ -4060,9 +4060,12 @@ static void main_loop(void) #endif } while (vm_can_run()); - if (qemu_debug_requested()) + if (qemu_debug_requested()) { + monitor_protocol_event(EVENT_DEBUG, NULL); vm_stop(EXCP_DEBUG); + } if (qemu_shutdown_requested()) { + monitor_protocol_event(EVENT_SHUTDOWN, NULL); if (no_shutdown) { vm_stop(0); no_shutdown = 0; @@ -4070,15 +4073,19 @@ static void main_loop(void) break; } if (qemu_reset_requested()) { + monitor_protocol_event(EVENT_RESET, NULL); pause_all_vcpus(); qemu_system_reset(); resume_all_vcpus(); } if (qemu_powerdown_requested()) { + monitor_protocol_event(EVENT_POWERDOWN, NULL); qemu_irq_raise(qemu_system_powerdown); } - if ((r = qemu_vmstop_requested())) + if ((r = qemu_vmstop_requested())) { + monitor_protocol_event(EVENT_STOP, NULL); vm_stop(r); + } } pause_all_vcpus(); } -- cgit v1.2.3-65-gdbad From 4a29a85db9e67fcd07e6ca55d69e369e9874ec95 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Nov 2009 22:59:05 -0200 Subject: QMP: Disable monitor print functions We still have handlers which will call monitor print functions in several places. Usually to report errors. If they do this when we are in control mode, we will be emitting garbage to our clients. To avoid this problem, this commit adds a way to disable those functions. If any of them is called when in control mode, we will emit a generic error. Although this is far from the perfect solution, it guarantees that only JSON is sent to Clients. Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- monitor.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index cd2f19c19..af6d3d5d2 100644 --- a/monitor.c +++ b/monitor.c @@ -98,6 +98,7 @@ struct mon_fd_t { typedef struct MonitorControl { QObject *id; + int print_enabled; JSONMessageParser parser; } MonitorControl; @@ -186,9 +187,13 @@ static void monitor_puts(Monitor *mon, const char *str) void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { - char buf[4096]; - vsnprintf(buf, sizeof(buf), fmt, ap); - monitor_puts(mon, buf); + if (mon->mc && !mon->mc->print_enabled) { + qemu_error_new(QERR_UNDEFINED_ERROR); + } else { + char buf[4096]; + vsnprintf(buf, sizeof(buf), fmt, ap); + monitor_puts(mon, buf); + } } void monitor_printf(Monitor *mon, const char *fmt, ...) @@ -272,7 +277,10 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data) json = qobject_to_json(data); assert(json != NULL); + mon->mc->print_enabled = 1; monitor_printf(mon, "%s\n", qstring_get_str(json)); + mon->mc->print_enabled = 0; + QDECREF(json); } -- cgit v1.2.3-65-gdbad From 26d5a1cd23c3803f931cedbcb352dfa66d388375 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Nov 2009 22:59:06 -0200 Subject: QMP: Introduce README file Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- QMP/README | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 QMP/README diff --git a/QMP/README b/QMP/README new file mode 100644 index 000000000..50c31f20c --- /dev/null +++ b/QMP/README @@ -0,0 +1,51 @@ + QEMU Monitor Protocol + ===================== + +Introduction +------------- + +The QEMU Monitor Protocol (QMP) is a JSON[1] based protocol for QEMU. + +By using it applications can control QEMU in reliable and "parseable" way, +QMP also provides asynchronous events support. + +For more information, please, refer to the following files: + +o qmp-spec.txt QEMU Monitor Protocol current draft specification +o qmp-events.txt List of available asynchronous events + +There are also two simple Python scripts available: + +o qmp-shell A shell +o vm-info Show some informations about the Virtal Machine + +[1] http://www.json.org + +Usage +----- + +To enable QMP, QEMU has to be started in "control mode". This is done +by passing the flag "control" to the "-monitor" command-line option. + +For example: + +$ qemu [...] -monitor control,tcp:localhost:4444,server + +Will start QEMU in control mode, waiting for a client TCP connection +on localhost port 4444. + +To manually test it you can connect with telnet and issue commands: + +$ telnet localhost 4444 +Trying ::1... +Connected to localhost. +Escape character is '^]'. +{"QMP": {"capabilities": []}} +{ "execute": "query-version" } +{"return": "0.11.50"} + +Contact +------- + +http://www.linux-kvm.org/page/MonitorProtocol +Luiz Fernando N. Capitulino -- cgit v1.2.3-65-gdbad From f544d174dfc9ff26a0ae52c68289a67722f19cdf Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Nov 2009 22:59:07 -0200 Subject: QMP: Introduce specification Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- QMP/qmp-spec.txt | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 QMP/qmp-spec.txt diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt new file mode 100644 index 000000000..8429789a9 --- /dev/null +++ b/QMP/qmp-spec.txt @@ -0,0 +1,192 @@ + QEMU Monitor Protocol Draft Specification - Version 0.1 + +1. Introduction +=============== + +This document specifies the QEMU Monitor Protocol (QMP), a JSON-based protocol +which is available for applications to control QEMU at the machine-level. + +To enable QMP support, QEMU has to be run in "control mode". This is done by +starting QEMU with the appropriate command-line options. Please, refer to the +QEMU manual page for more information. + +2. Protocol Specification +========================= + +This section details the protocol format. For the purpose of this document +"Client" is any application which is communicating with QEMU in control mode, +and "Server" is QEMU itself. + +JSON data structures, when mentioned in this document, are always in the +following format: + + json-DATA-STRUCTURE-NAME + +Where DATA-STRUCTURE-NAME is any valid JSON data structure, as defined by +the JSON standard: + +http://www.ietf.org/rfc/rfc4627.txt + +For convenience, json-objects mentioned in this document will have its members +in a certain order. However, in real protocol usage json-objects members can +be in ANY order, thus no particular order should be assumed. + +2.1 General Definitions +----------------------- + +2.1.1 All interactions transmitted by the Server are json-objects, always + terminating with CRLF + +2.1.2 All json-objects members are mandatory when not specified otherwise + +2.2 Server Greeting +------------------- + +Right when connected the Server will issue a greeting message, which signals +that the connection has been successfully established and that the Server is +waiting for commands. + +The format is: + +{ "QMP": { "capabilities": json-array } } + + Where, + +- The "capabilities" member specify the availability of features beyond the + baseline specification + +2.3 Issuing Commands +-------------------- + +The format for command execution is: + +{ "execute": json-string, "arguments": json-object, "id": json-value } + + Where, + +- The "execute" member identifies the command to be executed by the Server +- The "arguments" member is used to pass any arguments required for the + execution of the command, it is optional when no arguments are required +- The "id" member is a transaction identification associated with the + command execution, it is optional and will be part of the response if + provided + +2.4 Commands Responses +---------------------- + +There are two possible responses which the Server will issue as the result +of a command execution: success or error. + +2.4.1 success +------------- + +The success response is issued when the command execution has finished +without errors. + +The format is: + +{ "return": json-value, "id": json-value } + + Where, + +- The "return" member contains the command returned data, which is defined + in a per-command basis or "OK" if the command does not return data +- The "id" member contains the transaction identification associated + with the command execution (if issued by the Client) + +2.4.2 error +----------- + +The error response is issued when the command execution could not be +completed because of an error condition. + +The format is: + +{ "error": { "class": json-string, "data": json-value }, "id": json-value } + + Where, + +- The "class" member contains the error class name (eg. "ServiceUnavailable") +- The "data" member contains specific error data and is defined in a + per-command basis, it will be an empty json-object if the error has no data +- The "id" member contains the transaction identification associated with + the command execution (if issued by the Client) + +NOTE: Some errors can occur before the Server is able to read the "id" member, +in these cases the "id" member will not be part of the error response, even +if provided by the client. + +2.5 Asynchronous events +----------------------- + +As a result of state changes, the Server may send messages unilaterally +to the Client at any time. They are called 'asynchronous events'. + +The format is: + +{ "event": json-string, "data": json-value, + "timestamp": { "seconds": json-number, "microseconds": json-number } } + + Where, + +- The "event" member contains the event's name +- The "data" member contains event specific data, which is defined in a + per-event basis, it is optional +- The "timestamp" member contains the exact time of when the event ocurred + in the Server. It is a fixed json-object with time in seconds and + microseconds + +For a listing of supported asynchronous events, please, refer to the +qmp-events.txt file. + +3. QMP Examples +=============== + +This section provides some examples of real QMP usage, in all of them +'C' stands for 'Client' and 'S' stands for 'Server'. + +3.1 Server greeting +------------------- + +S: {"QMP": {"capabilities": []}} + +3.2 Simple 'stop' execution +--------------------------- + +C: { "execute": "stop" } +S: {"return": "OK"} + +3.3 KVM information +------------------- + +C: {"execute": "query-kvm", "id": "example"} +S: {"return": "enabled", "id": "example"} + +3.4 Parsing error +------------------ + +C: { "execute": } +S: {"error": {"class": "JSONParsing", "data": {}}} + +3.5 Powerdown event +------------------- + +S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event": +"POWERDOWN"} + +4. Notes to Client implementors +------------------------------- + +4.1 It is recommended to always start the Server in pause mode, thus the + Client is able to perform any setup procedure without the risk of + race conditions and related problems + +4.2 It is recommended to always check the capabilities json-array, issued + with the greeting message, at connection time + +4.3 Json-objects or json-arrays mentioned in this document are not fixed + and no particular size or number of members/elements should be assumed. + New members/elements can be added at any time. + +4.4 No particular order of json-objects members should be assumed, they + can change at any time -- cgit v1.2.3-65-gdbad From e2419113ddc6e1b7765a8ccebfc425e5547c7a19 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Nov 2009 22:59:08 -0200 Subject: QMP: Introduce qmp-events.txt Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- QMP/qmp-events.txt | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 QMP/qmp-events.txt diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt new file mode 100644 index 000000000..682a5e53a --- /dev/null +++ b/QMP/qmp-events.txt @@ -0,0 +1,26 @@ + QEMU Monitor Protocol: Events + ============================= + +1 SHUTDOWN +----------- + +Description: Issued when the Virtual Machine is powered down. +Data: None. + +2 RESET +------- + +Description: Issued when the Virtual Machine is reseted. +Data: None. + +3 STOP +------ + +Description: Issued when the Virtual Machine is stopped. +Data: None. + +4 DEBUG +------- + +Description: Issued when the Virtual Machine enters debug mode. +Data: None. -- cgit v1.2.3-65-gdbad From cedebdacd2307a3e4df9aec9839b12895c25e5f5 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Nov 2009 22:59:09 -0200 Subject: QMP: Introduce qmp-shell This is a very simple shell written in Python for demonstration purposes. Unfortunately it's a bit awkward right now, as the user has to specify the arguments names and the printed data can be a raw dictionary or list, like the following example: (QEMU) pci_add pci_addr=auto type=nic {u'slot': 5, u'bus': 0, u'domain': 0, u'function': 0} (QEMU) It's worth to note that the shell is broken into two files. One is the shell itself, the other is the QMP class which handles the communication with QEMU. Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- QMP/qmp-shell | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ QMP/qmp.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100755 QMP/qmp-shell create mode 100644 QMP/qmp.py diff --git a/QMP/qmp-shell b/QMP/qmp-shell new file mode 100755 index 000000000..f89b9af87 --- /dev/null +++ b/QMP/qmp-shell @@ -0,0 +1,72 @@ +#!/usr/bin/python +# +# Simple QEMU shell on top of QMP +# +# Copyright (C) 2009 Red Hat Inc. +# +# Authors: +# Luiz Capitulino +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# Usage: +# +# Start QEMU with: +# +# $ qemu [...] -monitor control,unix:./qmp,server +# +# Run the shell: +# +# $ qmp-shell ./qmp +# +# Commands have the following format: +# +# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ] +# +# For example: +# +# (QEMU) info item=network + +import qmp +import readline +from sys import argv,exit + +def shell_help(): + print 'bye exit from the shell' + +def main(): + if len(argv) != 2: + print 'qemu-shell ' + exit(1) + + qemu = qmp.QEMUMonitorProtocol(argv[1]) + qemu.connect() + + print 'Connected!' + + while True: + try: + cmd = raw_input('(QEMU) ') + except EOFError: + print + break + if cmd == '': + continue + elif cmd == 'bye': + break + elif cmd == 'help': + shell_help() + else: + try: + resp = qemu.send(cmd) + if resp == None: + print 'Disconnected' + break + print resp + except IndexError: + print '-> command format: ', + print '[arg-name1=arg1] ... [arg-nameN=argN]' + +if __name__ == '__main__': + main() diff --git a/QMP/qmp.py b/QMP/qmp.py new file mode 100644 index 000000000..d9da603be --- /dev/null +++ b/QMP/qmp.py @@ -0,0 +1,72 @@ +# QEMU Monitor Protocol Python class +# +# Copyright (C) 2009 Red Hat Inc. +# +# Authors: +# Luiz Capitulino +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. + +import socket, json + +class QMPError(Exception): + pass + +class QMPConnectError(QMPError): + pass + +class QEMUMonitorProtocol: + def connect(self): + self.sock.connect(self.filename) + data = self.__json_read() + if data == None: + raise QMPConnectError + if not data.has_key('QMP'): + raise QMPConnectError + return data['QMP']['capabilities'] + + def close(self): + self.sock.close() + + def send_raw(self, line): + self.sock.send(str(line)) + return self.__json_read() + + def send(self, cmdline): + cmd = self.__build_cmd(cmdline) + self.__json_send(cmd) + resp = self.__json_read() + if resp == None: + return + elif resp.has_key('error'): + return resp['error'] + else: + return resp['return'] + + def __build_cmd(self, cmdline): + cmdargs = cmdline.split() + qmpcmd = { 'execute': cmdargs[0], 'arguments': {} } + for arg in cmdargs[1:]: + opt = arg.split('=') + try: + value = int(opt[1]) + except ValueError: + value = opt[1] + qmpcmd['arguments'][opt[0]] = value + return qmpcmd + + def __json_send(self, cmd): + # XXX: We have to send any additional char, otherwise + # the Server won't read our input + self.sock.send(json.dumps(cmd) + ' ') + + def __json_read(self): + try: + return json.loads(self.sock.recv(1024)) + except ValueError: + return + + def __init__(self, filename): + self.filename = filename + self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -- cgit v1.2.3-65-gdbad From 01f2785ed7f316a48ed719e215bfa15b08d2d8da Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Nov 2009 22:59:10 -0200 Subject: QMP: Introduce vm-info A Python script which uses qmp.py to print some simple VM info. Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- QMP/vm-info | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100755 QMP/vm-info diff --git a/QMP/vm-info b/QMP/vm-info new file mode 100755 index 000000000..b150d8240 --- /dev/null +++ b/QMP/vm-info @@ -0,0 +1,32 @@ +#!/usr/bin/python +# +# Print Virtual Machine information +# +# Usage: +# +# Start QEMU with: +# +# $ qemu [...] -monitor control,unix:./qmp,server +# +# Run vm-info: +# +# $ vm-info ./qmp +# +# Luiz Capitulino + +import qmp +from sys import argv,exit + +def main(): + if len(argv) != 2: + print 'vm-info ' + exit(1) + + qemu = qmp.QEMUMonitorProtocol(argv[1]) + qemu.connect() + + for cmd in [ 'version', 'hpet', 'kvm', 'status', 'uuid', 'balloon' ]: + print cmd + ': ' + str(qemu.send('query-' + cmd)) + +if __name__ == '__main__': + main() -- cgit v1.2.3-65-gdbad From a244eb7429ecc34797abb23c0852257e31675716 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:33 +0100 Subject: audio: fix compilation of DEBUG_PLIVE Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- audio/audio_template.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/audio/audio_template.h b/audio/audio_template.h index 1a4707b2e..6b19848af 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -445,9 +445,9 @@ SW *glue (AUD_open_, TYPE) ( SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels); dolog ("New %s freq %d, bits %d, channels %d\n", name, - freq, - (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, - nchannels); + as->freq, + (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) ? 16 : 8, + as->nchannels); #endif if (live) { -- cgit v1.2.3-65-gdbad From d959fce9f06a53166c6d5fb593edf9c20cefc294 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:34 +0100 Subject: audio: port to vmstate Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- audio/audio.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 80a717bd2..a5305c492 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1784,23 +1784,15 @@ static void audio_atexit (void) } } -static void audio_save (QEMUFile *f, void *opaque) -{ - (void) f; - (void) opaque; -} - -static int audio_load (QEMUFile *f, void *opaque, int version_id) -{ - (void) f; - (void) opaque; - - if (version_id != 1) { - return -EINVAL; +static const VMStateDescription vmstate_audio = { + .name = "audio", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_END_OF_LIST() } - - return 0; -} +}; static void audio_init (void) { @@ -1900,7 +1892,7 @@ static void audio_init (void) } QLIST_INIT (&s->card_head); - register_savevm ("audio", 0, 1, audio_save, audio_load, s); + vmstate_register (0, &vmstate_audio, s); } void AUD_register_card (const char *name, QEMUSoundCard *card) -- cgit v1.2.3-65-gdbad From ebfd6f4d3f2b75db8b654723d480f51d023fd834 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:35 +0100 Subject: sb16: port to vmstate Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/sb16.c | 168 +++++++++++++++++++++++--------------------------------------- 1 file changed, 61 insertions(+), 107 deletions(-) diff --git a/hw/sb16.c b/hw/sb16.c index 12ddad43c..4c0d682fd 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -1244,115 +1244,10 @@ static void SB_audio_callback (void *opaque, int free) s->audio_free = free; } -static void SB_save (QEMUFile *f, void *opaque) +static int sb16_post_load (void *opaque, int version_id) { SB16State *s = opaque; - qemu_put_be32 (f, s->irq); - qemu_put_be32 (f, s->dma); - qemu_put_be32 (f, s->hdma); - qemu_put_be32 (f, s->port); - qemu_put_be32 (f, s->ver); - qemu_put_be32 (f, s->in_index); - qemu_put_be32 (f, s->out_data_len); - qemu_put_be32 (f, s->fmt_stereo); - qemu_put_be32 (f, s->fmt_signed); - qemu_put_be32 (f, s->fmt_bits); - qemu_put_be32s (f, &s->fmt); - qemu_put_be32 (f, s->dma_auto); - qemu_put_be32 (f, s->block_size); - qemu_put_be32 (f, s->fifo); - qemu_put_be32 (f, s->freq); - qemu_put_be32 (f, s->time_const); - qemu_put_be32 (f, s->speaker); - qemu_put_be32 (f, s->needed_bytes); - qemu_put_be32 (f, s->cmd); - qemu_put_be32 (f, s->use_hdma); - qemu_put_be32 (f, s->highspeed); - qemu_put_be32 (f, s->can_write); - qemu_put_be32 (f, s->v2x6); - - qemu_put_8s (f, &s->csp_param); - qemu_put_8s (f, &s->csp_value); - qemu_put_8s (f, &s->csp_mode); - qemu_put_8s (f, &s->csp_param); - qemu_put_buffer (f, s->csp_regs, 256); - qemu_put_8s (f, &s->csp_index); - qemu_put_buffer (f, s->csp_reg83, 4); - qemu_put_be32 (f, s->csp_reg83r); - qemu_put_be32 (f, s->csp_reg83w); - - qemu_put_buffer (f, s->in2_data, sizeof (s->in2_data)); - qemu_put_buffer (f, s->out_data, sizeof (s->out_data)); - qemu_put_8s (f, &s->test_reg); - qemu_put_8s (f, &s->last_read_byte); - - qemu_put_be32 (f, s->nzero); - qemu_put_be32 (f, s->left_till_irq); - qemu_put_be32 (f, s->dma_running); - qemu_put_be32 (f, s->bytes_per_second); - qemu_put_be32 (f, s->align); - - qemu_put_be32 (f, s->mixer_nreg); - qemu_put_buffer (f, s->mixer_regs, 256); -} - -static int SB_load (QEMUFile *f, void *opaque, int version_id) -{ - SB16State *s = opaque; - - if (version_id != 1) { - return -EINVAL; - } - - s->irq=qemu_get_be32 (f); - s->dma=qemu_get_be32 (f); - s->hdma=qemu_get_be32 (f); - s->port=qemu_get_be32 (f); - s->ver=qemu_get_be32 (f); - s->in_index=qemu_get_be32 (f); - s->out_data_len=qemu_get_be32 (f); - s->fmt_stereo=qemu_get_be32 (f); - s->fmt_signed=qemu_get_be32 (f); - s->fmt_bits=qemu_get_be32 (f); - qemu_get_be32s (f, &s->fmt); - s->dma_auto=qemu_get_be32 (f); - s->block_size=qemu_get_be32 (f); - s->fifo=qemu_get_be32 (f); - s->freq=qemu_get_be32 (f); - s->time_const=qemu_get_be32 (f); - s->speaker=qemu_get_be32 (f); - s->needed_bytes=qemu_get_be32 (f); - s->cmd=qemu_get_be32 (f); - s->use_hdma=qemu_get_be32 (f); - s->highspeed=qemu_get_be32 (f); - s->can_write=qemu_get_be32 (f); - s->v2x6=qemu_get_be32 (f); - - qemu_get_8s (f, &s->csp_param); - qemu_get_8s (f, &s->csp_value); - qemu_get_8s (f, &s->csp_mode); - qemu_get_8s (f, &s->csp_param); - qemu_get_buffer (f, s->csp_regs, 256); - qemu_get_8s (f, &s->csp_index); - qemu_get_buffer (f, s->csp_reg83, 4); - s->csp_reg83r=qemu_get_be32 (f); - s->csp_reg83w=qemu_get_be32 (f); - - qemu_get_buffer (f, s->in2_data, sizeof (s->in2_data)); - qemu_get_buffer (f, s->out_data, sizeof (s->out_data)); - qemu_get_8s (f, &s->test_reg); - qemu_get_8s (f, &s->last_read_byte); - - s->nzero=qemu_get_be32 (f); - s->left_till_irq=qemu_get_be32 (f); - s->dma_running=qemu_get_be32 (f); - s->bytes_per_second=qemu_get_be32 (f); - s->align=qemu_get_be32 (f); - - s->mixer_nreg=qemu_get_be32 (f); - qemu_get_buffer (f, s->mixer_regs, 256); - if (s->voice) { AUD_close_out (&s->card, s->voice); s->voice = NULL; @@ -1385,6 +1280,65 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) return 0; } +static const VMStateDescription vmstate_sb16 = { + .name = "sb16", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = sb16_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(irq, SB16State), + VMSTATE_UINT32(dma, SB16State), + VMSTATE_UINT32(hdma, SB16State), + VMSTATE_UINT32(port, SB16State), + VMSTATE_UINT32(ver, SB16State), + VMSTATE_INT32(in_index, SB16State), + VMSTATE_INT32(out_data_len, SB16State), + VMSTATE_INT32(fmt_stereo, SB16State), + VMSTATE_INT32(fmt_signed, SB16State), + VMSTATE_INT32(fmt_bits, SB16State), + VMSTATE_UINT32(fmt, SB16State), + VMSTATE_INT32(dma_auto, SB16State), + VMSTATE_INT32(block_size, SB16State), + VMSTATE_INT32(fifo, SB16State), + VMSTATE_INT32(freq, SB16State), + VMSTATE_INT32(time_const, SB16State), + VMSTATE_INT32(speaker, SB16State), + VMSTATE_INT32(needed_bytes, SB16State), + VMSTATE_INT32(cmd, SB16State), + VMSTATE_INT32(use_hdma, SB16State), + VMSTATE_INT32(highspeed, SB16State), + VMSTATE_INT32(can_write, SB16State), + VMSTATE_INT32(v2x6, SB16State), + + VMSTATE_UINT8(csp_param, SB16State), + VMSTATE_UINT8(csp_value, SB16State), + VMSTATE_UINT8(csp_mode, SB16State), + VMSTATE_UINT8(csp_param, SB16State), + VMSTATE_BUFFER(csp_regs, SB16State), + VMSTATE_UINT8(csp_index, SB16State), + VMSTATE_BUFFER(csp_reg83, SB16State), + VMSTATE_INT32(csp_reg83r, SB16State), + VMSTATE_INT32(csp_reg83w, SB16State), + + VMSTATE_BUFFER(in2_data, SB16State), + VMSTATE_BUFFER(out_data, SB16State), + VMSTATE_UINT8(test_reg, SB16State), + VMSTATE_UINT8(last_read_byte, SB16State), + + VMSTATE_INT32(nzero, SB16State), + VMSTATE_INT32(left_till_irq, SB16State), + VMSTATE_INT32(dma_running, SB16State), + VMSTATE_INT32(bytes_per_second, SB16State), + VMSTATE_INT32(align, SB16State), + + VMSTATE_INT32(mixer_nreg, SB16State), + VMSTATE_BUFFER(mixer_regs, SB16State), + + VMSTATE_END_OF_LIST() + } +}; + static int sb16_initfn (ISADevice *dev) { static const uint8_t dsp_write_ports[] = {0x6, 0xc}; @@ -1427,7 +1381,7 @@ static int sb16_initfn (ISADevice *dev) DMA_register_channel (s->dma, SB_read_DMA, s); s->can_write = 1; - register_savevm ("sb16", 0, 1, SB_save, SB_load, s); + vmstate_register (0, &vmstate_sb16, s); AUD_register_card ("sb16", &s->card); return 0; } -- cgit v1.2.3-65-gdbad From 3a14c2df4f42acab06e5adbd89092e5bd0c979d8 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:36 +0100 Subject: es1370: port to vmstate Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/es1370.c | 77 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/hw/es1370.c b/hw/es1370.c index 10da250bc..4e646dc57 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -924,48 +924,28 @@ static void es1370_map (PCIDevice *pci_dev, int region_num, register_ioport_read (addr, 0x40, 4, es1370_readl, s); } -static void es1370_save (QEMUFile *f, void *opaque) -{ - ES1370State *s = opaque; - size_t i; - - pci_device_save (&s->dev, f); - for (i = 0; i < NB_CHANNELS; ++i) { - struct chan *d = &s->chan[i]; - qemu_put_be32s (f, &d->shift); - qemu_put_be32s (f, &d->leftover); - qemu_put_be32s (f, &d->scount); - qemu_put_be32s (f, &d->frame_addr); - qemu_put_be32s (f, &d->frame_cnt); +static const VMStateDescription vmstate_es1370_channel = { + .name = "es1370_channel", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField []) { + VMSTATE_UINT32(shift, struct chan), + VMSTATE_UINT32(leftover, struct chan), + VMSTATE_UINT32(scount, struct chan), + VMSTATE_UINT32(frame_addr, struct chan), + VMSTATE_UINT32(frame_cnt, struct chan), + VMSTATE_END_OF_LIST() } - qemu_put_be32s (f, &s->ctl); - qemu_put_be32s (f, &s->status); - qemu_put_be32s (f, &s->mempage); - qemu_put_be32s (f, &s->codec); - qemu_put_be32s (f, &s->sctl); -} +}; -static int es1370_load (QEMUFile *f, void *opaque, int version_id) +static int es1370_post_load (void *opaque, int version_id) { - int ret; uint32_t ctl, sctl; ES1370State *s = opaque; size_t i; - if (version_id != 2) - return -EINVAL; - - ret = pci_device_load (&s->dev, f); - if (ret) - return ret; - for (i = 0; i < NB_CHANNELS; ++i) { - struct chan *d = &s->chan[i]; - qemu_get_be32s (f, &d->shift); - qemu_get_be32s (f, &d->leftover); - qemu_get_be32s (f, &d->scount); - qemu_get_be32s (f, &d->frame_addr); - qemu_get_be32s (f, &d->frame_cnt); if (i == ADC_CHANNEL) { if (s->adc_voice) { AUD_close_in (&s->card, s->adc_voice); @@ -980,18 +960,33 @@ static int es1370_load (QEMUFile *f, void *opaque, int version_id) } } - qemu_get_be32s (f, &ctl); - qemu_get_be32s (f, &s->status); - qemu_get_be32s (f, &s->mempage); - qemu_get_be32s (f, &s->codec); - qemu_get_be32s (f, &sctl); - + ctl = s->ctl; + sctl = s->sctl; s->ctl = 0; s->sctl = 0; es1370_update_voices (s, ctl, sctl); return 0; } +static const VMStateDescription vmstate_es1370 = { + .name = "es1370", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .post_load = es1370_post_load, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(dev, ES1370State), + VMSTATE_STRUCT_ARRAY(chan, ES1370State, NB_CHANNELS, 2, + vmstate_es1370_channel, struct chan), + VMSTATE_UINT32(ctl, ES1370State), + VMSTATE_UINT32(status, ES1370State), + VMSTATE_UINT32(mempage, ES1370State), + VMSTATE_UINT32(codec, ES1370State), + VMSTATE_UINT32(sctl, ES1370State), + VMSTATE_END_OF_LIST() + } +}; + static void es1370_on_reset (void *opaque) { ES1370State *s = opaque; @@ -1028,7 +1023,7 @@ static int es1370_initfn (PCIDevice *dev) c[0x3f] = 0x80; pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO, es1370_map); - register_savevm ("es1370", 0, 2, es1370_save, es1370_load, s); + vmstate_register (0, &vmstate_es1370, s); qemu_register_reset (es1370_on_reset, s); AUD_register_card ("es1370", &s->card); -- cgit v1.2.3-65-gdbad From 1d190d5ce79b97138a03fc799df2c9397e34231c Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:37 +0100 Subject: c4231a: port to vmstate Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/cs4231a.c | 58 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/hw/cs4231a.c b/hw/cs4231a.c index e03c5d242..7c29aa849 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -596,45 +596,47 @@ static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len) return dma_pos; } -static void cs_save (QEMUFile *f, void *opaque) +static int cs4231a_pre_load (void *opaque) { CSState *s = opaque; - unsigned int i; - uint32_t val; - for (i = 0; i < CS_REGS; i++) - qemu_put_be32s (f, &s->regs[i]); - - qemu_put_buffer (f, s->dregs, CS_DREGS); - val = s->dma_running; qemu_put_be32s (f, &val); - val = s->audio_free; qemu_put_be32s (f, &val); - val = s->transferred; qemu_put_be32s (f, &val); - val = s->aci_counter; qemu_put_be32s (f, &val); + if (s->dma_running) { + DMA_release_DREQ (s->dma); + AUD_set_active_out (s->voice, 0); + } + s->dma_running = 0; + return 0; } -static int cs_load (QEMUFile *f, void *opaque, int version_id) +static int cs4231a_post_load (void *opaque, int version_id) { CSState *s = opaque; - unsigned int i; - uint32_t val, dma_running; - - if (version_id > 1) - return -EINVAL; - for (i = 0; i < CS_REGS; i++) - qemu_get_be32s (f, &s->regs[i]); - - qemu_get_buffer (f, s->dregs, CS_DREGS); - - qemu_get_be32s (f, &dma_running); - qemu_get_be32s (f, &val); s->audio_free = val; - qemu_get_be32s (f, &val); s->transferred = val; - qemu_get_be32s (f, &val); s->aci_counter = val; - if (dma_running && (s->dregs[Interface_Configuration] & PEN)) + if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) { + s->dma_running = 0; cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]); + } return 0; } +static const VMStateDescription vmstate_cs4231a = { + .name = "cs4231a", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_load = cs4231a_pre_load, + .post_load = cs4231a_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS), + VMSTATE_BUFFER(dregs, CSState), + VMSTATE_INT32(dma_running, CSState), + VMSTATE_INT32(audio_free, CSState), + VMSTATE_INT32(transferred, CSState), + VMSTATE_INT32(aci_counter, CSState), + VMSTATE_END_OF_LIST() + } +}; + static int cs4231a_initfn (ISADevice *dev) { CSState *s = DO_UPCAST (CSState, dev, dev); @@ -649,7 +651,7 @@ static int cs4231a_initfn (ISADevice *dev) DMA_register_channel (s->dma, cs_dma_read, s); - register_savevm ("cs4231a", 0, 1, cs_save, cs_load, s); + vmstate_register (0, &vmstate_cs4231a, s); qemu_register_reset (cs_reset, s); cs_reset (s); -- cgit v1.2.3-65-gdbad From 709ae102bcc68a40c333f9baff308b9a48380986 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:38 +0100 Subject: gus: port to vmstate Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/gus.c | 47 +++++++++++++++++------------------------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/hw/gus.c b/hw/gus.c index c6b98b3ce..d35da0a0c 100644 --- a/hw/gus.c +++ b/hw/gus.c @@ -215,35 +215,22 @@ static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) return dma_len; } -static void GUS_save (QEMUFile *f, void *opaque) -{ - GUSState *s = opaque; - - qemu_put_be32 (f, s->pos); - qemu_put_be32 (f, s->left); - qemu_put_be32 (f, s->shift); - qemu_put_be32 (f, s->irqs); - qemu_put_be32 (f, s->samples); - qemu_put_be64 (f, s->last_ticks); - qemu_put_buffer (f, s->himem, sizeof (s->himem)); -} - -static int GUS_load (QEMUFile *f, void *opaque, int version_id) -{ - GUSState *s = opaque; - - if (version_id != 2) - return -EINVAL; - - s->pos = qemu_get_be32 (f); - s->left = qemu_get_be32 (f); - s->shift = qemu_get_be32 (f); - s->irqs = qemu_get_be32 (f); - s->samples = qemu_get_be32 (f); - s->last_ticks = qemu_get_be64 (f); - qemu_get_buffer (f, s->himem, sizeof (s->himem)); - return 0; -} +static const VMStateDescription vmstate_gus = { + .name = "gus", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField []) { + VMSTATE_INT32(pos, GUSState), + VMSTATE_INT32(left, GUSState), + VMSTATE_INT32(shift, GUSState), + VMSTATE_INT32(irqs, GUSState), + VMSTATE_INT32(samples, GUSState), + VMSTATE_INT64(last_ticks, GUSState), + VMSTATE_BUFFER(himem, GUSState), + VMSTATE_END_OF_LIST() + } +}; static int gus_initfn (ISADevice *dev) { @@ -300,7 +287,7 @@ static int gus_initfn (ISADevice *dev) AUD_set_active_out (s->voice, 1); - register_savevm ("gus", 0, 2, GUS_save, GUS_load, s); + vmstate_register (0, &vmstate_gus, s); return 0; } -- cgit v1.2.3-65-gdbad From 0148d1778b28b8c7f6205ecf20e3619aac1ccf8c Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:39 +0100 Subject: ac97: sizeof needs %zd This change makes DEBUG_AC97 to compile again Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/ac97.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index f72c46d03..36aab8ae3 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -323,7 +323,7 @@ static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r) static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) { if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_store: index %d out of bounds %d\n", + dolog ("mixer_store: index %d out of bounds %zd\n", i, sizeof (s->mixer_data)); return; } @@ -337,7 +337,7 @@ static uint16_t mixer_load (AC97LinkState *s, uint32_t i) uint16_t val = 0xffff; if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_store: index %d out of bounds %d\n", + dolog ("mixer_store: index %d out of bounds %zd\n", i, sizeof (s->mixer_data)); } else { -- cgit v1.2.3-65-gdbad From 7626f39fd5041e4b8fe7739132efce9916399704 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:40 +0100 Subject: ac97: recalculate active after loadvm Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/ac97.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/ac97.c b/hw/ac97.c index 36aab8ae3..e89a56a7f 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -1242,6 +1242,9 @@ static int ac97_load (QEMUFile *f, void *opaque, int version_id) V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); #undef V_ #endif + active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); + active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); + active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); reset_voices (s, active); s->bup_flag = 0; -- cgit v1.2.3-65-gdbad From 3b6b2126b2c2184f5ff0fb6a369b3e6ee8f2e002 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:41 +0100 Subject: ac97: up savevm version and remove active from state Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/ac97.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index e89a56a7f..cc5ec30bd 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -1170,7 +1170,6 @@ static void po_callback (void *opaque, int free) static void ac97_save (QEMUFile *f, void *opaque) { size_t i; - uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; pci_device_save (&s->dev, f); @@ -1193,11 +1192,6 @@ static void ac97_save (QEMUFile *f, void *opaque) qemu_put_be32s (f, &r->bd.ctl_len); } qemu_put_buffer (f, s->mixer_data, sizeof (s->mixer_data)); - - active[PI_INDEX] = AUD_is_active_in (s->voice_pi) ? 1 : 0; - active[PO_INDEX] = AUD_is_active_out (s->voice_po) ? 1 : 0; - active[MC_INDEX] = AUD_is_active_in (s->voice_mc) ? 1 : 0; - qemu_put_buffer (f, active, sizeof (active)); } static int ac97_load (QEMUFile *f, void *opaque, int version_id) @@ -1207,7 +1201,7 @@ static int ac97_load (QEMUFile *f, void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; - if (version_id != 2) + if (version_id < 2 || version_id > 3) return -EINVAL; ret = pci_device_load (&s->dev, f); @@ -1232,7 +1226,8 @@ static int ac97_load (QEMUFile *f, void *opaque, int version_id) qemu_get_be32s (f, &r->bd.ctl_len); } qemu_get_buffer (f, s->mixer_data, sizeof (s->mixer_data)); - qemu_get_buffer (f, active, sizeof (active)); + if (version_id < 3) + qemu_get_buffer (f, active, sizeof (active)); #ifdef USE_MIXER record_select (s, mixer_load (s, AC97_Record_Select)); @@ -1337,7 +1332,7 @@ static int ac97_initfn (PCIDevice *dev) pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map); pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map); - register_savevm ("ac97", 0, 2, ac97_save, ac97_load, s); + register_savevm ("ac97", 0, 3, ac97_save, ac97_load, s); qemu_register_reset (ac97_on_reset, s); AUD_register_card ("ac97", &s->card); ac97_on_reset (s); -- cgit v1.2.3-65-gdbad From a90ffa497d8102c142f7ea9c793de7b378430878 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 11:49:42 +0100 Subject: ac97: port to vmstate Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/ac97.c | 101 +++++++++++++++++++++++++++----------------------------------- 1 file changed, 44 insertions(+), 57 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index cc5ec30bd..f2d28233c 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -1167,68 +1167,31 @@ static void po_callback (void *opaque, int free) transfer_audio (opaque, PO_INDEX, free); } -static void ac97_save (QEMUFile *f, void *opaque) -{ - size_t i; - AC97LinkState *s = opaque; - - pci_device_save (&s->dev, f); - - qemu_put_be32s (f, &s->glob_cnt); - qemu_put_be32s (f, &s->glob_sta); - qemu_put_be32s (f, &s->cas); - - for (i = 0; i < ARRAY_SIZE (s->bm_regs); ++i) { - AC97BusMasterRegs *r = &s->bm_regs[i]; - qemu_put_be32s (f, &r->bdbar); - qemu_put_8s (f, &r->civ); - qemu_put_8s (f, &r->lvi); - qemu_put_be16s (f, &r->sr); - qemu_put_be16s (f, &r->picb); - qemu_put_8s (f, &r->piv); - qemu_put_8s (f, &r->cr); - qemu_put_be32s (f, &r->bd_valid); - qemu_put_be32s (f, &r->bd.addr); - qemu_put_be32s (f, &r->bd.ctl_len); +static const VMStateDescription vmstate_ac97_bm_regs = { + .name = "ac97_bm_regs", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(bdbar, AC97BusMasterRegs), + VMSTATE_UINT8(civ, AC97BusMasterRegs), + VMSTATE_UINT8(lvi, AC97BusMasterRegs), + VMSTATE_UINT16(sr, AC97BusMasterRegs), + VMSTATE_UINT16(picb, AC97BusMasterRegs), + VMSTATE_UINT8(piv, AC97BusMasterRegs), + VMSTATE_UINT8(cr, AC97BusMasterRegs), + VMSTATE_UINT32(bd_valid, AC97BusMasterRegs), + VMSTATE_UINT32(bd.addr, AC97BusMasterRegs), + VMSTATE_UINT32(bd.ctl_len, AC97BusMasterRegs), + VMSTATE_END_OF_LIST() } - qemu_put_buffer (f, s->mixer_data, sizeof (s->mixer_data)); -} +}; -static int ac97_load (QEMUFile *f, void *opaque, int version_id) +static int ac97_post_load (void *opaque, int version_id) { - int ret; - size_t i; uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; - if (version_id < 2 || version_id > 3) - return -EINVAL; - - ret = pci_device_load (&s->dev, f); - if (ret) - return ret; - - qemu_get_be32s (f, &s->glob_cnt); - qemu_get_be32s (f, &s->glob_sta); - qemu_get_be32s (f, &s->cas); - - for (i = 0; i < ARRAY_SIZE (s->bm_regs); ++i) { - AC97BusMasterRegs *r = &s->bm_regs[i]; - qemu_get_be32s (f, &r->bdbar); - qemu_get_8s (f, &r->civ); - qemu_get_8s (f, &r->lvi); - qemu_get_be16s (f, &r->sr); - qemu_get_be16s (f, &r->picb); - qemu_get_8s (f, &r->piv); - qemu_get_8s (f, &r->cr); - qemu_get_be32s (f, &r->bd_valid); - qemu_get_be32s (f, &r->bd.addr); - qemu_get_be32s (f, &r->bd.ctl_len); - } - qemu_get_buffer (f, s->mixer_data, sizeof (s->mixer_data)); - if (version_id < 3) - qemu_get_buffer (f, active, sizeof (active)); - #ifdef USE_MIXER record_select (s, mixer_load (s, AC97_Record_Select)); #define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) @@ -1247,6 +1210,30 @@ static int ac97_load (QEMUFile *f, void *opaque, int version_id) return 0; } +static bool is_version_2 (void *opaque, int version_id) +{ + return version_id == 2; +} + +static const VMStateDescription vmstate_ac97 = { + .name = "ac97", + .version_id = 3, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .post_load = ac97_post_load, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(dev, AC97LinkState), + VMSTATE_UINT32(glob_cnt, AC97LinkState), + VMSTATE_UINT32(glob_sta, AC97LinkState), + VMSTATE_UINT32(cas, AC97LinkState), + VMSTATE_STRUCT_ARRAY(bm_regs, AC97LinkState, 3, 1, + vmstate_ac97_bm_regs, AC97BusMasterRegs), + VMSTATE_BUFFER(mixer_data, AC97LinkState), + VMSTATE_UNUSED_TEST(is_version_2, 3), + VMSTATE_END_OF_LIST() + } +}; + static void ac97_map (PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type) { @@ -1332,7 +1319,7 @@ static int ac97_initfn (PCIDevice *dev) pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map); pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map); - register_savevm ("ac97", 0, 3, ac97_save, ac97_load, s); + vmstate_register (0, &vmstate_ac97, s); qemu_register_reset (ac97_on_reset, s); AUD_register_card ("ac97", &s->card); ac97_on_reset (s); -- cgit v1.2.3-65-gdbad From 68ac40d2c6ce453df9b7fcf546d806345f653433 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:48:54 +0000 Subject: net: move slirp code from net.c to net/slirp.c Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- Makefile | 1 + monitor.c | 1 + net.c | 718 +-------------------------------------------------------- net.h | 8 +- net/slirp.c | 752 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/slirp.h | 51 +++++ vl.c | 1 + 7 files changed, 814 insertions(+), 718 deletions(-) create mode 100644 net/slirp.c create mode 100644 net/slirp.h diff --git a/Makefile b/Makefile index 6306127bf..b3cc8d419 100644 --- a/Makefile +++ b/Makefile @@ -106,6 +106,7 @@ net-nested-$(CONFIG_WIN32) += tap-win32.o net-nested-$(CONFIG_BSD) += tap-bsd.o net-nested-$(CONFIG_SOLARIS) += tap-solaris.o net-nested-$(CONFIG_AIX) += tap-aix.o +net-nested-$(CONFIG_SLIRP) += slirp.o net-obj-y += $(addprefix net/, $(net-nested-y)) ###################################################################### diff --git a/monitor.c b/monitor.c index af6d3d5d2..5bf32f0a8 100644 --- a/monitor.c +++ b/monitor.c @@ -32,6 +32,7 @@ #include "hw/loader.h" #include "gdbstub.h" #include "net.h" +#include "net/slirp.h" #include "qemu-char.h" #include "sysemu.h" #include "monitor.h" diff --git a/net.c b/net.c index 7c44c1ad5..9887d95ac 100644 --- a/net.c +++ b/net.c @@ -40,9 +40,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -95,6 +93,7 @@ #include "qemu-common.h" #include "net.h" #include "net/tap.h" +#include "net/slirp.h" #include "monitor.h" #include "sysemu.h" #include "qemu-timer.h" @@ -104,15 +103,13 @@ #include "qemu-log.h" #include "qemu-config.h" -#include "slirp/libslirp.h" - static QTAILQ_HEAD(, VLANState) vlans; static QTAILQ_HEAD(, VLANClientState) non_vlan_clients; /***********************************************************/ /* network device redirectors */ -#if defined(DEBUG_NET) || defined(DEBUG_SLIRP) +#if defined(DEBUG_NET) static void hex_dump(FILE *f, const uint8_t *buf, int size) { int len, i, j, c; @@ -403,7 +400,7 @@ VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque) return NULL; } -static VLANClientState * +VLANClientState * qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, const char *client_str) { @@ -722,597 +719,6 @@ qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt) return qemu_sendv_packet_async(vc, iov, iovcnt, NULL); } -#if defined(CONFIG_SLIRP) - -/* slirp network adapter */ - -#define SLIRP_CFG_HOSTFWD 1 -#define SLIRP_CFG_LEGACY 2 - -struct slirp_config_str { - struct slirp_config_str *next; - int flags; - char str[1024]; - int legacy_format; -}; - -typedef struct SlirpState { - QTAILQ_ENTRY(SlirpState) entry; - VLANClientState *vc; - Slirp *slirp; -#ifndef _WIN32 - char smb_dir[128]; -#endif -} SlirpState; - -static struct slirp_config_str *slirp_configs; -const char *legacy_tftp_prefix; -const char *legacy_bootp_filename; -static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks = - QTAILQ_HEAD_INITIALIZER(slirp_stacks); - -static int slirp_hostfwd(SlirpState *s, const char *redir_str, - int legacy_format); -static int slirp_guestfwd(SlirpState *s, const char *config_str, - int legacy_format); - -#ifndef _WIN32 -static const char *legacy_smb_export; - -static int slirp_smb(SlirpState *s, const char *exported_dir, - struct in_addr vserver_addr); -static void slirp_smb_cleanup(SlirpState *s); -#else -static inline void slirp_smb_cleanup(SlirpState *s) { } -#endif - -int slirp_can_output(void *opaque) -{ - SlirpState *s = opaque; - - return qemu_can_send_packet(s->vc); -} - -void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len) -{ - SlirpState *s = opaque; - -#ifdef DEBUG_SLIRP - printf("slirp output:\n"); - hex_dump(stdout, pkt, pkt_len); -#endif - qemu_send_packet(s->vc, pkt, pkt_len); -} - -static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size) -{ - SlirpState *s = vc->opaque; - -#ifdef DEBUG_SLIRP - printf("slirp input:\n"); - hex_dump(stdout, buf, size); -#endif - slirp_input(s->slirp, buf, size); - return size; -} - -static void net_slirp_cleanup(VLANClientState *vc) -{ - SlirpState *s = vc->opaque; - - slirp_cleanup(s->slirp); - slirp_smb_cleanup(s); - QTAILQ_REMOVE(&slirp_stacks, s, entry); - qemu_free(s); -} - -static int net_slirp_init(VLANState *vlan, const char *model, - const char *name, int restricted, - const char *vnetwork, const char *vhost, - const char *vhostname, const char *tftp_export, - const char *bootfile, const char *vdhcp_start, - const char *vnameserver, const char *smb_export, - const char *vsmbserver) -{ - /* default settings according to historic slirp */ - struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ - struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ - struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */ - struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */ - struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */ -#ifndef _WIN32 - struct in_addr smbsrv = { .s_addr = 0 }; -#endif - SlirpState *s; - char buf[20]; - uint32_t addr; - int shift; - char *end; - struct slirp_config_str *config; - - if (!tftp_export) { - tftp_export = legacy_tftp_prefix; - } - if (!bootfile) { - bootfile = legacy_bootp_filename; - } - - if (vnetwork) { - if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) { - if (!inet_aton(vnetwork, &net)) { - return -1; - } - addr = ntohl(net.s_addr); - if (!(addr & 0x80000000)) { - mask.s_addr = htonl(0xff000000); /* class A */ - } else if ((addr & 0xfff00000) == 0xac100000) { - mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */ - } else if ((addr & 0xc0000000) == 0x80000000) { - mask.s_addr = htonl(0xffff0000); /* class B */ - } else if ((addr & 0xffff0000) == 0xc0a80000) { - mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */ - } else if ((addr & 0xffff0000) == 0xc6120000) { - mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */ - } else if ((addr & 0xe0000000) == 0xe0000000) { - mask.s_addr = htonl(0xffffff00); /* class C */ - } else { - mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */ - } - } else { - if (!inet_aton(buf, &net)) { - return -1; - } - shift = strtol(vnetwork, &end, 10); - if (*end != '\0') { - if (!inet_aton(vnetwork, &mask)) { - return -1; - } - } else if (shift < 4 || shift > 32) { - return -1; - } else { - mask.s_addr = htonl(0xffffffff << (32 - shift)); - } - } - net.s_addr &= mask.s_addr; - host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr); - dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr); - dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr); - } - - if (vhost && !inet_aton(vhost, &host)) { - return -1; - } - if ((host.s_addr & mask.s_addr) != net.s_addr) { - return -1; - } - - if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) { - return -1; - } - if ((dhcp.s_addr & mask.s_addr) != net.s_addr || - dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) { - return -1; - } - - if (vnameserver && !inet_aton(vnameserver, &dns)) { - return -1; - } - if ((dns.s_addr & mask.s_addr) != net.s_addr || - dns.s_addr == host.s_addr) { - return -1; - } - -#ifndef _WIN32 - if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) { - return -1; - } -#endif - - s = qemu_mallocz(sizeof(SlirpState)); - s->slirp = slirp_init(restricted, net, mask, host, vhostname, - tftp_export, bootfile, dhcp, dns, s); - QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); - - for (config = slirp_configs; config; config = config->next) { - if (config->flags & SLIRP_CFG_HOSTFWD) { - if (slirp_hostfwd(s, config->str, - config->flags & SLIRP_CFG_LEGACY) < 0) - return -1; - } else { - if (slirp_guestfwd(s, config->str, - config->flags & SLIRP_CFG_LEGACY) < 0) - return -1; - } - } -#ifndef _WIN32 - if (!smb_export) { - smb_export = legacy_smb_export; - } - if (smb_export) { - if (slirp_smb(s, smb_export, smbsrv) < 0) - return -1; - } -#endif - - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SLIRP, - vlan, NULL, model, name, NULL, - slirp_receive, NULL, NULL, - net_slirp_cleanup, s); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n'); - return 0; -} - -static SlirpState *slirp_lookup(Monitor *mon, const char *vlan, - const char *stack) -{ - VLANClientState *vc; - - if (vlan) { - vc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack); - if (!vc) { - return NULL; - } - if (strcmp(vc->model, "user")) { - monitor_printf(mon, "invalid device specified\n"); - return NULL; - } - return vc->opaque; - } else { - if (QTAILQ_EMPTY(&slirp_stacks)) { - monitor_printf(mon, "user mode network stack not in use\n"); - return NULL; - } - return QTAILQ_FIRST(&slirp_stacks); - } -} - -void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict) -{ - struct in_addr host_addr = { .s_addr = INADDR_ANY }; - int host_port; - char buf[256] = ""; - const char *src_str, *p; - SlirpState *s; - int is_udp = 0; - int err; - const char *arg1 = qdict_get_str(qdict, "arg1"); - const char *arg2 = qdict_get_try_str(qdict, "arg2"); - const char *arg3 = qdict_get_try_str(qdict, "arg3"); - - if (arg2) { - s = slirp_lookup(mon, arg1, arg2); - src_str = arg3; - } else { - s = slirp_lookup(mon, NULL, NULL); - src_str = arg1; - } - if (!s) { - return; - } - - if (!src_str || !src_str[0]) - goto fail_syntax; - - p = src_str; - get_str_sep(buf, sizeof(buf), &p, ':'); - - if (!strcmp(buf, "tcp") || buf[0] == '\0') { - is_udp = 0; - } else if (!strcmp(buf, "udp")) { - is_udp = 1; - } else { - goto fail_syntax; - } - - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { - goto fail_syntax; - } - - host_port = atoi(p); - - err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp, - host_addr, host_port); - - monitor_printf(mon, "host forwarding rule for %s %s\n", src_str, - err ? "removed" : "not found"); - return; - - fail_syntax: - monitor_printf(mon, "invalid format\n"); -} - -static int slirp_hostfwd(SlirpState *s, const char *redir_str, - int legacy_format) -{ - struct in_addr host_addr = { .s_addr = INADDR_ANY }; - struct in_addr guest_addr = { .s_addr = 0 }; - int host_port, guest_port; - const char *p; - char buf[256]; - int is_udp; - char *end; - - p = redir_str; - if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (!strcmp(buf, "tcp") || buf[0] == '\0') { - is_udp = 0; - } else if (!strcmp(buf, "udp")) { - is_udp = 1; - } else { - goto fail_syntax; - } - - if (!legacy_format) { - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { - goto fail_syntax; - } - } - - if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) { - goto fail_syntax; - } - host_port = strtol(buf, &end, 0); - if (*end != '\0' || host_port < 1 || host_port > 65535) { - goto fail_syntax; - } - - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) { - goto fail_syntax; - } - - guest_port = strtol(p, &end, 0); - if (*end != '\0' || guest_port < 1 || guest_port > 65535) { - goto fail_syntax; - } - - if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, - guest_port) < 0) { - qemu_error("could not set up host forwarding rule '%s'\n", - redir_str); - return -1; - } - return 0; - - fail_syntax: - qemu_error("invalid host forwarding rule '%s'\n", redir_str); - return -1; -} - -void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict) -{ - const char *redir_str; - SlirpState *s; - const char *arg1 = qdict_get_str(qdict, "arg1"); - const char *arg2 = qdict_get_try_str(qdict, "arg2"); - const char *arg3 = qdict_get_try_str(qdict, "arg3"); - - if (arg2) { - s = slirp_lookup(mon, arg1, arg2); - redir_str = arg3; - } else { - s = slirp_lookup(mon, NULL, NULL); - redir_str = arg1; - } - if (s) { - slirp_hostfwd(s, redir_str, 0); - } - -} - -int net_slirp_redir(const char *redir_str) -{ - struct slirp_config_str *config; - - if (QTAILQ_EMPTY(&slirp_stacks)) { - config = qemu_malloc(sizeof(*config)); - pstrcpy(config->str, sizeof(config->str), redir_str); - config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY; - config->next = slirp_configs; - slirp_configs = config; - return 0; - } - - return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1); -} - -#ifndef _WIN32 - -/* automatic user mode samba server configuration */ -static void slirp_smb_cleanup(SlirpState *s) -{ - char cmd[128]; - - if (s->smb_dir[0] != '\0') { - snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); - system(cmd); - s->smb_dir[0] = '\0'; - } -} - -static int slirp_smb(SlirpState* s, const char *exported_dir, - struct in_addr vserver_addr) -{ - static int instance; - char smb_conf[128]; - char smb_cmdline[128]; - FILE *f; - - snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d", - (long)getpid(), instance++); - if (mkdir(s->smb_dir, 0700) < 0) { - qemu_error("could not create samba server dir '%s'\n", s->smb_dir); - return -1; - } - snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); - - f = fopen(smb_conf, "w"); - if (!f) { - slirp_smb_cleanup(s); - qemu_error("could not create samba server configuration file '%s'\n", - smb_conf); - return -1; - } - fprintf(f, - "[global]\n" - "private dir=%s\n" - "smb ports=0\n" - "socket address=127.0.0.1\n" - "pid directory=%s\n" - "lock directory=%s\n" - "log file=%s/log.smbd\n" - "smb passwd file=%s/smbpasswd\n" - "security = share\n" - "[qemu]\n" - "path=%s\n" - "read only=no\n" - "guest ok=yes\n", - s->smb_dir, - s->smb_dir, - s->smb_dir, - s->smb_dir, - s->smb_dir, - exported_dir - ); - fclose(f); - - snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", - SMBD_COMMAND, smb_conf); - - if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) { - slirp_smb_cleanup(s); - qemu_error("conflicting/invalid smbserver address\n"); - return -1; - } - return 0; -} - -/* automatic user mode samba server configuration (legacy interface) */ -int net_slirp_smb(const char *exported_dir) -{ - struct in_addr vserver_addr = { .s_addr = 0 }; - - if (legacy_smb_export) { - fprintf(stderr, "-smb given twice\n"); - return -1; - } - legacy_smb_export = exported_dir; - if (!QTAILQ_EMPTY(&slirp_stacks)) { - return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir, - vserver_addr); - } - return 0; -} - -#endif /* !defined(_WIN32) */ - -struct GuestFwd { - CharDriverState *hd; - struct in_addr server; - int port; - Slirp *slirp; -}; - -static int guestfwd_can_read(void *opaque) -{ - struct GuestFwd *fwd = opaque; - return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port); -} - -static void guestfwd_read(void *opaque, const uint8_t *buf, int size) -{ - struct GuestFwd *fwd = opaque; - slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); -} - -static int slirp_guestfwd(SlirpState *s, const char *config_str, - int legacy_format) -{ - struct in_addr server = { .s_addr = 0 }; - struct GuestFwd *fwd; - const char *p; - char buf[128]; - char *end; - int port; - - p = config_str; - if (legacy_format) { - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - } else { - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (strcmp(buf, "tcp") && buf[0] != '\0') { - goto fail_syntax; - } - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &server)) { - goto fail_syntax; - } - if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) { - goto fail_syntax; - } - } - port = strtol(buf, &end, 10); - if (*end != '\0' || port < 1 || port > 65535) { - goto fail_syntax; - } - - fwd = qemu_malloc(sizeof(struct GuestFwd)); - snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port); - fwd->hd = qemu_chr_open(buf, p, NULL); - if (!fwd->hd) { - qemu_error("could not open guest forwarding device '%s'\n", buf); - qemu_free(fwd); - return -1; - } - - if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { - qemu_error("conflicting/invalid host:port in guest forwarding " - "rule '%s'\n", config_str); - qemu_free(fwd); - return -1; - } - fwd->server = server; - fwd->port = port; - fwd->slirp = s->slirp; - - qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, - NULL, fwd); - return 0; - - fail_syntax: - qemu_error("invalid guest forwarding rule '%s'\n", config_str); - return -1; -} - -void do_info_usernet(Monitor *mon) -{ - SlirpState *s; - - QTAILQ_FOREACH(s, &slirp_stacks, entry) { - monitor_printf(mon, "VLAN %d (%s):\n", s->vc->vlan->id, s->vc->name); - slirp_connection_info(s->slirp, mon); - } -} - -#endif /* CONFIG_SLIRP */ - #if defined(CONFIG_VDE) typedef struct VDEState { VLANClientState *vc; @@ -2113,101 +1519,6 @@ static int net_init_nic(QemuOpts *opts, return idx; } -#if defined(CONFIG_SLIRP) -static int net_init_slirp_configs(const char *name, const char *value, void *opaque) -{ - struct slirp_config_str *config; - - if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) { - return 0; - } - - config = qemu_mallocz(sizeof(*config)); - - pstrcpy(config->str, sizeof(config->str), value); - - if (!strcmp(name, "hostfwd")) { - config->flags = SLIRP_CFG_HOSTFWD; - } - - config->next = slirp_configs; - slirp_configs = config; - - return 0; -} - -static int net_init_slirp(QemuOpts *opts, - Monitor *mon, - const char *name, - VLANState *vlan) -{ - struct slirp_config_str *config; - const char *vhost; - const char *vhostname; - const char *vdhcp_start; - const char *vnamesrv; - const char *tftp_export; - const char *bootfile; - const char *smb_export; - const char *vsmbsrv; - char *vnet = NULL; - int restricted = 0; - int ret; - - vhost = qemu_opt_get(opts, "host"); - vhostname = qemu_opt_get(opts, "hostname"); - vdhcp_start = qemu_opt_get(opts, "dhcpstart"); - vnamesrv = qemu_opt_get(opts, "dns"); - tftp_export = qemu_opt_get(opts, "tftp"); - bootfile = qemu_opt_get(opts, "bootfile"); - smb_export = qemu_opt_get(opts, "smb"); - vsmbsrv = qemu_opt_get(opts, "smbserver"); - - if (qemu_opt_get(opts, "ip")) { - const char *ip = qemu_opt_get(opts, "ip"); - int l = strlen(ip) + strlen("/24") + 1; - - vnet = qemu_malloc(l); - - /* emulate legacy ip= parameter */ - pstrcpy(vnet, l, ip); - pstrcat(vnet, l, "/24"); - } - - if (qemu_opt_get(opts, "net")) { - if (vnet) { - qemu_free(vnet); - } - vnet = qemu_strdup(qemu_opt_get(opts, "net")); - } - - if (qemu_opt_get(opts, "restrict") && - qemu_opt_get(opts, "restrict")[0] == 'y') { - restricted = 1; - } - - qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0); - - ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost, - vhostname, tftp_export, bootfile, vdhcp_start, - vnamesrv, smb_export, vsmbsrv); - - while (slirp_configs) { - config = slirp_configs; - slirp_configs = config->next; - qemu_free(config); - } - - if (ret != -1 && vlan) { - vlan->nb_host_devs++; - } - - qemu_free(vnet); - - return ret; -} -#endif /* CONFIG_SLIRP */ - static int net_init_socket(QemuOpts *opts, Monitor *mon, const char *name, @@ -2857,29 +2168,12 @@ int net_init_clients(void) int net_client_parse(QemuOptsList *opts_list, const char *optarg) { #if defined(CONFIG_SLIRP) - /* handle legacy -net channel,port:chr */ - if (!strcmp(opts_list->name, "net") && - !strncmp(optarg, "channel,", strlen("channel,"))) { - int ret; - - optarg += strlen("channel,"); - - if (QTAILQ_EMPTY(&slirp_stacks)) { - struct slirp_config_str *config; - - config = qemu_malloc(sizeof(*config)); - pstrcpy(config->str, sizeof(config->str), optarg); - config->flags = SLIRP_CFG_LEGACY; - config->next = slirp_configs; - slirp_configs = config; - ret = 0; - } else { - ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1); - } - + int ret; + if (net_slirp_parse_legacy(opts_list, optarg, &ret)) { return ret; } #endif + if (!qemu_opts_parse(opts_list, optarg, "type")) { return -1; } diff --git a/net.h b/net.h index 4ffce9109..42ac42dfd 100644 --- a/net.h +++ b/net.h @@ -87,6 +87,8 @@ VLANClientState *qemu_new_vlan_client(net_client_type type, void *opaque); void qemu_del_vlan_client(VLANClientState *vc); VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque); +VLANClientState *qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, + const char *client_str); int qemu_can_send_packet(VLANClientState *vc); ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt); @@ -108,8 +110,6 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models, void do_info_network(Monitor *mon); void do_set_link(Monitor *mon, const QDict *qdict); -void do_info_usernet(Monitor *mon); - /* NIC info */ #define MAX_NICS 8 @@ -156,10 +156,6 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev); void net_client_uninit(NICInfo *nd); int net_client_parse(QemuOptsList *opts_list, const char *str); int net_init_clients(void); -int net_slirp_smb(const char *exported_dir); -void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict); -void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict); -int net_slirp_redir(const char *redir_str); void net_cleanup(void); void net_set_boot_mask(int boot_mask); void net_host_device_add(Monitor *mon, const QDict *qdict); diff --git a/net/slirp.c b/net/slirp.c new file mode 100644 index 000000000..d6d57721d --- /dev/null +++ b/net/slirp.c @@ -0,0 +1,752 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "net/slirp.h" + +#include "config-host.h" + +#include "net.h" +#include "monitor.h" +#include "sysemu.h" +#include "qemu_socket.h" +#include "slirp/libslirp.h" + +static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) +{ + const char *p, *p1; + int len; + p = *pp; + p1 = strchr(p, sep); + if (!p1) + return -1; + len = p1 - p; + p1++; + if (buf_size > 0) { + if (len > buf_size - 1) + len = buf_size - 1; + memcpy(buf, p, len); + buf[len] = '\0'; + } + *pp = p1; + return 0; +} + +/* slirp network adapter */ + +#define SLIRP_CFG_HOSTFWD 1 +#define SLIRP_CFG_LEGACY 2 + +struct slirp_config_str { + struct slirp_config_str *next; + int flags; + char str[1024]; + int legacy_format; +}; + +typedef struct SlirpState { + QTAILQ_ENTRY(SlirpState) entry; + VLANClientState *vc; + Slirp *slirp; +#ifndef _WIN32 + char smb_dir[128]; +#endif +} SlirpState; + +static struct slirp_config_str *slirp_configs; +const char *legacy_tftp_prefix; +const char *legacy_bootp_filename; +static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks = + QTAILQ_HEAD_INITIALIZER(slirp_stacks); + +static int slirp_hostfwd(SlirpState *s, const char *redir_str, + int legacy_format); +static int slirp_guestfwd(SlirpState *s, const char *config_str, + int legacy_format); + +#ifndef _WIN32 +static const char *legacy_smb_export; + +static int slirp_smb(SlirpState *s, const char *exported_dir, + struct in_addr vserver_addr); +static void slirp_smb_cleanup(SlirpState *s); +#else +static inline void slirp_smb_cleanup(SlirpState *s) { } +#endif + +int slirp_can_output(void *opaque) +{ + SlirpState *s = opaque; + + return qemu_can_send_packet(s->vc); +} + +void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len) +{ + SlirpState *s = opaque; + + qemu_send_packet(s->vc, pkt, pkt_len); +} + +static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +{ + SlirpState *s = vc->opaque; + + slirp_input(s->slirp, buf, size); + + return size; +} + +static void net_slirp_cleanup(VLANClientState *vc) +{ + SlirpState *s = vc->opaque; + + slirp_cleanup(s->slirp); + slirp_smb_cleanup(s); + QTAILQ_REMOVE(&slirp_stacks, s, entry); + qemu_free(s); +} + +static int net_slirp_init(VLANState *vlan, const char *model, + const char *name, int restricted, + const char *vnetwork, const char *vhost, + const char *vhostname, const char *tftp_export, + const char *bootfile, const char *vdhcp_start, + const char *vnameserver, const char *smb_export, + const char *vsmbserver) +{ + /* default settings according to historic slirp */ + struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ + struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ + struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */ + struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */ + struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */ +#ifndef _WIN32 + struct in_addr smbsrv = { .s_addr = 0 }; +#endif + SlirpState *s; + char buf[20]; + uint32_t addr; + int shift; + char *end; + struct slirp_config_str *config; + + if (!tftp_export) { + tftp_export = legacy_tftp_prefix; + } + if (!bootfile) { + bootfile = legacy_bootp_filename; + } + + if (vnetwork) { + if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) { + if (!inet_aton(vnetwork, &net)) { + return -1; + } + addr = ntohl(net.s_addr); + if (!(addr & 0x80000000)) { + mask.s_addr = htonl(0xff000000); /* class A */ + } else if ((addr & 0xfff00000) == 0xac100000) { + mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */ + } else if ((addr & 0xc0000000) == 0x80000000) { + mask.s_addr = htonl(0xffff0000); /* class B */ + } else if ((addr & 0xffff0000) == 0xc0a80000) { + mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */ + } else if ((addr & 0xffff0000) == 0xc6120000) { + mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */ + } else if ((addr & 0xe0000000) == 0xe0000000) { + mask.s_addr = htonl(0xffffff00); /* class C */ + } else { + mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */ + } + } else { + if (!inet_aton(buf, &net)) { + return -1; + } + shift = strtol(vnetwork, &end, 10); + if (*end != '\0') { + if (!inet_aton(vnetwork, &mask)) { + return -1; + } + } else if (shift < 4 || shift > 32) { + return -1; + } else { + mask.s_addr = htonl(0xffffffff << (32 - shift)); + } + } + net.s_addr &= mask.s_addr; + host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr); + dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr); + dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr); + } + + if (vhost && !inet_aton(vhost, &host)) { + return -1; + } + if ((host.s_addr & mask.s_addr) != net.s_addr) { + return -1; + } + + if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) { + return -1; + } + if ((dhcp.s_addr & mask.s_addr) != net.s_addr || + dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) { + return -1; + } + + if (vnameserver && !inet_aton(vnameserver, &dns)) { + return -1; + } + if ((dns.s_addr & mask.s_addr) != net.s_addr || + dns.s_addr == host.s_addr) { + return -1; + } + +#ifndef _WIN32 + if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) { + return -1; + } +#endif + + s = qemu_mallocz(sizeof(SlirpState)); + s->slirp = slirp_init(restricted, net, mask, host, vhostname, + tftp_export, bootfile, dhcp, dns, s); + QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); + + for (config = slirp_configs; config; config = config->next) { + if (config->flags & SLIRP_CFG_HOSTFWD) { + if (slirp_hostfwd(s, config->str, + config->flags & SLIRP_CFG_LEGACY) < 0) + return -1; + } else { + if (slirp_guestfwd(s, config->str, + config->flags & SLIRP_CFG_LEGACY) < 0) + return -1; + } + } +#ifndef _WIN32 + if (!smb_export) { + smb_export = legacy_smb_export; + } + if (smb_export) { + if (slirp_smb(s, smb_export, smbsrv) < 0) + return -1; + } +#endif + + s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SLIRP, + vlan, NULL, model, name, NULL, + slirp_receive, NULL, NULL, + net_slirp_cleanup, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n'); + return 0; +} + +static SlirpState *slirp_lookup(Monitor *mon, const char *vlan, + const char *stack) +{ + VLANClientState *vc; + + if (vlan) { + vc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack); + if (!vc) { + return NULL; + } + if (strcmp(vc->model, "user")) { + monitor_printf(mon, "invalid device specified\n"); + return NULL; + } + return vc->opaque; + } else { + if (QTAILQ_EMPTY(&slirp_stacks)) { + monitor_printf(mon, "user mode network stack not in use\n"); + return NULL; + } + return QTAILQ_FIRST(&slirp_stacks); + } +} + +void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict) +{ + struct in_addr host_addr = { .s_addr = INADDR_ANY }; + int host_port; + char buf[256] = ""; + const char *src_str, *p; + SlirpState *s; + int is_udp = 0; + int err; + const char *arg1 = qdict_get_str(qdict, "arg1"); + const char *arg2 = qdict_get_try_str(qdict, "arg2"); + const char *arg3 = qdict_get_try_str(qdict, "arg3"); + + if (arg2) { + s = slirp_lookup(mon, arg1, arg2); + src_str = arg3; + } else { + s = slirp_lookup(mon, NULL, NULL); + src_str = arg1; + } + if (!s) { + return; + } + + if (!src_str || !src_str[0]) + goto fail_syntax; + + p = src_str; + get_str_sep(buf, sizeof(buf), &p, ':'); + + if (!strcmp(buf, "tcp") || buf[0] == '\0') { + is_udp = 0; + } else if (!strcmp(buf, "udp")) { + is_udp = 1; + } else { + goto fail_syntax; + } + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { + goto fail_syntax; + } + + host_port = atoi(p); + + err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp, + host_addr, host_port); + + monitor_printf(mon, "host forwarding rule for %s %s\n", src_str, + err ? "removed" : "not found"); + return; + + fail_syntax: + monitor_printf(mon, "invalid format\n"); +} + +static int slirp_hostfwd(SlirpState *s, const char *redir_str, + int legacy_format) +{ + struct in_addr host_addr = { .s_addr = INADDR_ANY }; + struct in_addr guest_addr = { .s_addr = 0 }; + int host_port, guest_port; + const char *p; + char buf[256]; + int is_udp; + char *end; + + p = redir_str; + if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + if (!strcmp(buf, "tcp") || buf[0] == '\0') { + is_udp = 0; + } else if (!strcmp(buf, "udp")) { + is_udp = 1; + } else { + goto fail_syntax; + } + + if (!legacy_format) { + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { + goto fail_syntax; + } + } + + if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) { + goto fail_syntax; + } + host_port = strtol(buf, &end, 0); + if (*end != '\0' || host_port < 1 || host_port > 65535) { + goto fail_syntax; + } + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) { + goto fail_syntax; + } + + guest_port = strtol(p, &end, 0); + if (*end != '\0' || guest_port < 1 || guest_port > 65535) { + goto fail_syntax; + } + + if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, + guest_port) < 0) { + qemu_error("could not set up host forwarding rule '%s'\n", + redir_str); + return -1; + } + return 0; + + fail_syntax: + qemu_error("invalid host forwarding rule '%s'\n", redir_str); + return -1; +} + +void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict) +{ + const char *redir_str; + SlirpState *s; + const char *arg1 = qdict_get_str(qdict, "arg1"); + const char *arg2 = qdict_get_try_str(qdict, "arg2"); + const char *arg3 = qdict_get_try_str(qdict, "arg3"); + + if (arg2) { + s = slirp_lookup(mon, arg1, arg2); + redir_str = arg3; + } else { + s = slirp_lookup(mon, NULL, NULL); + redir_str = arg1; + } + if (s) { + slirp_hostfwd(s, redir_str, 0); + } + +} + +int net_slirp_redir(const char *redir_str) +{ + struct slirp_config_str *config; + + if (QTAILQ_EMPTY(&slirp_stacks)) { + config = qemu_malloc(sizeof(*config)); + pstrcpy(config->str, sizeof(config->str), redir_str); + config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY; + config->next = slirp_configs; + slirp_configs = config; + return 0; + } + + return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1); +} + +#ifndef _WIN32 + +/* automatic user mode samba server configuration */ +static void slirp_smb_cleanup(SlirpState *s) +{ + char cmd[128]; + + if (s->smb_dir[0] != '\0') { + snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); + system(cmd); + s->smb_dir[0] = '\0'; + } +} + +static int slirp_smb(SlirpState* s, const char *exported_dir, + struct in_addr vserver_addr) +{ + static int instance; + char smb_conf[128]; + char smb_cmdline[128]; + FILE *f; + + snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d", + (long)getpid(), instance++); + if (mkdir(s->smb_dir, 0700) < 0) { + qemu_error("could not create samba server dir '%s'\n", s->smb_dir); + return -1; + } + snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); + + f = fopen(smb_conf, "w"); + if (!f) { + slirp_smb_cleanup(s); + qemu_error("could not create samba server configuration file '%s'\n", + smb_conf); + return -1; + } + fprintf(f, + "[global]\n" + "private dir=%s\n" + "smb ports=0\n" + "socket address=127.0.0.1\n" + "pid directory=%s\n" + "lock directory=%s\n" + "log file=%s/log.smbd\n" + "smb passwd file=%s/smbpasswd\n" + "security = share\n" + "[qemu]\n" + "path=%s\n" + "read only=no\n" + "guest ok=yes\n", + s->smb_dir, + s->smb_dir, + s->smb_dir, + s->smb_dir, + s->smb_dir, + exported_dir + ); + fclose(f); + + snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", + SMBD_COMMAND, smb_conf); + + if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) { + slirp_smb_cleanup(s); + qemu_error("conflicting/invalid smbserver address\n"); + return -1; + } + return 0; +} + +/* automatic user mode samba server configuration (legacy interface) */ +int net_slirp_smb(const char *exported_dir) +{ + struct in_addr vserver_addr = { .s_addr = 0 }; + + if (legacy_smb_export) { + fprintf(stderr, "-smb given twice\n"); + return -1; + } + legacy_smb_export = exported_dir; + if (!QTAILQ_EMPTY(&slirp_stacks)) { + return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir, + vserver_addr); + } + return 0; +} + +#endif /* !defined(_WIN32) */ + +struct GuestFwd { + CharDriverState *hd; + struct in_addr server; + int port; + Slirp *slirp; +}; + +static int guestfwd_can_read(void *opaque) +{ + struct GuestFwd *fwd = opaque; + return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port); +} + +static void guestfwd_read(void *opaque, const uint8_t *buf, int size) +{ + struct GuestFwd *fwd = opaque; + slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); +} + +static int slirp_guestfwd(SlirpState *s, const char *config_str, + int legacy_format) +{ + struct in_addr server = { .s_addr = 0 }; + struct GuestFwd *fwd; + const char *p; + char buf[128]; + char *end; + int port; + + p = config_str; + if (legacy_format) { + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + } else { + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + if (strcmp(buf, "tcp") && buf[0] != '\0') { + goto fail_syntax; + } + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + if (buf[0] != '\0' && !inet_aton(buf, &server)) { + goto fail_syntax; + } + if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) { + goto fail_syntax; + } + } + port = strtol(buf, &end, 10); + if (*end != '\0' || port < 1 || port > 65535) { + goto fail_syntax; + } + + fwd = qemu_malloc(sizeof(struct GuestFwd)); + snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port); + fwd->hd = qemu_chr_open(buf, p, NULL); + if (!fwd->hd) { + qemu_error("could not open guest forwarding device '%s'\n", buf); + qemu_free(fwd); + return -1; + } + + if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { + qemu_error("conflicting/invalid host:port in guest forwarding " + "rule '%s'\n", config_str); + qemu_free(fwd); + return -1; + } + fwd->server = server; + fwd->port = port; + fwd->slirp = s->slirp; + + qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, + NULL, fwd); + return 0; + + fail_syntax: + qemu_error("invalid guest forwarding rule '%s'\n", config_str); + return -1; +} + +void do_info_usernet(Monitor *mon) +{ + SlirpState *s; + + QTAILQ_FOREACH(s, &slirp_stacks, entry) { + monitor_printf(mon, "VLAN %d (%s):\n", s->vc->vlan->id, s->vc->name); + slirp_connection_info(s->slirp, mon); + } +} + +static int net_init_slirp_configs(const char *name, const char *value, void *opaque) +{ + struct slirp_config_str *config; + + if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) { + return 0; + } + + config = qemu_mallocz(sizeof(*config)); + + pstrcpy(config->str, sizeof(config->str), value); + + if (!strcmp(name, "hostfwd")) { + config->flags = SLIRP_CFG_HOSTFWD; + } + + config->next = slirp_configs; + slirp_configs = config; + + return 0; +} + +int net_init_slirp(QemuOpts *opts, + Monitor *mon, + const char *name, + VLANState *vlan) +{ + struct slirp_config_str *config; + const char *vhost; + const char *vhostname; + const char *vdhcp_start; + const char *vnamesrv; + const char *tftp_export; + const char *bootfile; + const char *smb_export; + const char *vsmbsrv; + char *vnet = NULL; + int restricted = 0; + int ret; + + vhost = qemu_opt_get(opts, "host"); + vhostname = qemu_opt_get(opts, "hostname"); + vdhcp_start = qemu_opt_get(opts, "dhcpstart"); + vnamesrv = qemu_opt_get(opts, "dns"); + tftp_export = qemu_opt_get(opts, "tftp"); + bootfile = qemu_opt_get(opts, "bootfile"); + smb_export = qemu_opt_get(opts, "smb"); + vsmbsrv = qemu_opt_get(opts, "smbserver"); + + if (qemu_opt_get(opts, "ip")) { + const char *ip = qemu_opt_get(opts, "ip"); + int l = strlen(ip) + strlen("/24") + 1; + + vnet = qemu_malloc(l); + + /* emulate legacy ip= parameter */ + pstrcpy(vnet, l, ip); + pstrcat(vnet, l, "/24"); + } + + if (qemu_opt_get(opts, "net")) { + if (vnet) { + qemu_free(vnet); + } + vnet = qemu_strdup(qemu_opt_get(opts, "net")); + } + + if (qemu_opt_get(opts, "restrict") && + qemu_opt_get(opts, "restrict")[0] == 'y') { + restricted = 1; + } + + qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0); + + ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost, + vhostname, tftp_export, bootfile, vdhcp_start, + vnamesrv, smb_export, vsmbsrv); + + while (slirp_configs) { + config = slirp_configs; + slirp_configs = config->next; + qemu_free(config); + } + + if (ret != -1 && vlan) { + vlan->nb_host_devs++; + } + + qemu_free(vnet); + + return ret; +} + +int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret) +{ + if (strcmp(opts_list->name, "net") != 0 || + strncmp(optarg, "channel,", strlen("channel,")) != 0) { + return 0; + } + + /* handle legacy -net channel,port:chr */ + optarg += strlen("channel,"); + + if (QTAILQ_EMPTY(&slirp_stacks)) { + struct slirp_config_str *config; + + config = qemu_malloc(sizeof(*config)); + pstrcpy(config->str, sizeof(config->str), optarg); + config->flags = SLIRP_CFG_LEGACY; + config->next = slirp_configs; + slirp_configs = config; + *ret = 0; + } else { + *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1); + } + + return 1; +} + diff --git a/net/slirp.h b/net/slirp.h new file mode 100644 index 000000000..c17de8ed4 --- /dev/null +++ b/net/slirp.h @@ -0,0 +1,51 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_NET_SLIRP_H +#define QEMU_NET_SLIRP_H + +#include "qemu-common.h" +#include "qdict.h" +#include "qemu-option.h" + +#ifdef CONFIG_SLIRP + +int net_init_slirp(QemuOpts *opts, + Monitor *mon, + const char *name, + VLANState *vlan); + +void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict); +void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict); + +int net_slirp_redir(const char *redir_str); + +int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret); + +int net_slirp_smb(const char *exported_dir); + +void do_info_usernet(Monitor *mon); + +#endif + +#endif /* QEMU_NET_SLIRP_H */ diff --git a/vl.c b/vl.c index e6fcccf20..ba5bd3d80 100644 --- a/vl.c +++ b/vl.c @@ -138,6 +138,7 @@ int main(int argc, char **argv) #include "hw/loader.h" #include "bt-host.h" #include "net.h" +#include "net/slirp.h" #include "monitor.h" #include "console.h" #include "sysemu.h" -- cgit v1.2.3-65-gdbad From 5c361cc3225bd415720452a031a19dc8d9efad45 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:48:55 +0000 Subject: net: move vde code from net.c to net/vde.c Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- Makefile | 1 + net.c | 102 +-------------------------------------------------- net/vde.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/vde.h | 36 ++++++++++++++++++ 4 files changed, 162 insertions(+), 101 deletions(-) create mode 100644 net/vde.c create mode 100644 net/vde.h diff --git a/Makefile b/Makefile index b3cc8d419..fa10459e2 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,7 @@ net-nested-$(CONFIG_BSD) += tap-bsd.o net-nested-$(CONFIG_SOLARIS) += tap-solaris.o net-nested-$(CONFIG_AIX) += tap-aix.o net-nested-$(CONFIG_SLIRP) += slirp.o +net-nested-$(CONFIG_VDE) += vde.o net-obj-y += $(addprefix net/, $(net-nested-y)) ###################################################################### diff --git a/net.c b/net.c index 9887d95ac..a9ebaa2db 100644 --- a/net.c +++ b/net.c @@ -86,14 +86,11 @@ #include #endif -#if defined(CONFIG_VDE) -#include -#endif - #include "qemu-common.h" #include "net.h" #include "net/tap.h" #include "net/slirp.h" +#include "net/vde.h" #include "monitor.h" #include "sysemu.h" #include "qemu-timer.h" @@ -719,75 +716,6 @@ qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt) return qemu_sendv_packet_async(vc, iov, iovcnt, NULL); } -#if defined(CONFIG_VDE) -typedef struct VDEState { - VLANClientState *vc; - VDECONN *vde; -} VDEState; - -static void vde_to_qemu(void *opaque) -{ - VDEState *s = opaque; - uint8_t buf[4096]; - int size; - - size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0); - if (size > 0) { - qemu_send_packet(s->vc, buf, size); - } -} - -static ssize_t vde_receive(VLANClientState *vc, const uint8_t *buf, size_t size) -{ - VDEState *s = vc->opaque; - ssize_t ret; - - do { - ret = vde_send(s->vde, (const char *)buf, size, 0); - } while (ret < 0 && errno == EINTR); - - return ret; -} - -static void vde_cleanup(VLANClientState *vc) -{ - VDEState *s = vc->opaque; - qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL); - vde_close(s->vde); - qemu_free(s); -} - -static int net_vde_init(VLANState *vlan, const char *model, - const char *name, const char *sock, - int port, const char *group, int mode) -{ - VDEState *s; - char *init_group = (char *)group; - char *init_sock = (char *)sock; - - struct vde_open_args args = { - .port = port, - .group = init_group, - .mode = mode, - }; - - s = qemu_mallocz(sizeof(VDEState)); - s->vde = vde_open(init_sock, (char *)"QEMU", &args); - if (!s->vde){ - free(s); - return -1; - } - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_VDE, - vlan, NULL, model, name, NULL, - vde_receive, NULL, NULL, - vde_cleanup, s); - qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", - sock, vde_datafd(s->vde)); - return 0; -} -#endif - /* network connection */ typedef struct NetSocketState { VLANClientState *vc; @@ -1600,34 +1528,6 @@ static int net_init_socket(QemuOpts *opts, return 0; } -#ifdef CONFIG_VDE -static int net_init_vde(QemuOpts *opts, - Monitor *mon, - const char *name, - VLANState *vlan) -{ - const char *sock; - const char *group; - int port, mode; - - sock = qemu_opt_get(opts, "sock"); - group = qemu_opt_get(opts, "group"); - - port = qemu_opt_get_number(opts, "port", 0); - mode = qemu_opt_get_number(opts, "mode", 0700); - - if (net_vde_init(vlan, "vde", name, sock, port, group, mode) == -1) { - return -1; - } - - if (vlan) { - vlan->nb_host_devs++; - } - - return 0; -} -#endif - static int net_init_dump(QemuOpts *opts, Monitor *mon, const char *name, diff --git a/net/vde.c b/net/vde.c new file mode 100644 index 000000000..4d09967fd --- /dev/null +++ b/net/vde.c @@ -0,0 +1,124 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "net/vde.h" + +#include "config-host.h" + +#include + +#include "net.h" +#include "qemu-char.h" +#include "qemu-common.h" +#include "qemu-option.h" +#include "sysemu.h" + +typedef struct VDEState { + VLANClientState *vc; + VDECONN *vde; +} VDEState; + +static void vde_to_qemu(void *opaque) +{ + VDEState *s = opaque; + uint8_t buf[4096]; + int size; + + size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0); + if (size > 0) { + qemu_send_packet(s->vc, buf, size); + } +} + +static ssize_t vde_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +{ + VDEState *s = vc->opaque; + ssize_t ret; + + do { + ret = vde_send(s->vde, (const char *)buf, size, 0); + } while (ret < 0 && errno == EINTR); + + return ret; +} + +static void vde_cleanup(VLANClientState *vc) +{ + VDEState *s = vc->opaque; + qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL); + vde_close(s->vde); + qemu_free(s); +} + +static int net_vde_init(VLANState *vlan, const char *model, + const char *name, const char *sock, + int port, const char *group, int mode) +{ + VDEState *s; + char *init_group = (char *)group; + char *init_sock = (char *)sock; + + struct vde_open_args args = { + .port = port, + .group = init_group, + .mode = mode, + }; + + s = qemu_mallocz(sizeof(VDEState)); + s->vde = vde_open(init_sock, (char *)"QEMU", &args); + if (!s->vde){ + free(s); + return -1; + } + s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_VDE, + vlan, NULL, model, name, NULL, + vde_receive, NULL, NULL, + vde_cleanup, s); + qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", + sock, vde_datafd(s->vde)); + return 0; +} + +int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan) +{ + const char *sock; + const char *group; + int port, mode; + + sock = qemu_opt_get(opts, "sock"); + group = qemu_opt_get(opts, "group"); + + port = qemu_opt_get_number(opts, "port", 0); + mode = qemu_opt_get_number(opts, "mode", 0700); + + if (net_vde_init(vlan, "vde", name, sock, port, group, mode) == -1) { + return -1; + } + + if (vlan) { + vlan->nb_host_devs++; + } + + return 0; +} diff --git a/net/vde.h b/net/vde.h new file mode 100644 index 000000000..3e6ca3e87 --- /dev/null +++ b/net/vde.h @@ -0,0 +1,36 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_NET_VDE_H +#define QEMU_NET_VDE_H + +#include "qemu-common.h" +#include "qemu-option.h" + +#ifdef CONFIG_VDE + +int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan); + +#endif /* CONFIG_VDE */ + +#endif /* QEMU_NET_VDE_H */ -- cgit v1.2.3-65-gdbad From 42281ac9a3791749f5f77b5250ad54c8990fdcf2 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:48:56 +0000 Subject: net: move socket backend code from net.c to net/socket.c Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- Makefile | 1 + net.c | 530 +------------------------------------------------------ net/socket.c | 561 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/socket.h | 33 ++++ 4 files changed, 596 insertions(+), 529 deletions(-) create mode 100644 net/socket.c create mode 100644 net/socket.h diff --git a/Makefile b/Makefile index fa10459e2..29ef8a9cb 100644 --- a/Makefile +++ b/Makefile @@ -100,6 +100,7 @@ block-obj-y += $(addprefix block/, $(block-nested-y)) net-obj-y = net.o net-nested-y = queue.o checksum.o +net-nested-y += socket.o net-nested-$(CONFIG_POSIX) += tap.o net-nested-$(CONFIG_LINUX) += tap-linux.o net-nested-$(CONFIG_WIN32) += tap-win32.o diff --git a/net.c b/net.c index a9ebaa2db..765cd2c87 100644 --- a/net.c +++ b/net.c @@ -89,6 +89,7 @@ #include "qemu-common.h" #include "net.h" #include "net/tap.h" +#include "net/socket.h" #include "net/slirp.h" #include "net/vde.h" #include "monitor.h" @@ -716,454 +717,6 @@ qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt) return qemu_sendv_packet_async(vc, iov, iovcnt, NULL); } -/* network connection */ -typedef struct NetSocketState { - VLANClientState *vc; - int fd; - int state; /* 0 = getting length, 1 = getting data */ - unsigned int index; - unsigned int packet_len; - uint8_t buf[4096]; - struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ -} NetSocketState; - -typedef struct NetSocketListenState { - VLANState *vlan; - char *model; - char *name; - int fd; -} NetSocketListenState; - -/* XXX: we consider we can send the whole packet without blocking */ -static ssize_t net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size) -{ - NetSocketState *s = vc->opaque; - uint32_t len; - len = htonl(size); - - send_all(s->fd, (const uint8_t *)&len, sizeof(len)); - return send_all(s->fd, buf, size); -} - -static ssize_t net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size) -{ - NetSocketState *s = vc->opaque; - - return sendto(s->fd, (const void *)buf, size, 0, - (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); -} - -static void net_socket_send(void *opaque) -{ - NetSocketState *s = opaque; - int size, err; - unsigned l; - uint8_t buf1[4096]; - const uint8_t *buf; - - size = recv(s->fd, (void *)buf1, sizeof(buf1), 0); - if (size < 0) { - err = socket_error(); - if (err != EWOULDBLOCK) - goto eoc; - } else if (size == 0) { - /* end of connection */ - eoc: - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); - closesocket(s->fd); - return; - } - buf = buf1; - while (size > 0) { - /* reassemble a packet from the network */ - switch(s->state) { - case 0: - l = 4 - s->index; - if (l > size) - l = size; - memcpy(s->buf + s->index, buf, l); - buf += l; - size -= l; - s->index += l; - if (s->index == 4) { - /* got length */ - s->packet_len = ntohl(*(uint32_t *)s->buf); - s->index = 0; - s->state = 1; - } - break; - case 1: - l = s->packet_len - s->index; - if (l > size) - l = size; - if (s->index + l <= sizeof(s->buf)) { - memcpy(s->buf + s->index, buf, l); - } else { - fprintf(stderr, "serious error: oversized packet received," - "connection terminated.\n"); - s->state = 0; - goto eoc; - } - - s->index += l; - buf += l; - size -= l; - if (s->index >= s->packet_len) { - qemu_send_packet(s->vc, s->buf, s->packet_len); - s->index = 0; - s->state = 0; - } - break; - } - } -} - -static void net_socket_send_dgram(void *opaque) -{ - NetSocketState *s = opaque; - int size; - - size = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0); - if (size < 0) - return; - if (size == 0) { - /* end of connection */ - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); - return; - } - qemu_send_packet(s->vc, s->buf, size); -} - -static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) -{ - struct ip_mreq imr; - int fd; - int val, ret; - if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { - fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n", - inet_ntoa(mcastaddr->sin_addr), - (int)ntohl(mcastaddr->sin_addr.s_addr)); - return -1; - - } - fd = socket(PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - perror("socket(PF_INET, SOCK_DGRAM)"); - return -1; - } - - val = 1; - ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (const char *)&val, sizeof(val)); - if (ret < 0) { - perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); - goto fail; - } - - ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); - if (ret < 0) { - perror("bind"); - goto fail; - } - - /* Add host to multicast group */ - imr.imr_multiaddr = mcastaddr->sin_addr; - imr.imr_interface.s_addr = htonl(INADDR_ANY); - - ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (const char *)&imr, sizeof(struct ip_mreq)); - if (ret < 0) { - perror("setsockopt(IP_ADD_MEMBERSHIP)"); - goto fail; - } - - /* Force mcast msgs to loopback (eg. several QEMUs in same host */ - val = 1; - ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, - (const char *)&val, sizeof(val)); - if (ret < 0) { - perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); - goto fail; - } - - socket_set_nonblock(fd); - return fd; -fail: - if (fd >= 0) - closesocket(fd); - return -1; -} - -static void net_socket_cleanup(VLANClientState *vc) -{ - NetSocketState *s = vc->opaque; - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); - close(s->fd); - qemu_free(s); -} - -static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, - const char *model, - const char *name, - int fd, int is_connected) -{ - struct sockaddr_in saddr; - int newfd; - socklen_t saddr_len; - NetSocketState *s; - - /* fd passed: multicast: "learn" dgram_dst address from bound address and save it - * Because this may be "shared" socket from a "master" process, datagrams would be recv() - * by ONLY ONE process: we must "clone" this dgram socket --jjo - */ - - if (is_connected) { - if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) { - /* must be bound */ - if (saddr.sin_addr.s_addr==0) { - fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n", - fd); - return NULL; - } - /* clone dgram socket */ - newfd = net_socket_mcast_create(&saddr); - if (newfd < 0) { - /* error already reported by net_socket_mcast_create() */ - close(fd); - return NULL; - } - /* clone newfd to fd, close newfd */ - dup2(newfd, fd); - close(newfd); - - } else { - fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n", - fd, strerror(errno)); - return NULL; - } - } - - s = qemu_mallocz(sizeof(NetSocketState)); - s->fd = fd; - - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET, - vlan, NULL, model, name, NULL, - net_socket_receive_dgram, NULL, NULL, - net_socket_cleanup, s); - qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); - - /* mcast: save bound address as dst */ - if (is_connected) s->dgram_dst=saddr; - - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: fd=%d (%s mcast=%s:%d)", - fd, is_connected? "cloned" : "", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - return s; -} - -static void net_socket_connect(void *opaque) -{ - NetSocketState *s = opaque; - qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); -} - -static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, - const char *model, - const char *name, - int fd, int is_connected) -{ - NetSocketState *s; - s = qemu_mallocz(sizeof(NetSocketState)); - s->fd = fd; - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET, - vlan, NULL, model, name, NULL, - net_socket_receive, NULL, NULL, - net_socket_cleanup, s); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: fd=%d", fd); - if (is_connected) { - net_socket_connect(s); - } else { - qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); - } - return s; -} - -static NetSocketState *net_socket_fd_init(VLANState *vlan, - const char *model, const char *name, - int fd, int is_connected) -{ - int so_type = -1, optlen=sizeof(so_type); - - if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, - (socklen_t *)&optlen)< 0) { - fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd); - return NULL; - } - switch(so_type) { - case SOCK_DGRAM: - return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected); - case SOCK_STREAM: - return net_socket_fd_init_stream(vlan, model, name, fd, is_connected); - default: - /* who knows ... this could be a eg. a pty, do warn and continue as stream */ - fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd); - return net_socket_fd_init_stream(vlan, model, name, fd, is_connected); - } - return NULL; -} - -static void net_socket_accept(void *opaque) -{ - NetSocketListenState *s = opaque; - NetSocketState *s1; - struct sockaddr_in saddr; - socklen_t len; - int fd; - - for(;;) { - len = sizeof(saddr); - fd = accept(s->fd, (struct sockaddr *)&saddr, &len); - if (fd < 0 && errno != EINTR) { - return; - } else if (fd >= 0) { - break; - } - } - s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1); - if (!s1) { - closesocket(fd); - } else { - snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), - "socket: connection from %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - } -} - -static int net_socket_listen_init(VLANState *vlan, - const char *model, - const char *name, - const char *host_str) -{ - NetSocketListenState *s; - int fd, val, ret; - struct sockaddr_in saddr; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - s = qemu_mallocz(sizeof(NetSocketListenState)); - - fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; - } - socket_set_nonblock(fd); - - /* allow fast reuse */ - val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); - - ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) { - perror("bind"); - return -1; - } - ret = listen(fd, 0); - if (ret < 0) { - perror("listen"); - return -1; - } - s->vlan = vlan; - s->model = qemu_strdup(model); - s->name = name ? qemu_strdup(name) : NULL; - s->fd = fd; - qemu_set_fd_handler(fd, net_socket_accept, NULL, s); - return 0; -} - -static int net_socket_connect_init(VLANState *vlan, - const char *model, - const char *name, - const char *host_str) -{ - NetSocketState *s; - int fd, connected, ret, err; - struct sockaddr_in saddr; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; - } - socket_set_nonblock(fd); - - connected = 0; - for(;;) { - ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) { - err = socket_error(); - if (err == EINTR || err == EWOULDBLOCK) { - } else if (err == EINPROGRESS) { - break; -#ifdef _WIN32 - } else if (err == WSAEALREADY) { - break; -#endif - } else { - perror("connect"); - closesocket(fd); - return -1; - } - } else { - connected = 1; - break; - } - } - s = net_socket_fd_init(vlan, model, name, fd, connected); - if (!s) - return -1; - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: connect to %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - return 0; -} - -static int net_socket_mcast_init(VLANState *vlan, - const char *model, - const char *name, - const char *host_str) -{ - NetSocketState *s; - int fd; - struct sockaddr_in saddr; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - - fd = net_socket_mcast_create(&saddr); - if (fd < 0) - return -1; - - s = net_socket_fd_init(vlan, model, name, fd, 0); - if (!s) - return -1; - - s->dgram_dst = saddr; - - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: mcast=%s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - return 0; - -} - typedef struct DumpState { VLANClientState *pcap_vc; int fd; @@ -1447,87 +1000,6 @@ static int net_init_nic(QemuOpts *opts, return idx; } -static int net_init_socket(QemuOpts *opts, - Monitor *mon, - const char *name, - VLANState *vlan) -{ - if (qemu_opt_get(opts, "fd")) { - int fd; - - if (qemu_opt_get(opts, "listen") || - qemu_opt_get(opts, "connect") || - qemu_opt_get(opts, "mcast")) { - qemu_error("listen=, connect= and mcast= is invalid with fd=\n"); - return -1; - } - - fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd")); - if (fd == -1) { - return -1; - } - - if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) { - close(fd); - return -1; - } - } else if (qemu_opt_get(opts, "listen")) { - const char *listen; - - if (qemu_opt_get(opts, "fd") || - qemu_opt_get(opts, "connect") || - qemu_opt_get(opts, "mcast")) { - qemu_error("fd=, connect= and mcast= is invalid with listen=\n"); - return -1; - } - - listen = qemu_opt_get(opts, "listen"); - - if (net_socket_listen_init(vlan, "socket", name, listen) == -1) { - return -1; - } - } else if (qemu_opt_get(opts, "connect")) { - const char *connect; - - if (qemu_opt_get(opts, "fd") || - qemu_opt_get(opts, "listen") || - qemu_opt_get(opts, "mcast")) { - qemu_error("fd=, listen= and mcast= is invalid with connect=\n"); - return -1; - } - - connect = qemu_opt_get(opts, "connect"); - - if (net_socket_connect_init(vlan, "socket", name, connect) == -1) { - return -1; - } - } else if (qemu_opt_get(opts, "mcast")) { - const char *mcast; - - if (qemu_opt_get(opts, "fd") || - qemu_opt_get(opts, "connect") || - qemu_opt_get(opts, "listen")) { - qemu_error("fd=, connect= and listen= is invalid with mcast=\n"); - return -1; - } - - mcast = qemu_opt_get(opts, "mcast"); - - if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) { - return -1; - } - } else { - qemu_error("-socket requires fd=, listen=, connect= or mcast=\n"); - return -1; - } - - if (vlan) { - vlan->nb_host_devs++; - } - - return 0; -} - static int net_init_dump(QemuOpts *opts, Monitor *mon, const char *name, diff --git a/net/socket.c b/net/socket.c new file mode 100644 index 000000000..551fc2b9e --- /dev/null +++ b/net/socket.c @@ -0,0 +1,561 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "net/socket.h" + +#include "config-host.h" + +#include "net.h" +#include "qemu-char.h" +#include "qemu-common.h" +#include "qemu-option.h" +#include "qemu_socket.h" +#include "sysemu.h" + +typedef struct NetSocketState { + VLANClientState *vc; + int fd; + int state; /* 0 = getting length, 1 = getting data */ + unsigned int index; + unsigned int packet_len; + uint8_t buf[4096]; + struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ +} NetSocketState; + +typedef struct NetSocketListenState { + VLANState *vlan; + char *model; + char *name; + int fd; +} NetSocketListenState; + +/* XXX: we consider we can send the whole packet without blocking */ +static ssize_t net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +{ + NetSocketState *s = vc->opaque; + uint32_t len; + len = htonl(size); + + send_all(s->fd, (const uint8_t *)&len, sizeof(len)); + return send_all(s->fd, buf, size); +} + +static ssize_t net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size) +{ + NetSocketState *s = vc->opaque; + + return sendto(s->fd, (const void *)buf, size, 0, + (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); +} + +static void net_socket_send(void *opaque) +{ + NetSocketState *s = opaque; + int size, err; + unsigned l; + uint8_t buf1[4096]; + const uint8_t *buf; + + size = recv(s->fd, (void *)buf1, sizeof(buf1), 0); + if (size < 0) { + err = socket_error(); + if (err != EWOULDBLOCK) + goto eoc; + } else if (size == 0) { + /* end of connection */ + eoc: + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + closesocket(s->fd); + return; + } + buf = buf1; + while (size > 0) { + /* reassemble a packet from the network */ + switch(s->state) { + case 0: + l = 4 - s->index; + if (l > size) + l = size; + memcpy(s->buf + s->index, buf, l); + buf += l; + size -= l; + s->index += l; + if (s->index == 4) { + /* got length */ + s->packet_len = ntohl(*(uint32_t *)s->buf); + s->index = 0; + s->state = 1; + } + break; + case 1: + l = s->packet_len - s->index; + if (l > size) + l = size; + if (s->index + l <= sizeof(s->buf)) { + memcpy(s->buf + s->index, buf, l); + } else { + fprintf(stderr, "serious error: oversized packet received," + "connection terminated.\n"); + s->state = 0; + goto eoc; + } + + s->index += l; + buf += l; + size -= l; + if (s->index >= s->packet_len) { + qemu_send_packet(s->vc, s->buf, s->packet_len); + s->index = 0; + s->state = 0; + } + break; + } + } +} + +static void net_socket_send_dgram(void *opaque) +{ + NetSocketState *s = opaque; + int size; + + size = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0); + if (size < 0) + return; + if (size == 0) { + /* end of connection */ + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + return; + } + qemu_send_packet(s->vc, s->buf, size); +} + +static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) +{ + struct ip_mreq imr; + int fd; + int val, ret; + if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { + fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n", + inet_ntoa(mcastaddr->sin_addr), + (int)ntohl(mcastaddr->sin_addr.s_addr)); + return -1; + + } + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + perror("socket(PF_INET, SOCK_DGRAM)"); + return -1; + } + + val = 1; + ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (const char *)&val, sizeof(val)); + if (ret < 0) { + perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); + goto fail; + } + + ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); + if (ret < 0) { + perror("bind"); + goto fail; + } + + /* Add host to multicast group */ + imr.imr_multiaddr = mcastaddr->sin_addr; + imr.imr_interface.s_addr = htonl(INADDR_ANY); + + ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const char *)&imr, sizeof(struct ip_mreq)); + if (ret < 0) { + perror("setsockopt(IP_ADD_MEMBERSHIP)"); + goto fail; + } + + /* Force mcast msgs to loopback (eg. several QEMUs in same host */ + val = 1; + ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + (const char *)&val, sizeof(val)); + if (ret < 0) { + perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); + goto fail; + } + + socket_set_nonblock(fd); + return fd; +fail: + if (fd >= 0) + closesocket(fd); + return -1; +} + +static void net_socket_cleanup(VLANClientState *vc) +{ + NetSocketState *s = vc->opaque; + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + close(s->fd); + qemu_free(s); +} + +static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, + const char *model, + const char *name, + int fd, int is_connected) +{ + struct sockaddr_in saddr; + int newfd; + socklen_t saddr_len; + NetSocketState *s; + + /* fd passed: multicast: "learn" dgram_dst address from bound address and save it + * Because this may be "shared" socket from a "master" process, datagrams would be recv() + * by ONLY ONE process: we must "clone" this dgram socket --jjo + */ + + if (is_connected) { + if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) { + /* must be bound */ + if (saddr.sin_addr.s_addr==0) { + fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n", + fd); + return NULL; + } + /* clone dgram socket */ + newfd = net_socket_mcast_create(&saddr); + if (newfd < 0) { + /* error already reported by net_socket_mcast_create() */ + close(fd); + return NULL; + } + /* clone newfd to fd, close newfd */ + dup2(newfd, fd); + close(newfd); + + } else { + fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n", + fd, strerror(errno)); + return NULL; + } + } + + s = qemu_mallocz(sizeof(NetSocketState)); + s->fd = fd; + + s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET, + vlan, NULL, model, name, NULL, + net_socket_receive_dgram, NULL, NULL, + net_socket_cleanup, s); + qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); + + /* mcast: save bound address as dst */ + if (is_connected) s->dgram_dst=saddr; + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: fd=%d (%s mcast=%s:%d)", + fd, is_connected? "cloned" : "", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + return s; +} + +static void net_socket_connect(void *opaque) +{ + NetSocketState *s = opaque; + qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); +} + +static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, + const char *model, + const char *name, + int fd, int is_connected) +{ + NetSocketState *s; + s = qemu_mallocz(sizeof(NetSocketState)); + s->fd = fd; + s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET, + vlan, NULL, model, name, NULL, + net_socket_receive, NULL, NULL, + net_socket_cleanup, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: fd=%d", fd); + if (is_connected) { + net_socket_connect(s); + } else { + qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); + } + return s; +} + +static NetSocketState *net_socket_fd_init(VLANState *vlan, + const char *model, const char *name, + int fd, int is_connected) +{ + int so_type = -1, optlen=sizeof(so_type); + + if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, + (socklen_t *)&optlen)< 0) { + fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd); + return NULL; + } + switch(so_type) { + case SOCK_DGRAM: + return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected); + case SOCK_STREAM: + return net_socket_fd_init_stream(vlan, model, name, fd, is_connected); + default: + /* who knows ... this could be a eg. a pty, do warn and continue as stream */ + fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd); + return net_socket_fd_init_stream(vlan, model, name, fd, is_connected); + } + return NULL; +} + +static void net_socket_accept(void *opaque) +{ + NetSocketListenState *s = opaque; + NetSocketState *s1; + struct sockaddr_in saddr; + socklen_t len; + int fd; + + for(;;) { + len = sizeof(saddr); + fd = accept(s->fd, (struct sockaddr *)&saddr, &len); + if (fd < 0 && errno != EINTR) { + return; + } else if (fd >= 0) { + break; + } + } + s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1); + if (!s1) { + closesocket(fd); + } else { + snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), + "socket: connection from %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + } +} + +static int net_socket_listen_init(VLANState *vlan, + const char *model, + const char *name, + const char *host_str) +{ + NetSocketListenState *s; + int fd, val, ret; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + s = qemu_mallocz(sizeof(NetSocketListenState)); + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + socket_set_nonblock(fd); + + /* allow fast reuse */ + val = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); + + ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + perror("bind"); + return -1; + } + ret = listen(fd, 0); + if (ret < 0) { + perror("listen"); + return -1; + } + s->vlan = vlan; + s->model = qemu_strdup(model); + s->name = name ? qemu_strdup(name) : NULL; + s->fd = fd; + qemu_set_fd_handler(fd, net_socket_accept, NULL, s); + return 0; +} + +static int net_socket_connect_init(VLANState *vlan, + const char *model, + const char *name, + const char *host_str) +{ + NetSocketState *s; + int fd, connected, ret, err; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + socket_set_nonblock(fd); + + connected = 0; + for(;;) { + ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + err = socket_error(); + if (err == EINTR || err == EWOULDBLOCK) { + } else if (err == EINPROGRESS) { + break; +#ifdef _WIN32 + } else if (err == WSAEALREADY) { + break; +#endif + } else { + perror("connect"); + closesocket(fd); + return -1; + } + } else { + connected = 1; + break; + } + } + s = net_socket_fd_init(vlan, model, name, fd, connected); + if (!s) + return -1; + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: connect to %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + return 0; +} + +static int net_socket_mcast_init(VLANState *vlan, + const char *model, + const char *name, + const char *host_str) +{ + NetSocketState *s; + int fd; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + + fd = net_socket_mcast_create(&saddr); + if (fd < 0) + return -1; + + s = net_socket_fd_init(vlan, model, name, fd, 0); + if (!s) + return -1; + + s->dgram_dst = saddr; + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: mcast=%s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + return 0; + +} + +int net_init_socket(QemuOpts *opts, + Monitor *mon, + const char *name, + VLANState *vlan) +{ + if (qemu_opt_get(opts, "fd")) { + int fd; + + if (qemu_opt_get(opts, "listen") || + qemu_opt_get(opts, "connect") || + qemu_opt_get(opts, "mcast")) { + qemu_error("listen=, connect= and mcast= is invalid with fd=\n"); + return -1; + } + + fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd")); + if (fd == -1) { + return -1; + } + + if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) { + close(fd); + return -1; + } + } else if (qemu_opt_get(opts, "listen")) { + const char *listen; + + if (qemu_opt_get(opts, "fd") || + qemu_opt_get(opts, "connect") || + qemu_opt_get(opts, "mcast")) { + qemu_error("fd=, connect= and mcast= is invalid with listen=\n"); + return -1; + } + + listen = qemu_opt_get(opts, "listen"); + + if (net_socket_listen_init(vlan, "socket", name, listen) == -1) { + return -1; + } + } else if (qemu_opt_get(opts, "connect")) { + const char *connect; + + if (qemu_opt_get(opts, "fd") || + qemu_opt_get(opts, "listen") || + qemu_opt_get(opts, "mcast")) { + qemu_error("fd=, listen= and mcast= is invalid with connect=\n"); + return -1; + } + + connect = qemu_opt_get(opts, "connect"); + + if (net_socket_connect_init(vlan, "socket", name, connect) == -1) { + return -1; + } + } else if (qemu_opt_get(opts, "mcast")) { + const char *mcast; + + if (qemu_opt_get(opts, "fd") || + qemu_opt_get(opts, "connect") || + qemu_opt_get(opts, "listen")) { + qemu_error("fd=, connect= and listen= is invalid with mcast=\n"); + return -1; + } + + mcast = qemu_opt_get(opts, "mcast"); + + if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) { + return -1; + } + } else { + qemu_error("-socket requires fd=, listen=, connect= or mcast=\n"); + return -1; + } + + if (vlan) { + vlan->nb_host_devs++; + } + + return 0; +} diff --git a/net/socket.h b/net/socket.h new file mode 100644 index 000000000..ea46f02dd --- /dev/null +++ b/net/socket.h @@ -0,0 +1,33 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_NET_SOCKET_H +#define QEMU_NET_SOCKET_H + +#include "net.h" +#include "qemu-common.h" + +int net_init_socket(QemuOpts *opts, Monitor *mon, + const char *name, VLANState *vlan); + +#endif /* QEMU_NET_SOCKET_H */ -- cgit v1.2.3-65-gdbad From 1abecf77d87124076eff8e5836a6d0dd7bd595c5 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:48:57 +0000 Subject: net: move dump backend code from net.c to net/dump.c Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- Makefile | 1 + net.c | 127 +-------------------------------------------------- net/dump.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/dump.h | 33 ++++++++++++++ 4 files changed, 186 insertions(+), 126 deletions(-) create mode 100644 net/dump.c create mode 100644 net/dump.h diff --git a/Makefile b/Makefile index 29ef8a9cb..b59545a3e 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,7 @@ block-obj-y += $(addprefix block/, $(block-nested-y)) net-obj-y = net.o net-nested-y = queue.o checksum.o net-nested-y += socket.o +net-nested-y += dump.o net-nested-$(CONFIG_POSIX) += tap.o net-nested-$(CONFIG_LINUX) += tap-linux.o net-nested-$(CONFIG_WIN32) += tap-win32.o diff --git a/net.c b/net.c index 765cd2c87..5f225fde7 100644 --- a/net.c +++ b/net.c @@ -90,6 +90,7 @@ #include "net.h" #include "net/tap.h" #include "net/socket.h" +#include "net/dump.h" #include "net/slirp.h" #include "net/vde.h" #include "monitor.h" @@ -717,110 +718,6 @@ qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt) return qemu_sendv_packet_async(vc, iov, iovcnt, NULL); } -typedef struct DumpState { - VLANClientState *pcap_vc; - int fd; - int pcap_caplen; -} DumpState; - -#define PCAP_MAGIC 0xa1b2c3d4 - -struct pcap_file_hdr { - uint32_t magic; - uint16_t version_major; - uint16_t version_minor; - int32_t thiszone; - uint32_t sigfigs; - uint32_t snaplen; - uint32_t linktype; -}; - -struct pcap_sf_pkthdr { - struct { - int32_t tv_sec; - int32_t tv_usec; - } ts; - uint32_t caplen; - uint32_t len; -}; - -static ssize_t dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size) -{ - DumpState *s = vc->opaque; - struct pcap_sf_pkthdr hdr; - int64_t ts; - int caplen; - - /* Early return in case of previous error. */ - if (s->fd < 0) { - return size; - } - - ts = muldiv64(qemu_get_clock(vm_clock), 1000000, get_ticks_per_sec()); - caplen = size > s->pcap_caplen ? s->pcap_caplen : size; - - hdr.ts.tv_sec = ts / 1000000; - hdr.ts.tv_usec = ts % 1000000; - hdr.caplen = caplen; - hdr.len = size; - if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) || - write(s->fd, buf, caplen) != caplen) { - qemu_log("-net dump write error - stop dump\n"); - close(s->fd); - s->fd = -1; - } - - return size; -} - -static void net_dump_cleanup(VLANClientState *vc) -{ - DumpState *s = vc->opaque; - - close(s->fd); - qemu_free(s); -} - -static int net_dump_init(VLANState *vlan, const char *device, - const char *name, const char *filename, int len) -{ - struct pcap_file_hdr hdr; - DumpState *s; - - s = qemu_malloc(sizeof(DumpState)); - - s->fd = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644); - if (s->fd < 0) { - qemu_error("-net dump: can't open %s\n", filename); - return -1; - } - - s->pcap_caplen = len; - - hdr.magic = PCAP_MAGIC; - hdr.version_major = 2; - hdr.version_minor = 4; - hdr.thiszone = 0; - hdr.sigfigs = 0; - hdr.snaplen = s->pcap_caplen; - hdr.linktype = 1; - - if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { - qemu_error("-net dump write error: %s\n", strerror(errno)); - close(s->fd); - qemu_free(s); - return -1; - } - - s->pcap_vc = qemu_new_vlan_client(NET_CLIENT_TYPE_DUMP, - vlan, NULL, device, name, NULL, - dump_receive, NULL, NULL, - net_dump_cleanup, s); - snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str), - "dump to %s (len=%d)", filename, len); - return 0; -} - /* find or alloc a new VLAN */ VLANState *qemu_find_vlan(int id, int allocate) { @@ -1000,28 +897,6 @@ static int net_init_nic(QemuOpts *opts, return idx; } -static int net_init_dump(QemuOpts *opts, - Monitor *mon, - const char *name, - VLANState *vlan) -{ - int len; - const char *file; - char def_file[128]; - - assert(vlan); - - file = qemu_opt_get(opts, "file"); - if (!file) { - snprintf(def_file, sizeof(def_file), "qemu-vlan%d.pcap", vlan->id); - file = def_file; - } - - len = qemu_opt_get_size(opts, "len", 65536); - - return net_dump_init(vlan, "dump", name, file, len); -} - #define NET_COMMON_PARAMS_DESC \ { \ .name = "type", \ diff --git a/net/dump.c b/net/dump.c new file mode 100644 index 000000000..05a102be0 --- /dev/null +++ b/net/dump.c @@ -0,0 +1,151 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "dump.h" +#include "qemu-common.h" +#include "sysemu.h" +#include "qemu-log.h" + +typedef struct DumpState { + VLANClientState *pcap_vc; + int fd; + int pcap_caplen; +} DumpState; + +#define PCAP_MAGIC 0xa1b2c3d4 + +struct pcap_file_hdr { + uint32_t magic; + uint16_t version_major; + uint16_t version_minor; + int32_t thiszone; + uint32_t sigfigs; + uint32_t snaplen; + uint32_t linktype; +}; + +struct pcap_sf_pkthdr { + struct { + int32_t tv_sec; + int32_t tv_usec; + } ts; + uint32_t caplen; + uint32_t len; +}; + +static ssize_t dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +{ + DumpState *s = vc->opaque; + struct pcap_sf_pkthdr hdr; + int64_t ts; + int caplen; + + /* Early return in case of previous error. */ + if (s->fd < 0) { + return size; + } + + ts = muldiv64(qemu_get_clock(vm_clock), 1000000, get_ticks_per_sec()); + caplen = size > s->pcap_caplen ? s->pcap_caplen : size; + + hdr.ts.tv_sec = ts / 1000000; + hdr.ts.tv_usec = ts % 1000000; + hdr.caplen = caplen; + hdr.len = size; + if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) || + write(s->fd, buf, caplen) != caplen) { + qemu_log("-net dump write error - stop dump\n"); + close(s->fd); + s->fd = -1; + } + + return size; +} + +static void net_dump_cleanup(VLANClientState *vc) +{ + DumpState *s = vc->opaque; + + close(s->fd); + qemu_free(s); +} + +static int net_dump_init(VLANState *vlan, const char *device, + const char *name, const char *filename, int len) +{ + struct pcap_file_hdr hdr; + DumpState *s; + + s = qemu_malloc(sizeof(DumpState)); + + s->fd = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644); + if (s->fd < 0) { + qemu_error("-net dump: can't open %s\n", filename); + return -1; + } + + s->pcap_caplen = len; + + hdr.magic = PCAP_MAGIC; + hdr.version_major = 2; + hdr.version_minor = 4; + hdr.thiszone = 0; + hdr.sigfigs = 0; + hdr.snaplen = s->pcap_caplen; + hdr.linktype = 1; + + if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { + qemu_error("-net dump write error: %s\n", strerror(errno)); + close(s->fd); + qemu_free(s); + return -1; + } + + s->pcap_vc = qemu_new_vlan_client(NET_CLIENT_TYPE_DUMP, + vlan, NULL, device, name, NULL, + dump_receive, NULL, NULL, + net_dump_cleanup, s); + snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str), + "dump to %s (len=%d)", filename, len); + return 0; +} + +int net_init_dump(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan) +{ + int len; + const char *file; + char def_file[128]; + + assert(vlan); + + file = qemu_opt_get(opts, "file"); + if (!file) { + snprintf(def_file, sizeof(def_file), "qemu-vlan%d.pcap", vlan->id); + file = def_file; + } + + len = qemu_opt_get_size(opts, "len", 65536); + + return net_dump_init(vlan, "dump", name, file, len); +} diff --git a/net/dump.h b/net/dump.h new file mode 100644 index 000000000..fdc91ad6d --- /dev/null +++ b/net/dump.h @@ -0,0 +1,33 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_NET_DUMP_H +#define QEMU_NET_DUMP_H + +#include "net.h" +#include "qemu-common.h" + +int net_init_dump(QemuOpts *opts, Monitor *mon, + const char *name, VLANState *vlan); + +#endif /* QEMU_NET_DUMP_H */ -- cgit v1.2.3-65-gdbad From 1df49e0472f7577764b8472a99ee793825a1886a Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:48:58 +0000 Subject: net: clean up includes in net.c This is probably a little drastic, but the includes in this file are now totally out of control when compared with what includes are actually needed. This may break the build on e.g. *BSD, but it will be easily fixed by re-instating an include. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net.c | 73 +++---------------------------------------------------------------- 1 file changed, 3 insertions(+), 70 deletions(-) diff --git a/net.c b/net.c index 5f225fde7..599e5b051 100644 --- a/net.c +++ b/net.c @@ -21,73 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include - -/* Needed early for CONFIG_BSD etc. */ -#include "config-host.h" - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_BSD -#include -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#include -#else -#include -#endif -#ifdef __linux__ -#include -#include -#include - -/* For the benefit of older linux systems which don't supply it, - we use a local copy of hpet.h. */ -/* #include */ -#include "hpet.h" - -#include -#include -#endif -#ifdef __sun__ -#include -#include -#include -#include -#include -#include -#include -#include // must come after ip.h -#include -#include -#include -#include -#include -#endif -#endif -#endif +#include "net.h" -#if defined(__OpenBSD__) -#include -#endif +#include "config-host.h" -#include "qemu-common.h" -#include "net.h" #include "net/tap.h" #include "net/socket.h" #include "net/dump.h" @@ -95,12 +32,8 @@ #include "net/vde.h" #include "monitor.h" #include "sysemu.h" -#include "qemu-timer.h" -#include "qemu-char.h" -#include "audio/audio.h" +#include "qemu-common.h" #include "qemu_socket.h" -#include "qemu-log.h" -#include "qemu-config.h" static QTAILQ_HEAD(, VLANState) vlans; static QTAILQ_HEAD(, VLANClientState) non_vlan_clients; -- cgit v1.2.3-65-gdbad From e13b10be5ce0333f857b627e112230a547911369 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:48:59 +0000 Subject: net: remove NICInfo::vc Since 1cc33683, this field is not set for most devices, so just remove it and its remaining few uses. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/dp8393x.c | 10 +++++----- hw/etraxfs_eth.c | 10 +++++----- hw/mcf_fec.c | 10 +++++----- hw/mipsnet.c | 10 +++++----- hw/usb-net.c | 14 +++++++------- net.h | 1 - 6 files changed, 27 insertions(+), 28 deletions(-) diff --git a/hw/dp8393x.c b/hw/dp8393x.c index ae8b16e31..5143cc8ce 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -889,11 +889,11 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s); s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ - s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - nic_can_receive, nic_receive, NULL, NULL, - nic_cleanup, s); + s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, + nd->vlan, nd->netdev, + nd->model, nd->name, + nic_can_receive, nic_receive, NULL, NULL, + nic_cleanup, s); qemu_format_nic_info_str(s->vc, nd->macaddr); qemu_register_reset(nic_reset, s); diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index ffe708253..2cc233224 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -590,11 +590,11 @@ void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr) eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth); cpu_register_physical_memory (base, 0x5c, eth->ethregs); - eth->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - eth_can_receive, eth_receive, - NULL, NULL, eth_cleanup, eth); + eth->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, + nd->vlan, nd->netdev, + nd->model, nd->name, + eth_can_receive, eth_receive, + NULL, NULL, eth_cleanup, eth); eth->vc->opaque = eth; eth->vc->link_status_changed = eth_set_link; diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 9f0d0f4cb..8242c8a25 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -462,11 +462,11 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) mcf_fec_writefn, s); cpu_register_physical_memory(base, 0x400, s->mmio_index); - s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - mcf_fec_can_receive, mcf_fec_receive, - NULL, NULL, mcf_fec_cleanup, s); + s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, + nd->vlan, nd->netdev, + nd->model, nd->name, + mcf_fec_can_receive, mcf_fec_receive, + NULL, NULL, mcf_fec_cleanup, s); memcpy(s->macaddr, nd->macaddr, 6); qemu_format_nic_info_str(s->vc, s->macaddr); } diff --git a/hw/mipsnet.c b/hw/mipsnet.c index 65e1d5960..67160a432 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -263,11 +263,11 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) s->io_base = base; s->irq = irq; if (nd) { - s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - mipsnet_can_receive, mipsnet_receive, - NULL, NULL, mipsnet_cleanup, s); + s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, + nd->vlan, nd->netdev, + nd->model, nd->name, + mipsnet_can_receive, mipsnet_receive, + NULL, NULL, mipsnet_cleanup, s); } else { s->vc = NULL; } diff --git a/hw/usb-net.c b/hw/usb-net.c index 9c6549c75..7b8cc7ad1 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1460,13 +1460,13 @@ USBDevice *usb_net_init(NICInfo *nd) memcpy(s->mac, nd->macaddr, 6); - s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - usbnet_can_receive, - usbnet_receive, - NULL, NULL, - usbnet_cleanup, s); + s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, + nd->vlan, nd->netdev, + nd->model, nd->name, + usbnet_can_receive, + usbnet_receive, + NULL, NULL, + usbnet_cleanup, s); qemu_format_nic_info_str(s->vc, s->mac); diff --git a/net.h b/net.h index 42ac42dfd..bc8392b9a 100644 --- a/net.h +++ b/net.h @@ -124,7 +124,6 @@ struct NICInfo { char *devaddr; VLANState *vlan; VLANClientState *netdev; - VLANClientState *vc; void *private; int used; int bootable; -- cgit v1.2.3-65-gdbad From b50a3a21cac08ada88921eb5d2d330197c31a890 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:00 +0000 Subject: net: remove NICInfo::private Was used by hot-unplug, but not anymore. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net.h | 1 - 1 file changed, 1 deletion(-) diff --git a/net.h b/net.h index bc8392b9a..9ffcfe385 100644 --- a/net.h +++ b/net.h @@ -124,7 +124,6 @@ struct NICInfo { char *devaddr; VLANState *vlan; VLANClientState *netdev; - void *private; int used; int bootable; int nvectors; -- cgit v1.2.3-65-gdbad From 3ed79cc949369c7310217dfd05bc45351436fc71 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:01 +0000 Subject: net: introduce NetClientInfo This structure holds data which is common to all instances of a given net client type/model. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net.h b/net.h index 9ffcfe385..56c584944 100644 --- a/net.h +++ b/net.h @@ -42,6 +42,17 @@ typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int); typedef void (NetCleanup) (VLANClientState *); typedef void (LinkStatusChanged)(VLANClientState *); +typedef struct NetClientInfo { + net_client_type type; + size_t size; + NetReceive *receive; + NetReceive *receive_raw; + NetReceiveIOV *receive_iov; + NetCanReceive *can_receive; + NetCleanup *cleanup; + LinkStatusChanged *link_status_changed; +} NetClientInfo; + struct VLANClientState { net_client_type type; NetReceive *receive; -- cgit v1.2.3-65-gdbad From 45460d1a53d202550945e2b144af8ebb1d62bed0 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:02 +0000 Subject: net: introduce qemu_new_net_client() A replacement for qemu_new_vlan_client(), using NetClientInfo to replace most arguments. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++-------------------- net.h | 5 +++++ 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/net.c b/net.c index 599e5b051..355eb874a 100644 --- a/net.c +++ b/net.c @@ -248,34 +248,31 @@ static ssize_t qemu_deliver_packet_iov(VLANClientState *sender, int iovcnt, void *opaque); -VLANClientState *qemu_new_vlan_client(net_client_type type, - VLANState *vlan, - VLANClientState *peer, - const char *model, - const char *name, - NetCanReceive *can_receive, - NetReceive *receive, - NetReceive *receive_raw, - NetReceiveIOV *receive_iov, - NetCleanup *cleanup, - void *opaque) +VLANClientState *qemu_new_net_client(NetClientInfo *info, + VLANState *vlan, + VLANClientState *peer, + const char *model, + const char *name) { VLANClientState *vc; - vc = qemu_mallocz(sizeof(VLANClientState)); + assert(info->size >= sizeof(VLANClientState)); + + vc = qemu_mallocz(info->size); - vc->type = type; + vc->type = info->type; vc->model = qemu_strdup(model); - if (name) + if (name) { vc->name = qemu_strdup(name); - else + } else { vc->name = assign_name(vc, model); - vc->can_receive = can_receive; - vc->receive = receive; - vc->receive_raw = receive_raw; - vc->receive_iov = receive_iov; - vc->cleanup = cleanup; - vc->opaque = opaque; + } + vc->can_receive = info->can_receive; + vc->receive = info->receive; + vc->receive_raw = info->receive_raw; + vc->receive_iov = info->receive_iov; + vc->cleanup = info->cleanup; + vc->link_status_changed = info->link_status_changed; if (vlan) { assert(!peer); @@ -296,6 +293,37 @@ VLANClientState *qemu_new_vlan_client(net_client_type type, return vc; } +VLANClientState *qemu_new_vlan_client(net_client_type type, + VLANState *vlan, + VLANClientState *peer, + const char *model, + const char *name, + NetCanReceive *can_receive, + NetReceive *receive, + NetReceive *receive_raw, + NetReceiveIOV *receive_iov, + NetCleanup *cleanup, + void *opaque) +{ + VLANClientState *ret; + NetClientInfo info; + + info.type = type; + info.size = sizeof(VLANClientState); + info.can_receive = can_receive; + info.receive = receive; + info.receive_raw = receive_raw; + info.receive_iov = receive_iov; + info.cleanup = cleanup; + info.link_status_changed = NULL; + + ret = qemu_new_net_client(&info, vlan, peer, model, name); + + ret->opaque = opaque; + + return ret; +} + void qemu_del_vlan_client(VLANClientState *vc) { if (vc->vlan) { diff --git a/net.h b/net.h index 56c584944..71a9a443e 100644 --- a/net.h +++ b/net.h @@ -85,6 +85,11 @@ struct VLANState { VLANState *qemu_find_vlan(int id, int allocate); VLANClientState *qemu_find_netdev(const char *id); +VLANClientState *qemu_new_net_client(NetClientInfo *info, + VLANState *vlan, + VLANClientState *peer, + const char *model, + const char *name); VLANClientState *qemu_new_vlan_client(net_client_type type, VLANState *vlan, VLANClientState *peer, -- cgit v1.2.3-65-gdbad From 5096fae3fdabc889545ecae508e3dbd0579fcbc9 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:03 +0000 Subject: qdev: move DO_UPCAST() into osdep.h Nothing qdev specific about this, make it available throughtout. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/qdev.h | 10 ---------- osdep.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/qdev.h b/hw/qdev.h index 41642ee8a..8d53754d4 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -154,16 +154,6 @@ CharDriverState *qdev_init_chardev(DeviceState *dev); BusState *qdev_get_parent_bus(DeviceState *dev); -/* Convert from a base type to a parent type, with compile time checking. */ -#ifdef __GNUC__ -#define DO_UPCAST(type, field, dev) ( __extension__ ( { \ - char __attribute__((unused)) offset_must_be_zero[ \ - -offsetof(type, field)]; \ - container_of(dev, type, field);})) -#else -#define DO_UPCAST(type, field, dev) container_of(dev, type, field) -#endif - /*** BUS API. ***/ void qbus_create_inplace(BusState *bus, BusInfo *info, diff --git a/osdep.h b/osdep.h index 4b4aad4d4..75b581630 100644 --- a/osdep.h +++ b/osdep.h @@ -37,6 +37,16 @@ (type *) ((char *) __mptr - offsetof(type, member));}) #endif +/* Convert from a base type to a parent type, with compile time checking. */ +#ifdef __GNUC__ +#define DO_UPCAST(type, field, dev) ( __extension__ ( { \ + char __attribute__((unused)) offset_must_be_zero[ \ + -offsetof(type, field)]; \ + container_of(dev, type, field);})) +#else +#define DO_UPCAST(type, field, dev) container_of(dev, type, field) +#endif + #define typeof_field(type, field) typeof(((type *)0)->field) #define type_check(t1,t2) ((t1*)0 - (t2*)0) -- cgit v1.2.3-65-gdbad From 3e35ba93ec4c2fd19352737949e8105c06f775e6 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:04 +0000 Subject: net: convert tap to NetClientInfo Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/tap.c | 82 +++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/net/tap.c b/net/tap.c index b2e5908c3..d34feecd7 100644 --- a/net/tap.c +++ b/net/tap.c @@ -47,7 +47,7 @@ #define TAP_BUFSIZE (4096 + 65536) typedef struct TAPState { - VLANClientState *vc; + VLANClientState nc; int fd; char down_script[1024]; char down_script_arg[128]; @@ -92,7 +92,7 @@ static void tap_writable(void *opaque) tap_write_poll(s, 0); - qemu_flush_queued_packets(s->vc); + qemu_flush_queued_packets(&s->nc); } static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt) @@ -111,10 +111,10 @@ static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt return len; } -static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov, +static ssize_t tap_receive_iov(VLANClientState *nc, const struct iovec *iov, int iovcnt) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); const struct iovec *iovp = iov; struct iovec iov_copy[iovcnt + 1]; struct virtio_net_hdr hdr = { 0, }; @@ -130,9 +130,9 @@ static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov, return tap_write_packet(s, iovp, iovcnt); } -static ssize_t tap_receive_raw(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t tap_receive_raw(VLANClientState *nc, const uint8_t *buf, size_t size) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); struct iovec iov[2]; int iovcnt = 0; struct virtio_net_hdr hdr = { 0, }; @@ -150,13 +150,13 @@ static ssize_t tap_receive_raw(VLANClientState *vc, const uint8_t *buf, size_t s return tap_write_packet(s, iov, iovcnt); } -static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t tap_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); struct iovec iov[1]; if (s->has_vnet_hdr && !s->using_vnet_hdr) { - return tap_receive_raw(vc, buf, size); + return tap_receive_raw(nc, buf, size); } iov[0].iov_base = (char *)buf; @@ -169,7 +169,7 @@ static int tap_can_send(void *opaque) { TAPState *s = opaque; - return qemu_can_send_packet(s->vc); + return qemu_can_send_packet(&s->nc); } #ifndef __sun__ @@ -179,9 +179,9 @@ ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) } #endif -static void tap_send_completed(VLANClientState *vc, ssize_t len) +static void tap_send_completed(VLANClientState *nc, ssize_t len) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); tap_read_poll(s, 1); } @@ -203,56 +203,56 @@ static void tap_send(void *opaque) size -= sizeof(struct virtio_net_hdr); } - size = qemu_send_packet_async(s->vc, buf, size, tap_send_completed); + size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed); if (size == 0) { tap_read_poll(s, 0); } - } while (size > 0 && qemu_can_send_packet(s->vc)); + } while (size > 0 && qemu_can_send_packet(&s->nc)); } -int tap_has_ufo(VLANClientState *vc) +int tap_has_ufo(VLANClientState *nc) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(vc->type == NET_CLIENT_TYPE_TAP); + assert(nc->type == NET_CLIENT_TYPE_TAP); return s->has_ufo; } -int tap_has_vnet_hdr(VLANClientState *vc) +int tap_has_vnet_hdr(VLANClientState *nc) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(vc->type == NET_CLIENT_TYPE_TAP); + assert(nc->type == NET_CLIENT_TYPE_TAP); return s->has_vnet_hdr; } -void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr) +void tap_using_vnet_hdr(VLANClientState *nc, int using_vnet_hdr) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); using_vnet_hdr = using_vnet_hdr != 0; - assert(vc->type == NET_CLIENT_TYPE_TAP); + assert(nc->type == NET_CLIENT_TYPE_TAP); assert(s->has_vnet_hdr == using_vnet_hdr); s->using_vnet_hdr = using_vnet_hdr; } -void tap_set_offload(VLANClientState *vc, int csum, int tso4, +void tap_set_offload(VLANClientState *nc, int csum, int tso4, int tso6, int ecn, int ufo) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); return tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo); } -static void tap_cleanup(VLANClientState *vc) +static void tap_cleanup(VLANClientState *nc) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); - qemu_purge_queued_packets(vc); + qemu_purge_queued_packets(nc); if (s->down_script[0]) launch_script(s->down_script, s->down_script_arg, s->fd); @@ -260,29 +260,37 @@ static void tap_cleanup(VLANClientState *vc) tap_read_poll(s, 0); tap_write_poll(s, 0); close(s->fd); - qemu_free(s); } /* fd support */ +static NetClientInfo net_tap_info = { + .type = NET_CLIENT_TYPE_TAP, + .size = sizeof(TAPState), + .receive = tap_receive, + .receive_raw = tap_receive_raw, + .receive_iov = tap_receive_iov, + .cleanup = tap_cleanup, +}; + static TAPState *net_tap_fd_init(VLANState *vlan, const char *model, const char *name, int fd, int vnet_hdr) { + VLANClientState *nc; TAPState *s; - s = qemu_mallocz(sizeof(TAPState)); + nc = qemu_new_net_client(&net_tap_info, vlan, NULL, model, name); + + s = DO_UPCAST(TAPState, nc, nc); + s->fd = fd; s->has_vnet_hdr = vnet_hdr != 0; s->using_vnet_hdr = 0; - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP, - vlan, NULL, model, name, NULL, - tap_receive, tap_receive_raw, - tap_receive_iov, tap_cleanup, s); s->has_ufo = tap_probe_has_ufo(s->fd); - tap_set_offload(s->vc, 0, 0, 0, 0, 0); + tap_set_offload(&s->nc, 0, 0, 0, 0, 0); tap_read_poll(s, 1); return s; } @@ -415,7 +423,7 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan } if (qemu_opt_get(opts, "fd")) { - snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd); + snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); } else { const char *ifname, *script, *downscript; @@ -423,7 +431,7 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan script = qemu_opt_get(opts, "script"); downscript = qemu_opt_get(opts, "downscript"); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), + snprintf(s->nc.info_str, sizeof(s->nc.info_str), "ifname=%s,script=%s,downscript=%s", ifname, script, downscript); -- cgit v1.2.3-65-gdbad From dca91811bccf31468b3c719aef0a876194af472e Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:05 +0000 Subject: net: convert tap-win32 to NetClientInfo Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/tap-win32.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/net/tap-win32.c b/net/tap-win32.c index ea6647192..ef6378295 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -630,25 +630,24 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, /********************************************/ typedef struct TAPState { - VLANClientState *vc; + VLANClientState nc; tap_win32_overlapped_t *handle; } TAPState; -static void tap_cleanup(VLANClientState *vc) +static void tap_cleanup(VLANClientState *nc) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL); /* FIXME: need to kill thread and close file handle: tap_win32_close(s); */ - qemu_free(s); } -static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t tap_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - TAPState *s = vc->opaque; + TAPState *s = DO_UPCAST(TAPState, nc, nc); return tap_win32_write(s->handle, buf, size); } @@ -662,33 +661,41 @@ static void tap_win32_send(void *opaque) size = tap_win32_read(s->handle, &buf, max_size); if (size > 0) { - qemu_send_packet(s->vc, buf, size); + qemu_send_packet(&s->nc, buf, size); tap_win32_free_buffer(s->handle, buf); } } +static NetClientInfo net_tap_win32_info = { + .type = NET_CLIENT_TYPE_TAP, + .size = sizeof(TAPState), + .receive = tap_receive, + .cleanup = tap_cleanup, +}; + static int tap_win32_init(VLANState *vlan, const char *model, const char *name, const char *ifname) { + VLANClientState *nc; TAPState *s; + tap_win32_overlapped_t *handle; - s = qemu_mallocz(sizeof(TAPState)); - if (!s) - return -1; - if (tap_win32_open(&s->handle, ifname) < 0) { + if (tap_win32_open(&handle, ifname) < 0) { printf("tap: Could not open '%s'\n", ifname); return -1; } - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP, - vlan, NULL, model, name, - NULL, tap_receive, - NULL, NULL, tap_cleanup, s); + nc = qemu_new_net_client(&net_tap_win32_info, vlan, NULL, model, name); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), + snprintf(s->nc.info_str, sizeof(s->nc.info_str), "tap: ifname=%s", ifname); + s = DO_UPCAST(TAPState, nc, nc); + + s->handle = handle; + qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s); + return 0; } -- cgit v1.2.3-65-gdbad From ce20b5be502c4f1fd986ae3d9a7ac4192da621ba Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:06 +0000 Subject: net: convert slirp to NetClientInfo Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/slirp.c | 61 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/net/slirp.c b/net/slirp.c index d6d57721d..3f91c4bb3 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -64,8 +64,8 @@ struct slirp_config_str { }; typedef struct SlirpState { + VLANClientState nc; QTAILQ_ENTRY(SlirpState) entry; - VLANClientState *vc; Slirp *slirp; #ifndef _WIN32 char smb_dir[128]; @@ -97,35 +97,41 @@ int slirp_can_output(void *opaque) { SlirpState *s = opaque; - return qemu_can_send_packet(s->vc); + return qemu_can_send_packet(&s->nc); } void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len) { SlirpState *s = opaque; - qemu_send_packet(s->vc, pkt, pkt_len); + qemu_send_packet(&s->nc, pkt, pkt_len); } -static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t net_slirp_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - SlirpState *s = vc->opaque; + SlirpState *s = DO_UPCAST(SlirpState, nc, nc); slirp_input(s->slirp, buf, size); return size; } -static void net_slirp_cleanup(VLANClientState *vc) +static void net_slirp_cleanup(VLANClientState *nc) { - SlirpState *s = vc->opaque; + SlirpState *s = DO_UPCAST(SlirpState, nc, nc); slirp_cleanup(s->slirp); slirp_smb_cleanup(s); QTAILQ_REMOVE(&slirp_stacks, s, entry); - qemu_free(s); } +static NetClientInfo net_slirp_info = { + .type = NET_CLIENT_TYPE_SLIRP, + .size = sizeof(SlirpState), + .receive = net_slirp_receive, + .cleanup = net_slirp_cleanup, +}; + static int net_slirp_init(VLANState *vlan, const char *model, const char *name, int restricted, const char *vnetwork, const char *vhost, @@ -143,6 +149,7 @@ static int net_slirp_init(VLANState *vlan, const char *model, #ifndef _WIN32 struct in_addr smbsrv = { .s_addr = 0 }; #endif + VLANClientState *nc; SlirpState *s; char buf[20]; uint32_t addr; @@ -228,7 +235,13 @@ static int net_slirp_init(VLANState *vlan, const char *model, } #endif - s = qemu_mallocz(sizeof(SlirpState)); + nc = qemu_new_net_client(&net_slirp_info, vlan, NULL, model, name); + + snprintf(nc->info_str, sizeof(nc->info_str), + "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n'); + + s = DO_UPCAST(SlirpState, nc, nc); + s->slirp = slirp_init(restricted, net, mask, host, vhostname, tftp_export, bootfile, dhcp, dns, s); QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); @@ -237,11 +250,11 @@ static int net_slirp_init(VLANState *vlan, const char *model, if (config->flags & SLIRP_CFG_HOSTFWD) { if (slirp_hostfwd(s, config->str, config->flags & SLIRP_CFG_LEGACY) < 0) - return -1; + goto error; } else { if (slirp_guestfwd(s, config->str, config->flags & SLIRP_CFG_LEGACY) < 0) - return -1; + goto error; } } #ifndef _WIN32 @@ -250,34 +263,32 @@ static int net_slirp_init(VLANState *vlan, const char *model, } if (smb_export) { if (slirp_smb(s, smb_export, smbsrv) < 0) - return -1; + goto error; } #endif - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SLIRP, - vlan, NULL, model, name, NULL, - slirp_receive, NULL, NULL, - net_slirp_cleanup, s); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n'); return 0; + +error: + qemu_del_vlan_client(nc); + return -1; } static SlirpState *slirp_lookup(Monitor *mon, const char *vlan, const char *stack) { - VLANClientState *vc; if (vlan) { - vc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack); - if (!vc) { + VLANClientState *nc; + nc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack); + if (!nc) { return NULL; } - if (strcmp(vc->model, "user")) { + if (strcmp(nc->model, "user")) { monitor_printf(mon, "invalid device specified\n"); return NULL; } - return vc->opaque; + return DO_UPCAST(SlirpState, nc, nc); } else { if (QTAILQ_EMPTY(&slirp_stacks)) { monitor_printf(mon, "user mode network stack not in use\n"); @@ -626,7 +637,9 @@ void do_info_usernet(Monitor *mon) SlirpState *s; QTAILQ_FOREACH(s, &slirp_stacks, entry) { - monitor_printf(mon, "VLAN %d (%s):\n", s->vc->vlan->id, s->vc->name); + monitor_printf(mon, "VLAN %d (%s):\n", + s->nc.vlan ? s->nc.vlan->id : -1, + s->nc.name); slirp_connection_info(s->slirp, mon); } } -- cgit v1.2.3-65-gdbad From b4e859c6a19c8caee4839d46d5f9167759ddb785 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:07 +0000 Subject: net: convert vde to NetClientInfo Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/vde.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/net/vde.c b/net/vde.c index 4d09967fd..42b463350 100644 --- a/net/vde.c +++ b/net/vde.c @@ -34,7 +34,7 @@ #include "sysemu.h" typedef struct VDEState { - VLANClientState *vc; + VLANClientState nc; VDECONN *vde; } VDEState; @@ -46,13 +46,13 @@ static void vde_to_qemu(void *opaque) size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0); if (size > 0) { - qemu_send_packet(s->vc, buf, size); + qemu_send_packet(&s->nc, buf, size); } } -static ssize_t vde_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t vde_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - VDEState *s = vc->opaque; + VDEState *s = DO_UPCAST(VDEState, nc, nc); ssize_t ret; do { @@ -62,19 +62,27 @@ static ssize_t vde_receive(VLANClientState *vc, const uint8_t *buf, size_t size) return ret; } -static void vde_cleanup(VLANClientState *vc) +static void vde_cleanup(VLANClientState *nc) { - VDEState *s = vc->opaque; + VDEState *s = DO_UPCAST(VDEState, nc, nc); qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL); vde_close(s->vde); - qemu_free(s); } +static NetClientInfo net_vde_info = { + .type = NET_CLIENT_TYPE_VDE, + .size = sizeof(VDEState), + .receive = vde_receive, + .cleanup = vde_cleanup, +}; + static int net_vde_init(VLANState *vlan, const char *model, const char *name, const char *sock, int port, const char *group, int mode) { + VLANClientState *nc; VDEState *s; + VDECONN *vde; char *init_group = (char *)group; char *init_sock = (char *)sock; @@ -84,19 +92,22 @@ static int net_vde_init(VLANState *vlan, const char *model, .mode = mode, }; - s = qemu_mallocz(sizeof(VDEState)); - s->vde = vde_open(init_sock, (char *)"QEMU", &args); - if (!s->vde){ - free(s); + vde = vde_open(init_sock, (char *)"QEMU", &args); + if (!vde){ return -1; } - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_VDE, - vlan, NULL, model, name, NULL, - vde_receive, NULL, NULL, - vde_cleanup, s); + + nc = qemu_new_net_client(&net_vde_info, vlan, NULL, model, name); + + snprintf(nc->info_str, sizeof(nc->info_str), "sock=%s,fd=%d", + sock, vde_datafd(vde)); + + s = DO_UPCAST(VDEState, nc, nc); + + s->vde = vde; + qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", - sock, vde_datafd(s->vde)); + return 0; } -- cgit v1.2.3-65-gdbad From 564f63e3fc7b8d6af9dd91c2275bc4cfc07c0e2c Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:08 +0000 Subject: net: convert socket to NetClientInfo Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/socket.c | 74 ++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/net/socket.c b/net/socket.c index 551fc2b9e..7331d87c6 100644 --- a/net/socket.c +++ b/net/socket.c @@ -33,7 +33,7 @@ #include "sysemu.h" typedef struct NetSocketState { - VLANClientState *vc; + VLANClientState nc; int fd; int state; /* 0 = getting length, 1 = getting data */ unsigned int index; @@ -50,9 +50,9 @@ typedef struct NetSocketListenState { } NetSocketListenState; /* XXX: we consider we can send the whole packet without blocking */ -static ssize_t net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - NetSocketState *s = vc->opaque; + NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); uint32_t len; len = htonl(size); @@ -60,9 +60,9 @@ static ssize_t net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_ return send_all(s->fd, buf, size); } -static ssize_t net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size) { - NetSocketState *s = vc->opaque; + NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); return sendto(s->fd, (const void *)buf, size, 0, (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); @@ -124,7 +124,7 @@ static void net_socket_send(void *opaque) buf += l; size -= l; if (s->index >= s->packet_len) { - qemu_send_packet(s->vc, s->buf, s->packet_len); + qemu_send_packet(&s->nc, s->buf, s->packet_len); s->index = 0; s->state = 0; } @@ -146,7 +146,7 @@ static void net_socket_send_dgram(void *opaque) qemu_set_fd_handler(s->fd, NULL, NULL, NULL); return; } - qemu_send_packet(s->vc, s->buf, size); + qemu_send_packet(&s->nc, s->buf, size); } static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) @@ -209,14 +209,20 @@ fail: return -1; } -static void net_socket_cleanup(VLANClientState *vc) +static void net_socket_cleanup(VLANClientState *nc) { - NetSocketState *s = vc->opaque; + NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); qemu_set_fd_handler(s->fd, NULL, NULL, NULL); close(s->fd); - qemu_free(s); } +static NetClientInfo net_dgram_socket_info = { + .type = NET_CLIENT_TYPE_SOCKET, + .size = sizeof(NetSocketState), + .receive = net_socket_receive_dgram, + .cleanup = net_socket_cleanup, +}; + static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, const char *model, const char *name, @@ -225,6 +231,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, struct sockaddr_in saddr; int newfd; socklen_t saddr_len; + VLANClientState *nc; NetSocketState *s; /* fd passed: multicast: "learn" dgram_dst address from bound address and save it @@ -258,22 +265,22 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, } } - s = qemu_mallocz(sizeof(NetSocketState)); + nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name); + + snprintf(nc->info_str, sizeof(nc->info_str), + "socket: fd=%d (%s mcast=%s:%d)", + fd, is_connected ? "cloned" : "", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + + s = DO_UPCAST(NetSocketState, nc, nc); + s->fd = fd; - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET, - vlan, NULL, model, name, NULL, - net_socket_receive_dgram, NULL, NULL, - net_socket_cleanup, s); qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); /* mcast: save bound address as dst */ if (is_connected) s->dgram_dst=saddr; - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: fd=%d (%s mcast=%s:%d)", - fd, is_connected? "cloned" : "", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return s; } @@ -283,20 +290,29 @@ static void net_socket_connect(void *opaque) qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); } +static NetClientInfo net_socket_info = { + .type = NET_CLIENT_TYPE_SOCKET, + .size = sizeof(NetSocketState), + .receive = net_socket_receive, + .cleanup = net_socket_cleanup, +}; + static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, const char *model, const char *name, int fd, int is_connected) { + VLANClientState *nc; NetSocketState *s; - s = qemu_mallocz(sizeof(NetSocketState)); + + nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name); + + snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd); + + s = DO_UPCAST(NetSocketState, nc, nc); + s->fd = fd; - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET, - vlan, NULL, model, name, NULL, - net_socket_receive, NULL, NULL, - net_socket_cleanup, s); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: fd=%d", fd); + if (is_connected) { net_socket_connect(s); } else { @@ -350,7 +366,7 @@ static void net_socket_accept(void *opaque) if (!s1) { closesocket(fd); } else { - snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), + snprintf(s1->nc.info_str, sizeof(s1->nc.info_str), "socket: connection from %s:%d", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); } @@ -443,7 +459,7 @@ static int net_socket_connect_init(VLANState *vlan, s = net_socket_fd_init(vlan, model, name, fd, connected); if (!s) return -1; - snprintf(s->vc->info_str, sizeof(s->vc->info_str), + snprintf(s->nc.info_str, sizeof(s->nc.info_str), "socket: connect to %s:%d", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; @@ -472,7 +488,7 @@ static int net_socket_mcast_init(VLANState *vlan, s->dgram_dst = saddr; - snprintf(s->vc->info_str, sizeof(s->vc->info_str), + snprintf(s->nc.info_str, sizeof(s->nc.info_str), "socket: mcast=%s:%d", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; -- cgit v1.2.3-65-gdbad From 731d5856cbb9c160fe02b90cd3cf354ea4f52f34 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:09 +0000 Subject: net: convert dump to NetClientInfo aliguori: fix uninitialized use of pcap_len Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/dump.c | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/net/dump.c b/net/dump.c index 05a102be0..d50b4eeac 100644 --- a/net/dump.c +++ b/net/dump.c @@ -28,7 +28,7 @@ #include "qemu-log.h" typedef struct DumpState { - VLANClientState *pcap_vc; + VLANClientState nc; int fd; int pcap_caplen; } DumpState; @@ -54,9 +54,9 @@ struct pcap_sf_pkthdr { uint32_t len; }; -static ssize_t dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t dump_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - DumpState *s = vc->opaque; + DumpState *s = DO_UPCAST(DumpState, nc, nc); struct pcap_sf_pkthdr hdr; int64_t ts; int caplen; @@ -83,51 +83,58 @@ static ssize_t dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size return size; } -static void net_dump_cleanup(VLANClientState *vc) +static void dump_cleanup(VLANClientState *nc) { - DumpState *s = vc->opaque; + DumpState *s = DO_UPCAST(DumpState, nc, nc); close(s->fd); - qemu_free(s); } +static NetClientInfo net_dump_info = { + .type = NET_CLIENT_TYPE_DUMP, + .size = sizeof(DumpState), + .receive = dump_receive, + .cleanup = dump_cleanup, +}; + static int net_dump_init(VLANState *vlan, const char *device, const char *name, const char *filename, int len) { struct pcap_file_hdr hdr; + VLANClientState *nc; DumpState *s; + int fd; - s = qemu_malloc(sizeof(DumpState)); - - s->fd = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644); - if (s->fd < 0) { + fd = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644); + if (fd < 0) { qemu_error("-net dump: can't open %s\n", filename); return -1; } - s->pcap_caplen = len; - hdr.magic = PCAP_MAGIC; hdr.version_major = 2; hdr.version_minor = 4; hdr.thiszone = 0; hdr.sigfigs = 0; - hdr.snaplen = s->pcap_caplen; + hdr.snaplen = len; hdr.linktype = 1; - if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { + if (write(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { qemu_error("-net dump write error: %s\n", strerror(errno)); - close(s->fd); - qemu_free(s); + close(fd); return -1; } - s->pcap_vc = qemu_new_vlan_client(NET_CLIENT_TYPE_DUMP, - vlan, NULL, device, name, NULL, - dump_receive, NULL, NULL, - net_dump_cleanup, s); - snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str), + nc = qemu_new_net_client(&net_dump_info, vlan, NULL, device, name); + + snprintf(nc->info_str, sizeof(nc->info_str), "dump to %s (len=%d)", filename, len); + + s = DO_UPCAST(DumpState, nc, nc); + + s->fd = fd; + s->pcap_caplen = len; + return 0; } -- cgit v1.2.3-65-gdbad From ebef2c093e47103464cd459d811803692c7315e6 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:10 +0000 Subject: net: introduce NICState and qemu_new_nic() Common state for all NICs. The opaque member will replace the opaque member in VLANClientState since only NICs need it. The conf member will allow us to iterate over NICs, access the MAC addr for the NIC and send a packet from each NIC in qemu_announce_self(). Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net.c | 21 +++++++++++++++++++++ net.h | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/net.c b/net.c index 355eb874a..7195827cc 100644 --- a/net.c +++ b/net.c @@ -293,6 +293,27 @@ VLANClientState *qemu_new_net_client(NetClientInfo *info, return vc; } +NICState *qemu_new_nic(NetClientInfo *info, + NICConf *conf, + const char *model, + const char *name, + void *opaque) +{ + VLANClientState *nc; + NICState *nic; + + assert(info->type == NET_CLIENT_TYPE_NIC); + assert(info->size >= sizeof(NICState)); + + nc = qemu_new_net_client(info, conf->vlan, conf->peer, model, name); + + nic = DO_UPCAST(NICState, nc, nc); + nic->conf = conf; + nic->opaque = opaque; + + return nic; +} + VLANClientState *qemu_new_vlan_client(net_client_type type, VLANState *vlan, VLANClientState *peer, diff --git a/net.h b/net.h index 71a9a443e..4de20de35 100644 --- a/net.h +++ b/net.h @@ -75,6 +75,12 @@ struct VLANClientState { unsigned receive_disabled : 1; }; +typedef struct NICState { + VLANClientState nc; + NICConf *conf; + void *opaque; +} NICState; + struct VLANState { int id; QTAILQ_HEAD(, VLANClientState) clients; @@ -90,6 +96,11 @@ VLANClientState *qemu_new_net_client(NetClientInfo *info, VLANClientState *peer, const char *model, const char *name); +NICState *qemu_new_nic(NetClientInfo *info, + NICConf *conf, + const char *model, + const char *name, + void *opaque); VLANClientState *qemu_new_vlan_client(net_client_type type, VLANState *vlan, VLANClientState *peer, -- cgit v1.2.3-65-gdbad From eb6b6c121add5f708a920a68361099a8fa1ac45c Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:11 +0000 Subject: net: convert virtio to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/virtio-net.c | 73 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 2f147e522..4f8d89e25 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -31,7 +31,7 @@ typedef struct VirtIONet VirtQueue *rx_vq; VirtQueue *tx_vq; VirtQueue *ctrl_vq; - VLANClientState *vc; + NICState *nic; QEMUTimer *tx_timer; int tx_timer_active; uint32_t has_vnet_hdr; @@ -85,16 +85,16 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) if (memcmp(netcfg.mac, n->mac, ETH_ALEN)) { memcpy(n->mac, netcfg.mac, ETH_ALEN); - qemu_format_nic_info_str(n->vc, n->mac); + qemu_format_nic_info_str(&n->nic->nc, n->mac); } } -static void virtio_net_set_link_status(VLANClientState *vc) +static void virtio_net_set_link_status(VLANClientState *nc) { - VirtIONet *n = vc->opaque; + VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; uint16_t old_status = n->status; - if (vc->link_down) + if (nc->link_down) n->status &= ~VIRTIO_NET_S_LINK_UP; else n->status |= VIRTIO_NET_S_LINK_UP; @@ -126,13 +126,13 @@ static void virtio_net_reset(VirtIODevice *vdev) static int peer_has_vnet_hdr(VirtIONet *n) { - if (!n->vc->peer) + if (!n->nic->nc.peer) return 0; - if (n->vc->peer->type != NET_CLIENT_TYPE_TAP) + if (n->nic->nc.peer->type != NET_CLIENT_TYPE_TAP) return 0; - n->has_vnet_hdr = tap_has_vnet_hdr(n->vc->peer); + n->has_vnet_hdr = tap_has_vnet_hdr(n->nic->nc.peer); return n->has_vnet_hdr; } @@ -142,7 +142,7 @@ static int peer_has_ufo(VirtIONet *n) if (!peer_has_vnet_hdr(n)) return 0; - n->has_ufo = tap_has_ufo(n->vc->peer); + n->has_ufo = tap_has_ufo(n->nic->nc.peer); return n->has_ufo; } @@ -159,7 +159,7 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev) (1 << VIRTIO_NET_F_CTRL_RX_EXTRA); if (peer_has_vnet_hdr(n)) { - tap_using_vnet_hdr(n->vc->peer, 1); + tap_using_vnet_hdr(n->nic->nc.peer, 1); features |= (1 << VIRTIO_NET_F_CSUM); features |= (1 << VIRTIO_NET_F_HOST_TSO4); @@ -202,7 +202,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF)); if (n->has_vnet_hdr) { - tap_set_offload(n->vc->peer, + tap_set_offload(n->nic->nc.peer, (features >> VIRTIO_NET_F_GUEST_CSUM) & 1, (features >> VIRTIO_NET_F_GUEST_TSO4) & 1, (features >> VIRTIO_NET_F_GUEST_TSO6) & 1, @@ -360,16 +360,16 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = to_virtio_net(vdev); - qemu_flush_queued_packets(n->vc); + qemu_flush_queued_packets(&n->nic->nc); /* We now have RX buffers, signal to the IO thread to break out of the * select to re-poll the tap file descriptor */ qemu_notify_event(); } -static int virtio_net_can_receive(VLANClientState *vc) +static int virtio_net_can_receive(VLANClientState *nc) { - VirtIONet *n = vc->opaque; + VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; if (!virtio_queue_ready(n->rx_vq) || !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) @@ -511,13 +511,13 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } -static ssize_t virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - VirtIONet *n = vc->opaque; + VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL; size_t hdr_len, offset, i; - if (!virtio_net_can_receive(n->vc)) + if (!virtio_net_can_receive(&n->nic->nc)) return -1; if (!virtio_net_has_buffers(n, size)) @@ -590,9 +590,9 @@ static ssize_t virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_ static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq); -static void virtio_net_tx_complete(VLANClientState *vc, ssize_t len) +static void virtio_net_tx_complete(VLANClientState *nc, ssize_t len) { - VirtIONet *n = vc->opaque; + VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; virtqueue_push(n->tx_vq, &n->async_tx.elem, n->async_tx.len); virtio_notify(&n->vdev, n->tx_vq); @@ -644,7 +644,7 @@ static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) len += hdr_len; } - ret = qemu_sendv_packet_async(n->vc, out_sg, out_num, + ret = qemu_sendv_packet_async(&n->nic->nc, out_sg, out_num, virtio_net_tx_complete); if (ret == 0) { virtio_queue_set_notification(n->tx_vq, 0); @@ -766,8 +766,8 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } if (n->has_vnet_hdr) { - tap_using_vnet_hdr(n->vc->peer, 1); - tap_set_offload(n->vc->peer, + tap_using_vnet_hdr(n->nic->nc.peer, 1); + tap_set_offload(n->nic->nc.peer, (n->vdev.features >> VIRTIO_NET_F_GUEST_CSUM) & 1, (n->vdev.features >> VIRTIO_NET_F_GUEST_TSO4) & 1, (n->vdev.features >> VIRTIO_NET_F_GUEST_TSO6) & 1, @@ -811,13 +811,22 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void virtio_net_cleanup(VLANClientState *vc) +static void virtio_net_cleanup(VLANClientState *nc) { - VirtIONet *n = vc->opaque; + VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; - n->vc = NULL; + n->nic = NULL; } +static NetClientInfo net_virtio_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = virtio_net_can_receive, + .receive = virtio_net_receive, + .cleanup = virtio_net_cleanup, + .link_status_changed = virtio_net_set_link_status, +}; + VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf) { VirtIONet *n; @@ -839,14 +848,10 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf) qemu_macaddr_default_if_unset(&conf->macaddr); memcpy(&n->mac[0], &conf->macaddr, sizeof(n->mac)); n->status = VIRTIO_NET_S_LINK_UP; - n->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, conf->vlan, conf->peer, - dev->info->name, dev->id, - virtio_net_can_receive, - virtio_net_receive, NULL, NULL, - virtio_net_cleanup, n); - n->vc->link_status_changed = virtio_net_set_link_status; - qemu_format_nic_info_str(n->vc, conf->macaddr.a); + n->nic = qemu_new_nic(&net_virtio_info, conf, dev->info->name, dev->id, n); + + qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a); n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n); n->tx_timer_active = 0; @@ -867,7 +872,7 @@ void virtio_net_exit(VirtIODevice *vdev) { VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev); - qemu_purge_queued_packets(n->vc); + qemu_purge_queued_packets(&n->nic->nc); unregister_savevm("virtio-net", n); @@ -878,5 +883,5 @@ void virtio_net_exit(VirtIODevice *vdev) qemu_free_timer(n->tx_timer); virtio_cleanup(&n->vdev); - qemu_del_vlan_client(n->vc); + qemu_del_vlan_client(&n->nic->nc); } -- cgit v1.2.3-65-gdbad From a03e2aec9643981a9fc10206262b170e005d0b31 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:12 +0000 Subject: net: convert e1000 to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/e1000.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/hw/e1000.c b/hw/e1000.c index 00f6a57da..683fdccae 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -75,7 +75,7 @@ enum { typedef struct E1000State_st { PCIDevice dev; - VLANClientState *vc; + NICState *nic; NICConf conf; int mmio_index; @@ -385,9 +385,9 @@ xmit_seg(E1000State *s) if (tp->vlan_needed) { memmove(tp->vlan, tp->data, 12); memcpy(tp->data + 8, tp->vlan_header, 4); - qemu_send_packet(s->vc, tp->vlan, tp->size + 4); + qemu_send_packet(&s->nic->nc, tp->vlan, tp->size + 4); } else - qemu_send_packet(s->vc, tp->data, tp->size); + qemu_send_packet(&s->nic->nc, tp->data, tp->size); s->mac_reg[TPT]++; s->mac_reg[GPTC]++; n = s->mac_reg[TOTL]; @@ -590,12 +590,12 @@ receive_filter(E1000State *s, const uint8_t *buf, int size) } static void -e1000_set_link_status(VLANClientState *vc) +e1000_set_link_status(VLANClientState *nc) { - E1000State *s = vc->opaque; + E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque; uint32_t old_status = s->mac_reg[STATUS]; - if (vc->link_down) + if (nc->link_down) s->mac_reg[STATUS] &= ~E1000_STATUS_LU; else s->mac_reg[STATUS] |= E1000_STATUS_LU; @@ -605,17 +605,17 @@ e1000_set_link_status(VLANClientState *vc) } static int -e1000_can_receive(VLANClientState *vc) +e1000_can_receive(VLANClientState *nc) { - E1000State *s = vc->opaque; + E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque; return (s->mac_reg[RCTL] & E1000_RCTL_EN); } static ssize_t -e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - E1000State *s = vc->opaque; + E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque; struct e1000_rx_desc desc; target_phys_addr_t base; unsigned int n, rdt; @@ -1037,11 +1037,11 @@ e1000_mmio_map(PCIDevice *pci_dev, int region_num, } static void -e1000_cleanup(VLANClientState *vc) +e1000_cleanup(VLANClientState *nc) { - E1000State *d = vc->opaque; + E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque; - d->vc = NULL; + s->nic = NULL; } static int @@ -1050,7 +1050,7 @@ pci_e1000_uninit(PCIDevice *dev) E1000State *d = DO_UPCAST(E1000State, dev, dev); cpu_unregister_io_memory(d->mmio_index); - qemu_del_vlan_client(d->vc); + qemu_del_vlan_client(&d->nic->nc); vmstate_unregister(&vmstate_e1000, d); return 0; } @@ -1067,6 +1067,15 @@ static void e1000_reset(void *opaque) memset(&d->tx, 0, sizeof d->tx); } +static NetClientInfo net_e1000_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = e1000_can_receive, + .receive = e1000_receive, + .cleanup = e1000_cleanup, + .link_status_changed = e1000_set_link_status, +}; + static int pci_e1000_init(PCIDevice *pci_dev) { E1000State *d = DO_UPCAST(E1000State, dev, pci_dev); @@ -1107,14 +1116,10 @@ static int pci_e1000_init(PCIDevice *pci_dev) checksum = (uint16_t) EEPROM_SUM - checksum; d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum; - d->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - d->conf.vlan, d->conf.peer, - d->dev.qdev.info->name, d->dev.qdev.id, - e1000_can_receive, e1000_receive, NULL, - NULL, e1000_cleanup, d); - d->vc->link_status_changed = e1000_set_link_status; + d->nic = qemu_new_nic(&net_e1000_info, &d->conf, + d->dev.qdev.info->name, d->dev.qdev.id, d); - qemu_format_nic_info_str(d->vc, macaddr); + qemu_format_nic_info_str(&d->nic->nc, macaddr); vmstate_register(-1, &vmstate_e1000, d); -- cgit v1.2.3-65-gdbad From 1673ad513edcfc0a8b8a38116dd63d5bc83020ff Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:13 +0000 Subject: net: convert rtl8139 to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/rtl8139.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index be47f61c2..d2a944398 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -459,7 +459,7 @@ typedef struct RTL8139State { uint16_t CpCmd; uint8_t TxThresh; - VLANClientState *vc; + NICState *nic; NICConf conf; int rtl8139_mmio_io_addr; @@ -785,9 +785,9 @@ static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high) #endif } -static int rtl8139_can_receive(VLANClientState *vc) +static int rtl8139_can_receive(VLANClientState *nc) { - RTL8139State *s = vc->opaque; + RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; int avail; /* Receive (drop) packets if card is disabled. */ @@ -807,9 +807,9 @@ static int rtl8139_can_receive(VLANClientState *vc) } } -static ssize_t rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, size_t size_, int do_interrupt) +static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt) { - RTL8139State *s = vc->opaque; + RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; int size = size_; uint32_t packet_header = 0; @@ -1156,9 +1156,9 @@ static ssize_t rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, size_ return size_; } -static ssize_t rtl8139_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t rtl8139_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - return rtl8139_do_receive(vc, buf, size, 1); + return rtl8139_do_receive(nc, buf, size, 1); } static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) @@ -1744,11 +1744,11 @@ static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size if (TxLoopBack == (s->TxConfig & TxLoopBack)) { DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); - rtl8139_do_receive(s->vc, buf, size, do_interrupt); + rtl8139_do_receive(&s->nic->nc, buf, size, do_interrupt); } else { - qemu_send_packet(s->vc, buf, size); + qemu_send_packet(&s->nic->nc, buf, size); } } @@ -3280,11 +3280,11 @@ static void rtl8139_timer(void *opaque) } #endif /* RTL8139_ONBOARD_TIMER */ -static void rtl8139_cleanup(VLANClientState *vc) +static void rtl8139_cleanup(VLANClientState *nc) { - RTL8139State *s = vc->opaque; + RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; - s->vc = NULL; + s->nic = NULL; } static int pci_rtl8139_uninit(PCIDevice *dev) @@ -3301,10 +3301,18 @@ static int pci_rtl8139_uninit(PCIDevice *dev) qemu_free_timer(s->timer); #endif vmstate_unregister(&vmstate_rtl8139, s); - qemu_del_vlan_client(s->vc); + qemu_del_vlan_client(&s->nic->nc); return 0; } +static NetClientInfo net_rtl8139_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = rtl8139_can_receive, + .receive = rtl8139_receive, + .cleanup = rtl8139_cleanup, +}; + static int pci_rtl8139_init(PCIDevice *dev) { RTL8139State * s = DO_UPCAST(RTL8139State, dev, dev); @@ -3332,12 +3340,9 @@ static int pci_rtl8139_init(PCIDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - s->conf.vlan, s->conf.peer, - dev->qdev.info->name, dev->qdev.id, - rtl8139_can_receive, rtl8139_receive, NULL, - NULL, rtl8139_cleanup, s); - qemu_format_nic_info_str(s->vc, s->conf.macaddr.a); + s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf, + dev->qdev.info->name, dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); s->cplus_txbuffer = NULL; s->cplus_txbuffer_len = 0; -- cgit v1.2.3-65-gdbad From 1c2045b549df75a2869e408d4fdec6738c72da81 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:14 +0000 Subject: net: convert ne2000 to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/ne2000-isa.c | 22 ++++++++++++++-------- hw/ne2000.c | 35 +++++++++++++++++++++-------------- hw/ne2000.h | 2 +- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index 729e8e225..0260f849f 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -35,13 +35,21 @@ typedef struct ISANE2000State { NE2000State ne2000; } ISANE2000State; -static void isa_ne2000_cleanup(VLANClientState *vc) +static void isa_ne2000_cleanup(VLANClientState *nc) { - NE2000State *s = vc->opaque; + NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; - s->vc = NULL; + s->nic = NULL; } +static NetClientInfo net_ne2000_isa_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = ne2000_can_receive, + .receive = ne2000_receive, + .cleanup = isa_ne2000_cleanup, +}; + static int isa_ne2000_initfn(ISADevice *dev) { ISANE2000State *isa = DO_UPCAST(ISANE2000State, dev, dev); @@ -63,11 +71,9 @@ static int isa_ne2000_initfn(ISADevice *dev) qemu_macaddr_default_if_unset(&s->c.macaddr); ne2000_reset(s); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, s->c.vlan, s->c.peer, - dev->qdev.info->name, dev->qdev.id, - ne2000_can_receive, ne2000_receive, NULL, - NULL, isa_ne2000_cleanup, s); - qemu_format_nic_info_str(s->vc, s->c.macaddr.a); + s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c, + dev->qdev.info->name, dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a); vmstate_register(-1, &vmstate_ne2000, s); return 0; diff --git a/hw/ne2000.c b/hw/ne2000.c index 63efc3a1d..0be189af5 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -188,9 +188,9 @@ static int ne2000_buffer_full(NE2000State *s) return 0; } -int ne2000_can_receive(VLANClientState *vc) +int ne2000_can_receive(VLANClientState *nc) { - NE2000State *s = vc->opaque; + NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; if (s->cmd & E8390_STOP) return 1; @@ -199,9 +199,9 @@ int ne2000_can_receive(VLANClientState *vc) #define MIN_BUF_SIZE 60 -ssize_t ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size_) +ssize_t ne2000_receive(VLANClientState *nc, const uint8_t *buf, size_t size_) { - NE2000State *s = vc->opaque; + NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; int size = size_; uint8_t *p; unsigned int total_len, next, avail, len, index, mcast_idx; @@ -323,7 +323,7 @@ void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) index -= NE2000_PMEM_SIZE; /* fail safe: check range on the transmitted length */ if (index + s->tcnt <= NE2000_PMEM_END) { - qemu_send_packet(s->vc, s->mem + index, s->tcnt); + qemu_send_packet(&s->nic->nc, s->mem + index, s->tcnt); } /* signal end of transfer */ s->tsr = ENTSR_PTX; @@ -698,13 +698,21 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); } -static void ne2000_cleanup(VLANClientState *vc) +static void ne2000_cleanup(VLANClientState *nc) { - NE2000State *s = vc->opaque; + NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; - s->vc = NULL; + s->nic = NULL; } +static NetClientInfo net_ne2000_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = ne2000_can_receive, + .receive = ne2000_receive, + .cleanup = ne2000_cleanup, +}; + static int pci_ne2000_init(PCIDevice *pci_dev) { PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev); @@ -725,11 +733,10 @@ static int pci_ne2000_init(PCIDevice *pci_dev) qemu_macaddr_default_if_unset(&s->c.macaddr); ne2000_reset(s); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, s->c.vlan, s->c.peer, - pci_dev->qdev.info->name, pci_dev->qdev.id, - ne2000_can_receive, ne2000_receive, NULL, - NULL, ne2000_cleanup, s); - qemu_format_nic_info_str(s->vc, s->c.macaddr.a); + + s->nic = qemu_new_nic(&net_ne2000_info, &s->c, + pci_dev->qdev.info->name, pci_dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a); if (!pci_dev->qdev.hotplugged) { static int loaded = 0; @@ -749,7 +756,7 @@ static int pci_ne2000_exit(PCIDevice *pci_dev) NE2000State *s = &d->ne2000; vmstate_unregister(&vmstate_pci_ne2000, s); - qemu_del_vlan_client(s->vc); + qemu_del_vlan_client(&s->nic->nc); return 0; } diff --git a/hw/ne2000.h b/hw/ne2000.h index 2bbce71e6..54fdfca13 100644 --- a/hw/ne2000.h +++ b/hw/ne2000.h @@ -22,7 +22,7 @@ typedef struct NE2000State { uint8_t curpag; uint8_t mult[8]; /* multicast mask array */ qemu_irq irq; - VLANClientState *vc; + NICState *nic; NICConf c; uint8_t mem[NE2000_MEM_SIZE]; } NE2000State; -- cgit v1.2.3-65-gdbad From 1fa5148223e77a705a8626fd9cacb1ba3f1c779f Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:15 +0000 Subject: net: convert pcnet to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/lance.c | 14 +++++++++++--- hw/pcnet.c | 43 +++++++++++++++++++++++-------------------- hw/pcnet.h | 7 ++++--- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/hw/lance.c b/hw/lance.c index 0a96644b4..98033a4ed 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -92,14 +92,22 @@ static CPUWriteMemoryFunc * const lance_mem_write[3] = { NULL, }; -static void lance_cleanup(VLANClientState *vc) +static void lance_cleanup(VLANClientState *nc) { - PCNetState *d = vc->opaque; + PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; vmstate_unregister(&vmstate_pcnet, d); pcnet_common_cleanup(d); } +static NetClientInfo net_lance_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = pcnet_can_receive, + .receive = pcnet_receive, + .cleanup = lance_cleanup, +}; + static int lance_init(SysBusDevice *dev) { SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev); @@ -118,7 +126,7 @@ static int lance_init(SysBusDevice *dev) s->phys_mem_write = ledma_memory_write; vmstate_register(-1, &vmstate_pcnet, d); - return pcnet_common_init(&dev->qdev, s, lance_cleanup); + return pcnet_common_init(&dev->qdev, s, &net_lance_info); } static void lance_reset(DeviceState *dev) diff --git a/hw/pcnet.c b/hw/pcnet.c index ee3db0939..195c825c8 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1028,9 +1028,9 @@ static int pcnet_tdte_poll(PCNetState *s) return !!(CSR_CXST(s) & 0x8000); } -static int pcnet_can_receive(VLANClientState *vc) +int pcnet_can_receive(VLANClientState *nc) { - PCNetState *s = vc->opaque; + PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; if (CSR_STOP(s) || CSR_SPND(s)) return 0; @@ -1039,9 +1039,9 @@ static int pcnet_can_receive(VLANClientState *vc) #define MIN_BUF_SIZE 60 -static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size_) +ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_) { - PCNetState *s = vc->opaque; + PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; int is_padr = 0, is_bcast = 0, is_ladr = 0; uint8_t buf1[60]; int remaining; @@ -1268,11 +1268,11 @@ static void pcnet_transmit(PCNetState *s) if (BCR_SWSTYLE(s) == 1) add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; - pcnet_receive(s->vc, s->buffer, s->xmit_pos); + pcnet_receive(&s->nic->nc, s->buffer, s->xmit_pos); s->looptest = 0; } else - if (s->vc) - qemu_send_packet(s->vc, s->buffer, s->xmit_pos); + if (s->nic) + qemu_send_packet(&s->nic->nc, s->buffer, s->xmit_pos); s->csr[0] &= ~0x0008; /* clear TDMD */ s->csr[4] |= 0x0004; /* set TXSTRT */ @@ -1888,21 +1888,16 @@ static const VMStateDescription vmstate_pci_pcnet = { void pcnet_common_cleanup(PCNetState *d) { - d->vc = NULL; + d->nic = NULL; } -int pcnet_common_init(DeviceState *dev, PCNetState *s, - NetCleanup *cleanup) +int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info) { s->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, s); qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - s->conf.vlan, s->conf.peer, - dev->info->name, dev->id, - pcnet_can_receive, pcnet_receive, NULL, NULL, - cleanup, s); - qemu_format_nic_info_str(s->vc, s->conf.macaddr.a); + s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); return 0; } @@ -1945,9 +1940,9 @@ static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, cpu_physical_memory_read(addr, buf, len); } -static void pci_pcnet_cleanup(VLANClientState *vc) +static void pci_pcnet_cleanup(VLANClientState *nc) { - PCNetState *d = vc->opaque; + PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; pcnet_common_cleanup(d); } @@ -1960,10 +1955,18 @@ static int pci_pcnet_uninit(PCIDevice *dev) vmstate_unregister(&vmstate_pci_pcnet, d); qemu_del_timer(d->state.poll_timer); qemu_free_timer(d->state.poll_timer); - qemu_del_vlan_client(d->state.vc); + qemu_del_vlan_client(&d->state.nic->nc); return 0; } +static NetClientInfo net_pci_pcnet_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = pcnet_can_receive, + .receive = pcnet_receive, + .cleanup = pci_pcnet_cleanup, +}; + static int pci_pcnet_init(PCIDevice *pci_dev) { PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev); @@ -2017,7 +2020,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev) } } - return pcnet_common_init(&pci_dev->qdev, s, pci_pcnet_cleanup); + return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info); } static void pci_reset(DeviceState *dev) diff --git a/hw/pcnet.h b/hw/pcnet.h index e61d5a447..efacc9fa5 100644 --- a/hw/pcnet.h +++ b/hw/pcnet.h @@ -8,7 +8,7 @@ typedef struct PCNetState_st PCNetState; struct PCNetState_st { - VLANClientState *vc; + NICState *nic; NICConf conf; QEMUTimer *poll_timer; int rap, isr, lnkst; @@ -32,7 +32,8 @@ struct PCNetState_st { void pcnet_h_reset(void *opaque); void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val); uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr); +int pcnet_can_receive(VLANClientState *nc); +ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_); void pcnet_common_cleanup(PCNetState *d); -int pcnet_common_init(DeviceState *dev, PCNetState *s, - NetCleanup *cleanup); +int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info); extern const VMStateDescription vmstate_pcnet; -- cgit v1.2.3-65-gdbad From e00e365ef3bc58a3575e366b025cf01e377d62ab Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:16 +0000 Subject: net: convert eepro100 to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/eepro100.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index 8734907e4..eb16a51a4 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -195,7 +195,7 @@ typedef struct { PCIDevice dev; uint8_t mult[8]; /* multicast mask array */ int mmio_index; - VLANClientState *vc; + NICState *nic; NICConf conf; uint8_t scb_stat; /* SCB stat/ack byte */ uint8_t int_stat; /* PCI interrupt status */ @@ -868,7 +868,7 @@ static void action_command(EEPRO100State *s) } } TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size, nic_dump(buf, size))); - qemu_send_packet(s->vc, buf, size); + qemu_send_packet(&s->nic->nc, buf, size); s->statistics.tx_good_frames++; /* Transmit with bad status would raise an CX/TNO interrupt. * (82557 only). Emulation never has bad status. */ @@ -1599,21 +1599,21 @@ static void pci_mmio_map(PCIDevice * pci_dev, int region_num, } } -static int nic_can_receive(VLANClientState *vc) +static int nic_can_receive(VLANClientState *nc) { - EEPRO100State *s = vc->opaque; + EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque; TRACE(RXTX, logout("%p\n", s)); return get_ru_state(s) == ru_ready; //~ return !eepro100_buffer_full(s); } -static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) +static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size) { /* TODO: * - Magic packets should set bit 30 in power management driver register. * - Interesting packets should set bit 29 in power management driver register. */ - EEPRO100State *s = vc->opaque; + EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque; uint16_t rfd_status = 0xa000; static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -1779,11 +1779,11 @@ static const VMStateDescription vmstate_eepro100 = { } }; -static void nic_cleanup(VLANClientState *vc) +static void nic_cleanup(VLANClientState *nc) { - EEPRO100State *s = vc->opaque; + EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque; - s->vc = NULL; + s->nic = NULL; } static int pci_nic_uninit(PCIDevice *pci_dev) @@ -1793,10 +1793,18 @@ static int pci_nic_uninit(PCIDevice *pci_dev) cpu_unregister_io_memory(s->mmio_index); vmstate_unregister(s->vmstate, s); eeprom93xx_free(s->eeprom); - qemu_del_vlan_client(s->vc); + qemu_del_vlan_client(&s->nic->nc); return 0; } +static NetClientInfo net_eepro100_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = nic_can_receive, + .receive = nic_receive, + .cleanup = nic_cleanup, +}; + static int nic_init(PCIDevice *pci_dev, uint32_t device) { EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev); @@ -1829,27 +1837,24 @@ static int nic_init(PCIDevice *pci_dev, uint32_t device) nic_reset(s); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - s->conf.vlan, s->conf.peer, - pci_dev->qdev.info->name, pci_dev->qdev.id, - nic_can_receive, nic_receive, NULL, NULL, - nic_cleanup, s); + s->nic = qemu_new_nic(&net_eepro100_info, &s->conf, + pci_dev->qdev.info->name, pci_dev->qdev.id, s); - qemu_format_nic_info_str(s->vc, s->conf.macaddr.a); - TRACE(OTHER, logout("%s\n", s->vc->info_str)); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + TRACE(OTHER, logout("%s\n", s->nic->nc.info_str)); qemu_register_reset(nic_reset, s); s->vmstate = qemu_malloc(sizeof(vmstate_eepro100)); memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100)); - s->vmstate->name = s->vc->model; + s->vmstate->name = s->nic->nc.model; vmstate_register(-1, s->vmstate, s); if (!pci_dev->qdev.hotplugged) { static int loaded = 0; if (!loaded) { char fname[32]; - snprintf(fname, sizeof(fname), "pxe-%s.bin", s->vc->model); + snprintf(fname, sizeof(fname), "pxe-%s.bin", s->nic->nc.model); rom_add_option(fname); loaded = 1; } -- cgit v1.2.3-65-gdbad From 05f41fe3653f3c72dcc606c3a6f28fd69b791153 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:17 +0000 Subject: net: convert dp8393x to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/dp8393x.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 5143cc8ce..be9714dec 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -154,7 +154,8 @@ typedef struct dp8393xState { #endif QEMUTimer *watchdog; int64_t wt_last_update; - VLANClientState *vc; + NICConf conf; + NICState *nic; int mmio_index; /* Registers */ @@ -406,13 +407,13 @@ static void do_transmit_packets(dp8393xState *s) if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) { /* Loopback */ s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; - if (s->vc->can_receive(s->vc)) { + if (s->nic->nc.can_receive(&s->nic->nc)) { s->loopback_packet = 1; - s->vc->receive(s->vc, s->tx_buffer, tx_len); + s->nic->nc.receive(&s->nic->nc, s->tx_buffer, tx_len); } } else { /* Transmit packet */ - qemu_send_packet(s->vc, s->tx_buffer, tx_len); + qemu_send_packet(&s->nic->nc, s->tx_buffer, tx_len); } s->regs[SONIC_TCR] |= SONIC_TCR_PTX; @@ -675,9 +676,9 @@ static CPUWriteMemoryFunc * const dp8393x_write[3] = { dp8393x_writel, }; -static int nic_can_receive(VLANClientState *vc) +static int nic_can_receive(VLANClientState *nc) { - dp8393xState *s = vc->opaque; + dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque; if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN)) return 0; @@ -724,10 +725,10 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) return -1; } -static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) +static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size) { + dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque; uint16_t data[10]; - dp8393xState *s = vc->opaque; int packet_type; uint32_t available, address; int width, rx_len = size; @@ -860,9 +861,9 @@ static void nic_reset(void *opaque) dp8393x_update_irq(s); } -static void nic_cleanup(VLANClientState *vc) +static void nic_cleanup(VLANClientState *nc) { - dp8393xState *s = vc->opaque; + dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque; cpu_unregister_io_memory(s->mmio_index); @@ -872,6 +873,14 @@ static void nic_cleanup(VLANClientState *vc) qemu_free(s); } +static NetClientInfo net_dp83932_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = nic_can_receive, + .receive = nic_receive, + .cleanup = nic_cleanup, +}; + void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, qemu_irq irq, void* mem_opaque, void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)) @@ -889,13 +898,13 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s); s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - nic_can_receive, nic_receive, NULL, NULL, - nic_cleanup, s); + memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(s->conf.macaddr)); + s->conf.vlan = nd->vlan; + s->conf.peer = nd->netdev; + + s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s); - qemu_format_nic_info_str(s->vc, nd->macaddr); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); qemu_register_reset(nic_reset, s); nic_reset(s); -- cgit v1.2.3-65-gdbad From 163bf3a56d3ae925184c9d9fa4b07018a4bddae3 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:18 +0000 Subject: net: convert etrax to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/etraxfs_eth.c | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 2cc233224..dedd1077f 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -319,7 +319,8 @@ static void mdio_cycle(struct qemu_mdio *bus) struct fs_eth { - VLANClientState *vc; + NICState *nic; + NICConf conf; int ethregs; /* Two addrs in the filter. */ @@ -495,15 +496,15 @@ static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa) return match; } -static int eth_can_receive(VLANClientState *vc) +static int eth_can_receive(VLANClientState *nc) { return 1; } -static ssize_t eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t eth_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct fs_eth *eth = vc->opaque; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; int use_ma0 = eth->regs[RW_REC_CTRL] & 1; int use_ma1 = eth->regs[RW_REC_CTRL] & 2; int r_bcast = eth->regs[RW_REC_CTRL] & 8; @@ -533,15 +534,15 @@ static int eth_tx_push(void *opaque, unsigned char *buf, int len) struct fs_eth *eth = opaque; D(printf("%s buf=%p len=%d\n", __func__, buf, len)); - qemu_send_packet(eth->vc, buf, len); + qemu_send_packet(ð->nic->nc, buf, len); return len; } -static void eth_set_link(VLANClientState *vc) +static void eth_set_link(VLANClientState *nc) { - struct fs_eth *eth = vc->opaque; - D(printf("%s %d\n", __func__, vc->link_down)); - eth->phy.link = !vc->link_down; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + D(printf("%s %d\n", __func__, nc->link_down)); + eth->phy.link = !nc->link_down; } static CPUReadMemoryFunc * const eth_read[] = { @@ -554,9 +555,9 @@ static CPUWriteMemoryFunc * const eth_write[] = { ð_writel, }; -static void eth_cleanup(VLANClientState *vc) +static void eth_cleanup(VLANClientState *nc) { - struct fs_eth *eth = vc->opaque; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; cpu_unregister_io_memory(eth->ethregs); @@ -564,6 +565,15 @@ static void eth_cleanup(VLANClientState *vc) qemu_free(eth); } +static NetClientInfo net_etraxfs_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = eth_can_receive, + .receive = eth_receive, + .cleanup = eth_cleanup, + .link_status_changed = eth_set_link, +}; + void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr) { struct etraxfs_dma_client *dma = NULL; @@ -590,13 +600,12 @@ void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr) eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth); cpu_register_physical_memory (base, 0x5c, eth->ethregs); - eth->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - eth_can_receive, eth_receive, - NULL, NULL, eth_cleanup, eth); - eth->vc->opaque = eth; - eth->vc->link_status_changed = eth_set_link; + memcpy(eth->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr)); + eth->conf.vlan = nd->vlan; + eth->conf.peer = nd->netdev; + + eth->nic = qemu_new_nic(&net_etraxfs_info, ð->conf, + nd->model, nd->name, eth); return dma; } -- cgit v1.2.3-65-gdbad From 83b9f88c11a6647037ca365a70c97850392a54cb Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:19 +0000 Subject: net: convert LAN9118 to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/lan9118.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/hw/lan9118.c b/hw/lan9118.c index 6394f3a73..ba982d111 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -137,7 +137,7 @@ typedef struct { typedef struct { SysBusDevice busdev; - VLANClientState *vc; + NICState *nic; NICConf conf; qemu_irq irq; int mmio_index; @@ -212,7 +212,7 @@ static void lan9118_update(lan9118_state *s) static void lan9118_mac_changed(lan9118_state *s) { - qemu_format_nic_info_str(s->vc, s->conf.macaddr.a); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); } static void lan9118_reload_eeprom(lan9118_state *s) @@ -234,16 +234,16 @@ static void lan9118_reload_eeprom(lan9118_state *s) static void phy_update_link(lan9118_state *s) { /* Autonegotiation status mirrors link status. */ - if (s->vc->link_down) { + if (s->nic->nc.link_down) { s->phy_status &= ~0x0024; } else { s->phy_status |= 0x0024; } } -static void lan9118_set_link(VLANClientState *vc) +static void lan9118_set_link(VLANClientState *nc) { - phy_update_link(vc->opaque); + phy_update_link(DO_UPCAST(NICState, nc, nc)->opaque); } static void phy_reset(lan9118_state *s) @@ -305,7 +305,7 @@ static void lan9118_reset(DeviceState *d) lan9118_reload_eeprom(s); } -static int lan9118_can_receive(VLANClientState *vc) +static int lan9118_can_receive(VLANClientState *nc) { return 1; } @@ -358,10 +358,10 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr) } } -static ssize_t lan9118_receive(VLANClientState *vc, const uint8_t *buf, +static ssize_t lan9118_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - lan9118_state *s = vc->opaque; + lan9118_state *s = DO_UPCAST(NICState, nc, nc)->opaque; int fifo_len; int offset; int src_pos; @@ -506,9 +506,9 @@ static void do_tx_packet(lan9118_state *s) /* FIXME: Honor TX disable, and allow queueing of packets. */ if (s->phy_control & 0x4000) { /* This assumes the receive routine doesn't touch the VLANClient. */ - lan9118_receive(s->vc, s->txp->data, s->txp->len); + lan9118_receive(&s->nic->nc, s->txp->data, s->txp->len); } else { - qemu_send_packet(s->vc, s->txp->data, s->txp->len); + qemu_send_packet(&s->nic->nc, s->txp->data, s->txp->len); } s->txp->fifo_used = 0; @@ -1022,13 +1022,22 @@ static CPUWriteMemoryFunc * const lan9118_writefn[] = { lan9118_writel }; -static void lan9118_cleanup(VLANClientState *vc) +static void lan9118_cleanup(VLANClientState *nc) { - lan9118_state *s = vc->opaque; + lan9118_state *s = DO_UPCAST(NICState, nc, nc)->opaque; - s->vc = NULL; + s->nic = NULL; } +static NetClientInfo net_lan9118_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = lan9118_can_receive, + .receive = lan9118_receive, + .cleanup = lan9118_cleanup, + .link_status_changed = lan9118_set_link, +}; + static int lan9118_init1(SysBusDevice *dev) { lan9118_state *s = FROM_SYSBUS(lan9118_state, dev); @@ -1040,13 +1049,9 @@ static int lan9118_init1(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - s->conf.vlan, s->conf.peer, - dev->qdev.info->name, dev->qdev.id, - lan9118_can_receive, lan9118_receive, NULL, - NULL, lan9118_cleanup, s); - s->vc->link_status_changed = lan9118_set_link; - qemu_format_nic_info_str(s->vc, s->conf.macaddr.a); + s->nic = qemu_new_nic(&net_lan9118_info, &s->conf, + dev->qdev.info->name, dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); s->eeprom[0] = 0xa5; for (i = 0; i < 6; i++) { s->eeprom[i + 1] = s->conf.macaddr.a[i]; -- cgit v1.2.3-65-gdbad From 1cc49d95a1b74382ad425c76c9e14b84e18ba881 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:20 +0000 Subject: net: convert mcf_fec to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/mcf_fec.c | 58 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 8242c8a25..4e7fbed16 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -25,7 +25,8 @@ do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0) typedef struct { qemu_irq *irq; int mmio_index; - VLANClientState *vc; + NICState *nic; + NICConf conf; uint32_t irq_state; uint32_t eir; uint32_t eimr; @@ -42,7 +43,6 @@ typedef struct { uint32_t erdsr; uint32_t etdsr; uint32_t emrbr; - uint8_t macaddr[6]; } mcf_fec_state; #define FEC_INT_HB 0x80000000 @@ -172,7 +172,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s) if (bd.flags & FEC_BD_L) { /* Last buffer in frame. */ DPRINTF("Sending packet\n"); - qemu_send_packet(s->vc, frame, len); + qemu_send_packet(&s->nic->nc, frame, len); ptr = frame; frame_size = 0; s->eir |= FEC_INT_TXF; @@ -229,11 +229,11 @@ static uint32_t mcf_fec_read(void *opaque, target_phys_addr_t addr) case 0x084: return s->rcr; case 0x0c4: return s->tcr; case 0x0e4: /* PALR */ - return (s->macaddr[0] << 24) | (s->macaddr[1] << 16) - | (s->macaddr[2] << 8) | s->macaddr[3]; + return (s->conf.macaddr.a[0] << 24) | (s->conf.macaddr.a[1] << 16) + | (s->conf.macaddr.a[2] << 8) | s->conf.macaddr.a[3]; break; case 0x0e8: /* PAUR */ - return (s->macaddr[4] << 24) | (s->macaddr[5] << 16) | 0x8808; + return (s->conf.macaddr.a[4] << 24) | (s->conf.macaddr.a[5] << 16) | 0x8808; case 0x0ec: return 0x10000; /* OPD */ case 0x118: return 0; case 0x11c: return 0; @@ -303,14 +303,14 @@ static void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value) s->eir |= FEC_INT_GRA; break; case 0x0e4: /* PALR */ - s->macaddr[0] = value >> 24; - s->macaddr[1] = value >> 16; - s->macaddr[2] = value >> 8; - s->macaddr[3] = value; + s->conf.macaddr.a[0] = value >> 24; + s->conf.macaddr.a[1] = value >> 16; + s->conf.macaddr.a[2] = value >> 8; + s->conf.macaddr.a[3] = value; break; case 0x0e8: /* PAUR */ - s->macaddr[4] = value >> 24; - s->macaddr[5] = value >> 16; + s->conf.macaddr.a[4] = value >> 24; + s->conf.macaddr.a[5] = value >> 16; break; case 0x0ec: /* OPD */ @@ -347,15 +347,15 @@ static void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value) mcf_fec_update(s); } -static int mcf_fec_can_receive(VLANClientState *vc) +static int mcf_fec_can_receive(VLANClientState *nc) { - mcf_fec_state *s = vc->opaque; + mcf_fec_state *s = DO_UPCAST(NICState, nc, nc)->opaque; return s->rx_enabled; } -static ssize_t mcf_fec_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t mcf_fec_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - mcf_fec_state *s = vc->opaque; + mcf_fec_state *s = DO_UPCAST(NICState, nc, nc)->opaque; mcf_fec_bd bd; uint32_t flags = 0; uint32_t addr; @@ -441,15 +441,23 @@ static CPUWriteMemoryFunc * const mcf_fec_writefn[] = { mcf_fec_write }; -static void mcf_fec_cleanup(VLANClientState *vc) +static void mcf_fec_cleanup(VLANClientState *nc) { - mcf_fec_state *s = vc->opaque; + mcf_fec_state *s = DO_UPCAST(NICState, nc, nc)->opaque; cpu_unregister_io_memory(s->mmio_index); qemu_free(s); } +static NetClientInfo net_mcf_fec_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = mcf_fec_can_receive, + .receive = mcf_fec_receive, + .cleanup = mcf_fec_cleanup, +}; + void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) { mcf_fec_state *s; @@ -462,11 +470,11 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) mcf_fec_writefn, s); cpu_register_physical_memory(base, 0x400, s->mmio_index); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - mcf_fec_can_receive, mcf_fec_receive, - NULL, NULL, mcf_fec_cleanup, s); - memcpy(s->macaddr, nd->macaddr, 6); - qemu_format_nic_info_str(s->vc, s->macaddr); + memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr)); + s->conf.vlan = nd->vlan; + s->conf.peer = nd->netdev; + + s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s); + + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); } -- cgit v1.2.3-65-gdbad From 1f30d10a46697fd329eb6ad2d80a3366f120ddf9 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:21 +0000 Subject: net: convert mipsnet to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/mipsnet.c | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/hw/mipsnet.c b/hw/mipsnet.c index 67160a432..a066f6313 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -35,7 +35,8 @@ typedef struct MIPSnetState { uint8_t tx_buffer[MAX_ETH_FRAME_SIZE]; int io_base; qemu_irq irq; - VLANClientState *vc; + NICState *nic; + NICConf conf; } MIPSnetState; static void mipsnet_reset(MIPSnetState *s) @@ -66,23 +67,23 @@ static int mipsnet_buffer_full(MIPSnetState *s) return 0; } -static int mipsnet_can_receive(VLANClientState *vc) +static int mipsnet_can_receive(VLANClientState *nc) { - MIPSnetState *s = vc->opaque; + MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; if (s->busy) return 0; return !mipsnet_buffer_full(s); } -static ssize_t mipsnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - MIPSnetState *s = vc->opaque; + MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; #ifdef DEBUG_MIPSNET_RECEIVE printf("mipsnet: receiving len=%d\n", size); #endif - if (!mipsnet_can_receive(vc)) + if (!mipsnet_can_receive(nc)) return -1; s->busy = 1; @@ -183,7 +184,7 @@ static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val) #ifdef DEBUG_MIPSNET_SEND printf("mipsnet: sending len=%d\n", s->tx_count); #endif - qemu_send_packet(s->vc, s->tx_buffer, s->tx_count); + qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count); s->tx_count = s->tx_written = 0; s->intctl |= MIPSNET_INTCTL_TXDONE; s->busy = 1; @@ -234,9 +235,9 @@ static int mipsnet_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void mipsnet_cleanup(VLANClientState *vc) +static void mipsnet_cleanup(VLANClientState *nc) { - MIPSnetState *s = vc->opaque; + MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; unregister_savevm("mipsnet", s); @@ -245,6 +246,14 @@ static void mipsnet_cleanup(VLANClientState *vc) qemu_free(s); } +static NetClientInfo net_mipsnet_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = mipsnet_can_receive, + .receive = mipsnet_receive, + .cleanup = mipsnet_cleanup, +}; + void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) { MIPSnetState *s; @@ -262,17 +271,17 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) s->io_base = base; s->irq = irq; + if (nd) { - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - mipsnet_can_receive, mipsnet_receive, - NULL, NULL, mipsnet_cleanup, s); - } else { - s->vc = NULL; - } + memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr)); + s->conf.vlan = nd->vlan; + s->conf.peer = nd->netdev; - qemu_format_nic_info_str(s->vc, nd->macaddr); + s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf, + nd->model, nd->name, s); + + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + } mipsnet_reset(s); register_savevm("mipsnet", 0, 0, mipsnet_save, mipsnet_load, s); -- cgit v1.2.3-65-gdbad From 3a94dd18ff2d01296ebdfe7c781bea9724bab209 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:22 +0000 Subject: net: convert musicpal to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/musicpal.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/hw/musicpal.c b/hw/musicpal.c index 264669f61..4a33e28bc 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -151,7 +151,7 @@ typedef struct mv88w8618_eth_state { uint32_t rx_queue[4]; uint32_t frx_queue[4]; uint32_t cur_rx[4]; - VLANClientState *vc; + NICState *nic; NICConf conf; } mv88w8618_eth_state; @@ -175,14 +175,14 @@ static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc) le32_to_cpus(&desc->next); } -static int eth_can_receive(VLANClientState *vc) +static int eth_can_receive(VLANClientState *nc) { return 1; } -static ssize_t eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t eth_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - mv88w8618_eth_state *s = vc->opaque; + mv88w8618_eth_state *s = DO_UPCAST(NICState, nc, nc)->opaque; uint32_t desc_addr; mv88w8618_rx_desc desc; int i; @@ -250,7 +250,7 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index) len = desc.bytes; if (len < 2048) { cpu_physical_memory_read(desc.buffer, buf, len); - qemu_send_packet(s->vc, buf, len); + qemu_send_packet(&s->nic->nc, buf, len); } desc.cmdstat &= ~MP_ETH_TX_OWN; s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); @@ -365,23 +365,28 @@ static CPUWriteMemoryFunc * const mv88w8618_eth_writefn[] = { mv88w8618_eth_write }; -static void eth_cleanup(VLANClientState *vc) +static void eth_cleanup(VLANClientState *nc) { - mv88w8618_eth_state *s = vc->opaque; + mv88w8618_eth_state *s = DO_UPCAST(NICState, nc, nc)->opaque; - s->vc = NULL; + s->nic = NULL; } +static NetClientInfo net_mv88w8618_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = eth_can_receive, + .receive = eth_receive, + .cleanup = eth_cleanup, +}; + static int mv88w8618_eth_init(SysBusDevice *dev) { mv88w8618_eth_state *s = FROM_SYSBUS(mv88w8618_eth_state, dev); sysbus_init_irq(dev, &s->irq); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - s->conf.vlan, s->conf.peer, - dev->qdev.info->name, dev->qdev.id, - eth_can_receive, eth_receive, NULL, - NULL, eth_cleanup, s); + s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, + dev->qdev.info->name, dev->qdev.id, s); s->mmio_index = cpu_register_io_memory(mv88w8618_eth_readfn, mv88w8618_eth_writefn, s); sysbus_init_mmio(dev, MP_ETH_SIZE, s->mmio_index); -- cgit v1.2.3-65-gdbad From 42a4260f5138278a0ea65323fdef30835520fbed Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:23 +0000 Subject: net: convert smc91c111 to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/smc91c111.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/hw/smc91c111.c b/hw/smc91c111.c index b7398c929..c1a88c9e5 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -18,7 +18,7 @@ typedef struct { SysBusDevice busdev; - VLANClientState *vc; + NICState *nic; NICConf conf; uint16_t tcr; uint16_t rcr; @@ -207,7 +207,7 @@ static void smc91c111_do_tx(smc91c111_state *s) smc91c111_release_packet(s, packetnum); else if (s->tx_fifo_done_len < NUM_PACKETS) s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum; - qemu_send_packet(s->vc, p, len); + qemu_send_packet(&s->nic->nc, p, len); } s->tx_fifo_len = 0; smc91c111_update(s); @@ -591,9 +591,9 @@ static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset) return val; } -static int smc91c111_can_receive(VLANClientState *vc) +static int smc91c111_can_receive(VLANClientState *nc) { - smc91c111_state *s = vc->opaque; + smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque; if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) return 1; @@ -602,9 +602,9 @@ static int smc91c111_can_receive(VLANClientState *vc) return 1; } -static ssize_t smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t smc91c111_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - smc91c111_state *s = vc->opaque; + smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque; int status; int packetsize; uint32_t crc; @@ -692,13 +692,21 @@ static CPUWriteMemoryFunc * const smc91c111_writefn[] = { smc91c111_writel }; -static void smc91c111_cleanup(VLANClientState *vc) +static void smc91c111_cleanup(VLANClientState *nc) { - smc91c111_state *s = vc->opaque; + smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque; - s->vc = NULL; + s->nic = NULL; } +static NetClientInfo net_smc91c111_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = smc91c111_can_receive, + .receive = smc91c111_receive, + .cleanup = smc91c111_cleanup, +}; + static int smc91c111_init1(SysBusDevice *dev) { smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev); @@ -711,12 +719,9 @@ static int smc91c111_init1(SysBusDevice *dev) smc91c111_reset(s); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - s->conf.vlan, s->conf.peer, - dev->qdev.info->name, dev->qdev.id, - smc91c111_can_receive, smc91c111_receive, NULL, - NULL, smc91c111_cleanup, s); - qemu_format_nic_info_str(s->vc, s->conf.macaddr.a); + s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf, + dev->qdev.info->name, dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); /* ??? Save/restore. */ return 0; } -- cgit v1.2.3-65-gdbad From 8c9b63b9d45763ce831f87d7d3dd07684b892031 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:24 +0000 Subject: net: convert stellaris to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/stellaris_enet.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 2252f1a5f..d1d755e29 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -66,7 +66,7 @@ typedef struct { uint8_t *rx_fifo; int rx_fifo_len; int next_packet; - VLANClientState *vc; + NICState *nic; NICConf conf; qemu_irq irq; int mmio_index; @@ -78,9 +78,9 @@ static void stellaris_enet_update(stellaris_enet_state *s) } /* TODO: Implement MAC address filtering. */ -static ssize_t stellaris_enet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t stellaris_enet_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - stellaris_enet_state *s = vc->opaque; + stellaris_enet_state *s = DO_UPCAST(NICState, nc, nc)->opaque; int n; uint8_t *p; uint32_t crc; @@ -120,9 +120,9 @@ static ssize_t stellaris_enet_receive(VLANClientState *vc, const uint8_t *buf, s return size; } -static int stellaris_enet_can_receive(VLANClientState *vc) +static int stellaris_enet_can_receive(VLANClientState *nc) { - stellaris_enet_state *s = vc->opaque; + stellaris_enet_state *s = DO_UPCAST(NICState, nc, nc)->opaque; if ((s->rctl & SE_RCTL_RXEN) == 0) return 1; @@ -258,7 +258,7 @@ static void stellaris_enet_write(void *opaque, target_phys_addr_t offset, memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len); s->tx_fifo_len = 60; } - qemu_send_packet(s->vc, s->tx_fifo, s->tx_frame_len); + qemu_send_packet(&s->nic->nc, s->tx_fifo, s->tx_frame_len); s->tx_frame_len = -1; s->ris |= SE_INT_TXEMP; stellaris_enet_update(s); @@ -385,9 +385,9 @@ static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void stellaris_enet_cleanup(VLANClientState *vc) +static void stellaris_enet_cleanup(VLANClientState *nc) { - stellaris_enet_state *s = vc->opaque; + stellaris_enet_state *s = DO_UPCAST(NICState, nc, nc)->opaque; unregister_savevm("stellaris_enet", s); @@ -396,6 +396,14 @@ static void stellaris_enet_cleanup(VLANClientState *vc) qemu_free(s); } +static NetClientInfo net_stellaris_enet_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = stellaris_enet_can_receive, + .receive = stellaris_enet_receive, + .cleanup = stellaris_enet_cleanup, +}; + static int stellaris_enet_init(SysBusDevice *dev) { stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev); @@ -406,13 +414,9 @@ static int stellaris_enet_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - s->conf.vlan, s->conf.peer, - dev->qdev.info->name, dev->qdev.id, - stellaris_enet_can_receive, - stellaris_enet_receive, NULL, NULL, - stellaris_enet_cleanup, s); - qemu_format_nic_info_str(s->vc, s->conf.macaddr.a); + s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf, + dev->qdev.info->name, dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); stellaris_enet_reset(s); register_savevm("stellaris_enet", -1, 1, -- cgit v1.2.3-65-gdbad From e0394b8b5056c429bc9a753845acf7d56d936d6d Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:25 +0000 Subject: net: convert usb-net to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/usb-net.c | 57 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/hw/usb-net.c b/hw/usb-net.c index 7b8cc7ad1..2556e05dd 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -610,7 +610,6 @@ typedef struct USBNetState { uint32_t media_state; uint16_t filter; uint32_t vendorid; - uint8_t mac[6]; unsigned int out_ptr; uint8_t out_buf[2048]; @@ -620,7 +619,8 @@ typedef struct USBNetState { uint8_t in_buf[2048]; char usbstring_mac[13]; - VLANClientState *vc; + NICState *nic; + NICConf conf; QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp; } USBNetState; @@ -741,12 +741,12 @@ static int ndis_query(USBNetState *s, uint32_t oid, /* ieee802.3 OIDs (table 4-3) */ /* mandatory */ case OID_802_3_PERMANENT_ADDRESS: - memcpy(outbuf, s->mac, 6); + memcpy(outbuf, s->conf.macaddr.a, 6); return 6; /* mandatory */ case OID_802_3_CURRENT_ADDRESS: - memcpy(outbuf, s->mac, 6); + memcpy(outbuf, s->conf.macaddr.a, 6); return 6; /* mandatory */ @@ -1305,7 +1305,7 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) if (!s->rndis) { if (ret < 64) { - qemu_send_packet(s->vc, s->out_buf, s->out_ptr); + qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr); s->out_ptr = 0; } return ret; @@ -1317,7 +1317,7 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); uint32_t size = le32_to_cpu(msg->DataLength); if (offs + size <= len) - qemu_send_packet(s->vc, s->out_buf + offs, size); + qemu_send_packet(&s->nic->nc, s->out_buf + offs, size); } s->out_ptr -= len; memmove(s->out_buf, &s->out_buf[len], s->out_ptr); @@ -1369,9 +1369,9 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) return ret; } -static ssize_t usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t usbnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - USBNetState *s = vc->opaque; + USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; struct rndis_packet_msg_type *msg; if (s->rndis) { @@ -1406,9 +1406,9 @@ static ssize_t usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t si return size; } -static int usbnet_can_receive(VLANClientState *vc) +static int usbnet_can_receive(VLANClientState *nc) { - USBNetState *s = vc->opaque; + USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; if (s->rndis && !s->rndis_state == RNDIS_DATA_INITIALIZED) return 1; @@ -1416,9 +1416,9 @@ static int usbnet_can_receive(VLANClientState *vc) return !s->in_len; } -static void usbnet_cleanup(VLANClientState *vc) +static void usbnet_cleanup(VLANClientState *nc) { - USBNetState *s = vc->opaque; + USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; rndis_clear_responsequeue(s); qemu_free(s); @@ -1429,7 +1429,7 @@ static void usb_net_handle_destroy(USBDevice *dev) USBNetState *s = (USBNetState *) dev; /* TODO: remove the nd_table[] entry */ - qemu_del_vlan_client(s->vc); + qemu_del_vlan_client(&s->nic->nc); } static int usb_net_initfn(USBDevice *dev) @@ -1450,6 +1450,14 @@ static int usb_net_initfn(USBDevice *dev) return 0; } +static NetClientInfo net_usbnet_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = usbnet_can_receive, + .receive = usbnet_receive, + .cleanup = usbnet_cleanup, +}; + USBDevice *usb_net_init(NICInfo *nd) { USBDevice *dev; @@ -1458,25 +1466,22 @@ USBDevice *usb_net_init(NICInfo *nd) dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Network Interface"); s = DO_UPCAST(USBNetState, dev, dev); - memcpy(s->mac, nd->macaddr, 6); + memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr)); + s->conf.vlan = nd->vlan; + s->conf.peer = nd->netdev; - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - nd->vlan, nd->netdev, - nd->model, nd->name, - usbnet_can_receive, - usbnet_receive, - NULL, NULL, - usbnet_cleanup, s); + s->nic = qemu_new_nic(&net_usbnet_info, &s->conf, + nd->model, nd->name, s); - qemu_format_nic_info_str(s->vc, s->mac); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); snprintf(s->usbstring_mac, sizeof(s->usbstring_mac), "%02x%02x%02x%02x%02x%02x", - 0x40, s->mac[1], s->mac[2], - s->mac[3], s->mac[4], s->mac[5]); + 0x40, s->conf.macaddr.a[1], s->conf.macaddr.a[2], + s->conf.macaddr.a[3], s->conf.macaddr.a[4], s->conf.macaddr.a[5]); fprintf(stderr, "usbnet: initialized mac %02x:%02x:%02x:%02x:%02x:%02x\n", - s->mac[0], s->mac[1], s->mac[2], - s->mac[3], s->mac[4], s->mac[5]); + s->conf.macaddr.a[0], s->conf.macaddr.a[1], s->conf.macaddr.a[2], + s->conf.macaddr.a[3], s->conf.macaddr.a[4], s->conf.macaddr.a[5]); return (USBDevice *) s; } -- cgit v1.2.3-65-gdbad From d7539ab4bf78809202a8fcce292bf2b51594a0e9 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:26 +0000 Subject: net: convert xilinx_ethlite to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/xilinx_ethlite.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index b7129d5dd..37e33ec01 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -51,7 +51,7 @@ struct xlx_ethlite { SysBusDevice busdev; qemu_irq irq; - VLANClientState *vc; + NICState *nic; NICConf conf; uint32_t c_tx_pingpong; @@ -118,7 +118,7 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { - qemu_send_packet(s->vc, + qemu_send_packet(&s->nic->nc, (void *) &s->regs[base], s->regs[base + R_TX_LEN0]); D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0])); @@ -160,17 +160,17 @@ static CPUWriteMemoryFunc * const eth_write[] = { NULL, NULL, ð_writel, }; -static int eth_can_rx(VLANClientState *vc) +static int eth_can_rx(VLANClientState *nc) { - struct xlx_ethlite *s = vc->opaque; + struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque; int r; r = !(s->regs[R_RX_CTRL0] & CTRL_S); return r; } -static ssize_t eth_rx(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size) { - struct xlx_ethlite *s = vc->opaque; + struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque; unsigned int rxbase = s->rxbuf * (0x800 / 4); int i; @@ -201,13 +201,21 @@ static ssize_t eth_rx(VLANClientState *vc, const uint8_t *buf, size_t size) return size; } -static void eth_cleanup(VLANClientState *vc) +static void eth_cleanup(VLANClientState *nc) { - struct xlx_ethlite *s = vc->opaque; + struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque; - s->vc = NULL; + s->nic = NULL; } +static NetClientInfo net_xilinx_ethlite_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = eth_can_rx, + .receive = eth_rx, + .cleanup = eth_cleanup, +}; + static int xilinx_ethlite_init(SysBusDevice *dev) { struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev); @@ -220,12 +228,9 @@ static int xilinx_ethlite_init(SysBusDevice *dev) sysbus_init_mmio(dev, R_MAX * 4, regs); qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - s->conf.vlan, s->conf.peer, - dev->qdev.info->name, dev->qdev.id, - eth_can_rx, eth_rx, NULL, - NULL, eth_cleanup, s); - qemu_format_nic_info_str(s->vc, s->conf.macaddr.a); + s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf, + dev->qdev.info->name, dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); return 0; } -- cgit v1.2.3-65-gdbad From f1d078c341ccad97bc3cc849ac1006cda7bcfc0f Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:27 +0000 Subject: net: move parse_macaddr() to net/util.[ch] Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- Makefile | 2 +- net.c | 35 ++--------------------------------- net/util.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/util.h | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 34 deletions(-) create mode 100644 net/util.c create mode 100644 net/util.h diff --git a/Makefile b/Makefile index b59545a3e..b8b5e2e93 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,7 @@ block-nested-$(CONFIG_CURL) += curl.o block-obj-y += $(addprefix block/, $(block-nested-y)) net-obj-y = net.o -net-nested-y = queue.o checksum.o +net-nested-y = queue.o checksum.o util.o net-nested-y += socket.o net-nested-y += dump.o net-nested-$(CONFIG_POSIX) += tap.o diff --git a/net.c b/net.c index 7195827cc..cca008a91 100644 --- a/net.c +++ b/net.c @@ -30,6 +30,7 @@ #include "net/dump.h" #include "net/slirp.h" #include "net/vde.h" +#include "net/util.h" #include "monitor.h" #include "sysemu.h" #include "qemu-common.h" @@ -69,38 +70,6 @@ static void hex_dump(FILE *f, const uint8_t *buf, int size) } #endif -static int parse_macaddr(uint8_t *macaddr, const char *p) -{ - int i; - char *last_char; - long int offset; - - errno = 0; - offset = strtol(p, &last_char, 0); - if (0 == errno && '\0' == *last_char && - offset >= 0 && offset <= 0xFFFFFF) { - macaddr[3] = (offset & 0xFF0000) >> 16; - macaddr[4] = (offset & 0xFF00) >> 8; - macaddr[5] = offset & 0xFF; - return 0; - } else { - for(i = 0; i < 6; i++) { - macaddr[i] = strtol(p, (char **)&p, 16); - if (i == 5) { - if (*p != '\0') - return -1; - } else { - if (*p != ':' && *p != '-') - return -1; - p++; - } - } - return 0; - } - - return -1; -} - static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) { const char *p, *p1; @@ -858,7 +827,7 @@ static int net_init_nic(QemuOpts *opts, nd->macaddr[5] = 0x56 + idx; if (qemu_opt_get(opts, "macaddr") && - parse_macaddr(nd->macaddr, qemu_opt_get(opts, "macaddr")) < 0) { + net_parse_macaddr(nd->macaddr, qemu_opt_get(opts, "macaddr")) < 0) { qemu_error("invalid syntax for ethernet address\n"); return -1; } diff --git a/net/util.c b/net/util.c new file mode 100644 index 000000000..1e9afbc1a --- /dev/null +++ b/net/util.c @@ -0,0 +1,60 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "net/util.h" +#include +#include + +int net_parse_macaddr(uint8_t *macaddr, const char *p) +{ + int i; + char *last_char; + long int offset; + + errno = 0; + offset = strtol(p, &last_char, 0); + if (errno == 0 && *last_char == '\0' && + offset >= 0 && offset <= 0xFFFFFF) { + macaddr[3] = (offset & 0xFF0000) >> 16; + macaddr[4] = (offset & 0xFF00) >> 8; + macaddr[5] = offset & 0xFF; + return 0; + } + + for (i = 0; i < 6; i++) { + macaddr[i] = strtol(p, (char **)&p, 16); + if (i == 5) { + if (*p != '\0') { + return -1; + } + } else { + if (*p != ':' && *p != '-') { + return -1; + } + p++; + } + } + + return 0; +} diff --git a/net/util.h b/net/util.h new file mode 100644 index 000000000..10c7da95f --- /dev/null +++ b/net/util.h @@ -0,0 +1,32 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef QEMU_NET_UTIL_H +#define QEMU_NET_UTIL_H + +#include + +int net_parse_macaddr(uint8_t *macaddr, const char *p); + +#endif /* QEMU_NET_UTIL_H */ -- cgit v1.2.3-65-gdbad From 658788c5609ccd745bb800ed156bf6f9a19398dc Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:28 +0000 Subject: net: convert xen to NICState Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/xen_nic.c | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/hw/xen_nic.c b/hw/xen_nic.c index bcf161c86..08055b83f 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -41,6 +41,7 @@ #include "hw.h" #include "net.h" #include "net/checksum.h" +#include "net/util.h" #include "qemu-char.h" #include "xen_backend.h" @@ -56,7 +57,8 @@ struct XenNetDev { struct netif_rx_sring *rxs; netif_tx_back_ring_t tx_ring; netif_rx_back_ring_t rx_ring; - VLANClientState *vs; + NICConf conf; + NICState *nic; }; /* ------------------------------------------------------------- */ @@ -179,9 +181,9 @@ static void net_tx_packets(struct XenNetDev *netdev) tmpbuf = qemu_malloc(XC_PAGE_SIZE); memcpy(tmpbuf, page + txreq.offset, txreq.size); net_checksum_calculate(tmpbuf, txreq.size); - qemu_send_packet(netdev->vs, tmpbuf, txreq.size); + qemu_send_packet(&netdev->nic->nc, tmpbuf, txreq.size); } else { - qemu_send_packet(netdev->vs, page + txreq.offset, txreq.size); + qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size); } xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); net_tx_response(netdev, &txreq, NETIF_RSP_OKAY); @@ -223,9 +225,9 @@ static void net_rx_response(struct XenNetDev *netdev, #define NET_IP_ALIGN 2 -static int net_rx_ok(VLANClientState *vc) +static int net_rx_ok(VLANClientState *nc) { - struct XenNetDev *netdev = vc->opaque; + struct XenNetDev *netdev = DO_UPCAST(NICState, nc, nc)->opaque; RING_IDX rc, rp; if (netdev->xendev.be_state != XenbusStateConnected) @@ -243,9 +245,9 @@ static int net_rx_ok(VLANClientState *vc) return 1; } -static ssize_t net_rx_packet(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t size) { - struct XenNetDev *netdev = vc->opaque; + struct XenNetDev *netdev = DO_UPCAST(NICState, nc, nc)->opaque; netif_rx_request_t rxreq; RING_IDX rc, rp; void *page; @@ -288,10 +290,16 @@ static ssize_t net_rx_packet(VLANClientState *vc, const uint8_t *buf, size_t siz /* ------------------------------------------------------------- */ +static NetClientInfo net_xen_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = net_rx_ok, + .receive = net_rx_packet, +}; + static int net_init(struct XenDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); - VLANState *vlan; /* read xenstore entries */ if (netdev->mac == NULL) @@ -301,12 +309,16 @@ static int net_init(struct XenDevice *xendev) if (netdev->mac == NULL) return -1; - vlan = qemu_find_vlan(netdev->xendev.dev, 1); - netdev->vs = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC, - vlan, NULL, "xen", NULL, - net_rx_ok, net_rx_packet, NULL, NULL, - NULL, netdev); - snprintf(netdev->vs->info_str, sizeof(netdev->vs->info_str), + if (net_parse_macaddr(netdev->conf.macaddr.a, netdev->mac) < 0) + return -1; + + netdev->conf.vlan = qemu_find_vlan(netdev->xendev.dev, 1); + netdev->conf.peer = NULL; + + netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf, + "xen", NULL, netdev); + + snprintf(netdev->nic->nc.info_str, sizeof(netdev->nic->nc.info_str), "nic: xenbus vif macaddr=%s", netdev->mac); /* fill info */ @@ -376,9 +388,9 @@ static void net_disconnect(struct XenDevice *xendev) xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1); netdev->rxs = NULL; } - if (netdev->vs) { - qemu_del_vlan_client(netdev->vs); - netdev->vs = NULL; + if (netdev->nic) { + qemu_del_vlan_client(&netdev->nic->nc); + netdev->nic = NULL; } } -- cgit v1.2.3-65-gdbad From 68da46eeb6cbe60b03f7afcb4e3cd1b5f14cc259 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:29 +0000 Subject: net: remove qemu_new_vlan_client() ... and VLANClientState::opaque and qemu_find_vlan_client(). All of these are now unused Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net.c | 44 -------------------------------------------- net.h | 13 ------------- 2 files changed, 57 deletions(-) diff --git a/net.c b/net.c index cca008a91..d77320be8 100644 --- a/net.c +++ b/net.c @@ -283,37 +283,6 @@ NICState *qemu_new_nic(NetClientInfo *info, return nic; } -VLANClientState *qemu_new_vlan_client(net_client_type type, - VLANState *vlan, - VLANClientState *peer, - const char *model, - const char *name, - NetCanReceive *can_receive, - NetReceive *receive, - NetReceive *receive_raw, - NetReceiveIOV *receive_iov, - NetCleanup *cleanup, - void *opaque) -{ - VLANClientState *ret; - NetClientInfo info; - - info.type = type; - info.size = sizeof(VLANClientState); - info.can_receive = can_receive; - info.receive = receive; - info.receive_raw = receive_raw; - info.receive_iov = receive_iov; - info.cleanup = cleanup; - info.link_status_changed = NULL; - - ret = qemu_new_net_client(&info, vlan, peer, model, name); - - ret->opaque = opaque; - - return ret; -} - void qemu_del_vlan_client(VLANClientState *vc) { if (vc->vlan) { @@ -337,19 +306,6 @@ void qemu_del_vlan_client(VLANClientState *vc) qemu_free(vc); } -VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque) -{ - VLANClientState *vc; - - QTAILQ_FOREACH(vc, &vlan->clients, next) { - if (vc->opaque == opaque) { - return vc; - } - } - - return NULL; -} - VLANClientState * qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, const char *client_str) diff --git a/net.h b/net.h index 4de20de35..9185bcf79 100644 --- a/net.h +++ b/net.h @@ -64,7 +64,6 @@ struct VLANClientState { NetCleanup *cleanup; LinkStatusChanged *link_status_changed; int link_down; - void *opaque; QTAILQ_ENTRY(VLANClientState) next; struct VLANState *vlan; VLANClientState *peer; @@ -101,19 +100,7 @@ NICState *qemu_new_nic(NetClientInfo *info, const char *model, const char *name, void *opaque); -VLANClientState *qemu_new_vlan_client(net_client_type type, - VLANState *vlan, - VLANClientState *peer, - const char *model, - const char *name, - NetCanReceive *can_receive, - NetReceive *receive, - NetReceive *receive_raw, - NetReceiveIOV *receive_iov, - NetCleanup *cleanup, - void *opaque); void qemu_del_vlan_client(VLANClientState *vc); -VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque); VLANClientState *qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, const char *client_str); int qemu_can_send_packet(VLANClientState *vc); -- cgit v1.2.3-65-gdbad From 665a3b071dc6351f9d1840dc50f7cda80bca5f40 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:30 +0000 Subject: net: remove VLANClientState members now in NetClientInfo Add a NetClientInfo pointer to VLANClientState and use that for the typecode and function pointers. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- hw/dp8393x.c | 4 ++-- hw/virtio-net.c | 2 +- net.c | 45 ++++++++++++++++++++------------------------- net.h | 10 +--------- net/tap.c | 6 +++--- 5 files changed, 27 insertions(+), 40 deletions(-) diff --git a/hw/dp8393x.c b/hw/dp8393x.c index be9714dec..e65e4d153 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -407,9 +407,9 @@ static void do_transmit_packets(dp8393xState *s) if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) { /* Loopback */ s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; - if (s->nic->nc.can_receive(&s->nic->nc)) { + if (s->nic->nc.info->can_receive(&s->nic->nc)) { s->loopback_packet = 1; - s->nic->nc.receive(&s->nic->nc, s->tx_buffer, tx_len); + s->nic->nc.info->receive(&s->nic->nc, s->tx_buffer, tx_len); } } else { /* Transmit packet */ diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 4f8d89e25..2f201ffc7 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -129,7 +129,7 @@ static int peer_has_vnet_hdr(VirtIONet *n) if (!n->nic->nc.peer) return 0; - if (n->nic->nc.peer->type != NET_CLIENT_TYPE_TAP) + if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) return 0; n->has_vnet_hdr = tap_has_vnet_hdr(n->nic->nc.peer); diff --git a/net.c b/net.c index d77320be8..a1ec2437f 100644 --- a/net.c +++ b/net.c @@ -229,19 +229,13 @@ VLANClientState *qemu_new_net_client(NetClientInfo *info, vc = qemu_mallocz(info->size); - vc->type = info->type; + vc->info = info; vc->model = qemu_strdup(model); if (name) { vc->name = qemu_strdup(name); } else { vc->name = assign_name(vc, model); } - vc->can_receive = info->can_receive; - vc->receive = info->receive; - vc->receive_raw = info->receive_raw; - vc->receive_iov = info->receive_iov; - vc->cleanup = info->cleanup; - vc->link_status_changed = info->link_status_changed; if (vlan) { assert(!peer); @@ -297,8 +291,8 @@ void qemu_del_vlan_client(VLANClientState *vc) } } - if (vc->cleanup) { - vc->cleanup(vc); + if (vc->info->cleanup) { + vc->info->cleanup(vc); } qemu_free(vc->name); @@ -340,8 +334,8 @@ int qemu_can_send_packet(VLANClientState *sender) if (sender->peer) { if (sender->peer->receive_disabled) { return 0; - } else if (sender->peer->can_receive && - !sender->peer->can_receive(sender->peer)) { + } else if (sender->peer->info->can_receive && + !sender->peer->info->can_receive(sender->peer)) { return 0; } else { return 1; @@ -358,7 +352,7 @@ int qemu_can_send_packet(VLANClientState *sender) } /* no can_receive() handler, they can always receive */ - if (!vc->can_receive || vc->can_receive(vc)) { + if (!vc->info->can_receive || vc->info->can_receive(vc)) { return 1; } } @@ -382,10 +376,10 @@ static ssize_t qemu_deliver_packet(VLANClientState *sender, return 0; } - if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw) { - ret = vc->receive_raw(vc, data, size); + if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->info->receive_raw) { + ret = vc->info->receive_raw(vc, data, size); } else { - ret = vc->receive(vc, data, size); + ret = vc->info->receive(vc, data, size); } if (ret == 0) { @@ -422,10 +416,10 @@ static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender, continue; } - if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw) { - len = vc->receive_raw(vc, buf, size); + if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->info->receive_raw) { + len = vc->info->receive_raw(vc, buf, size); } else { - len = vc->receive(vc, buf, size); + len = vc->info->receive(vc, buf, size); } if (len == 0) { @@ -530,7 +524,7 @@ static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov, offset += len; } - return vc->receive(vc, buffer, offset); + return vc->info->receive(vc, buffer, offset); } static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) @@ -555,8 +549,8 @@ static ssize_t qemu_deliver_packet_iov(VLANClientState *sender, return calc_iov_length(iov, iovcnt); } - if (vc->receive_iov) { - return vc->receive_iov(vc, iov, iovcnt); + if (vc->info->receive_iov) { + return vc->info->receive_iov(vc, iov, iovcnt); } else { return vc_sendv_compat(vc, iov, iovcnt); } @@ -586,8 +580,8 @@ static ssize_t qemu_vlan_deliver_packet_iov(VLANClientState *sender, assert(!(flags & QEMU_NET_PACKET_FLAG_RAW)); - if (vc->receive_iov) { - len = vc->receive_iov(vc, iov, iovcnt); + if (vc->info->receive_iov) { + len = vc->info->receive_iov(vc, iov, iovcnt); } else { len = vc_sendv_compat(vc, iov, iovcnt); } @@ -1246,8 +1240,9 @@ done: monitor_printf(mon, "invalid link status '%s'; only 'up' or 'down' " "valid\n", up_or_down); - if (vc->link_status_changed) - vc->link_status_changed(vc); + if (vc->info->link_status_changed) { + vc->info->link_status_changed(vc); + } } void net_cleanup(void) diff --git a/net.h b/net.h index 9185bcf79..497a7373f 100644 --- a/net.h +++ b/net.h @@ -54,15 +54,7 @@ typedef struct NetClientInfo { } NetClientInfo; struct VLANClientState { - net_client_type type; - NetReceive *receive; - NetReceive *receive_raw; - NetReceiveIOV *receive_iov; - /* Packets may still be sent if this returns zero. It's used to - rate-limit the slirp code. */ - NetCanReceive *can_receive; - NetCleanup *cleanup; - LinkStatusChanged *link_status_changed; + NetClientInfo *info; int link_down; QTAILQ_ENTRY(VLANClientState) next; struct VLANState *vlan; diff --git a/net/tap.c b/net/tap.c index d34feecd7..a327a9a6b 100644 --- a/net/tap.c +++ b/net/tap.c @@ -214,7 +214,7 @@ int tap_has_ufo(VLANClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_TYPE_TAP); return s->has_ufo; } @@ -223,7 +223,7 @@ int tap_has_vnet_hdr(VLANClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_TYPE_TAP); return s->has_vnet_hdr; } @@ -234,7 +234,7 @@ void tap_using_vnet_hdr(VLANClientState *nc, int using_vnet_hdr) using_vnet_hdr = using_vnet_hdr != 0; - assert(nc->type == NET_CLIENT_TYPE_TAP); + assert(nc->info->type == NET_CLIENT_TYPE_TAP); assert(s->has_vnet_hdr == using_vnet_hdr); s->using_vnet_hdr = using_vnet_hdr; -- cgit v1.2.3-65-gdbad From 57f9ef173d940ec5c2d04a9d1a37b4c86c9f5b27 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:31 +0000 Subject: net: add qemu_foreach_nic() Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net.c | 20 ++++++++++++++++++++ net.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/net.c b/net.c index a1ec2437f..c71699de2 100644 --- a/net.c +++ b/net.c @@ -326,6 +326,26 @@ qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, return vc; } +void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) +{ + VLANClientState *nc; + VLANState *vlan; + + QTAILQ_FOREACH(nc, &non_vlan_clients, next) { + if (nc->info->type == NET_CLIENT_TYPE_NIC) { + func(DO_UPCAST(NICState, nc, nc), opaque); + } + } + + QTAILQ_FOREACH(vlan, &vlans, next) { + QTAILQ_FOREACH(nc, &vlan->clients, next) { + if (nc->info->type == NET_CLIENT_TYPE_NIC) { + func(DO_UPCAST(NICState, nc, nc), opaque); + } + } + } +} + int qemu_can_send_packet(VLANClientState *sender) { VLANState *vlan = sender->vlan; diff --git a/net.h b/net.h index 497a7373f..d583d590a 100644 --- a/net.h +++ b/net.h @@ -95,6 +95,8 @@ NICState *qemu_new_nic(NetClientInfo *info, void qemu_del_vlan_client(VLANClientState *vc); VLANClientState *qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, const char *client_str); +typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque); +void qemu_foreach_nic(qemu_nic_foreach func, void *opaque); int qemu_can_send_packet(VLANClientState *vc); ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt); -- cgit v1.2.3-65-gdbad From f401ca22d872e93fd5f12c99ffcb4f1261bb46b9 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:32 +0000 Subject: net: fix qemu_announce_self() Now that we have a way to iterate NICs. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- savevm.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/savevm.c b/savevm.c index 18c2e5486..d6da050f3 100644 --- a/savevm.c +++ b/savevm.c @@ -120,24 +120,24 @@ static int announce_self_create(uint8_t *buf, return 60; /* len (FCS will be added by hardware) */ } -static void qemu_announce_self_once(void *opaque) +static void qemu_announce_self_iter(NICState *nic, void *opaque) { - int i, len; - VLANState *vlan; - VLANClientState *vc; uint8_t buf[60]; + int len; + + len = announce_self_create(buf, nic->conf->macaddr.a); + + qemu_send_packet_raw(&nic->nc, buf, len); +} + + +static void qemu_announce_self_once(void *opaque) +{ static int count = SELF_ANNOUNCE_ROUNDS; QEMUTimer *timer = *(QEMUTimer **)opaque; - for (i = 0; i < MAX_NICS; i++) { - if (!nd_table[i].used) - continue; - len = announce_self_create(buf, nd_table[i].macaddr); - vlan = nd_table[i].vlan; - QTAILQ_FOREACH(vc, &vlan->clients, next) { - qemu_send_packet_raw(vc, buf, len); - } - } + qemu_foreach_nic(qemu_announce_self_iter, NULL); + if (--count) { /* delay 50ms, 150ms, 250ms, ... */ qemu_mod_timer(timer, qemu_get_clock(rt_clock) + -- cgit v1.2.3-65-gdbad From 0f2fbf40a9d1f0ccdd86bd47f17fff24666f01d9 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:33 +0000 Subject: net: print correct error for '-netdev ""' Reported-by: Markus Armbruster Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/net.c b/net.c index c71699de2..13bdbb2ca 100644 --- a/net.c +++ b/net.c @@ -1055,12 +1055,18 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) int i; type = qemu_opt_get(opts, "type"); - if (!type) { - qemu_error("No type specified for -net\n"); - return -1; - } - if (is_netdev) { + if (!is_netdev) { + if (!type) { + qemu_error("No type specified for -net\n"); + return -1; + } + } else { + if (!type) { + qemu_error("No type specified for -netdev\n"); + return -1; + } + if (strcmp(type, "tap") != 0 && #ifdef CONFIG_SLIRP strcmp(type, "user") != 0 && -- cgit v1.2.3-65-gdbad From 6720b35b8186e9c6a9f137c02f8c2c1e7c98085f Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Wed, 25 Nov 2009 18:49:34 +0000 Subject: net: fix TAP networking on host kernels without IFF_VNET_HDR support vnet_hdr is initialized at 1 by default. We need to reset it to 0 if the kernel doesn't support IFF_VNET_HDR. Signed-off-by: Pierre Riteau Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/tap-linux.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/tap-linux.c b/net/tap-linux.c index 0f621a231..e4f7e2723 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -52,6 +52,8 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required features & IFF_VNET_HDR) { *vnet_hdr = 1; ifr.ifr_flags |= IFF_VNET_HDR; + } else { + *vnet_hdr = 0; } if (vnet_hdr_required && !*vnet_hdr) { -- cgit v1.2.3-65-gdbad From 2e50326c44c802ca9b9d591341085e49208927be Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Wed, 25 Nov 2009 18:49:35 +0000 Subject: net: check for TUNSETOFFLOAD support before trying to enable offload features This avoids the "TUNSETOFFLOAD ioctl() failed: Invalid argument" message on kernels without TUNSETOFFLOAD support. Signed-off-by: Pierre Riteau Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/tap-linux.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/tap-linux.c b/net/tap-linux.c index e4f7e2723..6af9e824d 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -131,6 +131,11 @@ void tap_fd_set_offload(int fd, int csum, int tso4, { unsigned int offload = 0; + /* Check if our kernel supports TUNSETOFFLOAD */ + if (ioctl(fd, TUNSETOFFLOAD, 0) != 0 && errno == EINVAL) { + return; + } + if (csum) { offload |= TUN_F_CSUM; if (tso4) -- cgit v1.2.3-65-gdbad From df6c2a0fb2f498f488a391c5da13e7cd4de5083e Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:36 +0000 Subject: net: initialize vnet_hdr in net_init_tap() net_tap_init() always sets vnet_hdr using qemu_opt_get_bool(), but initialize it in net_init_tap() just to reduce confusion. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/tap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tap.c b/net/tap.c index a327a9a6b..0d8b42412 100644 --- a/net/tap.c +++ b/net/tap.c @@ -378,7 +378,7 @@ static int net_tap_init(QemuOpts *opts, int *vnet_hdr) int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan) { TAPState *s; - int fd, vnet_hdr; + int fd, vnet_hdr = 0; if (qemu_opt_get(opts, "fd")) { if (qemu_opt_get(opts, "ifname") || -- cgit v1.2.3-65-gdbad From f5c5e38179aff8cc9bb8bd4c9fe42966f0e9f9fd Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 25 Nov 2009 18:49:37 +0000 Subject: net: fix vnet_hdr handling in solaris tap code Print an error if the user specifies vnet_hdr=1 on the cmdline. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori --- net/tap-solaris.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/tap-solaris.c b/net/tap-solaris.c index ef4e60c87..e14fe36fd 100644 --- a/net/tap-solaris.c +++ b/net/tap-solaris.c @@ -180,6 +180,17 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required return -1; } pstrcpy(ifname, ifname_size, dev); + if (*vnet_hdr) { + /* Solaris doesn't have IFF_VNET_HDR */ + *vnet_hdr = 0; + + if (vnet_hdr_required && !*vnet_hdr) { + qemu_error("vnet_hdr=1 requested, but no kernel " + "support for IFF_VNET_HDR available"); + close(fd); + return -1; + } + } fcntl(fd, F_SETFL, O_NONBLOCK); return fd; } -- cgit v1.2.3-65-gdbad From 1e37607b5e32dc5f4ee422ae45da4de659db0691 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:47 +0100 Subject: scsi: add/fix header protection. Also delete the leftover and unused scsi-disk.h file. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/esp.h | 5 +++++ hw/scsi-disk.h | 67 ---------------------------------------------------------- hw/scsi.h | 4 ++-- 3 files changed, 7 insertions(+), 69 deletions(-) delete mode 100644 hw/scsi-disk.h diff --git a/hw/esp.h b/hw/esp.h index 369998f83..190bc2e26 100644 --- a/hw/esp.h +++ b/hw/esp.h @@ -1,3 +1,6 @@ +#ifndef QEMU_HW_ESP_H +#define QEMU_HW_ESP_H + /* esp.c */ #define ESP_MAX_DEVS 7 typedef void (*espdma_memory_read_write)(void *opaque, uint8_t *buf, int len); @@ -5,3 +8,5 @@ void esp_init(target_phys_addr_t espaddr, int it_shift, espdma_memory_read_write dma_memory_read, espdma_memory_read_write dma_memory_write, void *dma_opaque, qemu_irq irq, qemu_irq *reset); + +#endif diff --git a/hw/scsi-disk.h b/hw/scsi-disk.h deleted file mode 100644 index b6b6c1266..000000000 --- a/hw/scsi-disk.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef SCSI_DISK_H -#define SCSI_DISK_H - -#include "qdev.h" - -/* scsi-disk.c */ -enum scsi_reason { - SCSI_REASON_DONE, /* Command complete. */ - SCSI_REASON_DATA /* Transfer complete, more data required. */ -}; - -typedef struct SCSIBus SCSIBus; -typedef struct SCSIDevice SCSIDevice; -typedef struct SCSIDeviceInfo SCSIDeviceInfo; -typedef void (*scsi_completionfn)(SCSIBus *bus, int reason, uint32_t tag, - uint32_t arg); - -struct SCSIDevice -{ - DeviceState qdev; - uint32_t id; - SCSIDeviceInfo *info; -}; - -/* cdrom.c */ -int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); -int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); - -/* scsi-bus.c */ -typedef int (*scsi_qdev_initfn)(SCSIDevice *dev); -struct SCSIDeviceInfo { - DeviceInfo qdev; - scsi_qdev_initfn init; - void (*destroy)(SCSIDevice *s); - int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf, - int lun); - void (*read_data)(SCSIDevice *s, uint32_t tag); - int (*write_data)(SCSIDevice *s, uint32_t tag); - void (*cancel_io)(SCSIDevice *s, uint32_t tag); - uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag); -}; - -typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv, - int unit); -struct SCSIBus { - BusState qbus; - int busnr; - - int tcq, ndev; - scsi_completionfn complete; - - SCSIDevice *devs[8]; -}; - -void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev, - scsi_completionfn complete); -void scsi_qdev_register(SCSIDeviceInfo *info); - -static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) -{ - return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); -} - -SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, DriveInfo *dinfo, int unit); -void scsi_bus_legacy_handle_cmdline(SCSIBus *bus); - -#endif diff --git a/hw/scsi.h b/hw/scsi.h index b6b6c1266..d2b274cfd 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -1,5 +1,5 @@ -#ifndef SCSI_DISK_H -#define SCSI_DISK_H +#ifndef QEMU_HW_SCSI_H +#define QEMU_HW_SCSI_H #include "qdev.h" -- cgit v1.2.3-65-gdbad From 4c41d2ef5f599372a35d446fb75898fe9841bda4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:48 +0100 Subject: scsi: create common SCSIRequest structure. Rename the SCSIRequest structs in scsi-disk.c and scsi-generic.c to SCSIDiskReq and SCSIGenericReq. Create a SCSIRequest struct and move the common elements over. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 109 +++++++++++++++++++++++++++--------------------------- hw/scsi-generic.c | 104 +++++++++++++++++++++++++-------------------------- hw/scsi.h | 8 ++++ 3 files changed, 114 insertions(+), 107 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index a92b62f01..142d81dfd 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -46,10 +46,8 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) typedef struct SCSIDiskState SCSIDiskState; -typedef struct SCSIRequest { - SCSIBus *bus; - SCSIDiskState *dev; - uint32_t tag; +typedef struct SCSIDiskReq { + SCSIRequest req; /* ??? We should probably keep track of whether the data transfer is a read or a write. Currently we rely on the host getting it right. */ /* Both sector and sector_count are in terms of qemu 512 byte blocks. */ @@ -57,16 +55,15 @@ typedef struct SCSIRequest { uint32_t sector_count; struct iovec iov; QEMUIOVector qiov; - BlockDriverAIOCB *aiocb; - struct SCSIRequest *next; + struct SCSIDiskReq *next; uint32_t status; -} SCSIRequest; +} SCSIDiskReq; struct SCSIDiskState { SCSIDevice qdev; DriveInfo *dinfo; - SCSIRequest *requests; + SCSIDiskReq *requests; /* The qemu block layer uses a fixed 512 byte sector size. This is the number of 512 byte blocks in a single scsi sector. */ int cluster_size; @@ -77,26 +74,26 @@ struct SCSIDiskState }; /* Global pool of SCSIRequest structures. */ -static SCSIRequest *free_requests = NULL; +static SCSIDiskReq *free_requests = NULL; -static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag) +static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIRequest *r; + SCSIDiskReq *r; if (free_requests) { r = free_requests; free_requests = r->next; } else { - r = qemu_malloc(sizeof(SCSIRequest)); + r = qemu_malloc(sizeof(SCSIDiskReq)); r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE); } - r->bus = scsi_bus_from_device(d); - r->dev = s; - r->tag = tag; + r->req.bus = scsi_bus_from_device(d); + r->req.dev = d; + r->req.tag = tag; r->sector_count = 0; r->iov.iov_len = 0; - r->aiocb = NULL; + r->req.aiocb = NULL; r->status = 0; r->next = s->requests; @@ -104,10 +101,10 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag) return r; } -static void scsi_remove_request(SCSIRequest *r) +static void scsi_remove_request(SCSIDiskReq *r) { - SCSIRequest *last; - SCSIDiskState *s = r->dev; + SCSIDiskReq *last; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); if (s->requests == r) { s->requests = r->next; @@ -125,64 +122,65 @@ static void scsi_remove_request(SCSIRequest *r) free_requests = r; } -static SCSIRequest *scsi_find_request(SCSIDiskState *s, uint32_t tag) +static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag) { - SCSIRequest *r; + SCSIDiskReq *r; r = s->requests; - while (r && r->tag != tag) + while (r && r->req.tag != tag) r = r->next; return r; } /* Helper function for command completion. */ -static void scsi_command_complete(SCSIRequest *r, int status, int sense) +static void scsi_command_complete(SCSIDiskReq *r, int status, int sense) { - SCSIDiskState *s = r->dev; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint32_t tag; - DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->tag, status, sense); + DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", + r->req.tag, status, sense); s->sense = sense; - tag = r->tag; + tag = r->req.tag; scsi_remove_request(r); - r->bus->complete(r->bus, SCSI_REASON_DONE, tag, status); + r->req.bus->complete(r->req.bus, SCSI_REASON_DONE, tag, status); } /* Cancel a pending data transfer. */ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIRequest *r; + SCSIDiskReq *r; DPRINTF("Cancel tag=0x%x\n", tag); r = scsi_find_request(s, tag); if (r) { - if (r->aiocb) - bdrv_aio_cancel(r->aiocb); - r->aiocb = NULL; + if (r->req.aiocb) + bdrv_aio_cancel(r->req.aiocb); + r->req.aiocb = NULL; scsi_remove_request(r); } } static void scsi_read_complete(void * opaque, int ret) { - SCSIRequest *r = (SCSIRequest *)opaque; + SCSIDiskReq *r = (SCSIDiskReq *)opaque; if (ret) { DPRINTF("IO error\n"); - r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, 0); + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE); return; } - DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->tag, r->iov.iov_len); + DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->req.tag, r->iov.iov_len); - r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->iov.iov_len); + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len); } /* Read more data from scsi device into buffer. */ static void scsi_read_data(SCSIDevice *d, uint32_t tag) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIRequest *r; + SCSIDiskReq *r; uint32_t n; r = scsi_find_request(s, tag); @@ -195,7 +193,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) if (r->sector_count == (uint32_t)-1) { DPRINTF("Read buf_len=%" PRId64 "\n", r->iov.iov_len); r->sector_count = 0; - r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->iov.iov_len); + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len); return; } DPRINTF("Read sector_count=%d\n", r->sector_count); @@ -210,17 +208,18 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) r->iov.iov_len = n * 512; qemu_iovec_init_external(&r->qiov, &r->iov, 1); - r->aiocb = bdrv_aio_readv(s->dinfo->bdrv, r->sector, &r->qiov, n, + r->req.aiocb = bdrv_aio_readv(s->dinfo->bdrv, r->sector, &r->qiov, n, scsi_read_complete, r); - if (r->aiocb == NULL) + if (r->req.aiocb == NULL) scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); r->sector += n; r->sector_count -= n; } -static int scsi_handle_write_error(SCSIRequest *r, int error) +static int scsi_handle_write_error(SCSIDiskReq *r, int error) { - BlockInterfaceErrorAction action = drive_get_onerror(r->dev->dinfo->bdrv); + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + BlockInterfaceErrorAction action = drive_get_onerror(s->dinfo->bdrv); if (action == BLOCK_ERR_IGNORE) return 0; @@ -239,11 +238,11 @@ static int scsi_handle_write_error(SCSIRequest *r, int error) static void scsi_write_complete(void * opaque, int ret) { - SCSIRequest *r = (SCSIRequest *)opaque; + SCSIDiskReq *r = (SCSIDiskReq *)opaque; uint32_t len; uint32_t n; - r->aiocb = NULL; + r->req.aiocb = NULL; if (ret) { if (scsi_handle_write_error(r, -ret)) @@ -261,22 +260,22 @@ static void scsi_write_complete(void * opaque, int ret) len = SCSI_DMA_BUF_SIZE; } r->iov.iov_len = len; - DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len); - r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, len); + DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len); + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len); } } -static void scsi_write_request(SCSIRequest *r) +static void scsi_write_request(SCSIDiskReq *r) { - SCSIDiskState *s = r->dev; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint32_t n; n = r->iov.iov_len / 512; if (n) { qemu_iovec_init_external(&r->qiov, &r->iov, 1); - r->aiocb = bdrv_aio_writev(s->dinfo->bdrv, r->sector, &r->qiov, n, + r->req.aiocb = bdrv_aio_writev(s->dinfo->bdrv, r->sector, &r->qiov, n, scsi_write_complete, r); - if (r->aiocb == NULL) + if (r->req.aiocb == NULL) scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); } else { @@ -290,7 +289,7 @@ static void scsi_write_request(SCSIRequest *r) static int scsi_write_data(SCSIDevice *d, uint32_t tag) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIRequest *r; + SCSIDiskReq *r; DPRINTF("Write data tag=0x%x\n", tag); r = scsi_find_request(s, tag); @@ -300,7 +299,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) return 1; } - if (r->aiocb) + if (r->req.aiocb) BADF("Data transfer already in progress\n"); scsi_write_request(r); @@ -311,7 +310,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) static void scsi_dma_restart_bh(void *opaque) { SCSIDiskState *s = opaque; - SCSIRequest *r = s->requests; + SCSIDiskReq *r = s->requests; qemu_bh_delete(s->bh); s->bh = NULL; @@ -342,7 +341,7 @@ static void scsi_dma_restart_cb(void *opaque, int running, int reason) static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIRequest *r; + SCSIDiskReq *r; r = scsi_find_request(s, tag); if (!r) { @@ -368,7 +367,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, int is_write; uint8_t command; uint8_t *outbuf; - SCSIRequest *r; + SCSIDiskReq *r; command = buf[0]; r = scsi_find_request(s, tag); @@ -606,7 +605,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf[3] = 2; /* Format 2 */ outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */ /* Sync data transfer and TCQ. */ - outbuf[7] = 0x10 | (r->bus->tcq ? 0x02 : 0); + outbuf[7] = 0x10 | (r->req.bus->tcq ? 0x02 : 0); r->iov.iov_len = len; break; case 0x16: diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index cf56ea0f2..a7aa1f09f 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -54,24 +54,21 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) typedef struct SCSIGenericState SCSIGenericState; -typedef struct SCSIRequest { - BlockDriverAIOCB *aiocb; - struct SCSIRequest *next; - SCSIBus *bus; - SCSIGenericState *dev; - uint32_t tag; +typedef struct SCSIGenericReq { + SCSIRequest req; + struct SCSIGenericReq *next; uint8_t cmd[SCSI_CMD_BUF_SIZE]; int cmdlen; uint8_t *buf; int buflen; int len; sg_io_hdr_t io_header; -} SCSIRequest; +} SCSIGenericReq; struct SCSIGenericState { SCSIDevice qdev; - SCSIRequest *requests; + SCSIGenericReq *requests; DriveInfo *dinfo; int type; int blocksize; @@ -81,30 +78,30 @@ struct SCSIGenericState uint8_t senselen; }; -/* Global pool of SCSIRequest structures. */ -static SCSIRequest *free_requests = NULL; +/* Global pool of SCSIGenericReq structures. */ +static SCSIGenericReq *free_requests = NULL; -static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag) +static SCSIGenericReq *scsi_new_request(SCSIDevice *d, uint32_t tag) { SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIRequest *r; + SCSIGenericReq *r; if (free_requests) { r = free_requests; free_requests = r->next; } else { - r = qemu_malloc(sizeof(SCSIRequest)); + r = qemu_malloc(sizeof(SCSIGenericReq)); r->buf = NULL; r->buflen = 0; } - r->bus = scsi_bus_from_device(d); - r->dev = s; - r->tag = tag; + r->req.bus = scsi_bus_from_device(d); + r->req.dev = d; + r->req.tag = tag; memset(r->cmd, 0, sizeof(r->cmd)); memset(&r->io_header, 0, sizeof(r->io_header)); r->cmdlen = 0; r->len = 0; - r->aiocb = NULL; + r->req.aiocb = NULL; /* link */ @@ -113,10 +110,10 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag) return r; } -static void scsi_remove_request(SCSIRequest *r) +static void scsi_remove_request(SCSIGenericReq *r) { - SCSIRequest *last; - SCSIGenericState *s = r->dev; + SCSIGenericReq *last; + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); if (s->requests == r) { s->requests = r->next; @@ -134,12 +131,12 @@ static void scsi_remove_request(SCSIRequest *r) free_requests = r; } -static SCSIRequest *scsi_find_request(SCSIGenericState *s, uint32_t tag) +static SCSIGenericReq *scsi_find_request(SCSIGenericState *s, uint32_t tag) { - SCSIRequest *r; + SCSIGenericReq *r; r = s->requests; - while (r && r->tag != tag) + while (r && r->req.tag != tag) r = r->next; return r; @@ -148,8 +145,8 @@ static SCSIRequest *scsi_find_request(SCSIGenericState *s, uint32_t tag) /* Helper function for command completion. */ static void scsi_command_complete(void *opaque, int ret) { - SCSIRequest *r = (SCSIRequest *)opaque; - SCSIGenericState *s = r->dev; + SCSIGenericReq *r = (SCSIGenericReq *)opaque; + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); uint32_t tag; int status; @@ -171,10 +168,10 @@ static void scsi_command_complete(void *opaque, int ret) status = GOOD << 1; } DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", - r, r->tag, status); - tag = r->tag; + r, r->req.tag, status); + tag = r->req.tag; scsi_remove_request(r); - r->bus->complete(r->bus, SCSI_REASON_DONE, tag, status); + r->req.bus->complete(r->req.bus, SCSI_REASON_DONE, tag, status); } /* Cancel a pending data transfer. */ @@ -182,35 +179,37 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) { DPRINTF("scsi_cancel_io 0x%x\n", tag); SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIRequest *r; + SCSIGenericReq *r; DPRINTF("Cancel tag=0x%x\n", tag); r = scsi_find_request(s, tag); if (r) { - if (r->aiocb) - bdrv_aio_cancel(r->aiocb); - r->aiocb = NULL; + if (r->req.aiocb) + bdrv_aio_cancel(r->req.aiocb); + r->req.aiocb = NULL; scsi_remove_request(r); } } static int execute_command(BlockDriverState *bdrv, - SCSIRequest *r, int direction, + SCSIGenericReq *r, int direction, BlockDriverCompletionFunc *complete) { + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); + r->io_header.interface_id = 'S'; r->io_header.dxfer_direction = direction; r->io_header.dxferp = r->buf; r->io_header.dxfer_len = r->buflen; r->io_header.cmdp = r->cmd; r->io_header.cmd_len = r->cmdlen; - r->io_header.mx_sb_len = sizeof(r->dev->sensebuf); - r->io_header.sbp = r->dev->sensebuf; + r->io_header.mx_sb_len = sizeof(s->sensebuf); + r->io_header.sbp = s->sensebuf; r->io_header.timeout = MAX_UINT; r->io_header.usr_ptr = r; r->io_header.flags |= SG_FLAG_DIRECT_IO; - r->aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r); - if (r->aiocb == NULL) { + r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r); + if (r->req.aiocb == NULL) { BADF("execute_command: read failed !\n"); return -1; } @@ -220,7 +219,7 @@ static int execute_command(BlockDriverState *bdrv, static void scsi_read_complete(void * opaque, int ret) { - SCSIRequest *r = (SCSIRequest *)opaque; + SCSIGenericReq *r = (SCSIGenericReq *)opaque; int len; if (ret) { @@ -229,10 +228,10 @@ static void scsi_read_complete(void * opaque, int ret) return; } len = r->io_header.dxfer_len - r->io_header.resid; - DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, len); + DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len); r->len = -1; - r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, len); + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len); if (len == 0) scsi_command_complete(r, 0); } @@ -241,7 +240,7 @@ static void scsi_read_complete(void * opaque, int ret) static void scsi_read_data(SCSIDevice *d, uint32_t tag) { SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIRequest *r; + SCSIGenericReq *r; int ret; DPRINTF("scsi_read_data 0x%x\n", tag); @@ -266,11 +265,11 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) r->io_header.status = 0; r->io_header.dxfer_len = s->senselen; r->len = -1; - DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, s->senselen); + DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, s->senselen); DPRINTF("Sense: %d %d %d %d %d %d %d %d\n", r->buf[0], r->buf[1], r->buf[2], r->buf[3], r->buf[4], r->buf[5], r->buf[6], r->buf[7]); - r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, s->senselen); + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, s->senselen); return; } @@ -283,7 +282,8 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) static void scsi_write_complete(void * opaque, int ret) { - SCSIRequest *r = (SCSIRequest *)opaque; + SCSIGenericReq *r = (SCSIGenericReq *)opaque; + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); DPRINTF("scsi_write_complete() ret = %d\n", ret); if (ret) { @@ -293,9 +293,9 @@ static void scsi_write_complete(void * opaque, int ret) } if (r->cmd[0] == MODE_SELECT && r->cmd[4] == 12 && - r->dev->type == TYPE_TAPE) { - r->dev->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; - DPRINTF("block size %d\n", r->dev->blocksize); + s->type == TYPE_TAPE) { + s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; + DPRINTF("block size %d\n", s->blocksize); } scsi_command_complete(r, ret); @@ -306,7 +306,7 @@ static void scsi_write_complete(void * opaque, int ret) static int scsi_write_data(SCSIDevice *d, uint32_t tag) { SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIRequest *r; + SCSIGenericReq *r; int ret; DPRINTF("scsi_write_data 0x%x\n", tag); @@ -320,7 +320,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) if (r->len == 0) { r->len = r->buflen; - r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->len); + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->len); return 0; } @@ -337,7 +337,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) { SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIRequest *r; + SCSIGenericReq *r; r = scsi_find_request(s, tag); if (!r) { BADF("Bad buffer tag 0x%x\n", tag); @@ -512,7 +512,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); uint32_t len=0; int cmdlen=0; - SCSIRequest *r; + SCSIGenericReq *r; SCSIBus *bus; int ret; @@ -653,7 +653,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv) static void scsi_destroy(SCSIDevice *d) { SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIRequest *r, *n; + SCSIGenericReq *r, *n; r = s->requests; while (r) { diff --git a/hw/scsi.h b/hw/scsi.h index d2b274cfd..7906877fd 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -2,6 +2,7 @@ #define QEMU_HW_SCSI_H #include "qdev.h" +#include "block.h" /* scsi-disk.c */ enum scsi_reason { @@ -15,6 +16,13 @@ typedef struct SCSIDeviceInfo SCSIDeviceInfo; typedef void (*scsi_completionfn)(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg); +typedef struct SCSIRequest { + SCSIBus *bus; + SCSIDevice *dev; + uint32_t tag; + BlockDriverAIOCB *aiocb; +} SCSIRequest; + struct SCSIDevice { DeviceState qdev; -- cgit v1.2.3-65-gdbad From 9af99d980e9ff6270f291b11a064087b33dd3ab8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:49 +0100 Subject: scsi: move request lists to QTAILQ. Changes: * Move from open-coded lists to QTAILQ macros. * Move the struct elements to the common data structures (SCSIDevice + SCSIRequest). * Drop free request pools. * Fix request cleanup in the destroy callback. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 1 + hw/scsi-disk.c | 67 ++++++++++++++++-------------------------------- hw/scsi-generic.c | 76 ++++++++++++------------------------------------------- hw/scsi.h | 2 ++ 4 files changed, 41 insertions(+), 105 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 641db812f..801922b7d 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -50,6 +50,7 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) bus->devs[dev->id] = dev; dev->info = info; + QTAILQ_INIT(&dev->requests); rc = dev->info->init(dev); if (rc != 0) { bus->devs[dev->id] = NULL; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 142d81dfd..997eef639 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -55,7 +55,6 @@ typedef struct SCSIDiskReq { uint32_t sector_count; struct iovec iov; QEMUIOVector qiov; - struct SCSIDiskReq *next; uint32_t status; } SCSIDiskReq; @@ -63,7 +62,6 @@ struct SCSIDiskState { SCSIDevice qdev; DriveInfo *dinfo; - SCSIDiskReq *requests; /* The qemu block layer uses a fixed 512 byte sector size. This is the number of 512 byte blocks in a single scsi sector. */ int cluster_size; @@ -73,64 +71,37 @@ struct SCSIDiskState QEMUBH *bh; }; -/* Global pool of SCSIRequest structures. */ -static SCSIDiskReq *free_requests = NULL; - static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIDiskReq *r; - if (free_requests) { - r = free_requests; - free_requests = r->next; - } else { - r = qemu_malloc(sizeof(SCSIDiskReq)); - r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE); - } + r = qemu_mallocz(sizeof(SCSIDiskReq)); + r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE); r->req.bus = scsi_bus_from_device(d); r->req.dev = d; r->req.tag = tag; - r->sector_count = 0; - r->iov.iov_len = 0; - r->req.aiocb = NULL; - r->status = 0; - r->next = s->requests; - s->requests = r; + QTAILQ_INSERT_TAIL(&d->requests, &r->req, next); return r; } static void scsi_remove_request(SCSIDiskReq *r) { - SCSIDiskReq *last; - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - - if (s->requests == r) { - s->requests = r->next; - } else { - last = s->requests; - while (last && last->next != r) - last = last->next; - if (last) { - last->next = r->next; - } else { - BADF("Orphaned request\n"); - } - } - r->next = free_requests; - free_requests = r; + qemu_free(r->iov.iov_base); + QTAILQ_REMOVE(&r->req.dev->requests, &r->req, next); + qemu_free(r); } static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag) { - SCSIDiskReq *r; - - r = s->requests; - while (r && r->req.tag != tag) - r = r->next; + SCSIRequest *req; - return r; + QTAILQ_FOREACH(req, &s->qdev.requests, next) { + if (req->tag == tag) { + return DO_UPCAST(SCSIDiskReq, req, req); + } + } + return NULL; } /* Helper function for command completion. */ @@ -310,17 +281,18 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) static void scsi_dma_restart_bh(void *opaque) { SCSIDiskState *s = opaque; - SCSIDiskReq *r = s->requests; + SCSIRequest *req; + SCSIDiskReq *r; qemu_bh_delete(s->bh); s->bh = NULL; - while (r) { + QTAILQ_FOREACH(req, &s->qdev.requests, next) { + r = DO_UPCAST(SCSIDiskReq, req, req); if (r->status & SCSI_REQ_STATUS_RETRY) { r->status &= ~SCSI_REQ_STATUS_RETRY; scsi_write_request(r); } - r = r->next; } } @@ -959,7 +931,12 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, static void scsi_destroy(SCSIDevice *dev) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); + SCSIDiskReq *r; + while (!QTAILQ_EMPTY(&s->qdev.requests)) { + r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests)); + scsi_remove_request(r); + } drive_uninit(s->dinfo); } diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index a7aa1f09f..857ccb035 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -56,7 +56,6 @@ typedef struct SCSIGenericState SCSIGenericState; typedef struct SCSIGenericReq { SCSIRequest req; - struct SCSIGenericReq *next; uint8_t cmd[SCSI_CMD_BUF_SIZE]; int cmdlen; uint8_t *buf; @@ -68,7 +67,6 @@ typedef struct SCSIGenericReq { struct SCSIGenericState { SCSIDevice qdev; - SCSIGenericReq *requests; DriveInfo *dinfo; int type; int blocksize; @@ -78,68 +76,36 @@ struct SCSIGenericState uint8_t senselen; }; -/* Global pool of SCSIGenericReq structures. */ -static SCSIGenericReq *free_requests = NULL; - static SCSIGenericReq *scsi_new_request(SCSIDevice *d, uint32_t tag) { - SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); SCSIGenericReq *r; - if (free_requests) { - r = free_requests; - free_requests = r->next; - } else { - r = qemu_malloc(sizeof(SCSIGenericReq)); - r->buf = NULL; - r->buflen = 0; - } + r = qemu_mallocz(sizeof(SCSIGenericReq)); r->req.bus = scsi_bus_from_device(d); r->req.dev = d; r->req.tag = tag; - memset(r->cmd, 0, sizeof(r->cmd)); - memset(&r->io_header, 0, sizeof(r->io_header)); - r->cmdlen = 0; - r->len = 0; - r->req.aiocb = NULL; - /* link */ - - r->next = s->requests; - s->requests = r; + QTAILQ_INSERT_TAIL(&d->requests, &r->req, next); return r; } static void scsi_remove_request(SCSIGenericReq *r) { - SCSIGenericReq *last; - SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); - - if (s->requests == r) { - s->requests = r->next; - } else { - last = s->requests; - while (last && last->next != r) - last = last->next; - if (last) { - last->next = r->next; - } else { - BADF("Orphaned request\n"); - } - } - r->next = free_requests; - free_requests = r; + qemu_free(r->buf); + QTAILQ_REMOVE(&r->req.dev->requests, &r->req, next); + qemu_free(r); } static SCSIGenericReq *scsi_find_request(SCSIGenericState *s, uint32_t tag) { - SCSIGenericReq *r; - - r = s->requests; - while (r && r->req.tag != tag) - r = r->next; + SCSIRequest *req; - return r; + QTAILQ_FOREACH(req, &s->qdev.requests, next) { + if (req->tag == tag) { + return DO_UPCAST(SCSIGenericReq, req, req); + } + } + return NULL; } /* Helper function for command completion. */ @@ -653,22 +619,12 @@ static int get_stream_blocksize(BlockDriverState *bdrv) static void scsi_destroy(SCSIDevice *d) { SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIGenericReq *r, *n; - - r = s->requests; - while (r) { - n = r->next; - qemu_free(r); - r = n; - } + SCSIGenericReq *r; - r = free_requests; - while (r) { - n = r->next; - qemu_free(r); - r = n; + while (!QTAILQ_EMPTY(&s->qdev.requests)) { + r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests)); + scsi_remove_request(r); } - drive_uninit(s->dinfo); } diff --git a/hw/scsi.h b/hw/scsi.h index 7906877fd..a9b846cc1 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -21,6 +21,7 @@ typedef struct SCSIRequest { SCSIDevice *dev; uint32_t tag; BlockDriverAIOCB *aiocb; + QTAILQ_ENTRY(SCSIRequest) next; } SCSIRequest; struct SCSIDevice @@ -28,6 +29,7 @@ struct SCSIDevice DeviceState qdev; uint32_t id; SCSIDeviceInfo *info; + QTAILQ_HEAD(, SCSIRequest) requests; }; /* cdrom.c */ -- cgit v1.2.3-65-gdbad From 89b08ae15449fe433325061ebb928766a1c77381 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:50 +0100 Subject: scsi: move SCSIRequest management to common code. Create generic functions to allocate, find and release SCSIRequest structs. Make scsi-disk and scsi-generic use them. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 31 +++++++++++++++++++++++++++++++ hw/scsi-disk.c | 27 ++++++++------------------- hw/scsi-generic.c | 29 ++++++++--------------------- hw/scsi.h | 5 +++++ 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 801922b7d..cf445cebc 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -111,3 +111,34 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus) scsi_bus_legacy_add_drive(bus, dinfo, unit); } } + +SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun) +{ + SCSIRequest *req; + + req = qemu_mallocz(size); + req->bus = scsi_bus_from_device(d); + req->dev = d; + req->tag = tag; + req->lun = lun; + QTAILQ_INSERT_TAIL(&d->requests, req, next); + return req; +} + +SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag) +{ + SCSIRequest *req; + + QTAILQ_FOREACH(req, &d->requests, next) { + if (req->tag == tag) { + return req; + } + } + return NULL; +} + +void scsi_req_free(SCSIRequest *req) +{ + QTAILQ_REMOVE(&req->dev->requests, req, next); + qemu_free(req); +} diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 997eef639..c18b7f0cc 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -71,37 +71,26 @@ struct SCSIDiskState QEMUBH *bh; }; -static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag) +static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) { + SCSIRequest *req; SCSIDiskReq *r; - r = qemu_mallocz(sizeof(SCSIDiskReq)); + req = scsi_req_alloc(sizeof(SCSIDiskReq), d, tag, lun); + r = DO_UPCAST(SCSIDiskReq, req, req); r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE); - r->req.bus = scsi_bus_from_device(d); - r->req.dev = d; - r->req.tag = tag; - - QTAILQ_INSERT_TAIL(&d->requests, &r->req, next); return r; } static void scsi_remove_request(SCSIDiskReq *r) { qemu_free(r->iov.iov_base); - QTAILQ_REMOVE(&r->req.dev->requests, &r->req, next); - qemu_free(r); + scsi_req_free(&r->req); } static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag) { - SCSIRequest *req; - - QTAILQ_FOREACH(req, &s->qdev.requests, next) { - if (req->tag == tag) { - return DO_UPCAST(SCSIDiskReq, req, req); - } - } - return NULL; + return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag)); } /* Helper function for command completion. */ @@ -113,8 +102,8 @@ static void scsi_command_complete(SCSIDiskReq *r, int status, int sense) r->req.tag, status, sense); s->sense = sense; tag = r->req.tag; - scsi_remove_request(r); r->req.bus->complete(r->req.bus, SCSI_REASON_DONE, tag, status); + scsi_remove_request(r); } /* Cancel a pending data transfer. */ @@ -349,7 +338,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } /* ??? Tags are not unique for different luns. We only implement a single lun, so this should not matter. */ - r = scsi_new_request(d, tag); + r = scsi_new_request(d, tag, lun); outbuf = (uint8_t *)r->iov.iov_base; is_write = 0; DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 857ccb035..051d0746f 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -76,36 +76,23 @@ struct SCSIGenericState uint8_t senselen; }; -static SCSIGenericReq *scsi_new_request(SCSIDevice *d, uint32_t tag) +static SCSIGenericReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) { - SCSIGenericReq *r; - - r = qemu_mallocz(sizeof(SCSIGenericReq)); - r->req.bus = scsi_bus_from_device(d); - r->req.dev = d; - r->req.tag = tag; + SCSIRequest *req; - QTAILQ_INSERT_TAIL(&d->requests, &r->req, next); - return r; + req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun); + return DO_UPCAST(SCSIGenericReq, req, req); } static void scsi_remove_request(SCSIGenericReq *r) { qemu_free(r->buf); - QTAILQ_REMOVE(&r->req.dev->requests, &r->req, next); - qemu_free(r); + scsi_req_free(&r->req); } static SCSIGenericReq *scsi_find_request(SCSIGenericState *s, uint32_t tag) { - SCSIRequest *req; - - QTAILQ_FOREACH(req, &s->qdev.requests, next) { - if (req->tag == tag) { - return DO_UPCAST(SCSIGenericReq, req, req); - } - } - return NULL; + return DO_UPCAST(SCSIGenericReq, req, scsi_req_find(&s->qdev, tag)); } /* Helper function for command completion. */ @@ -136,8 +123,8 @@ static void scsi_command_complete(void *opaque, int ret) DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", r, r->req.tag, status); tag = r->req.tag; - scsi_remove_request(r); r->req.bus->complete(r->req.bus, SCSI_REASON_DONE, tag, status); + scsi_remove_request(r); } /* Cancel a pending data transfer. */ @@ -520,7 +507,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, BADF("Tag 0x%x already in use %p\n", tag, r); scsi_cancel_io(d, tag); } - r = scsi_new_request(d, tag); + r = scsi_new_request(d, tag, lun); memcpy(r->cmd, cmd, cmdlen); r->cmdlen = cmdlen; diff --git a/hw/scsi.h b/hw/scsi.h index a9b846cc1..ceeb26ad4 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -20,6 +20,7 @@ typedef struct SCSIRequest { SCSIBus *bus; SCSIDevice *dev; uint32_t tag; + uint32_t lun; BlockDriverAIOCB *aiocb; QTAILQ_ENTRY(SCSIRequest) next; } SCSIRequest; @@ -74,4 +75,8 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, DriveInfo *dinfo, int unit); void scsi_bus_legacy_handle_cmdline(SCSIBus *bus); +SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); +SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag); +void scsi_req_free(SCSIRequest *req); + #endif -- cgit v1.2.3-65-gdbad From 29362ebe9d21286f101ba095d624869b672a4180 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:51 +0100 Subject: scsi: move scsi command buffer from SCSIGenericReq to SCSIRequest. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-generic.c | 15 ++++++--------- hw/scsi.h | 6 ++++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 051d0746f..0bcee7ae9 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -42,7 +42,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) #define SET_CD_SPEED 0xbb #define BLANK 0xa1 -#define SCSI_CMD_BUF_SIZE 16 #define SCSI_SENSE_BUF_SIZE 96 #define SG_ERR_DRIVER_TIMEOUT 0x06 @@ -56,8 +55,6 @@ typedef struct SCSIGenericState SCSIGenericState; typedef struct SCSIGenericReq { SCSIRequest req; - uint8_t cmd[SCSI_CMD_BUF_SIZE]; - int cmdlen; uint8_t *buf; int buflen; int len; @@ -153,8 +150,8 @@ static int execute_command(BlockDriverState *bdrv, r->io_header.dxfer_direction = direction; r->io_header.dxferp = r->buf; r->io_header.dxfer_len = r->buflen; - r->io_header.cmdp = r->cmd; - r->io_header.cmd_len = r->cmdlen; + r->io_header.cmdp = r->req.cmd.buf; + r->io_header.cmd_len = r->req.cmd.len; r->io_header.mx_sb_len = sizeof(s->sensebuf); r->io_header.sbp = s->sensebuf; r->io_header.timeout = MAX_UINT; @@ -210,7 +207,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) return; } - if (r->cmd[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE) + if (r->req.cmd.buf[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE) { s->senselen = MIN(r->len, s->senselen); memcpy(r->buf, s->sensebuf, s->senselen); @@ -245,7 +242,7 @@ static void scsi_write_complete(void * opaque, int ret) return; } - if (r->cmd[0] == MODE_SELECT && r->cmd[4] == 12 && + if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && s->type == TYPE_TAPE) { s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; DPRINTF("block size %d\n", s->blocksize); @@ -509,8 +506,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } r = scsi_new_request(d, tag, lun); - memcpy(r->cmd, cmd, cmdlen); - r->cmdlen = cmdlen; + memcpy(r->req.cmd.buf, cmd, cmdlen); + r->req.cmd.len = cmdlen; if (len == 0) { if (r->buf != NULL) diff --git a/hw/scsi.h b/hw/scsi.h index ceeb26ad4..aec9c5935 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -4,6 +4,8 @@ #include "qdev.h" #include "block.h" +#define SCSI_CMD_BUF_SIZE 16 + /* scsi-disk.c */ enum scsi_reason { SCSI_REASON_DONE, /* Command complete. */ @@ -21,6 +23,10 @@ typedef struct SCSIRequest { SCSIDevice *dev; uint32_t tag; uint32_t lun; + struct { + uint8_t buf[SCSI_CMD_BUF_SIZE]; + int len; + } cmd; BlockDriverAIOCB *aiocb; QTAILQ_ENTRY(SCSIRequest) next; } SCSIRequest; -- cgit v1.2.3-65-gdbad From b07995e3caa6252025a76772ed008cecaab5033a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:52 +0100 Subject: scsi: move blocksize from SCSIGenericState to SCSIDevice Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 1 + hw/scsi-generic.c | 23 +++++++++++------------ hw/scsi.h | 1 + 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index c18b7f0cc..0a8b8bb0b 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -944,6 +944,7 @@ static int scsi_disk_initfn(SCSIDevice *dev) } else { s->cluster_size = 1; } + s->qdev.blocksize = 512 * s->cluster_size; bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors); nb_sectors /= s->cluster_size; if (nb_sectors) diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 0bcee7ae9..053fb73c2 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -66,7 +66,6 @@ struct SCSIGenericState SCSIDevice qdev; DriveInfo *dinfo; int type; - int blocksize; int lun; int driver_status; uint8_t sensebuf[SCSI_SENSE_BUF_SIZE]; @@ -244,7 +243,7 @@ static void scsi_write_complete(void * opaque, int ret) if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && s->type == TYPE_TAPE) { - s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; + s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; DPRINTF("block size %d\n", s->blocksize); } @@ -467,12 +466,12 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, int ret; if (s->type == TYPE_TAPE) { - if (scsi_stream_length(cmd, s->blocksize, &cmdlen, &len) == -1) { + if (scsi_stream_length(cmd, s->qdev.blocksize, &cmdlen, &len) == -1) { BADF("Unsupported command length, command %x\n", cmd[0]); return 0; } } else { - if (scsi_length(cmd, s->blocksize, &cmdlen, &len) == -1) { + if (scsi_length(cmd, s->qdev.blocksize, &cmdlen, &len) == -1) { BADF("Unsupported command length, command %x\n", cmd[0]); return 0; } @@ -648,20 +647,20 @@ static int scsi_generic_initfn(SCSIDevice *dev) s->type = scsiid.scsi_type; DPRINTF("device type %d\n", s->type); if (s->type == TYPE_TAPE) { - s->blocksize = get_stream_blocksize(s->dinfo->bdrv); - if (s->blocksize == -1) - s->blocksize = 0; + s->qdev.blocksize = get_stream_blocksize(s->dinfo->bdrv); + if (s->qdev.blocksize == -1) + s->qdev.blocksize = 0; } else { - s->blocksize = get_blocksize(s->dinfo->bdrv); + s->qdev.blocksize = get_blocksize(s->dinfo->bdrv); /* removable media returns 0 if not present */ - if (s->blocksize <= 0) { + if (s->qdev.blocksize <= 0) { if (s->type == TYPE_ROM || s->type == TYPE_WORM) - s->blocksize = 2048; + s->qdev.blocksize = 2048; else - s->blocksize = 512; + s->qdev.blocksize = 512; } } - DPRINTF("block size %d\n", s->blocksize); + DPRINTF("block size %d\n", s->qdev.blocksize); s->driver_status = 0; memset(s->sensebuf, 0, sizeof(s->sensebuf)); return 0; diff --git a/hw/scsi.h b/hw/scsi.h index aec9c5935..5eb5682ed 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -37,6 +37,7 @@ struct SCSIDevice uint32_t id; SCSIDeviceInfo *info; QTAILQ_HEAD(, SCSIRequest) requests; + int blocksize; }; /* cdrom.c */ -- cgit v1.2.3-65-gdbad From 0d65e1f856d6f5bd00cb90bcc394fbe95fe5d244 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:53 +0100 Subject: scsi: add scsi-defs.h Largely based on from linux. Added into the tree so we can use the defines everywhere, not just in scsi-generic.c (which is linux-specific). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-defs.h | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/scsi-disk.c | 41 ++++++-------- hw/scsi-generic.c | 8 +-- 3 files changed, 174 insertions(+), 31 deletions(-) create mode 100644 hw/scsi-defs.h diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h new file mode 100644 index 000000000..1701521ad --- /dev/null +++ b/hw/scsi-defs.h @@ -0,0 +1,156 @@ +/* Copyright (C) 1998, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* + * This header file contains public constants and structures used by + * the scsi code for linux. + */ + +/* + * SCSI opcodes + */ + +#define TEST_UNIT_READY 0x00 +#define REZERO_UNIT 0x01 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define READ_BLOCK_LIMITS 0x05 +#define REASSIGN_BLOCKS 0x07 +#define READ_6 0x08 +#define WRITE_6 0x0a +#define SEEK_6 0x0b +#define READ_REVERSE 0x0f +#define WRITE_FILEMARKS 0x10 +#define SPACE 0x11 +#define INQUIRY 0x12 +#define RECOVER_BUFFERED_DATA 0x14 +#define MODE_SELECT 0x15 +#define RESERVE 0x16 +#define RELEASE 0x17 +#define COPY 0x18 +#define ERASE 0x19 +#define MODE_SENSE 0x1a +#define START_STOP 0x1b +#define RECEIVE_DIAGNOSTIC 0x1c +#define SEND_DIAGNOSTIC 0x1d +#define ALLOW_MEDIUM_REMOVAL 0x1e + +#define SET_WINDOW 0x24 +#define READ_CAPACITY 0x25 +#define READ_10 0x28 +#define WRITE_10 0x2a +#define SEEK_10 0x2b +#define WRITE_VERIFY 0x2e +#define VERIFY 0x2f +#define SEARCH_HIGH 0x30 +#define SEARCH_EQUAL 0x31 +#define SEARCH_LOW 0x32 +#define SET_LIMITS 0x33 +#define PRE_FETCH 0x34 +#define READ_POSITION 0x34 +#define SYNCHRONIZE_CACHE 0x35 +#define LOCK_UNLOCK_CACHE 0x36 +#define READ_DEFECT_DATA 0x37 +#define MEDIUM_SCAN 0x38 +#define COMPARE 0x39 +#define COPY_VERIFY 0x3a +#define WRITE_BUFFER 0x3b +#define READ_BUFFER 0x3c +#define UPDATE_BLOCK 0x3d +#define READ_LONG 0x3e +#define WRITE_LONG 0x3f +#define CHANGE_DEFINITION 0x40 +#define WRITE_SAME 0x41 +#define READ_TOC 0x43 +#define LOG_SELECT 0x4c +#define LOG_SENSE 0x4d +#define MODE_SELECT_10 0x55 +#define RESERVE_10 0x56 +#define RELEASE_10 0x57 +#define MODE_SENSE_10 0x5a +#define PERSISTENT_RESERVE_IN 0x5e +#define PERSISTENT_RESERVE_OUT 0x5f +#define MOVE_MEDIUM 0xa5 +#define READ_12 0xa8 +#define WRITE_12 0xaa +#define WRITE_VERIFY_12 0xae +#define SEARCH_HIGH_12 0xb0 +#define SEARCH_EQUAL_12 0xb1 +#define SEARCH_LOW_12 0xb2 +#define READ_ELEMENT_STATUS 0xb8 +#define SEND_VOLUME_TAG 0xb6 +#define WRITE_LONG_2 0xea + +/* from hw/scsi-generic.c */ +#define REWIND 0x01 +#define REPORT_DENSITY_SUPPORT 0x44 +#define LOAD_UNLOAD 0xa6 +#define SET_CD_SPEED 0xbb +#define BLANK 0xa1 + +/* + * Status codes + */ + +#define GOOD 0x00 +#define CHECK_CONDITION 0x01 +#define CONDITION_GOOD 0x02 +#define BUSY 0x04 +#define INTERMEDIATE_GOOD 0x08 +#define INTERMEDIATE_C_GOOD 0x0a +#define RESERVATION_CONFLICT 0x0c +#define COMMAND_TERMINATED 0x11 +#define QUEUE_FULL 0x14 + +#define STATUS_MASK 0x3e + +/* + * SENSE KEYS + */ + +#define NO_SENSE 0x00 +#define RECOVERED_ERROR 0x01 +#define NOT_READY 0x02 +#define MEDIUM_ERROR 0x03 +#define HARDWARE_ERROR 0x04 +#define ILLEGAL_REQUEST 0x05 +#define UNIT_ATTENTION 0x06 +#define DATA_PROTECT 0x07 +#define BLANK_CHECK 0x08 +#define COPY_ABORTED 0x0a +#define ABORTED_COMMAND 0x0b +#define VOLUME_OVERFLOW 0x0d +#define MISCOMPARE 0x0e + + +/* + * DEVICE TYPES + */ + +#define TYPE_DISK 0x00 +#define TYPE_TAPE 0x01 +#define TYPE_PROCESSOR 0x03 /* HP scanners use this */ +#define TYPE_WORM 0x04 /* Treated as ROM by our system */ +#define TYPE_ROM 0x05 +#define TYPE_SCANNER 0x06 +#define TYPE_MOD 0x07 /* Magneto-optical disk - + * - treated as TYPE_DISK */ +#define TYPE_MEDIUM_CHANGER 0x08 +#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ +#define TYPE_NO_LUN 0x7f + diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 0a8b8bb0b..b0eceaf09 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -30,14 +30,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include "qemu-common.h" #include "block.h" #include "scsi.h" - -#define SENSE_NO_SENSE 0 -#define SENSE_NOT_READY 2 -#define SENSE_HARDWARE_ERROR 4 -#define SENSE_ILLEGAL_REQUEST 5 - -#define STATUS_GOOD 0 -#define STATUS_CHECK_CONDITION 2 +#include "scsi-defs.h" #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 @@ -128,7 +121,7 @@ static void scsi_read_complete(void * opaque, int ret) if (ret) { DPRINTF("IO error\n"); r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); - scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE); + scsi_command_complete(r, CHECK_CONDITION, NO_SENSE); return; } DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->req.tag, r->iov.iov_len); @@ -147,7 +140,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) if (!r) { BADF("Bad read tag 0x%x\n", tag); /* ??? This is the wrong error. */ - scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); + scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); return; } if (r->sector_count == (uint32_t)-1) { @@ -158,7 +151,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) } DPRINTF("Read sector_count=%d\n", r->sector_count); if (r->sector_count == 0) { - scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); + scsi_command_complete(r, GOOD, NO_SENSE); return; } @@ -171,7 +164,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) r->req.aiocb = bdrv_aio_readv(s->dinfo->bdrv, r->sector, &r->qiov, n, scsi_read_complete, r); if (r->req.aiocb == NULL) - scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); + scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); r->sector += n; r->sector_count -= n; } @@ -189,8 +182,8 @@ static int scsi_handle_write_error(SCSIDiskReq *r, int error) r->status |= SCSI_REQ_STATUS_RETRY; vm_stop(0); } else { - scsi_command_complete(r, STATUS_CHECK_CONDITION, - SENSE_HARDWARE_ERROR); + scsi_command_complete(r, CHECK_CONDITION, + HARDWARE_ERROR); } return 1; @@ -213,7 +206,7 @@ static void scsi_write_complete(void * opaque, int ret) r->sector += n; r->sector_count -= n; if (r->sector_count == 0) { - scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); + scsi_command_complete(r, GOOD, NO_SENSE); } else { len = r->sector_count * 512; if (len > SCSI_DMA_BUF_SIZE) { @@ -236,8 +229,8 @@ static void scsi_write_request(SCSIDiskReq *r) r->req.aiocb = bdrv_aio_writev(s->dinfo->bdrv, r->sector, &r->qiov, n, scsi_write_complete, r); if (r->req.aiocb == NULL) - scsi_command_complete(r, STATUS_CHECK_CONDITION, - SENSE_HARDWARE_ERROR); + scsi_command_complete(r, CHECK_CONDITION, + HARDWARE_ERROR); } else { /* Invoke completion routine to fetch data from host. */ scsi_write_complete(r, 0); @@ -255,7 +248,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) r = scsi_find_request(s, tag); if (!r) { BADF("Bad write tag 0x%x\n", tag); - scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); + scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); return 1; } @@ -401,7 +394,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, goto fail; memset(outbuf, 0, 4); r->iov.iov_len = 4; - if (s->sense == SENSE_NOT_READY && len >= 18) { + if (s->sense == NOT_READY && len >= 18) { memset(outbuf, 0, 18); r->iov.iov_len = 18; outbuf[7] = 10; @@ -767,7 +760,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->iov.iov_len = 8; } else { notready: - scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY); + scsi_command_complete(r, CHECK_CONDITION, NOT_READY); return 0; } break; @@ -877,7 +870,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, /* Protection, exponent and lowest lba field left blank. */ r->iov.iov_len = len; } else { - scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY); + scsi_command_complete(r, CHECK_CONDITION, NOT_READY); return 0; } break; @@ -898,14 +891,14 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, default: DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); fail: - scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST); + scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST); return 0; illegal_lba: - scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); + scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); return 0; } if (r->sector_count == 0 && r->iov.iov_len == 0) { - scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); + scsi_command_complete(r, GOOD, NO_SENSE); } len = r->sector_count * 512 + r->iov.iov_len; if (is_write) { diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 053fb73c2..3f4f7f951 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -34,13 +34,7 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) #include #include #include -#include - -#define REWIND 0x01 -#define REPORT_DENSITY_SUPPORT 0x44 -#define LOAD_UNLOAD 0xa6 -#define SET_CD_SPEED 0xbb -#define BLANK 0xa1 +#include "scsi-defs.h" #define SCSI_SENSE_BUF_SIZE 96 -- cgit v1.2.3-65-gdbad From 913766563fbd6faa17635fd802e83383e0224289 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:54 +0100 Subject: scsi: move type from SCSIGenericState to SCSIDevice Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 1 + hw/scsi-generic.c | 13 ++++++------- hw/scsi.h | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index b0eceaf09..6b5674b8a 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -938,6 +938,7 @@ static int scsi_disk_initfn(SCSIDevice *dev) s->cluster_size = 1; } s->qdev.blocksize = 512 * s->cluster_size; + s->qdev.type = TYPE_DISK; bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors); nb_sectors /= s->cluster_size; if (nb_sectors) diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 3f4f7f951..a66b83d3e 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -59,7 +59,6 @@ struct SCSIGenericState { SCSIDevice qdev; DriveInfo *dinfo; - int type; int lun; int driver_status; uint8_t sensebuf[SCSI_SENSE_BUF_SIZE]; @@ -236,7 +235,7 @@ static void scsi_write_complete(void * opaque, int ret) } if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && - s->type == TYPE_TAPE) { + s->qdev.type == TYPE_TAPE) { s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; DPRINTF("block size %d\n", s->blocksize); } @@ -459,7 +458,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, SCSIBus *bus; int ret; - if (s->type == TYPE_TAPE) { + if (s->qdev.type == TYPE_TAPE) { if (scsi_stream_length(cmd, s->qdev.blocksize, &cmdlen, &len) == -1) { BADF("Unsupported command length, command %x\n", cmd[0]); return 0; @@ -638,9 +637,9 @@ static int scsi_generic_initfn(SCSIDevice *dev) /* define device state */ s->lun = scsiid.lun; DPRINTF("LUN %d\n", s->lun); - s->type = scsiid.scsi_type; - DPRINTF("device type %d\n", s->type); - if (s->type == TYPE_TAPE) { + s->qdev.type = scsiid.scsi_type; + DPRINTF("device type %d\n", s->qdev.type); + if (s->qdev.type == TYPE_TAPE) { s->qdev.blocksize = get_stream_blocksize(s->dinfo->bdrv); if (s->qdev.blocksize == -1) s->qdev.blocksize = 0; @@ -648,7 +647,7 @@ static int scsi_generic_initfn(SCSIDevice *dev) s->qdev.blocksize = get_blocksize(s->dinfo->bdrv); /* removable media returns 0 if not present */ if (s->qdev.blocksize <= 0) { - if (s->type == TYPE_ROM || s->type == TYPE_WORM) + if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) s->qdev.blocksize = 2048; else s->qdev.blocksize = 512; diff --git a/hw/scsi.h b/hw/scsi.h index 5eb5682ed..95838a4d7 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -38,6 +38,7 @@ struct SCSIDevice SCSIDeviceInfo *info; QTAILQ_HEAD(, SCSIRequest) requests; int blocksize; + int type; }; /* cdrom.c */ -- cgit v1.2.3-65-gdbad From 2ec749cb8222c37400ef95b751bfee945dae0dbf Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:55 +0100 Subject: scsi: add request parsing helpers to common code. Add helper functions for scsi request parsing to common code. Getting command length, transfer size, and linear block address is handled. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/scsi-generic.c | 156 ++++++++------------------------------------------- hw/scsi.h | 3 + 3 files changed, 191 insertions(+), 132 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index cf445cebc..1580d600a 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1,6 +1,7 @@ #include "hw.h" #include "sysemu.h" #include "scsi.h" +#include "scsi-defs.h" #include "block.h" #include "qdev.h" @@ -142,3 +143,166 @@ void scsi_req_free(SCSIRequest *req) QTAILQ_REMOVE(&req->dev->requests, req, next); qemu_free(req); } + +static int scsi_req_length(SCSIRequest *req, uint8_t *cmd) +{ + switch (cmd[0] >> 5) { + case 0: + req->cmd.xfer = cmd[4]; + req->cmd.len = 6; + /* length 0 means 256 blocks */ + if (req->cmd.xfer == 0) + req->cmd.xfer = 256; + break; + case 1: + case 2: + req->cmd.xfer = cmd[8] | (cmd[7] << 8); + req->cmd.len = 10; + break; + case 4: + req->cmd.xfer = cmd[13] | (cmd[12] << 8) | (cmd[11] << 16) | (cmd[10] << 24); + req->cmd.len = 16; + break; + case 5: + req->cmd.xfer = cmd[9] | (cmd[8] << 8) | (cmd[7] << 16) | (cmd[6] << 24); + req->cmd.len = 12; + break; + default: + return -1; + } + + switch(cmd[0]) { + case TEST_UNIT_READY: + case REZERO_UNIT: + case START_STOP: + case SEEK_6: + case WRITE_FILEMARKS: + case SPACE: + case ERASE: + case ALLOW_MEDIUM_REMOVAL: + case VERIFY: + case SEEK_10: + case SYNCHRONIZE_CACHE: + case LOCK_UNLOCK_CACHE: + case LOAD_UNLOAD: + case SET_CD_SPEED: + case SET_LIMITS: + case WRITE_LONG: + case MOVE_MEDIUM: + case UPDATE_BLOCK: + req->cmd.xfer = 0; + break; + case MODE_SENSE: + break; + case WRITE_SAME: + req->cmd.xfer = 1; + break; + case READ_CAPACITY: + req->cmd.xfer = 8; + break; + case READ_BLOCK_LIMITS: + req->cmd.xfer = 6; + break; + case READ_POSITION: + req->cmd.xfer = 20; + break; + case SEND_VOLUME_TAG: + req->cmd.xfer *= 40; + break; + case MEDIUM_SCAN: + req->cmd.xfer *= 8; + break; + case WRITE_10: + case WRITE_VERIFY: + case WRITE_6: + case WRITE_12: + case WRITE_VERIFY_12: + req->cmd.xfer *= req->dev->blocksize; + break; + case READ_10: + case READ_6: + case READ_REVERSE: + case RECOVER_BUFFERED_DATA: + case READ_12: + req->cmd.xfer *= req->dev->blocksize; + break; + case INQUIRY: + req->cmd.xfer = cmd[4] | (cmd[3] << 8); + break; + } + return 0; +} + +static int scsi_req_stream_length(SCSIRequest *req, uint8_t *cmd) +{ + switch(cmd[0]) { + /* stream commands */ + case READ_6: + case READ_REVERSE: + case RECOVER_BUFFERED_DATA: + case WRITE_6: + req->cmd.len = 6; + req->cmd.xfer = cmd[4] | (cmd[3] << 8) | (cmd[2] << 16); + if (cmd[1] & 0x01) /* fixed */ + req->cmd.xfer *= req->dev->blocksize; + break; + case REWIND: + case START_STOP: + req->cmd.len = 6; + req->cmd.xfer = 0; + break; + /* generic commands */ + default: + return scsi_req_length(req, cmd); + } + return 0; +} + +static uint64_t scsi_req_lba(SCSIRequest *req) +{ + uint8_t *buf = req->cmd.buf; + uint64_t lba; + + switch (buf[0] >> 5) { + case 0: + lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) | + (((uint64_t) buf[1] & 0x1f) << 16); + break; + case 1: + case 2: + lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | + ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); + break; + case 4: + lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) | + ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) | + ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) | + ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56); + break; + case 5: + lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | + ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); + break; + default: + lba = -1; + + } + return lba; +} + +int scsi_req_parse(SCSIRequest *req, uint8_t *buf) +{ + int rc; + + if (req->dev->type == TYPE_TAPE) { + rc = scsi_req_stream_length(req, buf); + } else { + rc = scsi_req_length(req, buf); + } + if (rc != 0) + return rc; + + memcpy(req->cmd.buf, buf, req->cmd.len); + req->cmd.lba = scsi_req_lba(req); + return 0; +} diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index a66b83d3e..e032f36d8 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -288,121 +288,23 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) return r->buf; } -static int scsi_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len) +static void scsi_req_fixup(SCSIRequest *req) { - switch (cmd[0] >> 5) { - case 0: - *len = cmd[4]; - *cmdlen = 6; - /* length 0 means 256 blocks */ - if (*len == 0) - *len = 256; - break; - case 1: - case 2: - *len = cmd[8] | (cmd[7] << 8); - *cmdlen = 10; - break; - case 4: - *len = cmd[13] | (cmd[12] << 8) | (cmd[11] << 16) | (cmd[10] << 24); - *cmdlen = 16; - break; - case 5: - *len = cmd[9] | (cmd[8] << 8) | (cmd[7] << 16) | (cmd[6] << 24); - *cmdlen = 12; - break; - default: - return -1; - } - - switch(cmd[0]) { - case TEST_UNIT_READY: - case REZERO_UNIT: - case START_STOP: - case SEEK_6: - case WRITE_FILEMARKS: - case SPACE: - case ERASE: - case ALLOW_MEDIUM_REMOVAL: - case VERIFY: - case SEEK_10: - case SYNCHRONIZE_CACHE: - case LOCK_UNLOCK_CACHE: - case LOAD_UNLOAD: - case SET_CD_SPEED: - case SET_LIMITS: - case WRITE_LONG: - case MOVE_MEDIUM: - case UPDATE_BLOCK: - *len = 0; - break; - case MODE_SENSE: - break; - case WRITE_SAME: - *len = 1; - break; - case READ_CAPACITY: - *len = 8; - break; - case READ_BLOCK_LIMITS: - *len = 6; - break; - case READ_POSITION: - *len = 20; - break; - case SEND_VOLUME_TAG: - *len *= 40; - break; - case MEDIUM_SCAN: - *len *= 8; - break; + switch(req->cmd.buf[0]) { case WRITE_10: - cmd[1] &= ~0x08; /* disable FUA */ - case WRITE_VERIFY: - case WRITE_6: - case WRITE_12: - case WRITE_VERIFY_12: - *len *= blocksize; + req->cmd.buf[1] &= ~0x08; /* disable FUA */ break; case READ_10: - cmd[1] &= ~0x08; /* disable FUA */ - case READ_6: - case READ_REVERSE: - case RECOVER_BUFFERED_DATA: - case READ_12: - *len *= blocksize; - break; - case INQUIRY: - *len = cmd[4] | (cmd[3] << 8); - break; - } - return 0; -} - -static int scsi_stream_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len) -{ - switch(cmd[0]) { - /* stream commands */ - case READ_6: - case READ_REVERSE: - case RECOVER_BUFFERED_DATA: - case WRITE_6: - *cmdlen = 6; - *len = cmd[4] | (cmd[3] << 8) | (cmd[2] << 16); - if (cmd[1] & 0x01) /* fixed */ - *len *= blocksize; + req->cmd.buf[1] &= ~0x08; /* disable FUA */ break; case REWIND: case START_STOP: - *cmdlen = 6; - *len = 0; - cmd[1] = 0x01; /* force IMMED, otherwise qemu waits end of command */ + if (req->dev->type == TYPE_TAPE) { + /* force IMMED, otherwise qemu waits end of command */ + req->cmd.buf[1] = 0x01; + } break; - /* generic commands */ - default: - return scsi_length(cmd, blocksize, cmdlen, len); } - return 0; } static int is_write(int command) @@ -452,27 +354,10 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, uint8_t *cmd, int lun) { SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - uint32_t len=0; - int cmdlen=0; SCSIGenericReq *r; SCSIBus *bus; int ret; - if (s->qdev.type == TYPE_TAPE) { - if (scsi_stream_length(cmd, s->qdev.blocksize, &cmdlen, &len) == -1) { - BADF("Unsupported command length, command %x\n", cmd[0]); - return 0; - } - } else { - if (scsi_length(cmd, s->qdev.blocksize, &cmdlen, &len) == -1) { - BADF("Unsupported command length, command %x\n", cmd[0]); - return 0; - } - } - - DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag, - cmd[0], len); - if (cmd[0] != REQUEST_SENSE && (lun != s->lun || (cmd[1] >> 5) != s->lun)) { DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5); @@ -498,10 +383,17 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } r = scsi_new_request(d, tag, lun); - memcpy(r->req.cmd.buf, cmd, cmdlen); - r->req.cmd.len = cmdlen; + if (-1 == scsi_req_parse(&r->req, cmd)) { + BADF("Unsupported command length, command %x\n", cmd[0]); + scsi_remove_request(r); + return 0; + } + scsi_req_fixup(&r->req); + + DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag, + cmd[0], r->req.cmd.xfer); - if (len == 0) { + if (r->req.cmd.xfer == 0) { if (r->buf != NULL) qemu_free(r->buf); r->buflen = 0; @@ -514,21 +406,21 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, return 0; } - if (r->buflen != len) { + if (r->buflen != r->req.cmd.xfer) { if (r->buf != NULL) qemu_free(r->buf); - r->buf = qemu_malloc(len); - r->buflen = len; + r->buf = qemu_malloc(r->req.cmd.xfer); + r->buflen = r->req.cmd.xfer; } memset(r->buf, 0, r->buflen); - r->len = len; + r->len = r->req.cmd.xfer; if (is_write(cmd[0])) { r->len = 0; - return -len; + return -r->req.cmd.xfer; } - return len; + return r->req.cmd.xfer; } static int get_blocksize(BlockDriverState *bdrv) diff --git a/hw/scsi.h b/hw/scsi.h index 95838a4d7..8c6406754 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -26,6 +26,8 @@ typedef struct SCSIRequest { struct { uint8_t buf[SCSI_CMD_BUF_SIZE]; int len; + size_t xfer; + uint64_t lba; } cmd; BlockDriverAIOCB *aiocb; QTAILQ_ENTRY(SCSIRequest) next; @@ -86,5 +88,6 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus); SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag); void scsi_req_free(SCSIRequest *req); +int scsi_req_parse(SCSIRequest *req, uint8_t *buf); #endif -- cgit v1.2.3-65-gdbad From ebf460231276efe86ca75613e3cd4169956f7076 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:56 +0100 Subject: scsi: use command defines in scsi-disk.c Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 6b5674b8a..4e929104b 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -379,16 +379,16 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, if (lun || buf[1] >> 5) { /* Only LUN 0 supported. */ DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); - if (command != 0x03 && command != 0x12) /* REQUEST SENSE and INQUIRY */ + if (command != REQUEST_SENSE && command != INQUIRY) goto fail; } switch (command) { - case 0x0: + case TEST_UNIT_READY: DPRINTF("Test Unit Ready\n"); if (!bdrv_is_inserted(s->dinfo->bdrv)) goto notready; break; - case 0x03: + case REQUEST_SENSE: DPRINTF("Request Sense (len %d)\n", len); if (len < 4) goto fail; @@ -406,7 +406,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf[1] = 0; outbuf[2] = s->sense; break; - case 0x12: + case INQUIRY: DPRINTF("Inquiry (len %d)\n", len); if (buf[1] & 0x2) { /* Command support data - optional, not implemented */ @@ -562,18 +562,18 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf[7] = 0x10 | (r->req.bus->tcq ? 0x02 : 0); r->iov.iov_len = len; break; - case 0x16: + case RESERVE: DPRINTF("Reserve(6)\n"); if (buf[1] & 1) goto fail; break; - case 0x17: + case RELEASE: DPRINTF("Release(6)\n"); if (buf[1] & 1) goto fail; break; - case 0x1a: - case 0x5a: + case MODE_SENSE: + case MODE_SENSE_10: { uint8_t *p; int page; @@ -724,18 +724,18 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->iov.iov_len = len; } break; - case 0x1b: + case START_STOP: DPRINTF("Start Stop Unit\n"); if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM && (buf[4] & 2)) /* load/eject medium */ bdrv_eject(s->dinfo->bdrv, !(buf[4] & 1)); break; - case 0x1e: + case ALLOW_MEDIUM_REMOVAL: DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3); bdrv_set_locked(s->dinfo->bdrv, buf[4] & 1); break; - case 0x25: + case READ_CAPACITY: DPRINTF("Read Capacity\n"); /* The normal LEN field for this command is zero. */ memset(outbuf, 0, 8); @@ -764,8 +764,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, return 0; } break; - case 0x08: - case 0x28: + case READ_6: + case READ_10: case 0x88: DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len); if (lba > s->max_lba) @@ -773,8 +773,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->sector = lba * s->cluster_size; r->sector_count = len * s->cluster_size; break; - case 0x0a: - case 0x2a: + case WRITE_6: + case WRITE_10: case 0x8a: DPRINTF("Write (sector %" PRId64 ", count %d)\n", lba, len); if (lba > s->max_lba) @@ -783,11 +783,11 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->sector_count = len * s->cluster_size; is_write = 1; break; - case 0x35: + case SYNCHRONIZE_CACHE: DPRINTF("Synchronise cache (sector %" PRId64 ", count %d)\n", lba, len); bdrv_flush(s->dinfo->bdrv); break; - case 0x43: + case READ_TOC: { int start_track, format, msf, toclen; @@ -833,12 +833,12 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf[7] = 8; // CD-ROM r->iov.iov_len = 8; break; - case 0x56: + case RESERVE_10: DPRINTF("Reserve(10)\n"); if (buf[1] & 3) goto fail; break; - case 0x57: + case RELEASE_10: DPRINTF("Release(10)\n"); if (buf[1] & 3) goto fail; @@ -885,7 +885,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf[3] = 8; r->iov.iov_len = 16; break; - case 0x2f: + case VERIFY: DPRINTF("Verify (sector %" PRId64 ", count %d)\n", lba, len); break; default: -- cgit v1.2.3-65-gdbad From 97a064356704af1756270b1d56dea2690ae015de Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:57 +0100 Subject: scsi: add xfer mode Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ hw/scsi-generic.c | 40 +--------------------------------------- hw/scsi.h | 7 +++++++ 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 1580d600a..e250e4f9d 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -258,6 +258,51 @@ static int scsi_req_stream_length(SCSIRequest *req, uint8_t *cmd) return 0; } +static void scsi_req_xfer_mode(SCSIRequest *req) +{ + switch (req->cmd.buf[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_VERIFY: + case WRITE_12: + case WRITE_VERIFY_12: + case COPY: + case COPY_VERIFY: + case COMPARE: + case CHANGE_DEFINITION: + case LOG_SELECT: + case MODE_SELECT: + case MODE_SELECT_10: + case SEND_DIAGNOSTIC: + case WRITE_BUFFER: + case FORMAT_UNIT: + case REASSIGN_BLOCKS: + case RESERVE: + case SEARCH_EQUAL: + case SEARCH_HIGH: + case SEARCH_LOW: + case UPDATE_BLOCK: + case WRITE_LONG: + case WRITE_SAME: + case SEARCH_HIGH_12: + case SEARCH_EQUAL_12: + case SEARCH_LOW_12: + case SET_WINDOW: + case MEDIUM_SCAN: + case SEND_VOLUME_TAG: + case WRITE_LONG_2: + req->cmd.mode = SCSI_XFER_TO_DEV; + break; + default: + if (req->cmd.xfer) + req->cmd.mode = SCSI_XFER_FROM_DEV; + else { + req->cmd.mode = SCSI_XFER_NONE; + } + break; + } +} + static uint64_t scsi_req_lba(SCSIRequest *req) { uint8_t *buf = req->cmd.buf; @@ -303,6 +348,7 @@ int scsi_req_parse(SCSIRequest *req, uint8_t *buf) return rc; memcpy(req->cmd.buf, buf, req->cmd.len); + scsi_req_xfer_mode(req); req->cmd.lba = scsi_req_lba(req); return 0; } diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index e032f36d8..e81facc7b 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -307,44 +307,6 @@ static void scsi_req_fixup(SCSIRequest *req) } } -static int is_write(int command) -{ - switch (command) { - case COPY: - case COPY_VERIFY: - case COMPARE: - case CHANGE_DEFINITION: - case LOG_SELECT: - case MODE_SELECT: - case MODE_SELECT_10: - case SEND_DIAGNOSTIC: - case WRITE_BUFFER: - case FORMAT_UNIT: - case REASSIGN_BLOCKS: - case RESERVE: - case SEARCH_EQUAL: - case SEARCH_HIGH: - case SEARCH_LOW: - case WRITE_6: - case WRITE_10: - case WRITE_VERIFY: - case UPDATE_BLOCK: - case WRITE_LONG: - case WRITE_SAME: - case SEARCH_HIGH_12: - case SEARCH_EQUAL_12: - case SEARCH_LOW_12: - case WRITE_12: - case WRITE_VERIFY_12: - case SET_WINDOW: - case MEDIUM_SCAN: - case SEND_VOLUME_TAG: - case WRITE_LONG_2: - return 1; - } - return 0; -} - /* Execute a scsi command. Returns the length of the data expected by the command. This will be Positive for data transfers from the device (eg. disk reads), negative for transfers to the device (eg. disk writes), @@ -415,7 +377,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, memset(r->buf, 0, r->buflen); r->len = r->req.cmd.xfer; - if (is_write(cmd[0])) { + if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { r->len = 0; return -r->req.cmd.xfer; } diff --git a/hw/scsi.h b/hw/scsi.h index 8c6406754..c5b30b82b 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -18,6 +18,12 @@ typedef struct SCSIDeviceInfo SCSIDeviceInfo; typedef void (*scsi_completionfn)(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg); +enum SCSIXferMode { + SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */ + SCSI_XFER_FROM_DEV, /* READ, INQUIRY, MODE_SENSE, ... */ + SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ +}; + typedef struct SCSIRequest { SCSIBus *bus; SCSIDevice *dev; @@ -28,6 +34,7 @@ typedef struct SCSIRequest { int len; size_t xfer; uint64_t lba; + enum SCSIXferMode mode; } cmd; BlockDriverAIOCB *aiocb; QTAILQ_ENTRY(SCSIRequest) next; -- cgit v1.2.3-65-gdbad From 37659e510483fd8758424356b76209124ccfd98c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:58 +0100 Subject: scsi: move sense to SCSIDevice, create SCSISense struct. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 10 ++++++++++ hw/scsi-disk.c | 8 ++++---- hw/scsi.h | 9 +++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index e250e4f9d..666ca3c41 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -113,6 +113,16 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus) } } +void scsi_dev_clear_sense(SCSIDevice *dev) +{ + memset(&dev->sense, 0, sizeof(dev->sense)); +} + +void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key) +{ + dev->sense.key = key; +} + SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun) { SCSIRequest *req; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 4e929104b..2eac40083 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -59,7 +59,6 @@ struct SCSIDiskState This is the number of 512 byte blocks in a single scsi sector. */ int cluster_size; uint64_t max_lba; - int sense; char drive_serial_str[21]; QEMUBH *bh; }; @@ -93,7 +92,7 @@ static void scsi_command_complete(SCSIDiskReq *r, int status, int sense) uint32_t tag; DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->req.tag, status, sense); - s->sense = sense; + scsi_dev_set_sense(&s->qdev, sense); tag = r->req.tag; r->req.bus->complete(r->req.bus, SCSI_REASON_DONE, tag, status); scsi_remove_request(r); @@ -394,7 +393,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, goto fail; memset(outbuf, 0, 4); r->iov.iov_len = 4; - if (s->sense == NOT_READY && len >= 18) { + if (s->qdev.sense.key == NOT_READY && len >= 18) { memset(outbuf, 0, 18); r->iov.iov_len = 18; outbuf[7] = 10; @@ -404,7 +403,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } outbuf[0] = 0xf0; outbuf[1] = 0; - outbuf[2] = s->sense; + outbuf[2] = s->qdev.sense.key; + scsi_dev_clear_sense(&s->qdev); break; case INQUIRY: DPRINTF("Inquiry (len %d)\n", len); diff --git a/hw/scsi.h b/hw/scsi.h index c5b30b82b..f0aaed59a 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -24,6 +24,10 @@ enum SCSIXferMode { SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ }; +typedef struct SCSISense { + uint8_t key; +} SCSISense; + typedef struct SCSIRequest { SCSIBus *bus; SCSIDevice *dev; @@ -48,6 +52,7 @@ struct SCSIDevice QTAILQ_HEAD(, SCSIRequest) requests; int blocksize; int type; + struct SCSISense sense; }; /* cdrom.c */ @@ -92,9 +97,13 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, DriveInfo *dinfo, int unit); void scsi_bus_legacy_handle_cmdline(SCSIBus *bus); +void scsi_dev_clear_sense(SCSIDevice *dev); +void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key); + SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag); void scsi_req_free(SCSIRequest *req); + int scsi_req_parse(SCSIRequest *req, uint8_t *buf); #endif -- cgit v1.2.3-65-gdbad From 251882b7e4532cb42fca89412bb6670dcec4158f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:33:59 +0100 Subject: scsi: move dinfo to SCSIDevice Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 63 +++++++++++++++++++++++++++---------------------------- hw/scsi-generic.c | 23 ++++++++++---------- hw/scsi.h | 1 + 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 2eac40083..2fc6cf9ea 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -54,7 +54,6 @@ typedef struct SCSIDiskReq { struct SCSIDiskState { SCSIDevice qdev; - DriveInfo *dinfo; /* The qemu block layer uses a fixed 512 byte sector size. This is the number of 512 byte blocks in a single scsi sector. */ int cluster_size; @@ -160,7 +159,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) r->iov.iov_len = n * 512; qemu_iovec_init_external(&r->qiov, &r->iov, 1); - r->req.aiocb = bdrv_aio_readv(s->dinfo->bdrv, r->sector, &r->qiov, n, + r->req.aiocb = bdrv_aio_readv(s->qdev.dinfo->bdrv, r->sector, &r->qiov, n, scsi_read_complete, r); if (r->req.aiocb == NULL) scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); @@ -171,7 +170,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) static int scsi_handle_write_error(SCSIDiskReq *r, int error) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - BlockInterfaceErrorAction action = drive_get_onerror(s->dinfo->bdrv); + BlockInterfaceErrorAction action = drive_get_onerror(s->qdev.dinfo->bdrv); if (action == BLOCK_ERR_IGNORE) return 0; @@ -225,7 +224,7 @@ static void scsi_write_request(SCSIDiskReq *r) n = r->iov.iov_len / 512; if (n) { qemu_iovec_init_external(&r->qiov, &r->iov, 1); - r->req.aiocb = bdrv_aio_writev(s->dinfo->bdrv, r->sector, &r->qiov, n, + r->req.aiocb = bdrv_aio_writev(s->qdev.dinfo->bdrv, r->sector, &r->qiov, n, scsi_write_complete, r); if (r->req.aiocb == NULL) scsi_command_complete(r, CHECK_CONDITION, @@ -384,7 +383,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, switch (command) { case TEST_UNIT_READY: DPRINTF("Test Unit Ready\n"); - if (!bdrv_is_inserted(s->dinfo->bdrv)) + if (!bdrv_is_inserted(s->qdev.dinfo->bdrv)) goto notready; break; case REQUEST_SENSE: @@ -431,7 +430,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->iov.iov_len = 0; - if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) { + if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { outbuf[r->iov.iov_len++] = 5; } else { outbuf[r->iov.iov_len++] = 0; @@ -462,7 +461,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->iov.iov_len = 0; /* Supported page codes */ - if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) { + if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { outbuf[r->iov.iov_len++] = 5; } else { outbuf[r->iov.iov_len++] = 0; @@ -480,14 +479,14 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, { /* Device identification page, mandatory */ int max_len = 255 - 8; - int id_len = strlen(bdrv_get_device_name(s->dinfo->bdrv)); + int id_len = strlen(bdrv_get_device_name(s->qdev.dinfo->bdrv)); if (id_len > max_len) id_len = max_len; DPRINTF("Inquiry EVPD[Device identification] " "buffer size %d\n", len); r->iov.iov_len = 0; - if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) { + if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { outbuf[r->iov.iov_len++] = 5; } else { outbuf[r->iov.iov_len++] = 0; @@ -503,7 +502,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf[r->iov.iov_len++] = id_len; // length of data following memcpy(&outbuf[r->iov.iov_len], - bdrv_get_device_name(s->dinfo->bdrv), id_len); + bdrv_get_device_name(s->qdev.dinfo->bdrv), id_len); r->iov.iov_len += id_len; } break; @@ -543,7 +542,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, if (lun || buf[1] >> 5) { outbuf[0] = 0x7f; /* LUN not supported */ - } else if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) { + } else if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { outbuf[0] = 5; outbuf[1] = 0x80; memcpy(&outbuf[16], "QEMU CD-ROM ", 16); @@ -586,12 +585,12 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, memset(p, 0, 4); outbuf[1] = 0; /* Default media type. */ outbuf[3] = 0; /* Block descriptor length. */ - if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM || - bdrv_is_read_only(s->dinfo->bdrv)) { + if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM || + bdrv_is_read_only(s->qdev.dinfo->bdrv)) { outbuf[2] = 0x80; /* Readonly. */ } p += 4; - bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors); + bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); if ((~dbd) & nb_sectors) { nb_sectors /= s->cluster_size; nb_sectors--; @@ -616,7 +615,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, p[0] = 4; p[1] = 0x16; /* if a geometry hint is available, use it */ - bdrv_get_geometry_hint(s->dinfo->bdrv, &cylinders, &heads, &secs); + bdrv_get_geometry_hint(s->qdev.dinfo->bdrv, &cylinders, &heads, &secs); p[2] = (cylinders >> 16) & 0xff; p[3] = (cylinders >> 8) & 0xff; p[4] = cylinders & 0xff; @@ -650,7 +649,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, p[2] = 5000 >> 8; p[3] = 5000 & 0xff; /* if a geometry hint is available, use it */ - bdrv_get_geometry_hint(s->dinfo->bdrv, &cylinders, &heads, &secs); + bdrv_get_geometry_hint(s->qdev.dinfo->bdrv, &cylinders, &heads, &secs); p[4] = heads & 0xff; p[5] = secs & 0xff; p[6] = s->cluster_size * 2; @@ -683,13 +682,13 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, memset(p,0,20); p[0] = 8; p[1] = 0x12; - if (bdrv_enable_write_cache(s->dinfo->bdrv)) { + if (bdrv_enable_write_cache(s->qdev.dinfo->bdrv)) { p[2] = 4; /* WCE */ } p += 20; } if ((page == 0x3f || page == 0x2a) - && (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM)) { + && (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM)) { /* CD Capabilities and Mechanical Status page. */ p[0] = 0x2a; p[1] = 0x14; @@ -700,7 +699,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, p[5] = 0xff; /* CD DA, DA accurate, RW supported, RW corrected, C2 errors, ISRC, UPC, Bar code */ - p[6] = 0x2d | (bdrv_is_locked(s->dinfo->bdrv)? 2 : 0); + p[6] = 0x2d | (bdrv_is_locked(s->qdev.dinfo->bdrv)? 2 : 0); /* Locking supported, jumper present, eject, tray */ p[7] = 0; /* no volume & mute control, no changer */ @@ -726,20 +725,20 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, break; case START_STOP: DPRINTF("Start Stop Unit\n"); - if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM && + if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM && (buf[4] & 2)) /* load/eject medium */ - bdrv_eject(s->dinfo->bdrv, !(buf[4] & 1)); + bdrv_eject(s->qdev.dinfo->bdrv, !(buf[4] & 1)); break; case ALLOW_MEDIUM_REMOVAL: DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3); - bdrv_set_locked(s->dinfo->bdrv, buf[4] & 1); + bdrv_set_locked(s->qdev.dinfo->bdrv, buf[4] & 1); break; case READ_CAPACITY: DPRINTF("Read Capacity\n"); /* The normal LEN field for this command is zero. */ memset(outbuf, 0, 8); - bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors); + bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); nb_sectors /= s->cluster_size; /* Returned value is the address of the last sector. */ if (nb_sectors) { @@ -785,7 +784,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, break; case SYNCHRONIZE_CACHE: DPRINTF("Synchronise cache (sector %" PRId64 ", count %d)\n", lba, len); - bdrv_flush(s->dinfo->bdrv); + bdrv_flush(s->qdev.dinfo->bdrv); break; case READ_TOC: { @@ -794,7 +793,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, msf = buf[1] & 2; format = buf[2] & 0xf; start_track = buf[6]; - bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors); + bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); nb_sectors /= s->cluster_size; switch(format) { @@ -848,7 +847,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, if ((buf[1] & 31) == 0x10) { DPRINTF("SAI READ CAPACITY(16)\n"); memset(outbuf, 0, len); - bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors); + bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); nb_sectors /= s->cluster_size; /* Returned value is the address of the last sector. */ if (nb_sectors) { @@ -919,7 +918,7 @@ static void scsi_destroy(SCSIDevice *dev) r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests)); scsi_remove_request(r); } - drive_uninit(s->dinfo); + drive_uninit(s->qdev.dinfo); } static int scsi_disk_initfn(SCSIDevice *dev) @@ -927,24 +926,24 @@ static int scsi_disk_initfn(SCSIDevice *dev) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); uint64_t nb_sectors; - if (!s->dinfo || !s->dinfo->bdrv) { + if (!s->qdev.dinfo || !s->qdev.dinfo->bdrv) { qemu_error("scsi-disk: drive property not set\n"); return -1; } - if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) { + if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { s->cluster_size = 4; } else { s->cluster_size = 1; } s->qdev.blocksize = 512 * s->cluster_size; s->qdev.type = TYPE_DISK; - bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors); + bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); nb_sectors /= s->cluster_size; if (nb_sectors) nb_sectors--; s->max_lba = nb_sectors; - strncpy(s->drive_serial_str, drive_get_serial(s->dinfo->bdrv), + strncpy(s->drive_serial_str, drive_get_serial(s->qdev.dinfo->bdrv), sizeof(s->drive_serial_str)); if (strlen(s->drive_serial_str) == 0) pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0"); @@ -964,7 +963,7 @@ static SCSIDeviceInfo scsi_disk_info = { .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, .qdev.props = (Property[]) { - DEFINE_PROP_DRIVE("drive", SCSIDiskState, dinfo), + DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.dinfo), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index e81facc7b..31bd0669f 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -58,7 +58,6 @@ typedef struct SCSIGenericReq { struct SCSIGenericState { SCSIDevice qdev; - DriveInfo *dinfo; int lun; int driver_status; uint8_t sensebuf[SCSI_SENSE_BUF_SIZE]; @@ -215,7 +214,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) return; } - ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete); + ret = execute_command(s->qdev.dinfo->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete); if (ret == -1) { scsi_command_complete(r, -EINVAL); return; @@ -266,7 +265,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) return 0; } - ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete); + ret = execute_command(s->qdev.dinfo->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete); if (ret == -1) { scsi_command_complete(r, -EINVAL); return 1; @@ -360,7 +359,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, qemu_free(r->buf); r->buflen = 0; r->buf = NULL; - ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_NONE, scsi_command_complete); + ret = execute_command(s->qdev.dinfo->bdrv, r, SG_DXFER_NONE, scsi_command_complete); if (ret == -1) { scsi_command_complete(r, -EINVAL); return 0; @@ -455,7 +454,7 @@ static void scsi_destroy(SCSIDevice *d) r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests)); scsi_remove_request(r); } - drive_uninit(s->dinfo); + drive_uninit(s->qdev.dinfo); } static int scsi_generic_initfn(SCSIDevice *dev) @@ -464,26 +463,26 @@ static int scsi_generic_initfn(SCSIDevice *dev) int sg_version; struct sg_scsi_id scsiid; - if (!s->dinfo || !s->dinfo->bdrv) { + if (!s->qdev.dinfo || !s->qdev.dinfo->bdrv) { qemu_error("scsi-generic: drive property not set\n"); return -1; } /* check we are really using a /dev/sg* file */ - if (!bdrv_is_sg(s->dinfo->bdrv)) { + if (!bdrv_is_sg(s->qdev.dinfo->bdrv)) { qemu_error("scsi-generic: not /dev/sg*\n"); return -1; } /* check we are using a driver managing SG_IO (version 3 and after */ - if (bdrv_ioctl(s->dinfo->bdrv, SG_GET_VERSION_NUM, &sg_version) < 0 || + if (bdrv_ioctl(s->qdev.dinfo->bdrv, SG_GET_VERSION_NUM, &sg_version) < 0 || sg_version < 30000) { qemu_error("scsi-generic: scsi generic interface too old\n"); return -1; } /* get LUN of the /dev/sg? */ - if (bdrv_ioctl(s->dinfo->bdrv, SG_GET_SCSI_ID, &scsiid)) { + if (bdrv_ioctl(s->qdev.dinfo->bdrv, SG_GET_SCSI_ID, &scsiid)) { qemu_error("scsi-generic: SG_GET_SCSI_ID ioctl failed\n"); return -1; } @@ -494,11 +493,11 @@ static int scsi_generic_initfn(SCSIDevice *dev) s->qdev.type = scsiid.scsi_type; DPRINTF("device type %d\n", s->qdev.type); if (s->qdev.type == TYPE_TAPE) { - s->qdev.blocksize = get_stream_blocksize(s->dinfo->bdrv); + s->qdev.blocksize = get_stream_blocksize(s->qdev.dinfo->bdrv); if (s->qdev.blocksize == -1) s->qdev.blocksize = 0; } else { - s->qdev.blocksize = get_blocksize(s->dinfo->bdrv); + s->qdev.blocksize = get_blocksize(s->qdev.dinfo->bdrv); /* removable media returns 0 if not present */ if (s->qdev.blocksize <= 0) { if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) @@ -525,7 +524,7 @@ static SCSIDeviceInfo scsi_generic_info = { .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, .qdev.props = (Property[]) { - DEFINE_PROP_DRIVE("drive", SCSIGenericState, dinfo), + DEFINE_PROP_DRIVE("drive", SCSIGenericState, qdev.dinfo), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/hw/scsi.h b/hw/scsi.h index f0aaed59a..788c45917 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -48,6 +48,7 @@ struct SCSIDevice { DeviceState qdev; uint32_t id; + DriveInfo *dinfo; SCSIDeviceInfo *info; QTAILQ_HEAD(, SCSIRequest) requests; int blocksize; -- cgit v1.2.3-65-gdbad From ed3a34a3c8dcae6f46556ae7e2a667e6c16c8daa Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:00 +0100 Subject: scsi: move status to SCSIRequest. Also add and use the scsi_req_complete() helper function for calling the completion callback. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 9 +++++++++ hw/scsi-disk.c | 13 ++++++++----- hw/scsi-generic.c | 18 ++++++++---------- hw/scsi.h | 2 ++ 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 666ca3c41..2e4fd3874 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -132,6 +132,7 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l req->dev = d; req->tag = tag; req->lun = lun; + req->status = -1; QTAILQ_INSERT_TAIL(&d->requests, req, next); return req; } @@ -362,3 +363,11 @@ int scsi_req_parse(SCSIRequest *req, uint8_t *buf) req->cmd.lba = scsi_req_lba(req); return 0; } + +void scsi_req_complete(SCSIRequest *req) +{ + assert(req->status != -1); + req->bus->complete(req->bus, SCSI_REASON_DONE, + req->tag, + req->status); +} diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 2fc6cf9ea..bc8270ce8 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -84,16 +84,19 @@ static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag) return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag)); } +static void scsi_req_set_status(SCSIRequest *req, int status, int sense_code) +{ + req->status = status; + scsi_dev_set_sense(req->dev, sense_code); +} + /* Helper function for command completion. */ static void scsi_command_complete(SCSIDiskReq *r, int status, int sense) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - uint32_t tag; DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->req.tag, status, sense); - scsi_dev_set_sense(&s->qdev, sense); - tag = r->req.tag; - r->req.bus->complete(r->req.bus, SCSI_REASON_DONE, tag, status); + scsi_req_set_status(&r->req, status, sense); + scsi_req_complete(&r->req); scsi_remove_request(r); } diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 31bd0669f..f60ad96d7 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -88,30 +88,28 @@ static void scsi_command_complete(void *opaque, int ret) { SCSIGenericReq *r = (SCSIGenericReq *)opaque; SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); - uint32_t tag; - int status; s->driver_status = r->io_header.driver_status; if (s->driver_status & SG_ERR_DRIVER_SENSE) s->senselen = r->io_header.sb_len_wr; if (ret != 0) - status = BUSY << 1; + r->req.status = BUSY << 1; else { if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) { - status = BUSY << 1; + r->req.status = BUSY << 1; BADF("Driver Timeout\n"); } else if (r->io_header.status) - status = r->io_header.status; + r->req.status = r->io_header.status; else if (s->driver_status & SG_ERR_DRIVER_SENSE) - status = CHECK_CONDITION << 1; + r->req.status = CHECK_CONDITION << 1; else - status = GOOD << 1; + r->req.status = GOOD << 1; } DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", - r, r->req.tag, status); - tag = r->req.tag; - r->req.bus->complete(r->req.bus, SCSI_REASON_DONE, tag, status); + r, r->req.tag, r->req.status); + + scsi_req_complete(&r->req); scsi_remove_request(r); } diff --git a/hw/scsi.h b/hw/scsi.h index 788c45917..2fe8c1206 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -33,6 +33,7 @@ typedef struct SCSIRequest { SCSIDevice *dev; uint32_t tag; uint32_t lun; + uint32_t status; struct { uint8_t buf[SCSI_CMD_BUF_SIZE]; int len; @@ -106,5 +107,6 @@ SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag); void scsi_req_free(SCSIRequest *req); int scsi_req_parse(SCSIRequest *req, uint8_t *buf); +void scsi_req_complete(SCSIRequest *req); #endif -- cgit v1.2.3-65-gdbad From ec766865633be4a36803fa33ee518c4166cfc459 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:01 +0100 Subject: scsi: add scsi_req_print() Handy for debugging. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/scsi.h | 1 + 2 files changed, 115 insertions(+) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 2e4fd3874..e362671d8 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -364,6 +364,120 @@ int scsi_req_parse(SCSIRequest *req, uint8_t *buf) return 0; } +static const char *scsi_command_name(uint8_t cmd) +{ + static const char *names[] = { + [ TEST_UNIT_READY ] = "TEST_UNIT_READY", + [ REZERO_UNIT ] = "REZERO_UNIT", + [ REQUEST_SENSE ] = "REQUEST_SENSE", + [ FORMAT_UNIT ] = "FORMAT_UNIT", + [ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS", + [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS", + [ READ_6 ] = "READ_6", + [ WRITE_6 ] = "WRITE_6", + [ SEEK_6 ] = "SEEK_6", + [ READ_REVERSE ] = "READ_REVERSE", + [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS", + [ SPACE ] = "SPACE", + [ INQUIRY ] = "INQUIRY", + [ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA", + [ MODE_SELECT ] = "MODE_SELECT", + [ RESERVE ] = "RESERVE", + [ RELEASE ] = "RELEASE", + [ COPY ] = "COPY", + [ ERASE ] = "ERASE", + [ MODE_SENSE ] = "MODE_SENSE", + [ START_STOP ] = "START_STOP", + [ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC", + [ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC", + [ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL", + + [ SET_WINDOW ] = "SET_WINDOW", + [ READ_CAPACITY ] = "READ_CAPACITY", + [ READ_10 ] = "READ_10", + [ WRITE_10 ] = "WRITE_10", + [ SEEK_10 ] = "SEEK_10", + [ WRITE_VERIFY ] = "WRITE_VERIFY", + [ VERIFY ] = "VERIFY", + [ SEARCH_HIGH ] = "SEARCH_HIGH", + [ SEARCH_EQUAL ] = "SEARCH_EQUAL", + [ SEARCH_LOW ] = "SEARCH_LOW", + [ SET_LIMITS ] = "SET_LIMITS", + [ PRE_FETCH ] = "PRE_FETCH", + [ READ_POSITION ] = "READ_POSITION", + [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE", + [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE", + [ READ_DEFECT_DATA ] = "READ_DEFECT_DATA", + [ MEDIUM_SCAN ] = "MEDIUM_SCAN", + [ COMPARE ] = "COMPARE", + [ COPY_VERIFY ] = "COPY_VERIFY", + [ WRITE_BUFFER ] = "WRITE_BUFFER", + [ READ_BUFFER ] = "READ_BUFFER", + [ UPDATE_BLOCK ] = "UPDATE_BLOCK", + [ READ_LONG ] = "READ_LONG", + [ WRITE_LONG ] = "WRITE_LONG", + [ CHANGE_DEFINITION ] = "CHANGE_DEFINITION", + [ WRITE_SAME ] = "WRITE_SAME", + [ READ_TOC ] = "READ_TOC", + [ LOG_SELECT ] = "LOG_SELECT", + [ LOG_SENSE ] = "LOG_SENSE", + [ MODE_SELECT_10 ] = "MODE_SELECT_10", + [ RESERVE_10 ] = "RESERVE_10", + [ RELEASE_10 ] = "RELEASE_10", + [ MODE_SENSE_10 ] = "MODE_SENSE_10", + [ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN", + [ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT", + [ MOVE_MEDIUM ] = "MOVE_MEDIUM", + [ READ_12 ] = "READ_12", + [ WRITE_12 ] = "WRITE_12", + [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12", + [ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12", + [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12", + [ SEARCH_LOW_12 ] = "SEARCH_LOW_12", + [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS", + [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG", + [ WRITE_LONG_2 ] = "WRITE_LONG_2", + + [ REWIND ] = "REWIND", + [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", + [ LOAD_UNLOAD ] = "LOAD_UNLOAD", + [ SET_CD_SPEED ] = "SET_CD_SPEED", + [ BLANK ] = "BLANK", + }; + + if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) + return "*UNKNOWN*"; + return names[cmd]; +} + +void scsi_req_print(SCSIRequest *req) +{ + FILE *fp = stderr; + int i; + + fprintf(fp, "[%s id=%d] %s", + req->dev->qdev.parent_bus->name, + req->dev->id, + scsi_command_name(req->cmd.buf[0])); + for (i = 1; i < req->cmd.len; i++) { + fprintf(fp, " 0x%02x", req->cmd.buf[i]); + } + switch (req->cmd.mode) { + case SCSI_XFER_NONE: + fprintf(fp, " - none\n"); + break; + case SCSI_XFER_FROM_DEV: + fprintf(fp, " - from-dev len=%zd\n", req->cmd.xfer); + break; + case SCSI_XFER_TO_DEV: + fprintf(fp, " - to-dev len=%zd\n", req->cmd.xfer); + break; + default: + fprintf(fp, " - Oops\n"); + break; + } +} + void scsi_req_complete(SCSIRequest *req) { assert(req->status != -1); diff --git a/hw/scsi.h b/hw/scsi.h index 2fe8c1206..8f0200d16 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -107,6 +107,7 @@ SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag); void scsi_req_free(SCSIRequest *req); int scsi_req_parse(SCSIRequest *req, uint8_t *buf); +void scsi_req_print(SCSIRequest *req); void scsi_req_complete(SCSIRequest *req); #endif -- cgit v1.2.3-65-gdbad From aa5dbdc190644cf36e4e7fbd68b4e40e13209039 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:02 +0100 Subject: scsi-disk: restruct emulation: core + TEST_UNIT_READY. Add new scsi_disk_emulate_command() function, which will -- when finished -- handle all scsi disk command emulation except actual I/O (READ+WRITE commands) which goes to the block layer. The function builds on top of the new SCSIRequest struct. SCSI command emulation code is moved over from scsi_send_command() in steps to ease review and make it easier to pin down regressions (if any) using bisect. This patch moves over TEST_UNIT_READY only. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index bc8270ce8..f851694a0 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -306,6 +306,31 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) return (uint8_t *)r->iov.iov_base; } +static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) +{ + BlockDriverState *bdrv = req->dev->dinfo->bdrv; + int buflen = 0; + + switch (req->cmd.buf[0]) { + case TEST_UNIT_READY: + if (!bdrv_is_inserted(bdrv)) + goto not_ready; + break; + default: + goto illegal_request; + } + scsi_req_set_status(req, GOOD, NO_SENSE); + return buflen; + +not_ready: + scsi_req_set_status(req, CHECK_CONDITION, NOT_READY); + return 0; + +illegal_request: + scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST); + return 0; +} + /* Execute a scsi command. Returns the length of the data expected by the command. This will be Positive for data transfers from the device (eg. disk reads), negative for transfers to the device (eg. disk writes), @@ -323,6 +348,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, uint8_t command; uint8_t *outbuf; SCSIDiskReq *r; + int rc; command = buf[0]; r = scsi_find_request(s, tag); @@ -377,6 +403,14 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, printf("\n"); } #endif + + if (scsi_req_parse(&r->req, buf) != 0) { + BADF("Unsupported command length, command %x\n", command); + goto fail; + } + assert(r->req.cmd.len == cmdlen); + assert(r->req.cmd.lba == lba); + if (lun || buf[1] >> 5) { /* Only LUN 0 supported. */ DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); @@ -385,10 +419,14 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } switch (command) { case TEST_UNIT_READY: - DPRINTF("Test Unit Ready\n"); - if (!bdrv_is_inserted(s->qdev.dinfo->bdrv)) - goto notready; - break; + rc = scsi_disk_emulate_command(&r->req, outbuf); + if (rc > 0) { + r->iov.iov_len = rc; + } else { + scsi_req_complete(&r->req); + scsi_remove_request(r); + } + return rc; case REQUEST_SENSE: DPRINTF("Request Sense (len %d)\n", len); if (len < 4) @@ -761,7 +799,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf[7] = 0; r->iov.iov_len = 8; } else { - notready: scsi_command_complete(r, CHECK_CONDITION, NOT_READY); return 0; } -- cgit v1.2.3-65-gdbad From 51ad87c963dfd3fb12316338cee8b75395bd1686 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:03 +0100 Subject: scsi-disk: restruct emulation: REQUEST_SENSE Move REQUEST_SENSE emulation from scsi_send_command() to scsi_disk_emulate_command(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index f851694a0..7597b5226 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -316,6 +316,24 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) if (!bdrv_is_inserted(bdrv)) goto not_ready; break; + case REQUEST_SENSE: + if (req->cmd.xfer < 4) + goto illegal_request; + memset(outbuf, 0, 4); + buflen = 4; + if (req->dev->sense.key == NOT_READY && req->cmd.xfer >= 18) { + memset(outbuf, 0, 18); + buflen = 18; + outbuf[7] = 10; + /* asc 0x3a, ascq 0: Medium not present */ + outbuf[12] = 0x3a; + outbuf[13] = 0; + } + outbuf[0] = 0xf0; + outbuf[1] = 0; + outbuf[2] = req->dev->sense.key; + scsi_dev_clear_sense(req->dev); + break; default: goto illegal_request; } @@ -419,6 +437,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } switch (command) { case TEST_UNIT_READY: + case REQUEST_SENSE: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -427,25 +446,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, scsi_remove_request(r); } return rc; - case REQUEST_SENSE: - DPRINTF("Request Sense (len %d)\n", len); - if (len < 4) - goto fail; - memset(outbuf, 0, 4); - r->iov.iov_len = 4; - if (s->qdev.sense.key == NOT_READY && len >= 18) { - memset(outbuf, 0, 18); - r->iov.iov_len = 18; - outbuf[7] = 10; - /* asc 0x3a, ascq 0: Medium not present */ - outbuf[12] = 0x3a; - outbuf[13] = 0; - } - outbuf[0] = 0xf0; - outbuf[1] = 0; - outbuf[2] = s->qdev.sense.key; - scsi_dev_clear_sense(&s->qdev); - break; case INQUIRY: DPRINTF("Inquiry (len %d)\n", len); if (buf[1] & 0x2) { -- cgit v1.2.3-65-gdbad From 0b06c05979075cbf224724f5ac1a3f4d713ccdd8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:04 +0100 Subject: scsi-disk: restruct emulation: INQUIRY Move INQUIRY emulation from scsi_send_command() to scsi_disk_emulate_command(). Also split the longish INQUITY emulation code into the new scsi_disk_emulate_inquiry() function. Serial number handling is slightly changed, we don't copy it any more but look it up directly in DriveInfo which we have at hand anyway. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 305 +++++++++++++++++++++++++++------------------------------ 1 file changed, 143 insertions(+), 162 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 7597b5226..f94d51382 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -58,7 +58,6 @@ struct SCSIDiskState This is the number of 512 byte blocks in a single scsi sector. */ int cluster_size; uint64_t max_lba; - char drive_serial_str[21]; QEMUBH *bh; }; @@ -306,6 +305,141 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) return (uint8_t *)r->iov.iov_base; } +static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) +{ + BlockDriverState *bdrv = req->dev->dinfo->bdrv; + int buflen = 0; + + if (req->cmd.buf[1] & 0x2) { + /* Command support data - optional, not implemented */ + BADF("optional INQUIRY command support request not implemented\n"); + return -1; + } + + if (req->cmd.buf[1] & 0x1) { + /* Vital product data */ + uint8_t page_code = req->cmd.buf[2]; + if (req->cmd.xfer < 4) { + BADF("Error: Inquiry (EVPD[%02X]) buffer size %zd is " + "less than 4\n", page_code, req->cmd.xfer); + return -1; + } + + if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) { + outbuf[buflen++] = 5; + } else { + outbuf[buflen++] = 0; + } + outbuf[buflen++] = page_code ; // this page + outbuf[buflen++] = 0x00; + + switch (page_code) { + case 0x00: /* Supported page codes, mandatory */ + DPRINTF("Inquiry EVPD[Supported pages] " + "buffer size %zd\n", req->cmd.xfer); + outbuf[buflen++] = 3; // number of pages + outbuf[buflen++] = 0x00; // list of supported pages (this page) + outbuf[buflen++] = 0x80; // unit serial number + outbuf[buflen++] = 0x83; // device identification + break; + + case 0x80: /* Device serial number, optional */ + { + const char *serial = req->dev->dinfo->serial ?: "0"; + int l = strlen(serial); + + if (l > req->cmd.xfer) + l = req->cmd.xfer; + if (l > 20) + l = 20; + + DPRINTF("Inquiry EVPD[Serial number] " + "buffer size %zd\n", req->cmd.xfer); + outbuf[buflen++] = l; + memcpy(outbuf+buflen, serial, l); + buflen += l; + break; + } + + case 0x83: /* Device identification page, mandatory */ + { + int max_len = 255 - 8; + int id_len = strlen(bdrv_get_device_name(bdrv)); + + if (id_len > max_len) + id_len = max_len; + DPRINTF("Inquiry EVPD[Device identification] " + "buffer size %zd\n", req->cmd.xfer); + + outbuf[buflen++] = 3 + id_len; + outbuf[buflen++] = 0x2; // ASCII + outbuf[buflen++] = 0; // not officially assigned + outbuf[buflen++] = 0; // reserved + outbuf[buflen++] = id_len; // length of data following + + memcpy(outbuf+buflen, bdrv_get_device_name(bdrv), id_len); + buflen += id_len; + break; + } + default: + BADF("Error: unsupported Inquiry (EVPD[%02X]) " + "buffer size %zd\n", page_code, req->cmd.xfer); + return -1; + } + /* done with EVPD */ + return buflen; + } + + /* Standard INQUIRY data */ + if (req->cmd.buf[2] != 0) { + BADF("Error: Inquiry (STANDARD) page or code " + "is non-zero [%02X]\n", req->cmd.buf[2]); + return -1; + } + + /* PAGE CODE == 0 */ + if (req->cmd.xfer < 5) { + BADF("Error: Inquiry (STANDARD) buffer size %zd " + "is less than 5\n", req->cmd.xfer); + return -1; + } + + if (req->cmd.xfer < 36) { + BADF("Error: Inquiry (STANDARD) buffer size %zd " + "is less than 36 (TODO: only 5 required)\n", req->cmd.xfer); + } + + buflen = req->cmd.xfer; + if (buflen > SCSI_MAX_INQUIRY_LEN) + buflen = SCSI_MAX_INQUIRY_LEN; + + memset(outbuf, 0, buflen); + + if (req->lun || req->cmd.buf[1] >> 5) { + outbuf[0] = 0x7f; /* LUN not supported */ + return buflen; + } + + if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) { + outbuf[0] = 5; + outbuf[1] = 0x80; + memcpy(&outbuf[16], "QEMU CD-ROM ", 16); + } else { + outbuf[0] = 0; + memcpy(&outbuf[16], "QEMU HARDDISK ", 16); + } + memcpy(&outbuf[8], "QEMU ", 8); + memcpy(&outbuf[32], QEMU_VERSION, 4); + /* Identify device as SCSI-3 rev 1. + Some later commands are also implemented. */ + outbuf[2] = 3; + outbuf[3] = 2; /* Format 2 */ + outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */ + /* Sync data transfer and TCQ. */ + outbuf[7] = 0x10 | (req->bus->tcq ? 0x02 : 0); + return buflen; +} + static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) { BlockDriverState *bdrv = req->dev->dinfo->bdrv; @@ -334,6 +468,11 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) outbuf[2] = req->dev->sense.key; scsi_dev_clear_sense(req->dev); break; + case INQUIRY: + buflen = scsi_disk_emulate_inquiry(req, outbuf); + if (buflen < 0) + goto illegal_request; + break; default: goto illegal_request; } @@ -438,170 +577,16 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, switch (command) { case TEST_UNIT_READY: case REQUEST_SENSE: + case INQUIRY: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; } else { scsi_req_complete(&r->req); scsi_remove_request(r); + return 0; } - return rc; - case INQUIRY: - DPRINTF("Inquiry (len %d)\n", len); - if (buf[1] & 0x2) { - /* Command support data - optional, not implemented */ - BADF("optional INQUIRY command support request not implemented\n"); - goto fail; - } - else if (buf[1] & 0x1) { - /* Vital product data */ - uint8_t page_code = buf[2]; - if (len < 4) { - BADF("Error: Inquiry (EVPD[%02X]) buffer size %d is " - "less than 4\n", page_code, len); - goto fail; - } - - switch (page_code) { - case 0x00: - { - /* Supported page codes, mandatory */ - DPRINTF("Inquiry EVPD[Supported pages] " - "buffer size %d\n", len); - - r->iov.iov_len = 0; - - if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { - outbuf[r->iov.iov_len++] = 5; - } else { - outbuf[r->iov.iov_len++] = 0; - } - - outbuf[r->iov.iov_len++] = 0x00; // this page - outbuf[r->iov.iov_len++] = 0x00; - outbuf[r->iov.iov_len++] = 3; // number of pages - outbuf[r->iov.iov_len++] = 0x00; // list of supported pages (this page) - outbuf[r->iov.iov_len++] = 0x80; // unit serial number - outbuf[r->iov.iov_len++] = 0x83; // device identification - } - break; - case 0x80: - { - int l; - - /* Device serial number, optional */ - if (len < 4) { - BADF("Error: EVPD[Serial number] Inquiry buffer " - "size %d too small, %d needed\n", len, 4); - goto fail; - } - - DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len); - l = MIN(len, strlen(s->drive_serial_str)); - - r->iov.iov_len = 0; - - /* Supported page codes */ - if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { - outbuf[r->iov.iov_len++] = 5; - } else { - outbuf[r->iov.iov_len++] = 0; - } - - outbuf[r->iov.iov_len++] = 0x80; // this page - outbuf[r->iov.iov_len++] = 0x00; - outbuf[r->iov.iov_len++] = l; - memcpy(&outbuf[r->iov.iov_len], s->drive_serial_str, l); - r->iov.iov_len += l; - } - - break; - case 0x83: - { - /* Device identification page, mandatory */ - int max_len = 255 - 8; - int id_len = strlen(bdrv_get_device_name(s->qdev.dinfo->bdrv)); - if (id_len > max_len) - id_len = max_len; - - DPRINTF("Inquiry EVPD[Device identification] " - "buffer size %d\n", len); - r->iov.iov_len = 0; - if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { - outbuf[r->iov.iov_len++] = 5; - } else { - outbuf[r->iov.iov_len++] = 0; - } - - outbuf[r->iov.iov_len++] = 0x83; // this page - outbuf[r->iov.iov_len++] = 0x00; - outbuf[r->iov.iov_len++] = 3 + id_len; - - outbuf[r->iov.iov_len++] = 0x2; // ASCII - outbuf[r->iov.iov_len++] = 0; // not officially assigned - outbuf[r->iov.iov_len++] = 0; // reserved - outbuf[r->iov.iov_len++] = id_len; // length of data following - - memcpy(&outbuf[r->iov.iov_len], - bdrv_get_device_name(s->qdev.dinfo->bdrv), id_len); - r->iov.iov_len += id_len; - } - break; - default: - BADF("Error: unsupported Inquiry (EVPD[%02X]) " - "buffer size %d\n", page_code, len); - goto fail; - } - /* done with EVPD */ - break; - } - else { - /* Standard INQUIRY data */ - if (buf[2] != 0) { - BADF("Error: Inquiry (STANDARD) page or code " - "is non-zero [%02X]\n", buf[2]); - goto fail; - } - - /* PAGE CODE == 0 */ - if (len < 5) { - BADF("Error: Inquiry (STANDARD) buffer size %d " - "is less than 5\n", len); - goto fail; - } - - if (len < 36) { - BADF("Error: Inquiry (STANDARD) buffer size %d " - "is less than 36 (TODO: only 5 required)\n", len); - } - } - - if(len > SCSI_MAX_INQUIRY_LEN) - len = SCSI_MAX_INQUIRY_LEN; - - memset(outbuf, 0, len); - - if (lun || buf[1] >> 5) { - outbuf[0] = 0x7f; /* LUN not supported */ - } else if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { - outbuf[0] = 5; - outbuf[1] = 0x80; - memcpy(&outbuf[16], "QEMU CD-ROM ", 16); - } else { - outbuf[0] = 0; - memcpy(&outbuf[16], "QEMU HARDDISK ", 16); - } - memcpy(&outbuf[8], "QEMU ", 8); - memcpy(&outbuf[32], QEMU_VERSION, 4); - /* Identify device as SCSI-3 rev 1. - Some later commands are also implemented. */ - outbuf[2] = 3; - outbuf[3] = 2; /* Format 2 */ - outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */ - /* Sync data transfer and TCQ. */ - outbuf[7] = 0x10 | (r->req.bus->tcq ? 0x02 : 0); - r->iov.iov_len = len; - break; + break; case RESERVE: DPRINTF("Reserve(6)\n"); if (buf[1] & 1) @@ -983,10 +968,6 @@ static int scsi_disk_initfn(SCSIDevice *dev) if (nb_sectors) nb_sectors--; s->max_lba = nb_sectors; - strncpy(s->drive_serial_str, drive_get_serial(s->qdev.dinfo->bdrv), - sizeof(s->drive_serial_str)); - if (strlen(s->drive_serial_str) == 0) - pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0"); qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s); return 0; } -- cgit v1.2.3-65-gdbad From 3d53ba18f5bae3208fe42d9c8fba9687394655d5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:05 +0100 Subject: scsi-disk: restruct emulation: RESERVE+RELEASE Move RESERVE+RELEASE emulation from scsi_send_command() to scsi_disk_emulate_command(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index f94d51382..c67712a01 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -473,6 +473,22 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) if (buflen < 0) goto illegal_request; break; + case RESERVE: + if (req->cmd.buf[1] & 1) + goto illegal_request; + break; + case RESERVE_10: + if (req->cmd.buf[1] & 3) + goto illegal_request; + break; + case RELEASE: + if (req->cmd.buf[1] & 1) + goto illegal_request; + break; + case RELEASE_10: + if (req->cmd.buf[1] & 3) + goto illegal_request; + break; default: goto illegal_request; } @@ -578,6 +594,10 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case TEST_UNIT_READY: case REQUEST_SENSE: case INQUIRY: + case RESERVE: + case RESERVE_10: + case RELEASE: + case RELEASE_10: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -587,16 +607,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, return 0; } break; - case RESERVE: - DPRINTF("Reserve(6)\n"); - if (buf[1] & 1) - goto fail; - break; - case RELEASE: - DPRINTF("Release(6)\n"); - if (buf[1] & 1) - goto fail; - break; case MODE_SENSE: case MODE_SENSE_10: { @@ -857,16 +867,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf[7] = 8; // CD-ROM r->iov.iov_len = 8; break; - case RESERVE_10: - DPRINTF("Reserve(10)\n"); - if (buf[1] & 3) - goto fail; - break; - case RELEASE_10: - DPRINTF("Release(10)\n"); - if (buf[1] & 3) - goto fail; - break; case 0x9e: /* Service Action In subcommands. */ if ((buf[1] & 31) == 0x10) { -- cgit v1.2.3-65-gdbad From ebddfcbe14c0184ef3821b987b0a9746b4802c27 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:06 +0100 Subject: scsi-disk: restruct emulation: MODE_SENSE Move MODE_SENSE emulation from scsi_send_command() to scsi_disk_emulate_command(). Create two helper functions: mode_sense_page() which writes the actual mode pages and scsi_disk_emulate_mode_sense() which holds the longish MODE_SENSE emulation code, calling into mode_sense_page() as needed. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 335 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 183 insertions(+), 152 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index c67712a01..06289c3c1 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -440,6 +440,181 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) return buflen; } +static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + BlockDriverState *bdrv = req->dev->dinfo->bdrv; + int cylinders, heads, secs; + + switch (page) { + case 4: /* Rigid disk device geometry page. */ + p[0] = 4; + p[1] = 0x16; + /* if a geometry hint is available, use it */ + bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs); + p[2] = (cylinders >> 16) & 0xff; + p[3] = (cylinders >> 8) & 0xff; + p[4] = cylinders & 0xff; + p[5] = heads & 0xff; + /* Write precomp start cylinder, disabled */ + p[6] = (cylinders >> 16) & 0xff; + p[7] = (cylinders >> 8) & 0xff; + p[8] = cylinders & 0xff; + /* Reduced current start cylinder, disabled */ + p[9] = (cylinders >> 16) & 0xff; + p[10] = (cylinders >> 8) & 0xff; + p[11] = cylinders & 0xff; + /* Device step rate [ns], 200ns */ + p[12] = 0; + p[13] = 200; + /* Landing zone cylinder */ + p[14] = 0xff; + p[15] = 0xff; + p[16] = 0xff; + /* Medium rotation rate [rpm], 5400 rpm */ + p[20] = (5400 >> 8) & 0xff; + p[21] = 5400 & 0xff; + return 0x16; + + case 5: /* Flexible disk device geometry page. */ + p[0] = 5; + p[1] = 0x1e; + /* Transfer rate [kbit/s], 5Mbit/s */ + p[2] = 5000 >> 8; + p[3] = 5000 & 0xff; + /* if a geometry hint is available, use it */ + bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs); + p[4] = heads & 0xff; + p[5] = secs & 0xff; + p[6] = s->cluster_size * 2; + p[8] = (cylinders >> 8) & 0xff; + p[9] = cylinders & 0xff; + /* Write precomp start cylinder, disabled */ + p[10] = (cylinders >> 8) & 0xff; + p[11] = cylinders & 0xff; + /* Reduced current start cylinder, disabled */ + p[12] = (cylinders >> 8) & 0xff; + p[13] = cylinders & 0xff; + /* Device step rate [100us], 100us */ + p[14] = 0; + p[15] = 1; + /* Device step pulse width [us], 1us */ + p[16] = 1; + /* Device head settle delay [100us], 100us */ + p[17] = 0; + p[18] = 1; + /* Motor on delay [0.1s], 0.1s */ + p[19] = 1; + /* Motor off delay [0.1s], 0.1s */ + p[20] = 1; + /* Medium rotation rate [rpm], 5400 rpm */ + p[28] = (5400 >> 8) & 0xff; + p[29] = 5400 & 0xff; + return 0x1e; + + case 8: /* Caching page. */ + p[0] = 8; + p[1] = 0x12; + if (bdrv_enable_write_cache(s->qdev.dinfo->bdrv)) { + p[2] = 4; /* WCE */ + } + return 20; + + case 0x2a: /* CD Capabilities and Mechanical Status page. */ + if (bdrv_get_type_hint(bdrv) != BDRV_TYPE_CDROM) + return 0; + p[0] = 0x2a; + p[1] = 0x14; + p[2] = 3; // CD-R & CD-RW read + p[3] = 0; // Writing not supported + p[4] = 0x7f; /* Audio, composite, digital out, + mode 2 form 1&2, multi session */ + p[5] = 0xff; /* CD DA, DA accurate, RW supported, + RW corrected, C2 errors, ISRC, + UPC, Bar code */ + p[6] = 0x2d | (bdrv_is_locked(s->qdev.dinfo->bdrv)? 2 : 0); + /* Locking supported, jumper present, eject, tray */ + p[7] = 0; /* no volume & mute control, no + changer */ + p[8] = (50 * 176) >> 8; // 50x read speed + p[9] = (50 * 176) & 0xff; + p[10] = 0 >> 8; // No volume + p[11] = 0 & 0xff; + p[12] = 2048 >> 8; // 2M buffer + p[13] = 2048 & 0xff; + p[14] = (16 * 176) >> 8; // 16x read speed current + p[15] = (16 * 176) & 0xff; + p[18] = (16 * 176) >> 8; // 16x write speed + p[19] = (16 * 176) & 0xff; + p[20] = (16 * 176) >> 8; // 16x write speed current + p[21] = (16 * 176) & 0xff; + return 22; + + default: + return 0; + } +} + +static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + BlockDriverState *bdrv = req->dev->dinfo->bdrv; + uint64_t nb_sectors; + int page, dbd, buflen; + uint8_t *p; + + dbd = req->cmd.buf[1] & 0x8; + page = req->cmd.buf[2] & 0x3f; + DPRINTF("Mode Sense (page %d, len %zd)\n", page, req->cmd.xfer); + memset(outbuf, 0, req->cmd.xfer); + p = outbuf; + + p[1] = 0; /* Default media type. */ + p[3] = 0; /* Block descriptor length. */ + if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM || + bdrv_is_read_only(bdrv)) { + p[2] = 0x80; /* Readonly. */ + } + p += 4; + + bdrv_get_geometry(bdrv, &nb_sectors); + if ((~dbd) & nb_sectors) { + outbuf[3] = 8; /* Block descriptor length */ + nb_sectors /= s->cluster_size; + nb_sectors--; + if (nb_sectors > 0xffffff) + nb_sectors = 0xffffff; + p[0] = 0; /* media density code */ + p[1] = (nb_sectors >> 16) & 0xff; + p[2] = (nb_sectors >> 8) & 0xff; + p[3] = nb_sectors & 0xff; + p[4] = 0; /* reserved */ + p[5] = 0; /* bytes 5-7 are the sector size in bytes */ + p[6] = s->cluster_size * 2; + p[7] = 0; + p += 8; + } + + switch (page) { + case 0x04: + case 0x05: + case 0x08: + case 0x2a: + p += mode_sense_page(req, page, p); + break; + case 0x3f: + p += mode_sense_page(req, 0x08, p); + p += mode_sense_page(req, 0x2a, p); + break; + } + + buflen = p - outbuf; + outbuf[0] = buflen - 4; + if (buflen > req->cmd.xfer) + buflen = req->cmd.xfer; + return buflen; +} + static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) { BlockDriverState *bdrv = req->dev->dinfo->bdrv; @@ -473,6 +648,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) if (buflen < 0) goto illegal_request; break; + case MODE_SENSE: + case MODE_SENSE_10: + buflen = scsi_disk_emulate_mode_sense(req, outbuf); + if (buflen < 0) + goto illegal_request; + break; case RESERVE: if (req->cmd.buf[1] & 1) goto illegal_request; @@ -594,6 +775,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case TEST_UNIT_READY: case REQUEST_SENSE: case INQUIRY: + case MODE_SENSE: + case MODE_SENSE_10: case RESERVE: case RESERVE_10: case RELEASE: @@ -607,158 +790,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, return 0; } break; - case MODE_SENSE: - case MODE_SENSE_10: - { - uint8_t *p; - int page; - int dbd; - - dbd = buf[1] & 0x8; - page = buf[2] & 0x3f; - DPRINTF("Mode Sense (page %d, len %d)\n", page, len); - p = outbuf; - memset(p, 0, 4); - outbuf[1] = 0; /* Default media type. */ - outbuf[3] = 0; /* Block descriptor length. */ - if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM || - bdrv_is_read_only(s->qdev.dinfo->bdrv)) { - outbuf[2] = 0x80; /* Readonly. */ - } - p += 4; - bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); - if ((~dbd) & nb_sectors) { - nb_sectors /= s->cluster_size; - nb_sectors--; - if (nb_sectors > 0xffffff) - nb_sectors = 0xffffff; - outbuf[3] = 8; /* Block descriptor length */ - p[0] = 0; /* media density code */ - p[1] = (nb_sectors >> 16) & 0xff; - p[2] = (nb_sectors >> 8) & 0xff; - p[3] = nb_sectors & 0xff; - p[4] = 0; /* reserved */ - p[5] = 0; /* bytes 5-7 are the sector size in bytes */ - p[6] = s->cluster_size * 2; - p[7] = 0; - p += 8; - } - - if (page == 4) { - int cylinders, heads, secs; - - /* Rigid disk device geometry page. */ - p[0] = 4; - p[1] = 0x16; - /* if a geometry hint is available, use it */ - bdrv_get_geometry_hint(s->qdev.dinfo->bdrv, &cylinders, &heads, &secs); - p[2] = (cylinders >> 16) & 0xff; - p[3] = (cylinders >> 8) & 0xff; - p[4] = cylinders & 0xff; - p[5] = heads & 0xff; - /* Write precomp start cylinder, disabled */ - p[6] = (cylinders >> 16) & 0xff; - p[7] = (cylinders >> 8) & 0xff; - p[8] = cylinders & 0xff; - /* Reduced current start cylinder, disabled */ - p[9] = (cylinders >> 16) & 0xff; - p[10] = (cylinders >> 8) & 0xff; - p[11] = cylinders & 0xff; - /* Device step rate [ns], 200ns */ - p[12] = 0; - p[13] = 200; - /* Landing zone cylinder */ - p[14] = 0xff; - p[15] = 0xff; - p[16] = 0xff; - /* Medium rotation rate [rpm], 5400 rpm */ - p[20] = (5400 >> 8) & 0xff; - p[21] = 5400 & 0xff; - p += 0x16; - } else if (page == 5) { - int cylinders, heads, secs; - - /* Flexible disk device geometry page. */ - p[0] = 5; - p[1] = 0x1e; - /* Transfer rate [kbit/s], 5Mbit/s */ - p[2] = 5000 >> 8; - p[3] = 5000 & 0xff; - /* if a geometry hint is available, use it */ - bdrv_get_geometry_hint(s->qdev.dinfo->bdrv, &cylinders, &heads, &secs); - p[4] = heads & 0xff; - p[5] = secs & 0xff; - p[6] = s->cluster_size * 2; - p[8] = (cylinders >> 8) & 0xff; - p[9] = cylinders & 0xff; - /* Write precomp start cylinder, disabled */ - p[10] = (cylinders >> 8) & 0xff; - p[11] = cylinders & 0xff; - /* Reduced current start cylinder, disabled */ - p[12] = (cylinders >> 8) & 0xff; - p[13] = cylinders & 0xff; - /* Device step rate [100us], 100us */ - p[14] = 0; - p[15] = 1; - /* Device step pulse width [us], 1us */ - p[16] = 1; - /* Device head settle delay [100us], 100us */ - p[17] = 0; - p[18] = 1; - /* Motor on delay [0.1s], 0.1s */ - p[19] = 1; - /* Motor off delay [0.1s], 0.1s */ - p[20] = 1; - /* Medium rotation rate [rpm], 5400 rpm */ - p[28] = (5400 >> 8) & 0xff; - p[29] = 5400 & 0xff; - p += 0x1e; - } else if ((page == 8 || page == 0x3f)) { - /* Caching page. */ - memset(p,0,20); - p[0] = 8; - p[1] = 0x12; - if (bdrv_enable_write_cache(s->qdev.dinfo->bdrv)) { - p[2] = 4; /* WCE */ - } - p += 20; - } - if ((page == 0x3f || page == 0x2a) - && (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM)) { - /* CD Capabilities and Mechanical Status page. */ - p[0] = 0x2a; - p[1] = 0x14; - p[2] = 3; // CD-R & CD-RW read - p[3] = 0; // Writing not supported - p[4] = 0x7f; /* Audio, composite, digital out, - mode 2 form 1&2, multi session */ - p[5] = 0xff; /* CD DA, DA accurate, RW supported, - RW corrected, C2 errors, ISRC, - UPC, Bar code */ - p[6] = 0x2d | (bdrv_is_locked(s->qdev.dinfo->bdrv)? 2 : 0); - /* Locking supported, jumper present, eject, tray */ - p[7] = 0; /* no volume & mute control, no - changer */ - p[8] = (50 * 176) >> 8; // 50x read speed - p[9] = (50 * 176) & 0xff; - p[10] = 0 >> 8; // No volume - p[11] = 0 & 0xff; - p[12] = 2048 >> 8; // 2M buffer - p[13] = 2048 & 0xff; - p[14] = (16 * 176) >> 8; // 16x read speed current - p[15] = (16 * 176) & 0xff; - p[18] = (16 * 176) >> 8; // 16x write speed - p[19] = (16 * 176) & 0xff; - p[20] = (16 * 176) >> 8; // 16x write speed current - p[21] = (16 * 176) & 0xff; - p += 22; - } - r->iov.iov_len = p - outbuf; - outbuf[0] = r->iov.iov_len - 4; - if (r->iov.iov_len > len) - r->iov.iov_len = len; - } - break; case START_STOP: DPRINTF("Start Stop Unit\n"); if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM && -- cgit v1.2.3-65-gdbad From 8d3628fff4131775dd4b7ad1748e0deb0b53aae8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:07 +0100 Subject: scsi-disk: restruct emulation: START_STOP Move START_STOP emulation from scsi_send_command() to scsi_disk_emulate_command(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 06289c3c1..11e85f28f 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -670,6 +670,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) if (req->cmd.buf[1] & 3) goto illegal_request; break; + case START_STOP: + if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM && (req->cmd.buf[4] & 2)) { + /* load/eject medium */ + bdrv_eject(bdrv, !(req->cmd.buf[4] & 1)); + } + break; default: goto illegal_request; } @@ -781,6 +787,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case RESERVE_10: case RELEASE: case RELEASE_10: + case START_STOP: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -790,13 +797,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, return 0; } break; - case START_STOP: - DPRINTF("Start Stop Unit\n"); - if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM && - (buf[4] & 2)) - /* load/eject medium */ - bdrv_eject(s->qdev.dinfo->bdrv, !(buf[4] & 1)); - break; case ALLOW_MEDIUM_REMOVAL: DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3); bdrv_set_locked(s->qdev.dinfo->bdrv, buf[4] & 1); -- cgit v1.2.3-65-gdbad From c68b9f34c136ce4ff77fc165227596b267e15fa1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:08 +0100 Subject: scsi-disk: restruct emulation: ALLOW_MEDIUM_REMOVAL Move ALLOW_MEDIUM_REMOVAL emulation from scsi_send_command() to scsi_disk_emulate_command(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 11e85f28f..7d5999899 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -676,6 +676,9 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) bdrv_eject(bdrv, !(req->cmd.buf[4] & 1)); } break; + case ALLOW_MEDIUM_REMOVAL: + bdrv_set_locked(bdrv, req->cmd.buf[4] & 1); + break; default: goto illegal_request; } @@ -788,6 +791,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case RELEASE: case RELEASE_10: case START_STOP: + case ALLOW_MEDIUM_REMOVAL: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -797,10 +801,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, return 0; } break; - case ALLOW_MEDIUM_REMOVAL: - DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3); - bdrv_set_locked(s->qdev.dinfo->bdrv, buf[4] & 1); - break; case READ_CAPACITY: DPRINTF("Read Capacity\n"); /* The normal LEN field for this command is zero. */ -- cgit v1.2.3-65-gdbad From e7e25e32693b052b29edb8396dbc577e1bf2a09f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:09 +0100 Subject: scsi-disk: restruct emulation: READ_CAPACITY Move READ_CAPACITY emulation from scsi_send_command() to scsi_disk_emulate_command(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 55 +++++++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 7d5999899..4f56a2290 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -617,7 +617,9 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); BlockDriverState *bdrv = req->dev->dinfo->bdrv; + uint64_t nb_sectors; int buflen = 0; switch (req->cmd.buf[0]) { @@ -679,6 +681,30 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) case ALLOW_MEDIUM_REMOVAL: bdrv_set_locked(bdrv, req->cmd.buf[4] & 1); break; + case READ_CAPACITY: + /* The normal LEN field for this command is zero. */ + memset(outbuf, 0, 8); + bdrv_get_geometry(bdrv, &nb_sectors); + if (!nb_sectors) + goto not_ready; + nb_sectors /= s->cluster_size; + /* Returned value is the address of the last sector. */ + nb_sectors--; + /* Remember the new size for read/write sanity checking. */ + s->max_lba = nb_sectors; + /* Clip to 2TB, instead of returning capacity modulo 2TB. */ + if (nb_sectors > UINT32_MAX) + nb_sectors = UINT32_MAX; + outbuf[0] = (nb_sectors >> 24) & 0xff; + outbuf[1] = (nb_sectors >> 16) & 0xff; + outbuf[2] = (nb_sectors >> 8) & 0xff; + outbuf[3] = nb_sectors & 0xff; + outbuf[4] = 0; + outbuf[5] = 0; + outbuf[6] = s->cluster_size * 2; + outbuf[7] = 0; + buflen = 8; + break; default: goto illegal_request; } @@ -792,6 +818,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case RELEASE_10: case START_STOP: case ALLOW_MEDIUM_REMOVAL: + case READ_CAPACITY: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -801,34 +828,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, return 0; } break; - case READ_CAPACITY: - DPRINTF("Read Capacity\n"); - /* The normal LEN field for this command is zero. */ - memset(outbuf, 0, 8); - bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); - nb_sectors /= s->cluster_size; - /* Returned value is the address of the last sector. */ - if (nb_sectors) { - nb_sectors--; - /* Remember the new size for read/write sanity checking. */ - s->max_lba = nb_sectors; - /* Clip to 2TB, instead of returning capacity modulo 2TB. */ - if (nb_sectors > UINT32_MAX) - nb_sectors = UINT32_MAX; - outbuf[0] = (nb_sectors >> 24) & 0xff; - outbuf[1] = (nb_sectors >> 16) & 0xff; - outbuf[2] = (nb_sectors >> 8) & 0xff; - outbuf[3] = nb_sectors & 0xff; - outbuf[4] = 0; - outbuf[5] = 0; - outbuf[6] = s->cluster_size * 2; - outbuf[7] = 0; - r->iov.iov_len = 8; - } else { - scsi_command_complete(r, CHECK_CONDITION, NOT_READY); - return 0; - } - break; case READ_6: case READ_10: case 0x88: -- cgit v1.2.3-65-gdbad From fc903943f8df1226294783b0df607c928393bae4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:10 +0100 Subject: scsi-disk: restruct emulation: SYNCHRONIZE_CACHE Move SYNCHRONIZE_CACHE emulation from scsi_send_command() to scsi_disk_emulate_command(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 4f56a2290..865c5db8f 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -705,6 +705,9 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) outbuf[7] = 0; buflen = 8; break; + case SYNCHRONIZE_CACHE: + bdrv_flush(bdrv); + break; default: goto illegal_request; } @@ -819,6 +822,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case START_STOP: case ALLOW_MEDIUM_REMOVAL: case READ_CAPACITY: + case SYNCHRONIZE_CACHE: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -847,10 +851,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->sector_count = len * s->cluster_size; is_write = 1; break; - case SYNCHRONIZE_CACHE: - DPRINTF("Synchronise cache (sector %" PRId64 ", count %d)\n", lba, len); - bdrv_flush(s->qdev.dinfo->bdrv); - break; case READ_TOC: { int start_track, format, msf, toclen; -- cgit v1.2.3-65-gdbad From 02880f434912ca9dcc346d28d375003172b9e650 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:11 +0100 Subject: scsi-disk: restruct emulation: READ_TOC Move READ_TOC emulation from scsi_send_command() to scsi_disk_emulate_command(). Add scsi_disk_emulate_read_toc() function which holds the longisch READ_TOC emulation code. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 80 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 865c5db8f..6ba8f85cd 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -615,6 +615,42 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) return buflen; } +static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + BlockDriverState *bdrv = req->dev->dinfo->bdrv; + int start_track, format, msf, toclen; + uint64_t nb_sectors; + + msf = req->cmd.buf[1] & 2; + format = req->cmd.buf[2] & 0xf; + start_track = req->cmd.buf[6]; + bdrv_get_geometry(bdrv, &nb_sectors); + DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); + nb_sectors /= s->cluster_size; + switch (format) { + case 0: + toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track); + break; + case 1: + /* multi session : only a single session defined */ + toclen = 12; + memset(outbuf, 0, 12); + outbuf[1] = 0x0a; + outbuf[2] = 0x01; + outbuf[3] = 0x01; + break; + case 2: + toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track); + break; + default: + return -1; + } + if (toclen > req->cmd.xfer) + toclen = req->cmd.xfer; + return toclen; +} + static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); @@ -656,6 +692,11 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) if (buflen < 0) goto illegal_request; break; + case READ_TOC: + buflen = scsi_disk_emulate_read_toc(req, outbuf); + if (buflen < 0) + goto illegal_request; + break; case RESERVE: if (req->cmd.buf[1] & 1) goto illegal_request; @@ -823,6 +864,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case ALLOW_MEDIUM_REMOVAL: case READ_CAPACITY: case SYNCHRONIZE_CACHE: + case READ_TOC: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -851,44 +893,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->sector_count = len * s->cluster_size; is_write = 1; break; - case READ_TOC: - { - int start_track, format, msf, toclen; - - msf = buf[1] & 2; - format = buf[2] & 0xf; - start_track = buf[6]; - bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); - DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); - nb_sectors /= s->cluster_size; - switch(format) { - case 0: - toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track); - break; - case 1: - /* multi session : only a single session defined */ - toclen = 12; - memset(outbuf, 0, 12); - outbuf[1] = 0x0a; - outbuf[2] = 0x01; - outbuf[3] = 0x01; - break; - case 2: - toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track); - break; - default: - goto error_cmd; - } - if (toclen > 0) { - if (len > toclen) - len = toclen; - r->iov.iov_len = len; - break; - } - error_cmd: - DPRINTF("Read TOC error\n"); - goto fail; - } case 0x46: DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); memset(outbuf, 0, 8); -- cgit v1.2.3-65-gdbad From 382155536cdbffb9ea621f61773109594626ba01 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:12 +0100 Subject: scsi-disk: restruct emulation: GET_CONFIGURATION Move GET_CONFIGURATION emulation from scsi_send_command() to scsi_disk_emulate_command(). Also add GET_CONFIGURATION to scsi-defs.h and scsi_command_name(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 1 + hw/scsi-defs.h | 1 + hw/scsi-disk.c | 16 ++++++++-------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index e362671d8..09b6fa98d 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -440,6 +440,7 @@ static const char *scsi_command_name(uint8_t cmd) [ REWIND ] = "REWIND", [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", + [ GET_CONFIGURATION ] = "GET_CONFIGURATION", [ LOAD_UNLOAD ] = "LOAD_UNLOAD", [ SET_CD_SPEED ] = "SET_CD_SPEED", [ BLANK ] = "BLANK", diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index 1701521ad..fbcfaa677 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -99,6 +99,7 @@ /* from hw/scsi-generic.c */ #define REWIND 0x01 #define REPORT_DENSITY_SUPPORT 0x44 +#define GET_CONFIGURATION 0x46 #define LOAD_UNLOAD 0xa6 #define SET_CD_SPEED 0xbb #define BLANK 0xa1 diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 6ba8f85cd..4a3e6fe10 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -749,6 +749,13 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) case SYNCHRONIZE_CACHE: bdrv_flush(bdrv); break; + case GET_CONFIGURATION: + memset(outbuf, 0, 8); + /* ??? This should probably return much more information. For now + just return the basic header indicating the CD-ROM profile. */ + outbuf[7] = 8; // CD-ROM + buflen = 8; + break; default: goto illegal_request; } @@ -865,6 +872,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case READ_CAPACITY: case SYNCHRONIZE_CACHE: case READ_TOC: + case GET_CONFIGURATION: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -893,14 +901,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->sector_count = len * s->cluster_size; is_write = 1; break; - case 0x46: - DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); - memset(outbuf, 0, 8); - /* ??? This should probably return much more information. For now - just return the basic header indicating the CD-ROM profile. */ - outbuf[7] = 8; // CD-ROM - r->iov.iov_len = 8; - break; case 0x9e: /* Service Action In subcommands. */ if ((buf[1] & 31) == 0x10) { -- cgit v1.2.3-65-gdbad From 5dd90e2ad7a0ac27fc132f778827e70b7dbaf627 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:13 +0100 Subject: scsi-disk: restruct emulation: SERVICE_ACTION_IN Move SERVICE_ACTION_IN emulation from scsi_send_command() to scsi_disk_emulate_command(). Also add SERVICE_ACTION_IN to scsi-defs.h and scsi_command_name(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 1 + hw/scsi-defs.h | 1 + hw/scsi-disk.c | 67 ++++++++++++++++++++++++++++------------------------------ 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 09b6fa98d..deb6b4f3a 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -441,6 +441,7 @@ static const char *scsi_command_name(uint8_t cmd) [ REWIND ] = "REWIND", [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", [ GET_CONFIGURATION ] = "GET_CONFIGURATION", + [ SERVICE_ACTION_IN ] = "SERVICE_ACTION_IN", [ LOAD_UNLOAD ] = "LOAD_UNLOAD", [ SET_CD_SPEED ] = "SET_CD_SPEED", [ BLANK ] = "BLANK", diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index fbcfaa677..4aeb667a7 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -100,6 +100,7 @@ #define REWIND 0x01 #define REPORT_DENSITY_SUPPORT 0x44 #define GET_CONFIGURATION 0x46 +#define SERVICE_ACTION_IN 0x9e #define LOAD_UNLOAD 0xa6 #define SET_CD_SPEED 0xbb #define BLANK 0xa1 diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 4a3e6fe10..b481c1396 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -756,6 +756,37 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) outbuf[7] = 8; // CD-ROM buflen = 8; break; + case SERVICE_ACTION_IN: + /* Service Action In subcommands. */ + if ((req->cmd.buf[1] & 31) == 0x10) { + DPRINTF("SAI READ CAPACITY(16)\n"); + memset(outbuf, 0, req->cmd.xfer); + bdrv_get_geometry(bdrv, &nb_sectors); + if (!nb_sectors) + goto not_ready; + nb_sectors /= s->cluster_size; + /* Returned value is the address of the last sector. */ + nb_sectors--; + /* Remember the new size for read/write sanity checking. */ + s->max_lba = nb_sectors; + outbuf[0] = (nb_sectors >> 56) & 0xff; + outbuf[1] = (nb_sectors >> 48) & 0xff; + outbuf[2] = (nb_sectors >> 40) & 0xff; + outbuf[3] = (nb_sectors >> 32) & 0xff; + outbuf[4] = (nb_sectors >> 24) & 0xff; + outbuf[5] = (nb_sectors >> 16) & 0xff; + outbuf[6] = (nb_sectors >> 8) & 0xff; + outbuf[7] = nb_sectors & 0xff; + outbuf[8] = 0; + outbuf[9] = 0; + outbuf[10] = s->cluster_size * 2; + outbuf[11] = 0; + /* Protection, exponent and lowest lba field left blank. */ + buflen = req->cmd.xfer; + break; + } + DPRINTF("Unsupported Service Action In\n"); + goto illegal_request; default: goto illegal_request; } @@ -780,7 +811,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, uint8_t *buf, int lun) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - uint64_t nb_sectors; uint64_t lba; uint32_t len; int cmdlen; @@ -873,6 +903,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case SYNCHRONIZE_CACHE: case READ_TOC: case GET_CONFIGURATION: + case SERVICE_ACTION_IN: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -901,40 +932,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->sector_count = len * s->cluster_size; is_write = 1; break; - case 0x9e: - /* Service Action In subcommands. */ - if ((buf[1] & 31) == 0x10) { - DPRINTF("SAI READ CAPACITY(16)\n"); - memset(outbuf, 0, len); - bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); - nb_sectors /= s->cluster_size; - /* Returned value is the address of the last sector. */ - if (nb_sectors) { - nb_sectors--; - /* Remember the new size for read/write sanity checking. */ - s->max_lba = nb_sectors; - outbuf[0] = (nb_sectors >> 56) & 0xff; - outbuf[1] = (nb_sectors >> 48) & 0xff; - outbuf[2] = (nb_sectors >> 40) & 0xff; - outbuf[3] = (nb_sectors >> 32) & 0xff; - outbuf[4] = (nb_sectors >> 24) & 0xff; - outbuf[5] = (nb_sectors >> 16) & 0xff; - outbuf[6] = (nb_sectors >> 8) & 0xff; - outbuf[7] = nb_sectors & 0xff; - outbuf[8] = 0; - outbuf[9] = 0; - outbuf[10] = s->cluster_size * 2; - outbuf[11] = 0; - /* Protection, exponent and lowest lba field left blank. */ - r->iov.iov_len = len; - } else { - scsi_command_complete(r, CHECK_CONDITION, NOT_READY); - return 0; - } - break; - } - DPRINTF("Unsupported Service Action In\n"); - goto fail; case 0xa0: DPRINTF("Report LUNs (len %d)\n", len); if (len < 16) -- cgit v1.2.3-65-gdbad From 39ec9a504ddebc9432de892c185447af5b192f2a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:14 +0100 Subject: scsi-disk: restruct emulation: REPORT_LUNS Move REPORT_LUNS emulation from scsi_send_command() to scsi_disk_emulate_command(). Also add REPORT_LUNS to scsi-defs.h and scsi_command_name(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 1 + hw/scsi-defs.h | 1 + hw/scsi-disk.c | 16 ++++++++-------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index deb6b4f3a..b6de5c633 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -442,6 +442,7 @@ static const char *scsi_command_name(uint8_t cmd) [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", [ GET_CONFIGURATION ] = "GET_CONFIGURATION", [ SERVICE_ACTION_IN ] = "SERVICE_ACTION_IN", + [ REPORT_LUNS ] = "REPORT_LUNS", [ LOAD_UNLOAD ] = "LOAD_UNLOAD", [ SET_CD_SPEED ] = "SET_CD_SPEED", [ BLANK ] = "BLANK", diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index 4aeb667a7..cc7f35eaa 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -101,6 +101,7 @@ #define REPORT_DENSITY_SUPPORT 0x44 #define GET_CONFIGURATION 0x46 #define SERVICE_ACTION_IN 0x9e +#define REPORT_LUNS 0xa0 #define LOAD_UNLOAD 0xa6 #define SET_CD_SPEED 0xbb #define BLANK 0xa1 diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index b481c1396..1507bcd1f 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -787,6 +787,13 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) } DPRINTF("Unsupported Service Action In\n"); goto illegal_request; + case REPORT_LUNS: + if (req->cmd.xfer < 16) + goto illegal_request; + memset(outbuf, 0, 16); + outbuf[3] = 8; + buflen = 16; + break; default: goto illegal_request; } @@ -904,6 +911,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case READ_TOC: case GET_CONFIGURATION: case SERVICE_ACTION_IN: + case REPORT_LUNS: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -932,14 +940,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->sector_count = len * s->cluster_size; is_write = 1; break; - case 0xa0: - DPRINTF("Report LUNs (len %d)\n", len); - if (len < 16) - goto fail; - memset(outbuf, 0, 16); - outbuf[3] = 8; - r->iov.iov_len = 16; - break; case VERIFY: DPRINTF("Verify (sector %" PRId64 ", count %d)\n", lba, len); break; -- cgit v1.2.3-65-gdbad From 88f8a5ed0f4f1454ba53661fed0f676180e9be32 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:15 +0100 Subject: scsi-disk: restruct emulation: VERIFY Move VERIFY emulation from scsi_send_command() to scsi_disk_emulate_command(). Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-disk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 1507bcd1f..291078292 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -794,6 +794,8 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) outbuf[3] = 8; buflen = 16; break; + case VERIFY: + break; default: goto illegal_request; } @@ -912,6 +914,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case GET_CONFIGURATION: case SERVICE_ACTION_IN: case REPORT_LUNS: + case VERIFY: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; @@ -940,9 +943,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->sector_count = len * s->cluster_size; is_write = 1; break; - case VERIFY: - DPRINTF("Verify (sector %" PRId64 ", count %d)\n", lba, len); - break; default: DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); fail: -- cgit v1.2.3-65-gdbad From bd536cf3302e258cace9cfa9f554ec9f9e27591a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Nov 2009 15:34:16 +0100 Subject: scsi: add read/write 16 commands. Add READ_16 + friends to scsi-defs.h, scsi_command_name() and the request parsing helper functions. Use them in scsi-disk.c too. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/scsi-bus.c | 8 ++++++++ hw/scsi-defs.h | 3 +++ hw/scsi-disk.c | 6 ++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index b6de5c633..736e91e91 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -228,6 +228,8 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd) case WRITE_6: case WRITE_12: case WRITE_VERIFY_12: + case WRITE_16: + case WRITE_VERIFY_16: req->cmd.xfer *= req->dev->blocksize; break; case READ_10: @@ -235,6 +237,7 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd) case READ_REVERSE: case RECOVER_BUFFERED_DATA: case READ_12: + case READ_16: req->cmd.xfer *= req->dev->blocksize; break; case INQUIRY: @@ -277,6 +280,8 @@ static void scsi_req_xfer_mode(SCSIRequest *req) case WRITE_VERIFY: case WRITE_12: case WRITE_VERIFY_12: + case WRITE_16: + case WRITE_VERIFY_16: case COPY: case COPY_VERIFY: case COMPARE: @@ -441,6 +446,9 @@ static const char *scsi_command_name(uint8_t cmd) [ REWIND ] = "REWIND", [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", [ GET_CONFIGURATION ] = "GET_CONFIGURATION", + [ READ_16 ] = "READ_16", + [ WRITE_16 ] = "WRITE_16", + [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16", [ SERVICE_ACTION_IN ] = "SERVICE_ACTION_IN", [ REPORT_LUNS ] = "REPORT_LUNS", [ LOAD_UNLOAD ] = "LOAD_UNLOAD", diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index cc7f35eaa..4759d8004 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -100,6 +100,9 @@ #define REWIND 0x01 #define REPORT_DENSITY_SUPPORT 0x44 #define GET_CONFIGURATION 0x46 +#define READ_16 0x88 +#define WRITE_16 0x8a +#define WRITE_VERIFY_16 0x8e #define SERVICE_ACTION_IN 0x9e #define REPORT_LUNS 0xa0 #define LOAD_UNLOAD 0xa6 diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 291078292..c802ccdbd 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -926,7 +926,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, break; case READ_6: case READ_10: - case 0x88: + case READ_12: + case READ_16: DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len); if (lba > s->max_lba) goto illegal_lba; @@ -935,7 +936,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, break; case WRITE_6: case WRITE_10: - case 0x8a: + case WRITE_12: + case WRITE_16: DPRINTF("Write (sector %" PRId64 ", count %d)\n", lba, len); if (lba > s->max_lba) goto illegal_lba; -- cgit v1.2.3-65-gdbad From a15fdf861976d0c4a7358e4ddd729116bcd34348 Mon Sep 17 00:00:00 2001 From: Laszlo Ast Date: Thu, 19 Nov 2009 11:07:12 +0100 Subject: lsi53c895a: Whitespace and typo fixes Signed-off-by: Laszlo Ast Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- hw/lsi53c895a.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 8b8a80b89..f0e8be930 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -10,7 +10,7 @@ /* ??? Need to check if the {read,write}[wl] routines work properly on big-endian targets. */ -#include \ +#include #include "hw.h" #include "pci.h" @@ -185,7 +185,7 @@ typedef struct { int carry; /* ??? Should this be an a visible register somewhere? */ int sense; /* Action to take at the end of a MSG IN phase. - 0 = COMMAND, 1 = disconect, 2 = DATA OUT, 3 = DATA IN. */ + 0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN. */ int msg_action; int msg_len; uint8_t msg[LSI_MAX_MSGIN_LEN]; @@ -1062,7 +1062,7 @@ again: lsi_set_phase(s, PHASE_MO); break; case 1: /* Disconnect */ - DPRINTF("Wait Disconect\n"); + DPRINTF("Wait Disconnect\n"); s->scntl1 &= ~LSI_SCNTL1_CON; break; case 2: /* Wait Reselect */ @@ -1554,9 +1554,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) SCRIPTS register move instructions are. */ s->sfbr = val; break; - case 0x0a: case 0x0b: + case 0x0a: case 0x0b: /* Openserver writes to these readonly registers on startup */ - return; + return; case 0x0c: case 0x0d: case 0x0e: case 0x0f: /* Linux writes to these readonly registers on startup. */ return; -- cgit v1.2.3-65-gdbad From cc9f28bc2a95eb96959c39ce498800bbd95cc77b Mon Sep 17 00:00:00 2001 From: Laszlo Ast Date: Thu, 19 Nov 2009 11:07:12 +0100 Subject: lsi53c895a: Add support for LSI53C700 Family Compatibility bit Signed-off-by: Laszlo Ast Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- hw/lsi53c895a.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index f0e8be930..0c5e50ab3 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -585,6 +585,10 @@ static void lsi_reselect(LSIState *s, uint32_t tag) } id = (tag >> 8) & 0xf; s->ssid = id | 0x80; + /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */ + if (!s->dcntl & LSI_DCNTL_COM) { + s->sfbr = 1 << (id & 0x7); + } DPRINTF("Reselected target %d\n", id); s->current_dev = s->bus.devs[id]; s->current_tag = tag; -- cgit v1.2.3-65-gdbad From 77203ea00b3abc8246722a0e6f982c2932387a09 Mon Sep 17 00:00:00 2001 From: Laszlo Ast Date: Thu, 19 Nov 2009 11:07:12 +0100 Subject: lsi53c895a: Fix message code of DISCONNECT See SCSI-2, 6.5 Message system description/message codes. Signed-off-by: Laszlo Ast Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- hw/lsi53c895a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 0c5e50ab3..f466824dd 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -790,7 +790,7 @@ static void lsi_do_msgout(LSIState *s) s->sfbr = msg; switch (msg) { - case 0x00: + case 0x04: DPRINTF("MSG: Disconnect\n"); lsi_disconnect(s); break; -- cgit v1.2.3-65-gdbad From 07a1bea883895522a89e632757041c364ce2e12e Mon Sep 17 00:00:00 2001 From: Laszlo Ast Date: Thu, 19 Nov 2009 11:07:12 +0100 Subject: lsi53c895a: Fix SDID in SELECT ID command See SCRIPTS Programming Guide, 3.2.17 SELECT. Signed-off-by: Laszlo Ast Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- hw/lsi53c895a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index f466824dd..7e141a0ac 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -1030,7 +1030,7 @@ again: if (insn & (1 << 25)) { id = read_dword(s, s->dsa + sxt24(insn)); } else { - id = addr; + id = insn; } id = (id >> 16) & 0xf; if (insn & (1 << 26)) { -- cgit v1.2.3-65-gdbad From 38f5b2b88cbe02492a4cad3aa06a778a952f7146 Mon Sep 17 00:00:00 2001 From: Laszlo Ast Date: Thu, 19 Nov 2009 11:07:12 +0100 Subject: lsi53c895a: Use alternative address when already reselected See SCRIPTS, 3.2.17 SELECT. Signed-off-by: Laszlo Ast Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- hw/lsi53c895a.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 7e141a0ac..7fed1d866 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -1040,8 +1040,9 @@ again: switch (opcode) { case 0: /* Select */ s->sdid = id; - if (s->current_dma_len && (s->ssid & 0xf) == id) { - DPRINTF("Already reselected by target %d\n", id); + if (s->scntl1 & LSI_SCNTL1_CON) { + DPRINTF("Already reselected, jumping to alternative address\n"); + s->dsp = s->dnad; break; } s->sstat0 |= LSI_SSTAT0_WOA; -- cgit v1.2.3-65-gdbad From e560125e2692714054b718b51211f32a311538b5 Mon Sep 17 00:00:00 2001 From: Laszlo Ast Date: Thu, 19 Nov 2009 11:07:12 +0100 Subject: lsi53c895a: Implement IRQ on reselection The critical part of this change is how to deal with simultaneaous generation of interrupts. The only (normal) case when this happens in the emulation is near simultaneous reselection + selection. If selection comes first, there is no problem, since the target attempting reselection loses the arbitration (in the emulation it only means that the reselect function will not be started). In the worst case the host adapter is reselected, but the device driver already started a selection, so we jump to the alternative address to handle the situation. The SCRIPTS code can trigger another interrupt to notify the driver that the new task has to be postponed. I suppose that on real hardware there is enough time after the reselection interrupt to set the SIP bit before the next interrupt comes, so it would result in 2 stacked interrupts (a SCSI and a DMA one). However, in the emulation there is no interrupt stacking, so there is a good chance that the 2 interrupts will get to the interrupt handler at the same time. Nevertheless, it should not make a big difference in interrupt handling, since in both cases both interrupts have to be fetched first, and after that the new task (that failed during the selection phase) has to be prepared/reset for a later restart, and the reconnected device has to be serviced. The changes do not modify the host adapter's behavior if this interrupt is not enabled. See also LSI53C895A technical manual, SCID and SIEN0. Signed-off-by: Laszlo Ast Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- hw/lsi53c895a.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 7fed1d866..ab0de8610 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -154,6 +154,9 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) #define LSI_CCNTL1_DDAC 0x08 #define LSI_CCNTL1_ZMOD 0x80 +/* Enable Response to Reselection */ +#define LSI_SCID_RRE 0x60 + #define LSI_CCNTL1_40BIT (LSI_CCNTL1_EN64TIBMV|LSI_CCNTL1_64TIMOD) #define PHASE_DO 0 @@ -272,6 +275,11 @@ typedef struct { uint32_t script_ram[2048]; } LSIState; +static inline int lsi_irq_on_rsl(LSIState *s) +{ + return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE); +} + static void lsi_soft_reset(LSIState *s) { DPRINTF("Reset\n"); @@ -362,6 +370,7 @@ static int lsi_dma_64bit(LSIState *s) static uint8_t lsi_reg_readb(LSIState *s, int offset); static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); static void lsi_execute_script(LSIState *s); +static void lsi_reselect(LSIState *s, uint32_t tag); static inline uint32_t read_dword(LSIState *s, uint32_t addr) { @@ -382,6 +391,7 @@ static void lsi_stop_script(LSIState *s) static void lsi_update_irq(LSIState *s) { + int i; int level; static int last_level; @@ -413,6 +423,17 @@ static void lsi_update_irq(LSIState *s) last_level = level; } qemu_set_irq(s->dev.irq[0], level); + + if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) { + DPRINTF("Handled IRQs & disconnected, looking for pending " + "processes\n"); + for (i = 0; i < s->active_commands; i++) { + if (s->queue[i].pending) { + lsi_reselect(s, s->queue[i].tag); + break; + } + } + } } /* Stop SCRIPTS execution and raise a SCSI interrupt. */ @@ -607,6 +628,10 @@ static void lsi_reselect(LSIState *s, uint32_t tag) if (n != s->active_commands) { s->queue[n] = s->queue[s->active_commands]; } + + if (lsi_irq_on_rsl(s)) { + lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0); + } } /* Record that data is available for a queued command. Returns zero if @@ -622,7 +647,14 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) BADF("Multiple IO pending for tag %d\n", tag); } p->pending = arg; - if (s->waiting == 1) { + /* Reselect if waiting for it, or if reselection triggers an IRQ + and the bus is free. + Since no interrupt stacking is implemented in the emulation, it + is also required that there are no pending interrupts waiting + for service from the device driver. */ + if (s->waiting == 1 || + (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) && + !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) { /* Reselect device. */ lsi_reselect(s, tag); return 0; @@ -659,10 +691,13 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, return; } - if (s->waiting == 1 || tag != s->current_tag) { + if (s->waiting == 1 || tag != s->current_tag || + (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { if (lsi_queue_tag(s, tag, arg)) return; } + + /* host adapter (re)connected */ DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg); s->current_dma_len = arg; s->command_complete = 1; @@ -1071,7 +1106,9 @@ again: s->scntl1 &= ~LSI_SCNTL1_CON; break; case 2: /* Wait Reselect */ - lsi_wait_reselect(s); + if (!lsi_irq_on_rsl(s)) { + lsi_wait_reselect(s); + } break; case 3: /* Set */ DPRINTF("Set%s%s%s%s\n", -- cgit v1.2.3-65-gdbad From 21174c34b6b9ace9ad82e0deb13be752d28a5907 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 2 Dec 2009 12:36:35 +0100 Subject: vmstate: Avoid seeking Seeking on vmstate save/load does not work if the underlying file is a stream. We could try to make all QEMUFile* forward-seek-aware, but first attempts in this direction indicated that it's saner to convert the few qemu_fseek-on-vmstates users to plain reads/writes. This fixes various subtle vmstate corruptions where unused fields were involved. Signed-off-by: Jan Kiszka Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- savevm.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/savevm.c b/savevm.c index d6da050f3..55a2763f0 100644 --- a/savevm.c +++ b/savevm.c @@ -959,13 +959,27 @@ const VMStateInfo vmstate_info_buffer = { static int get_unused_buffer(QEMUFile *f, void *pv, size_t size) { - qemu_fseek(f, size, SEEK_CUR); - return 0; + uint8_t buf[1024]; + int block_len; + + while (size > 0) { + block_len = MIN(sizeof(buf), size); + size -= block_len; + qemu_get_buffer(f, buf, block_len); + } + return 0; } static void put_unused_buffer(QEMUFile *f, void *pv, size_t size) { - qemu_fseek(f, size, SEEK_CUR); + static const uint8_t buf[1024]; + int block_len; + + while (size > 0) { + block_len = MIN(sizeof(buf), size); + size -= block_len; + qemu_put_buffer(f, buf, block_len); + } } const VMStateInfo vmstate_info_unused_buffer = { -- cgit v1.2.3-65-gdbad From d9494b19e3239aaba3eaf85bcdc1ceab3cea3f72 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 2 Dec 2009 12:36:36 +0100 Subject: vmstate: Fix info field of VMSTATE_MACADDR Signed-off-by: Jan Kiszka Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/hw.h b/hw/hw.h index 7889aa3ce..c3c0c9fe3 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -545,7 +545,7 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_MACADDR(_field, _state) { \ .name = (stringify(_field)), \ .size = sizeof(MACAddr), \ - .info = &vmstate_info_uint8, \ + .info = &vmstate_info_buffer, \ .flags = VMS_BUFFER, \ .offset = vmstate_offset_macaddr(_state, _field), \ } -- cgit v1.2.3-65-gdbad From 8595387e3e08cae5ae1caef5633b551f09ba4211 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:37 +0100 Subject: vmstate: fix missing ARRAY_OF_POINTERS support on save state Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- savevm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/savevm.c b/savevm.c index 55a2763f0..cafb9e7f0 100644 --- a/savevm.c +++ b/savevm.c @@ -1206,6 +1206,9 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, for (i = 0; i < n_elems; i++) { void *addr = base_addr + field->size * i; + if (field->flags & VMS_ARRAY_OF_POINTER) { + addr = *(void **)addr; + } if (field->flags & VMS_STRUCT) { vmstate_save_state(f, field->vmsd, addr); } else { -- cgit v1.2.3-65-gdbad From e61a1e0a1147018d26f894c17f56f08117c0ba7b Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:38 +0100 Subject: vmstate: Add support for VBUFFERS Support for buffer that are pointed by a pointer (i.e. not embedded) where the size that we want to use is a field in the state. We also need a new place to store where to start in the middle of the buffer, as now it is a pointer, not the offset of the 1st field. Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/hw.h | 20 ++++++++++++++++++++ savevm.c | 20 ++++++++++++++------ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/hw/hw.h b/hw/hw.h index c3c0c9fe3..47fb12b14 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -294,14 +294,17 @@ enum VMStateFlags { VMS_BUFFER = 0x020, /* static sized buffer */ VMS_ARRAY_OF_POINTER = 0x040, VMS_VARRAY_UINT16 = 0x080, /* Array with size in uint16_t field */ + VMS_VBUFFER = 0x100, /* Buffer with size in int32_t field */ }; typedef struct { const char *name; size_t offset; size_t size; + size_t start; int num; size_t num_offset; + size_t size_offset; const VMStateInfo *info; enum VMStateFlags flags; const VMStateDescription *vmsd; @@ -490,6 +493,17 @@ extern const VMStateInfo vmstate_info_unused_buffer; .offset = vmstate_offset_buffer(_state, _field) + _start, \ } +#define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .field_exists = (_test), \ + .size_offset = vmstate_offset_value(_state, _field_size, int32_t),\ + .info = &vmstate_info_buffer, \ + .flags = VMS_VBUFFER|VMS_POINTER, \ + .offset = offsetof(_state, _field), \ + .start = (_start), \ +} + #define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \ .name = (stringify(_field)), \ .version_id = (_version), \ @@ -683,6 +697,12 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \ VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, _start, sizeof(typeof_field(_s, _f))) +#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \ + VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size) + +#define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size) \ + VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size) + #define VMSTATE_BUFFER_TEST(_f, _s, _test) \ VMSTATE_STATIC_BUFFER(_f, _s, 0, _test, 0, sizeof(typeof_field(_s, _f))) diff --git a/savevm.c b/savevm.c index cafb9e7f0..1125ef2d5 100644 --- a/savevm.c +++ b/savevm.c @@ -1143,7 +1143,11 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, field->version_id <= version_id)) { void *base_addr = opaque + field->offset; int ret, i, n_elems = 1; + int size = field->size; + if (field->flags & VMS_VBUFFER) { + size = *(int32_t *)(opaque+field->size_offset); + } if (field->flags & VMS_ARRAY) { n_elems = field->num; } else if (field->flags & VMS_VARRAY_INT32) { @@ -1152,10 +1156,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, n_elems = *(uint16_t *)(opaque+field->num_offset); } if (field->flags & VMS_POINTER) { - base_addr = *(void **)base_addr; + base_addr = *(void **)base_addr + field->start; } for (i = 0; i < n_elems; i++) { - void *addr = base_addr + field->size * i; + void *addr = base_addr + size * i; if (field->flags & VMS_ARRAY_OF_POINTER) { addr = *(void **)addr; @@ -1163,7 +1167,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, if (field->flags & VMS_STRUCT) { ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id); } else { - ret = field->info->get(f, addr, field->size); + ret = field->info->get(f, addr, size); } if (ret < 0) { @@ -1192,7 +1196,11 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, field->field_exists(opaque, vmsd->version_id)) { void *base_addr = opaque + field->offset; int i, n_elems = 1; + int size = field->size; + if (field->flags & VMS_VBUFFER) { + size = *(int32_t *)(opaque+field->size_offset); + } if (field->flags & VMS_ARRAY) { n_elems = field->num; } else if (field->flags & VMS_VARRAY_INT32) { @@ -1201,10 +1209,10 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, n_elems = *(uint16_t *)(opaque+field->num_offset); } if (field->flags & VMS_POINTER) { - base_addr = *(void **)base_addr; + base_addr = *(void **)base_addr + field->start; } for (i = 0; i < n_elems; i++) { - void *addr = base_addr + field->size * i; + void *addr = base_addr + size * i; if (field->flags & VMS_ARRAY_OF_POINTER) { addr = *(void **)addr; @@ -1212,7 +1220,7 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, if (field->flags & VMS_STRUCT) { vmstate_save_state(f, field->vmsd, addr); } else { - field->info->put(f, addr, field->size); + field->info->put(f, addr, size); } } } -- cgit v1.2.3-65-gdbad From 11fe0e6e0ea631c1c4278de7c97eebacda254b3d Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:39 +0100 Subject: vmstate: Introduce VMSTATE_STRUCT_TEST Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/hw.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/hw/hw.h b/hw/hw.h index 47fb12b14..0f4442a86 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -436,13 +436,14 @@ extern const VMStateInfo vmstate_info_unused_buffer; .offset = offsetof(_state, _field), \ } -#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) { \ - .name = (stringify(_field)), \ - .version_id = (_version), \ - .vmsd = &(_vmsd), \ - .size = sizeof(_type), \ - .flags = VMS_STRUCT, \ - .offset = vmstate_offset_value(_state, _field, _type), \ +#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .field_exists = (_test), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type), \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, _type), \ } #define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) { \ @@ -574,6 +575,9 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \ VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type) +#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \ + VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type) + #define VMSTATE_INT8_V(_f, _s, _v) \ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t) #define VMSTATE_INT16_V(_f, _s, _v) \ -- cgit v1.2.3-65-gdbad From 543fc7b27a0e498d89b56a9fe0f9ac4f0f687f13 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:40 +0100 Subject: vmstate: Introduce VMSTATE_STRUCT_POINTER_TEST Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/hw.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/hw.h b/hw/hw.h index 0f4442a86..0a5acd4ce 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -446,12 +446,13 @@ extern const VMStateInfo vmstate_info_unused_buffer; .offset = vmstate_offset_value(_state, _field, _type), \ } -#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) { \ - .name = (stringify(_field)), \ - .vmsd = &(_vmsd), \ - .size = sizeof(_type), \ - .flags = VMS_STRUCT|VMS_POINTER, \ - .offset = vmstate_offset_value(_state, _field, _type), \ +#define VMSTATE_STRUCT_POINTER_TEST(_field, _state, _test, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .field_exists = (_test), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type), \ + .flags = VMS_STRUCT|VMS_POINTER, \ + .offset = vmstate_offset_value(_state, _field, _type), \ } #define VMSTATE_ARRAY_OF_POINTER(_field, _state, _num, _version, _info, _type) {\ @@ -578,6 +579,9 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \ VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type) +#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \ + VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type) + #define VMSTATE_INT8_V(_f, _s, _v) \ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t) #define VMSTATE_INT16_V(_f, _s, _v) \ -- cgit v1.2.3-65-gdbad From 2fee40782cb6462137f49023b8e55e22c4571790 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:41 +0100 Subject: vmstate: Introduce UINT16_TEST support Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/hw.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/hw.h b/hw/hw.h index 0a5acd4ce..5994d8609 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -633,6 +633,9 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_INT32_LE(_f, _s) \ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t) +#define VMSTATE_UINT16_TEST(_f, _s, _t) \ + VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t) + #define VMSTATE_UINT32_TEST(_f, _s, _t) \ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t) -- cgit v1.2.3-65-gdbad From bfb811ade56e62da44404f55e224f4f5d07a902c Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:42 +0100 Subject: vmstate: remove usused VMSTATE_STRUCT_ARRAY_SIZE_UINT8 Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/hw.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/hw/hw.h b/hw/hw.h index 5994d8609..41e13cc1d 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -475,16 +475,6 @@ extern const VMStateInfo vmstate_info_unused_buffer; .offset = vmstate_offset_array(_state, _field, _type, _num), \ } -#define VMSTATE_STRUCT_ARRAY_SIZE_UINT8(_field, _state, _field__num, _version, _vmsd, _type) { \ - .name = (stringify(_field)), \ - .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \ - .version_id = (_version), \ - .vmsd = &(_vmsd), \ - .size = sizeof(_type), \ - .flags = VMS_STRUCT|VMS_ARRAY, \ - .offset = vmstate_offset_array(_state, _field, _type, _num), \ -} - #define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \ .name = (stringify(_field)), \ .version_id = (_version), \ -- cgit v1.2.3-65-gdbad From 33599e2a6164b1c7a5b634be1c2e54b8f0fb91bd Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:43 +0100 Subject: vmstate: Add support for multiplying size for a constant When the size that we want to transmit is in another field, but in an unit different that bytes Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/hw.h | 13 +++++++++++++ savevm.c | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/hw/hw.h b/hw/hw.h index 41e13cc1d..5f3499196 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -295,6 +295,7 @@ enum VMStateFlags { VMS_ARRAY_OF_POINTER = 0x040, VMS_VARRAY_UINT16 = 0x080, /* Array with size in uint16_t field */ VMS_VBUFFER = 0x100, /* Buffer with size in int32_t field */ + VMS_MULTIPLY = 0x200, /* multiply "size" field by field_size */ }; typedef struct { @@ -485,6 +486,18 @@ extern const VMStateInfo vmstate_info_unused_buffer; .offset = vmstate_offset_buffer(_state, _field) + _start, \ } +#define VMSTATE_BUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .field_exists = (_test), \ + .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\ + .size = (_multiply), \ + .info = &vmstate_info_buffer, \ + .flags = VMS_VBUFFER|VMS_MULTIPLY, \ + .offset = offsetof(_state, _field), \ + .start = (_start), \ +} + #define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \ .name = (stringify(_field)), \ .version_id = (_version), \ diff --git a/savevm.c b/savevm.c index 1125ef2d5..17a6c9705 100644 --- a/savevm.c +++ b/savevm.c @@ -1147,6 +1147,9 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, if (field->flags & VMS_VBUFFER) { size = *(int32_t *)(opaque+field->size_offset); + if (field->flags & VMS_MULTIPLY) { + size *= field->size; + } } if (field->flags & VMS_ARRAY) { n_elems = field->num; @@ -1200,6 +1203,9 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, if (field->flags & VMS_VBUFFER) { size = *(int32_t *)(opaque+field->size_offset); + if (field->flags & VMS_MULTIPLY) { + size *= field->size; + } } if (field->flags & VMS_ARRAY) { n_elems = field->num; -- cgit v1.2.3-65-gdbad From 5084bca17f9d2b0a39337df4bd991838ed70d866 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:44 +0100 Subject: pci: vmstate_register() already assign consecutive numbers starting at 0 Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/pci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 0359f3001..f2b6cff38 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -161,8 +161,6 @@ PCIBus *pci_find_root_bus(int domain) void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, int devfn_min) { - static int nbus = 0; - qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name); bus->devfn_min = devfn_min; @@ -170,7 +168,7 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, QLIST_INIT(&bus->child); pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */ - vmstate_register(nbus++, &vmstate_pcibus, bus); + vmstate_register(-1, &vmstate_pcibus, bus); qemu_register_reset(pci_bus_reset, bus); } -- cgit v1.2.3-65-gdbad From 70cca6d87261f3ab330e2be34fbe9596b13342ae Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:45 +0100 Subject: qdev: enable vmstate_unregister() support Now vmstate_unregister have the right type Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/qdev.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index 875ca501b..13c9fe236 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -296,10 +296,8 @@ void qdev_free(DeviceState *dev) bus = QLIST_FIRST(&dev->child_bus); qbus_free(bus); } -#if 0 /* FIXME: need sane vmstate_unregister function */ if (dev->info->vmsd) vmstate_unregister(dev->info->vmsd, dev); -#endif if (dev->info->exit) dev->info->exit(dev); if (dev->opts) -- cgit v1.2.3-65-gdbad From be73cfe2be9a41de4f97e4847b3f12a7d6d61159 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 2 Dec 2009 12:36:46 +0100 Subject: savevm: Port to qdev.vmsd all devices that have qdev Signed-off-by: Juan Quintela Signed-off-by: Anthony Liguori --- hw/ac97.c | 2 +- hw/cirrus_vga.c | 2 +- hw/cs4231a.c | 2 +- hw/e1000.c | 4 +--- hw/es1370.c | 2 +- hw/gus.c | 2 +- hw/lance.c | 15 ++++++++++++--- hw/lm832x.c | 2 +- hw/lsi53c895a.c | 2 +- hw/max7310.c | 2 +- hw/ne2000-isa.c | 12 +++++++++++- hw/ne2000.c | 3 +-- hw/pckbd.c | 13 ++++++++++++- hw/pcnet.c | 4 +--- hw/piix_pci.c | 4 ++-- hw/rtl8139.c | 4 +--- hw/sb16.c | 2 +- hw/ssd0303.c | 2 +- hw/tmp105.c | 2 +- hw/twl92230.c | 2 +- hw/usb-uhci.c | 3 ++- hw/vga-pci.c | 2 +- hw/vmware_vga.c | 2 +- hw/wdt_i6300esb.c | 3 +-- hw/wdt_ib700.c | 2 +- hw/wm8750.c | 2 +- 26 files changed, 60 insertions(+), 37 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index f2d28233c..62e349a90 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -1319,7 +1319,6 @@ static int ac97_initfn (PCIDevice *dev) pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map); pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map); - vmstate_register (0, &vmstate_ac97, s); qemu_register_reset (ac97_on_reset, s); AUD_register_card ("ac97", &s->card); ac97_on_reset (s); @@ -1336,6 +1335,7 @@ static PCIDeviceInfo ac97_info = { .qdev.name = "AC97", .qdev.desc = "Intel 82801AA AC97 Audio", .qdev.size = sizeof (AC97LinkState), + .qdev.vmsd = &vmstate_ac97, .init = ac97_initfn, }; diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index d76e5bb9c..1194b5a53 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -3245,7 +3245,6 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) pci_register_bar((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map); } - vmstate_register(0, &vmstate_pci_cirrus_vga, d); /* ROM BIOS */ rom_add_vga(VGABIOS_CIRRUS_FILENAME); @@ -3260,6 +3259,7 @@ void pci_cirrus_vga_init(PCIBus *bus) static PCIDeviceInfo cirrus_vga_info = { .qdev.name = "Cirrus VGA", .qdev.size = sizeof(PCICirrusVGAState), + .qdev.vmsd = &vmstate_pci_cirrus_vga, .init = pci_cirrus_vga_initfn, .config_write = pci_cirrus_write_config, }; diff --git a/hw/cs4231a.c b/hw/cs4231a.c index 7c29aa849..4d5ce5c27 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -651,7 +651,6 @@ static int cs4231a_initfn (ISADevice *dev) DMA_register_channel (s->dma, cs_dma_read, s); - vmstate_register (0, &vmstate_cs4231a, s); qemu_register_reset (cs_reset, s); cs_reset (s); @@ -669,6 +668,7 @@ static ISADeviceInfo cs4231a_info = { .qdev.name = "cs4231a", .qdev.desc = "Crystal Semiconductor CS4231A", .qdev.size = sizeof (CSState), + .qdev.vmsd = &vmstate_cs4231a, .init = cs4231a_initfn, .qdev.props = (Property[]) { DEFINE_PROP_HEX32 ("iobase", CSState, port, 0x534), diff --git a/hw/e1000.c b/hw/e1000.c index 683fdccae..b65a74fe9 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1051,7 +1051,6 @@ pci_e1000_uninit(PCIDevice *dev) cpu_unregister_io_memory(d->mmio_index); qemu_del_vlan_client(&d->nic->nc); - vmstate_unregister(&vmstate_e1000, d); return 0; } @@ -1121,8 +1120,6 @@ static int pci_e1000_init(PCIDevice *pci_dev) qemu_format_nic_info_str(&d->nic->nc, macaddr); - vmstate_register(-1, &vmstate_e1000, d); - if (!pci_dev->qdev.hotplugged) { static int loaded = 0; if (!loaded) { @@ -1144,6 +1141,7 @@ static PCIDeviceInfo e1000_info = { .qdev.desc = "Intel Gigabit Ethernet", .qdev.size = sizeof(E1000State), .qdev.reset = qdev_e1000_reset, + .qdev.vmsd = &vmstate_e1000, .init = pci_e1000_init, .exit = pci_e1000_uninit, .qdev.props = (Property[]) { diff --git a/hw/es1370.c b/hw/es1370.c index 4e646dc57..c3582539d 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -1023,7 +1023,6 @@ static int es1370_initfn (PCIDevice *dev) c[0x3f] = 0x80; pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO, es1370_map); - vmstate_register (0, &vmstate_es1370, s); qemu_register_reset (es1370_on_reset, s); AUD_register_card ("es1370", &s->card); @@ -1041,6 +1040,7 @@ static PCIDeviceInfo es1370_info = { .qdev.name = "ES1370", .qdev.desc = "ENSONIQ AudioPCI ES1370", .qdev.size = sizeof (ES1370State), + .qdev.vmsd = &vmstate_es1370, .init = es1370_initfn, }; diff --git a/hw/gus.c b/hw/gus.c index d35da0a0c..e9016d810 100644 --- a/hw/gus.c +++ b/hw/gus.c @@ -287,7 +287,6 @@ static int gus_initfn (ISADevice *dev) AUD_set_active_out (s->voice, 1); - vmstate_register (0, &vmstate_gus, s); return 0; } @@ -301,6 +300,7 @@ static ISADeviceInfo gus_info = { .qdev.name = "gus", .qdev.desc = "Gravis Ultrasound GF1", .qdev.size = sizeof (GUSState), + .qdev.vmsd = &vmstate_gus, .init = gus_initfn, .qdev.props = (Property[]) { DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100), diff --git a/hw/lance.c b/hw/lance.c index 98033a4ed..b6b04ddb9 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -96,7 +96,6 @@ static void lance_cleanup(VLANClientState *nc) { PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; - vmstate_unregister(&vmstate_pcnet, d); pcnet_common_cleanup(d); } @@ -108,6 +107,17 @@ static NetClientInfo net_lance_info = { .cleanup = lance_cleanup, }; +static const VMStateDescription vmstate_lance = { + .name = "pcnet", + .version_id = 3, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField []) { + VMSTATE_STRUCT(state, SysBusPCNetState, 0, vmstate_pcnet, PCNetState), + VMSTATE_END_OF_LIST() + } +}; + static int lance_init(SysBusDevice *dev) { SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev); @@ -124,8 +134,6 @@ static int lance_init(SysBusDevice *dev) s->phys_mem_read = ledma_memory_read; s->phys_mem_write = ledma_memory_write; - - vmstate_register(-1, &vmstate_pcnet, d); return pcnet_common_init(&dev->qdev, s, &net_lance_info); } @@ -141,6 +149,7 @@ static SysBusDeviceInfo lance_info = { .qdev.name = "lance", .qdev.size = sizeof(SysBusPCNetState), .qdev.reset = lance_reset, + .qdev.vmsd = &vmstate_lance, .qdev.props = (Property[]) { DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque), DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf), diff --git a/hw/lm832x.c b/hw/lm832x.c index 7e552c720..ce7dcac68 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -471,7 +471,6 @@ static int lm8323_init(i2c_slave *i2c) lm_kbd_reset(s); qemu_register_reset((void *) lm_kbd_reset, s); - vmstate_register(-1, &vmstate_lm_kbd, s); return 0; } @@ -498,6 +497,7 @@ void lm832x_key_event(struct i2c_slave *i2c, int key, int state) static I2CSlaveInfo lm8323_info = { .qdev.name = "lm8323", .qdev.size = sizeof(LM823KbdState), + .qdev.vmsd = &vmstate_lm_kbd, .init = lm8323_init, .event = lm_i2c_event, .recv = lm_i2c_rx, diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index ab0de8610..9abac94c2 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -2148,7 +2148,6 @@ static int lsi_scsi_init(PCIDevice *dev) if (!dev->qdev.hotplugged) { scsi_bus_legacy_handle_cmdline(&s->bus); } - vmstate_register(-1, &vmstate_lsi_scsi, s); return 0; } @@ -2156,6 +2155,7 @@ static PCIDeviceInfo lsi_info = { .qdev.name = "lsi53c895a", .qdev.alias = "lsi", .qdev.size = sizeof(LSIState), + .qdev.vmsd = &vmstate_lsi_scsi, .init = lsi_scsi_init, .exit = lsi_scsi_uninit, }; diff --git a/hw/max7310.c b/hw/max7310.c index 0ce6ac9ec..c302eb6aa 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -184,7 +184,6 @@ static int max7310_init(i2c_slave *i2c) max7310_reset(&s->i2c); - vmstate_register(-1, &vmstate_max7310, s); return 0; } @@ -206,6 +205,7 @@ void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler) static I2CSlaveInfo max7310_info = { .qdev.name = "max7310", .qdev.size = sizeof(MAX7310State), + .qdev.vmsd = &vmstate_max7310, .init = max7310_init, .event = max7310_event, .recv = max7310_rx, diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index 0260f849f..d2e9283be 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -50,6 +50,17 @@ static NetClientInfo net_ne2000_isa_info = { .cleanup = isa_ne2000_cleanup, }; +const VMStateDescription vmstate_isa_ne2000 = { + .name = "ne2000", + .version_id = 2, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField []) { + VMSTATE_STRUCT(ne2000, ISANE2000State, 0, vmstate_ne2000, NE2000State), + VMSTATE_END_OF_LIST() + } +}; + static int isa_ne2000_initfn(ISADevice *dev) { ISANE2000State *isa = DO_UPCAST(ISANE2000State, dev, dev); @@ -75,7 +86,6 @@ static int isa_ne2000_initfn(ISADevice *dev) dev->qdev.info->name, dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a); - vmstate_register(-1, &vmstate_ne2000, s); return 0; } diff --git a/hw/ne2000.c b/hw/ne2000.c index 0be189af5..e0655ffa4 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -746,7 +746,6 @@ static int pci_ne2000_init(PCIDevice *pci_dev) } } - vmstate_register(-1, &vmstate_pci_ne2000, d); return 0; } @@ -755,7 +754,6 @@ static int pci_ne2000_exit(PCIDevice *pci_dev) PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev); NE2000State *s = &d->ne2000; - vmstate_unregister(&vmstate_pci_ne2000, s); qemu_del_vlan_client(&s->nic->nc); return 0; } @@ -763,6 +761,7 @@ static int pci_ne2000_exit(PCIDevice *pci_dev) static PCIDeviceInfo ne2000_info = { .qdev.name = "ne2k_pci", .qdev.size = sizeof(PCINE2000State), + .qdev.vmsd = &vmstate_pci_ne2000, .init = pci_ne2000_init, .exit = pci_ne2000_exit, .qdev.props = (Property[]) { diff --git a/hw/pckbd.c b/hw/pckbd.c index a81b303da..7e0d68df2 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -414,6 +414,17 @@ typedef struct ISAKBDState { KBDState kbd; } ISAKBDState; +const VMStateDescription vmstate_kbd_isa = { + .name = "pckbd", + .version_id = 3, + .minimum_version_id = 3, + .minimum_version_id_old = 3, + .fields = (VMStateField []) { + VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState), + VMSTATE_END_OF_LIST() + } +}; + static int i8042_initfn(ISADevice *dev) { KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd); @@ -421,7 +432,6 @@ static int i8042_initfn(ISADevice *dev) isa_init_irq(dev, &s->irq_kbd, 1); isa_init_irq(dev, &s->irq_mouse, 12); - vmstate_register(0, &vmstate_kbd, s); register_ioport_read(0x60, 1, 1, kbd_read_data, s); register_ioport_write(0x60, 1, 1, kbd_write_data, s); register_ioport_read(0x64, 1, 1, kbd_read_status, s); @@ -439,6 +449,7 @@ static int i8042_initfn(ISADevice *dev) static ISADeviceInfo i8042_info = { .qdev.name = "i8042", .qdev.size = sizeof(ISAKBDState), + .qdev.vmsd = &vmstate_kbd_isa, .qdev.no_user = 1, .init = i8042_initfn, }; diff --git a/hw/pcnet.c b/hw/pcnet.c index 195c825c8..138fbc6d0 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1952,7 +1952,6 @@ static int pci_pcnet_uninit(PCIDevice *dev) PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev); cpu_unregister_io_memory(d->state.mmio_index); - vmstate_unregister(&vmstate_pci_pcnet, d); qemu_del_timer(d->state.poll_timer); qemu_free_timer(d->state.poll_timer); qemu_del_vlan_client(&d->state.nic->nc); @@ -2010,8 +2009,6 @@ static int pci_pcnet_init(PCIDevice *pci_dev) s->phys_mem_read = pci_physical_memory_read; s->phys_mem_write = pci_physical_memory_write; - vmstate_register(-1, &vmstate_pci_pcnet, d); - if (!pci_dev->qdev.hotplugged) { static int loaded = 0; if (!loaded) { @@ -2034,6 +2031,7 @@ static PCIDeviceInfo pcnet_info = { .qdev.name = "pcnet", .qdev.size = sizeof(PCIPCNetState), .qdev.reset = pci_reset, + .qdev.vmsd = &vmstate_pci_pcnet, .init = pci_pcnet_init, .exit = pci_pcnet_uninit, .qdev.props = (Property[]) { diff --git a/hw/piix_pci.c b/hw/piix_pci.c index a44f941dc..1b67475e0 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -198,7 +198,6 @@ static int i440fx_initfn(PCIDevice *dev) d->dev.config[0x72] = 0x02; /* SMRAM */ - vmstate_register(0, &vmstate_i440fx, d); return 0; } @@ -312,7 +311,6 @@ static int piix3_initfn(PCIDevice *dev) uint8_t *pci_conf; isa_bus_new(&d->dev.qdev); - vmstate_register(0, &vmstate_piix3, d); pci_conf = d->dev.config; pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); @@ -330,6 +328,7 @@ static PCIDeviceInfo i440fx_info[] = { .qdev.name = "i440FX", .qdev.desc = "Host bridge", .qdev.size = sizeof(PCII440FXState), + .qdev.vmsd = &vmstate_i440fx, .qdev.no_user = 1, .init = i440fx_initfn, .config_write = i440fx_write_config, @@ -337,6 +336,7 @@ static PCIDeviceInfo i440fx_info[] = { .qdev.name = "PIIX3", .qdev.desc = "ISA bridge", .qdev.size = sizeof(PIIX3State), + .qdev.vmsd = &vmstate_piix3, .qdev.no_user = 1, .init = piix3_initfn, },{ diff --git a/hw/rtl8139.c b/hw/rtl8139.c index d2a944398..9fd05a8a1 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3300,7 +3300,6 @@ static int pci_rtl8139_uninit(PCIDevice *dev) qemu_del_timer(s->timer); qemu_free_timer(s->timer); #endif - vmstate_unregister(&vmstate_rtl8139, s); qemu_del_vlan_client(&s->nic->nc); return 0; } @@ -3348,8 +3347,6 @@ static int pci_rtl8139_init(PCIDevice *dev) s->cplus_txbuffer_len = 0; s->cplus_txbuffer_offset = 0; - vmstate_register(-1, &vmstate_rtl8139, s); - #ifdef RTL8139_ONBOARD_TIMER s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); @@ -3371,6 +3368,7 @@ static PCIDeviceInfo rtl8139_info = { .qdev.name = "rtl8139", .qdev.size = sizeof(RTL8139State), .qdev.reset = rtl8139_reset, + .qdev.vmsd = &vmstate_rtl8139, .init = pci_rtl8139_init, .exit = pci_rtl8139_uninit, .qdev.props = (Property[]) { diff --git a/hw/sb16.c b/hw/sb16.c index 4c0d682fd..9f4ac5040 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -1381,7 +1381,6 @@ static int sb16_initfn (ISADevice *dev) DMA_register_channel (s->dma, SB_read_DMA, s); s->can_write = 1; - vmstate_register (0, &vmstate_sb16, s); AUD_register_card ("sb16", &s->card); return 0; } @@ -1396,6 +1395,7 @@ static ISADeviceInfo sb16_info = { .qdev.name = "sb16", .qdev.desc = "Creative Sound Blaster 16", .qdev.size = sizeof (SB16State), + .qdev.vmsd = &vmstate_sb16, .init = sb16_initfn, .qdev.props = (Property[]) { DEFINE_PROP_HEX32 ("version", SB16State, ver, 0x0405), /* 4.5 */ diff --git a/hw/ssd0303.c b/hw/ssd0303.c index f60930e3b..108c0683c 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -291,13 +291,13 @@ static int ssd0303_init(i2c_slave *i2c) ssd0303_invalidate_display, NULL, NULL, s); qemu_console_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); - vmstate_register(-1, &vmstate_ssd0303, s); return 0; } static I2CSlaveInfo ssd0303_info = { .qdev.name = "ssd0303", .qdev.size = sizeof(ssd0303_state), + .qdev.vmsd = &vmstate_ssd0303, .init = ssd0303_init, .event = ssd0303_event, .recv = ssd0303_recv, diff --git a/hw/tmp105.c b/hw/tmp105.c index 74141b378..8343afff8 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -228,13 +228,13 @@ static int tmp105_init(i2c_slave *i2c) tmp105_reset(&s->i2c); - vmstate_register(-1, &vmstate_tmp105, s); return 0; } static I2CSlaveInfo tmp105_info = { .qdev.name = "tmp105", .qdev.size = sizeof(TMP105State), + .qdev.vmsd = &vmstate_tmp105, .init = tmp105_init, .event = tmp105_event, .recv = tmp105_rx, diff --git a/hw/twl92230.c b/hw/twl92230.c index 93232da2d..b1b2ac9ce 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -855,13 +855,13 @@ static int twl92230_init(i2c_slave *i2c) menelaus_reset(&s->i2c); - vmstate_register(-1, &vmstate_menelaus, s); return 0; } static I2CSlaveInfo twl92230_info = { .qdev.name ="twl92230", .qdev.size = sizeof(MenelausState), + .qdev.vmsd = &vmstate_menelaus, .init = twl92230_init, .event = menelaus_event, .recv = menelaus_rx, diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 671916e05..ba26a4efc 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1086,7 +1086,6 @@ static int usb_uhci_common_initfn(UHCIState *s) pci_register_bar(&s->dev, 4, 0x20, PCI_BASE_ADDRESS_SPACE_IO, uhci_map); - vmstate_register(0, &vmstate_uhci, s); return 0; } @@ -1114,10 +1113,12 @@ static PCIDeviceInfo uhci_info[] = { { .qdev.name = "PIIX3 USB-UHCI", .qdev.size = sizeof(UHCIState), + .qdev.vmsd = &vmstate_uhci, .init = usb_uhci_piix3_initfn, },{ .qdev.name = "PIIX4 USB-UHCI", .qdev.size = sizeof(UHCIState), + .qdev.vmsd = &vmstate_uhci, .init = usb_uhci_piix4_initfn, },{ /* end of list */ diff --git a/hw/vga-pci.c b/hw/vga-pci.c index a6ad46ba7..e8cc0247a 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -82,7 +82,6 @@ static int pci_vga_initfn(PCIDevice *dev) // vga + console init vga_common_init(s, VGA_RAM_SIZE); vga_init(s); - vmstate_register(0, &vmstate_vga_pci, d); s->ds = graphic_console_init(s->update, s->invalidate, s->screen_dump, s->text_update, s); @@ -134,6 +133,7 @@ int pci_vga_init(PCIBus *bus, static PCIDeviceInfo vga_info = { .qdev.name = "VGA", .qdev.size = sizeof(PCIVGAState), + .qdev.vmsd = &vmstate_vga_pci, .init = pci_vga_initfn, .config_write = pci_vga_write_config, .qdev.props = (Property[]) { diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index bb3410105..24ea6205b 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1189,7 +1189,6 @@ static int pci_vmsvga_initfn(PCIDevice *dev) vmsvga_init(&s->chip, VGA_RAM_SIZE); - vmstate_register(0, &vmstate_vmware_vga, s); return 0; } @@ -1201,6 +1200,7 @@ void pci_vmsvga_init(PCIBus *bus) static PCIDeviceInfo vmsvga_info = { .qdev.name = "QEMUware SVGA", .qdev.size = sizeof(struct pci_vmsvga_state_s), + .qdev.vmsd = &vmstate_vmware_vga, .init = pci_vmsvga_initfn, }; diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 27fa09e41..805b3028f 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -416,8 +416,6 @@ static int i6300esb_init(PCIDevice *dev) pci_register_bar(&d->dev, 0, 0x10, PCI_BASE_ADDRESS_SPACE_MEMORY, i6300esb_map); - vmstate_register(-1, &vmstate_i6300esb, d); - return 0; } @@ -429,6 +427,7 @@ static WatchdogTimerModel model = { static PCIDeviceInfo i6300esb_info = { .qdev.name = "i6300esb", .qdev.size = sizeof(I6300State), + .qdev.vmsd = &vmstate_i6300esb, .config_read = i6300esb_config_read, .config_write = i6300esb_config_write, .init = i6300esb_init, diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c index d67bf9eb4..c34687bca 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -98,7 +98,6 @@ static int wdt_ib700_init(ISADevice *dev) IB700State *s = DO_UPCAST(IB700State, dev, dev); s->timer = qemu_new_timer(vm_clock, ib700_timer_expired, s); - vmstate_register(-1, &vmstate_ib700, s); register_ioport_write(0x441, 2, 1, ib700_write_disable_reg, s); register_ioport_write(0x443, 2, 1, ib700_write_enable_reg, s); @@ -113,6 +112,7 @@ static WatchdogTimerModel model = { static ISADeviceInfo wdt_ib700_info = { .qdev.name = "ib700", .qdev.size = sizeof(IB700State), + .qdev.vmsd = &vmstate_ib700, .init = wdt_ib700_init, }; diff --git a/hw/wm8750.c b/hw/wm8750.c index e6a9c0681..6064da041 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -622,7 +622,6 @@ static int wm8750_init(i2c_slave *i2c) AUD_register_card(CODEC, &s->card); wm8750_reset(&s->i2c); - vmstate_register(-1, &vmstate_wm8750, s); return 0; } @@ -699,6 +698,7 @@ void wm8750_set_bclk_in(void *opaque, int new_hz) static I2CSlaveInfo wm8750_info = { .qdev.name = "wm8750", .qdev.size = sizeof(WM8750State), + .qdev.vmsd = &vmstate_wm8750, .init = wm8750_init, .event = wm8750_event, .recv = wm8750_rx, -- cgit v1.2.3-65-gdbad From 5d39c799c3245244ebb1e89da0177dbc089962b2 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:19 +0100 Subject: migration: Fix use of file after release qemu_fclose frees the passed file structure, but do_migrate_set_speed may access it later on. Fix it by setting file NULL in migrate_fd_cleanup and checking for this. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- migration.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/migration.c b/migration.c index 3ae0be86c..dcde7c38d 100644 --- a/migration.c +++ b/migration.c @@ -118,12 +118,11 @@ void do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data) } max_throttle = (uint32_t)d; - s = migrate_to_fms(current_migration); - if (s) { + s = migrate_to_fms(current_migration); + if (s && s->file) { qemu_file_set_rate_limit(s->file, max_throttle); } - } /* amount of nanoseconds we are willing to wait for migration to be down. @@ -209,6 +208,7 @@ void migrate_fd_cleanup(FdMigrationState *s) if (s->file) { dprintf("closing file\n"); qemu_fclose(s->file); + s->file = NULL; } if (s->fd != -1) -- cgit v1.2.3-65-gdbad From 1302425d737857e7598b812eb25c159f31d4ab27 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:19 +0100 Subject: migration: Catch multiple start commands Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- migration.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/migration.c b/migration.c index dcde7c38d..d7fb75676 100644 --- a/migration.c +++ b/migration.c @@ -58,7 +58,13 @@ void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data) const char *p; int detach = qdict_get_int(qdict, "detach"); const char *uri = qdict_get_str(qdict, "uri"); - + + if (current_migration && + current_migration->get_status(current_migration) == MIG_STATE_ACTIVE) { + monitor_printf(mon, "migration already in progress\n"); + return; + } + if (strstart(uri, "tcp:", &p)) s = tcp_start_outgoing_migration(p, max_throttle, detach, (int)qdict_get_int(qdict, "blk"), -- cgit v1.2.3-65-gdbad From a55eb92c22a7be05bae0de6163bbe1e5f1d43ba3 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:19 +0100 Subject: block migration: Fix coding style and whitespaces No functional changes. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 390 ++++++++++++++++++++++++++---------------------------- block-migration.h | 10 -- block.c | 49 +++---- block.h | 4 +- 4 files changed, 212 insertions(+), 241 deletions(-) diff --git a/block-migration.c b/block-migration.c index 09771eded..37e41abe2 100644 --- a/block-migration.c +++ b/block-migration.c @@ -21,7 +21,7 @@ #define SECTOR_SIZE (1 << SECTOR_BITS) #define SECTOR_MASK ~(SECTOR_SIZE - 1); -#define BLOCK_SIZE (block_mig_state->sectors_per_block << SECTOR_BITS) +#define BLOCK_SIZE (block_mig_state->sectors_per_block << SECTOR_BITS) #define BLK_MIG_FLAG_DEVICE_BLOCK 0x01 #define BLK_MIG_FLAG_EOS 0x02 @@ -34,13 +34,23 @@ //#define DEBUG_BLK_MIGRATION #ifdef DEBUG_BLK_MIGRATION -#define dprintf(fmt, ...) \ +#define dprintf(fmt, ...) \ do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0) #else -#define dprintf(fmt, ...) \ +#define dprintf(fmt, ...) \ do { } while (0) #endif +typedef struct BlkMigDevState { + BlockDriverState *bs; + int bulk_completed; + int shared_base; + struct BlkMigDevState *next; + int64_t cur_sector; + int64_t total_sectors; + int64_t dirty; +} BlkMigDevState; + typedef struct BlkMigBlock { uint8_t *buf; BlkMigDevState *bmds; @@ -68,87 +78,85 @@ typedef struct BlkMigState { int64_t print_completion; } BlkMigState; -static BlkMigState *block_mig_state = NULL; +static BlkMigState *block_mig_state = NULL; static void blk_mig_read_cb(void *opaque, int ret) { BlkMigBlock *blk = opaque; - + blk->ret = ret; - + /* insert at the end */ - if(block_mig_state->last_blk == NULL) { + if (block_mig_state->last_blk == NULL) { block_mig_state->first_blk = blk; block_mig_state->last_blk = blk; } else { block_mig_state->last_blk->next = blk; block_mig_state->last_blk = blk; } - + block_mig_state->submitted--; block_mig_state->read_done++; assert(block_mig_state->submitted >= 0); - - return; } static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) -{ +{ int nr_sectors; int64_t total_sectors, cur_sector = 0; BlockDriverState *bs = bms->bs; BlkMigBlock *blk; - + blk = qemu_malloc(sizeof(BlkMigBlock)); blk->buf = qemu_malloc(BLOCK_SIZE); - + cur_sector = bms->cur_sector; total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; - - if(bms->shared_base) { - while(cur_sector < bms->total_sectors && - !bdrv_is_allocated(bms->bs, cur_sector, - MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { + + if (bms->shared_base) { + while (cur_sector < bms->total_sectors && + !bdrv_is_allocated(bms->bs, cur_sector, + MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { cur_sector += nr_sectors; } } - - if(cur_sector >= total_sectors) { + + if (cur_sector >= total_sectors) { bms->cur_sector = total_sectors; qemu_free(blk->buf); qemu_free(blk); return 1; } - - if(cur_sector >= block_mig_state->print_completion) { + + if (cur_sector >= block_mig_state->print_completion) { printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors); fflush(stdout); - block_mig_state->print_completion += + block_mig_state->print_completion += (block_mig_state->sectors_per_block * 10000); } - + /* we going to transfder BLOCK_SIZE any way even if it is not allocated */ nr_sectors = block_mig_state->sectors_per_block; cur_sector &= ~((int64_t)block_mig_state->sectors_per_block -1); - - if(total_sectors - cur_sector < block_mig_state->sectors_per_block) { + + if (total_sectors - cur_sector < block_mig_state->sectors_per_block) { nr_sectors = (total_sectors - cur_sector); } - + bms->cur_sector = cur_sector + nr_sectors; blk->sector = cur_sector; blk->bmds = bms; blk->next = NULL; - + blk->iov.iov_base = blk->buf; blk->iov.iov_len = nr_sectors * SECTOR_SIZE; qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); - + blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); - - if(!blk->aiocb) { + + if (!blk->aiocb) { printf("Error reading sector %" PRId64 "\n", cur_sector); qemu_free(blk->buf); qemu_free(blk); @@ -157,91 +165,87 @@ static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) bdrv_reset_dirty(bms->bs, cur_sector, nr_sectors); block_mig_state->submitted++; - + return (bms->cur_sector >= total_sectors); } static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) -{ +{ int len, nr_sectors; int64_t total_sectors = bmds->total_sectors, cur_sector = 0; uint8_t *tmp_buf = NULL; BlockDriverState *bs = bmds->bs; tmp_buf = qemu_malloc(BLOCK_SIZE); - + cur_sector = bmds->cur_sector; - - if(bmds->shared_base) { - while(cur_sector < bmds->total_sectors && - !bdrv_is_allocated(bmds->bs, cur_sector, - MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { + + if (bmds->shared_base) { + while (cur_sector < bmds->total_sectors && + !bdrv_is_allocated(bmds->bs, cur_sector, + MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { cur_sector += nr_sectors; } } - - if(cur_sector >= total_sectors) { + + if (cur_sector >= total_sectors) { bmds->cur_sector = total_sectors; qemu_free(tmp_buf); return 1; } - - if(cur_sector >= block_mig_state->print_completion) { + + if (cur_sector >= block_mig_state->print_completion) { printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors); fflush(stdout); - block_mig_state->print_completion += + block_mig_state->print_completion += (block_mig_state->sectors_per_block * 10000); } - + cur_sector &= ~((int64_t)block_mig_state->sectors_per_block -1); - - /* we going to transfer - BLOCK_SIZE - any way even if it is not allocated */ + + /* we going to transfer BLOCK_SIZE any way even if it is not allocated */ nr_sectors = block_mig_state->sectors_per_block; - - if(total_sectors - cur_sector < block_mig_state->sectors_per_block) { + + if (total_sectors - cur_sector < block_mig_state->sectors_per_block) { nr_sectors = (total_sectors - cur_sector); } - - if(bdrv_read(bs, cur_sector, tmp_buf, nr_sectors) < 0) { + + if (bdrv_read(bs, cur_sector, tmp_buf, nr_sectors) < 0) { printf("Error reading sector %" PRId64 "\n", cur_sector); } bdrv_reset_dirty(bs, cur_sector, nr_sectors); - - /* Device name */ - qemu_put_be64(f,(cur_sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK); - + + /* sector number and flags */ + qemu_put_be64(f, (cur_sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK); + + /* device name */ len = strlen(bs->device_name); qemu_put_byte(f, len); qemu_put_buffer(f, (uint8_t *)bs->device_name, len); - - qemu_put_buffer(f, tmp_buf, - BLOCK_SIZE); - + + qemu_put_buffer(f, tmp_buf, BLOCK_SIZE); + bmds->cur_sector = cur_sector + block_mig_state->sectors_per_block; - + qemu_free(tmp_buf); - + return (bmds->cur_sector >= total_sectors); } static void send_blk(QEMUFile *f, BlkMigBlock * blk) { int len; - - /* Device name */ - qemu_put_be64(f,(blk->sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK); - + + /* sector number and flags */ + qemu_put_be64(f, (blk->sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK); + + /* device name */ len = strlen(blk->bmds->bs->device_name); qemu_put_byte(f, len); qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len); - - qemu_put_buffer(f, blk->buf, - BLOCK_SIZE); - - return; + + qemu_put_buffer(f, blk->buf, BLOCK_SIZE); } static void blk_mig_save_dev_info(QEMUFile *f, BlkMigDevState *bmds) @@ -251,47 +255,43 @@ static void blk_mig_save_dev_info(QEMUFile *f, BlkMigDevState *bmds) static void set_dirty_tracking(int enable) { BlkMigDevState *bmds; - for(bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { - bdrv_set_dirty_tracking(bmds->bs,enable); + for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { + bdrv_set_dirty_tracking(bmds->bs, enable); } - - return; } static void init_blk_migration(QEMUFile *f) { BlkMigDevState **pbmds, *bmds; BlockDriverState *bs; - + for (bs = bdrv_first; bs != NULL; bs = bs->next) { - if(bs->type == BDRV_TYPE_HD) { + if (bs->type == BDRV_TYPE_HD) { bmds = qemu_mallocz(sizeof(BlkMigDevState)); bmds->bs = bs; bmds->bulk_completed = 0; bmds->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; bmds->shared_base = block_mig_state->shared_base; - - if(bmds->shared_base) { - printf("Start migration for %s with shared base image\n", + + if (bmds->shared_base) { + printf("Start migration for %s with shared base image\n", bs->device_name); } else { printf("Start full migration for %s\n", bs->device_name); } - + /* insert at the end */ pbmds = &block_mig_state->bmds_first; - while (*pbmds != NULL) + while (*pbmds != NULL) { pbmds = &(*pbmds)->next; + } *pbmds = bmds; - + blk_mig_save_dev_info(f, bmds); - } - } - + } + block_mig_state->sectors_per_block = bdrv_get_sectors_per_chunk(); - - return; } static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) @@ -299,14 +299,14 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) BlkMigDevState *bmds; for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { - if(bmds->bulk_completed == 0) { - if(is_async) { - if(mig_read_device_bulk(f, bmds) == 1) { + if (bmds->bulk_completed == 0) { + if (is_async) { + if (mig_read_device_bulk(f, bmds) == 1) { /* completed bulk section for this device */ bmds->bulk_completed = 1; } } else { - if(mig_save_device_bulk(f,bmds) == 1) { + if (mig_save_device_bulk(f, bmds) == 1) { /* completed bulk section for this device */ bmds->bulk_completed = 1; } @@ -314,12 +314,11 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) return 1; } } - + /* we reached here means bulk is completed */ block_mig_state->bulk_completed = 1; - + return 0; - } #define MAX_NUM_BLOCKS 4 @@ -330,143 +329,131 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) uint8_t buf[BLOCK_SIZE]; int64_t sector; int len; - - for(bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { - for(sector = 0; sector < bmds->cur_sector;) { - - if(bdrv_get_dirty(bmds->bs,sector)) { - - if(bdrv_read(bmds->bs, sector, buf, - block_mig_state->sectors_per_block) < 0) { + + for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { + for (sector = 0; sector < bmds->cur_sector;) { + if (bdrv_get_dirty(bmds->bs, sector)) { + if (bdrv_read(bmds->bs, sector, buf, + block_mig_state->sectors_per_block) < 0) { + /* FIXME: add error handling */ } - + + /* sector number and flags */ + qemu_put_be64(f, (sector << SECTOR_BITS) + | BLK_MIG_FLAG_DEVICE_BLOCK); + /* device name */ - qemu_put_be64(f,(sector << SECTOR_BITS) - | BLK_MIG_FLAG_DEVICE_BLOCK); - len = strlen(bmds->bs->device_name); - qemu_put_byte(f, len); qemu_put_buffer(f, (uint8_t *)bmds->bs->device_name, len); - - qemu_put_buffer(f, buf, - (block_mig_state->sectors_per_block * + + qemu_put_buffer(f, buf, + (block_mig_state->sectors_per_block * SECTOR_SIZE)); - - bdrv_reset_dirty(bmds->bs, sector, + + bdrv_reset_dirty(bmds->bs, sector, block_mig_state->sectors_per_block); - - sector += block_mig_state->sectors_per_block; - } else { - /* sector is clean */ - sector += block_mig_state->sectors_per_block; - } + } + sector += block_mig_state->sectors_per_block; } } - - return; } static void flush_blks(QEMUFile* f) { - BlkMigBlock *blk, *tmp; - - dprintf("%s Enter submitted %d read_done %d transfered\n", __FUNCTION__, + BlkMigBlock *blk, *next; + + dprintf("%s Enter submitted %d read_done %d transfered\n", __FUNCTION__, submitted, read_done, transfered); - - for(blk = block_mig_state->first_blk; - blk != NULL && !qemu_file_rate_limit(f); blk = tmp) { + + for (blk = block_mig_state->first_blk; + blk != NULL && !qemu_file_rate_limit(f); + blk = next) { send_blk(f, blk); - - tmp = blk->next; + + next = blk->next; qemu_free(blk->buf); qemu_free(blk); - + block_mig_state->read_done--; block_mig_state->transferred++; assert(block_mig_state->read_done >= 0); } block_mig_state->first_blk = blk; - - if(block_mig_state->first_blk == NULL) { + + if (block_mig_state->first_blk == NULL) { block_mig_state->last_blk = NULL; } - dprintf("%s Exit submitted %d read_done %d transferred%d\n", __FUNCTION__, - block_mig_state->submitted, block_mig_state->read_done, + dprintf("%s Exit submitted %d read_done %d transferred%d\n", __FUNCTION__, + block_mig_state->submitted, block_mig_state->read_done, block_mig_state->transferred); - - return; } static int is_stage2_completed(void) { BlkMigDevState *bmds; - - if(block_mig_state->submitted > 0) { + + if (block_mig_state->submitted > 0) { return 0; } - + for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { - if(bmds->bulk_completed == 0) { + if (bmds->bulk_completed == 0) { return 0; } } - + return 1; } static int block_save_live(QEMUFile *f, int stage, void *opaque) { - int ret = 1; - - dprintf("Enter save live stage %d submitted %d transferred %d\n", stage, + dprintf("Enter save live stage %d submitted %d transferred %d\n", stage, submitted, transferred); - - if(block_mig_state->blk_enable != 1) { + + if (block_mig_state->blk_enable != 1) { /* no need to migrate storage */ - - qemu_put_be64(f,BLK_MIG_FLAG_EOS); + qemu_put_be64(f, BLK_MIG_FLAG_EOS); return 1; } - - if(stage == 1) { + + if (stage == 1) { init_blk_migration(f); - + /* start track dirty blocks */ set_dirty_tracking(1); - } flush_blks(f); - + /* control the rate of transfer */ - while ((block_mig_state->submitted + block_mig_state->read_done) * - (BLOCK_SIZE) < - (qemu_file_get_rate_limit(f))) { - - ret = blk_mig_save_bulked_block(f, 1); - - if (ret == 0) /* no more bulk blocks for now*/ + while ((block_mig_state->submitted + + block_mig_state->read_done) * BLOCK_SIZE < + qemu_file_get_rate_limit(f)) { + if (blk_mig_save_bulked_block(f, 1) == 0) { + /* no more bulk blocks for now */ break; + } } - + flush_blks(f); - - if(stage == 3) { - - while(blk_mig_save_bulked_block(f, 0) != 0); - + + if (stage == 3) { + while (blk_mig_save_bulked_block(f, 0) != 0) { + /* empty */ + } + blk_mig_save_dirty_blocks(f); - + /* stop track dirty blocks */ - set_dirty_tracking(0);; - - printf("\nBlock migration completed\n"); + set_dirty_tracking(0); + + printf("\nBlock migration completed\n"); } - - qemu_put_be64(f,BLK_MIG_FLAG_EOS); - + + qemu_put_be64(f, BLK_MIG_FLAG_EOS); + return ((stage == 2) && is_stage2_completed()); } @@ -477,43 +464,39 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) int64_t addr; BlockDriverState *bs; uint8_t *buf; - + block_mig_state->sectors_per_block = bdrv_get_sectors_per_chunk(); buf = qemu_malloc(BLOCK_SIZE); - + do { - addr = qemu_get_be64(f); - + flags = addr & ~SECTOR_MASK; addr &= SECTOR_MASK; - - if(flags & BLK_MIG_FLAG_DEVICE_BLOCK) { - + + if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) { /* get device name */ len = qemu_get_byte(f); - + qemu_get_buffer(f, (uint8_t *)device_name, len); device_name[len] = '\0'; - + bs = bdrv_find(device_name); - - qemu_get_buffer(f, buf, - BLOCK_SIZE); - if(bs != NULL) { - - bdrv_write(bs, (addr >> SECTOR_BITS), + + qemu_get_buffer(f, buf, BLOCK_SIZE); + if (bs != NULL) { + bdrv_write(bs, (addr >> SECTOR_BITS), buf, block_mig_state->sectors_per_block); } else { printf("Error unknown block device %s\n", device_name); + /* FIXME: add error handling */ } - } else if(flags & BLK_MIG_FLAG_EOS) { - - } else { + } else if (!(flags & BLK_MIG_FLAG_EOS)) { printf("Unknown flags\n"); + /* FIXME: add error handling */ } - } while(!(flags & BLK_MIG_FLAG_EOS)); - + } while (!(flags & BLK_MIG_FLAG_EOS)); + qemu_free(buf); return 0; @@ -525,33 +508,28 @@ static void block_set_params(int blk_enable, int shared_base, void *opaque) block_mig_state->blk_enable = blk_enable; block_mig_state->shared_base = shared_base; - + /* shared base means that blk_enable = 1 */ block_mig_state->blk_enable |= shared_base; - - return; } void blk_mig_info(void) { BlockDriverState *bs; - + for (bs = bdrv_first; bs != NULL; bs = bs->next) { printf("Device %s\n", bs->device_name); - if(bs->type == BDRV_TYPE_HD) { - printf("device %s format %s\n", + if (bs->type == BDRV_TYPE_HD) { + printf("device %s format %s\n", bs->device_name, bs->drv->format_name); } } } void blk_mig_init(void) -{ - +{ block_mig_state = qemu_mallocz(sizeof(BlkMigState)); - - register_savevm_live("block", 0, 1, block_set_params, block_save_live, - NULL, block_load, block_mig_state); - + register_savevm_live("block", 0, 1, block_set_params, block_save_live, + NULL, block_load, block_mig_state); } diff --git a/block-migration.h b/block-migration.h index c33d3cbf0..39ee88988 100644 --- a/block-migration.h +++ b/block-migration.h @@ -14,16 +14,6 @@ #ifndef BLOCK_MIGRATION_H #define BLOCK_MIGRATION_H -typedef struct BlkMigDevState { - BlockDriverState *bs; - int bulk_completed; - int shared_base; - struct BlkMigDevState *next; - int64_t cur_sector; - int64_t total_sectors; - int64_t dirty; -} BlkMigDevState; - void blk_mig_init(void); void blk_mig_info(void); #endif /* BLOCK_MIGRATION_H */ diff --git a/block.c b/block.c index 6fdabff12..75ea22351 100644 --- a/block.c +++ b/block.c @@ -643,13 +643,14 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, } static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, int dirty) + int nb_sectors, int dirty) { int64_t start, end; + start = sector_num / SECTORS_PER_DIRTY_CHUNK; end = (sector_num + nb_sectors) / SECTORS_PER_DIRTY_CHUNK; - - for(; start <= end; start++) { + + for (; start <= end; start++) { bs->dirty_bitmap[start] = dirty; } } @@ -670,11 +671,11 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, return -EACCES; if (bdrv_check_request(bs, sector_num, nb_sectors)) return -EIO; - - if(bs->dirty_tracking) { + + if (bs->dirty_tracking) { set_dirty_bitmap(bs, sector_num, nb_sectors, 1); } - + return drv->bdrv_write(bs, sector_num, buf, nb_sectors); } @@ -1220,11 +1221,11 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, return -ENOTSUP; if (bdrv_check_request(bs, sector_num, nb_sectors)) return -EIO; - - if(bs->dirty_tracking) { + + if (bs->dirty_tracking) { set_dirty_bitmap(bs, sector_num, nb_sectors, 1); } - + return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors); } @@ -1422,10 +1423,10 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, if (bdrv_check_request(bs, sector_num, nb_sectors)) return NULL; - if(bs->dirty_tracking) { + if (bs->dirty_tracking) { set_dirty_bitmap(bs, sector_num, nb_sectors, 1); } - + ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors, cb, opaque); @@ -1966,41 +1967,43 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size) void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) { int64_t bitmap_size; - if(enable) { - if(bs->dirty_tracking == 0) { + + if (enable) { + if (bs->dirty_tracking == 0) { int64_t i; uint8_t test; + bitmap_size = (bdrv_getlength(bs) >> SECTOR_BITS); bitmap_size /= SECTORS_PER_DIRTY_CHUNK; bitmap_size++; - + bs->dirty_bitmap = qemu_mallocz(bitmap_size); - + bs->dirty_tracking = enable; for(i = 0; i < bitmap_size; i++) test = bs->dirty_bitmap[i]; - } + } } else { - if(bs->dirty_tracking != 0) { + if (bs->dirty_tracking != 0) { qemu_free(bs->dirty_bitmap); bs->dirty_tracking = enable; - } + } } } int bdrv_get_dirty(BlockDriverState *bs, int64_t sector) { int64_t chunk = sector / (int64_t)SECTORS_PER_DIRTY_CHUNK; - - if(bs->dirty_bitmap != NULL && - (sector << SECTOR_BITS) <= bdrv_getlength(bs)) { + + if (bs->dirty_bitmap != NULL && + (sector << SECTOR_BITS) <= bdrv_getlength(bs)) { return bs->dirty_bitmap[chunk]; } else { return 0; } } -void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, - int nr_sectors) +void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, + int nr_sectors) { set_dirty_bitmap(bs, cur_sector, nr_sectors, 0); } diff --git a/block.h b/block.h index 2d4f06690..85d231df6 100644 --- a/block.h +++ b/block.h @@ -190,7 +190,7 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable); int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); -void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, - int nr_sectors); +void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, + int nr_sectors); int bdrv_get_sectors_per_chunk(void); #endif -- cgit v1.2.3-65-gdbad From 6ea44308b0e8156d352f07b97b2b05eaed89aa6d Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:19 +0100 Subject: block migration: Rework constants API Instead of duplicating the definition of constants or introducing trivial retrieval functions move the SECTOR constants into the public block API. This also obsoletes sector_per_block in BlkMigState. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 63 ++++++++++++++++++++++++------------------------------- block.c | 60 ++++++++++++++++++++++------------------------------ block.h | 7 ++++++- 3 files changed, 58 insertions(+), 72 deletions(-) diff --git a/block-migration.c b/block-migration.c index 37e41abe2..5aff5a718 100644 --- a/block-migration.c +++ b/block-migration.c @@ -17,11 +17,7 @@ #include "block-migration.h" #include -#define SECTOR_BITS 9 -#define SECTOR_SIZE (1 << SECTOR_BITS) -#define SECTOR_MASK ~(SECTOR_SIZE - 1); - -#define BLOCK_SIZE (block_mig_state->sectors_per_block << SECTOR_BITS) +#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS) #define BLK_MIG_FLAG_DEVICE_BLOCK 0x01 #define BLK_MIG_FLAG_EOS 0x02 @@ -69,7 +65,6 @@ typedef struct BlkMigState { int no_dirty; QEMUFile *load_file; BlkMigDevState *bmds_first; - int sectors_per_block; BlkMigBlock *first_blk; BlkMigBlock *last_blk; int submitted; @@ -111,7 +106,7 @@ static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) blk->buf = qemu_malloc(BLOCK_SIZE); cur_sector = bms->cur_sector; - total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; + total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; if (bms->shared_base) { while (cur_sector < bms->total_sectors && @@ -132,15 +127,15 @@ static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors); fflush(stdout); block_mig_state->print_completion += - (block_mig_state->sectors_per_block * 10000); + (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); } - /* we going to transfder BLOCK_SIZE any way even if it is not allocated */ - nr_sectors = block_mig_state->sectors_per_block; + /* we are going to transfer a full block even if it is not allocated */ + nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK; - cur_sector &= ~((int64_t)block_mig_state->sectors_per_block -1); + cur_sector &= ~((int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK - 1); - if (total_sectors - cur_sector < block_mig_state->sectors_per_block) { + if (total_sectors - cur_sector < BDRV_SECTORS_PER_DIRTY_CHUNK) { nr_sectors = (total_sectors - cur_sector); } @@ -150,7 +145,7 @@ static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) blk->next = NULL; blk->iov.iov_base = blk->buf; - blk->iov.iov_len = nr_sectors * SECTOR_SIZE; + blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, @@ -198,15 +193,15 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors); fflush(stdout); block_mig_state->print_completion += - (block_mig_state->sectors_per_block * 10000); + (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); } - cur_sector &= ~((int64_t)block_mig_state->sectors_per_block -1); + cur_sector &= ~((int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK - 1); - /* we going to transfer BLOCK_SIZE any way even if it is not allocated */ - nr_sectors = block_mig_state->sectors_per_block; + /* we are going to transfer a full block even if it is not allocated */ + nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK; - if (total_sectors - cur_sector < block_mig_state->sectors_per_block) { + if (total_sectors - cur_sector < BDRV_SECTORS_PER_DIRTY_CHUNK) { nr_sectors = (total_sectors - cur_sector); } @@ -217,7 +212,8 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) bdrv_reset_dirty(bs, cur_sector, nr_sectors); /* sector number and flags */ - qemu_put_be64(f, (cur_sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK); + qemu_put_be64(f, (cur_sector << BDRV_SECTOR_BITS) + | BLK_MIG_FLAG_DEVICE_BLOCK); /* device name */ len = strlen(bs->device_name); @@ -226,7 +222,7 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) qemu_put_buffer(f, tmp_buf, BLOCK_SIZE); - bmds->cur_sector = cur_sector + block_mig_state->sectors_per_block; + bmds->cur_sector = cur_sector + BDRV_SECTORS_PER_DIRTY_CHUNK; qemu_free(tmp_buf); @@ -238,7 +234,8 @@ static void send_blk(QEMUFile *f, BlkMigBlock * blk) int len; /* sector number and flags */ - qemu_put_be64(f, (blk->sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK); + qemu_put_be64(f, (blk->sector << BDRV_SECTOR_BITS) + | BLK_MIG_FLAG_DEVICE_BLOCK); /* device name */ len = strlen(blk->bmds->bs->device_name); @@ -270,7 +267,7 @@ static void init_blk_migration(QEMUFile *f) bmds = qemu_mallocz(sizeof(BlkMigDevState)); bmds->bs = bs; bmds->bulk_completed = 0; - bmds->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; + bmds->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; bmds->shared_base = block_mig_state->shared_base; if (bmds->shared_base) { @@ -290,8 +287,6 @@ static void init_blk_migration(QEMUFile *f) blk_mig_save_dev_info(f, bmds); } } - - block_mig_state->sectors_per_block = bdrv_get_sectors_per_chunk(); } static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) @@ -334,12 +329,12 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) for (sector = 0; sector < bmds->cur_sector;) { if (bdrv_get_dirty(bmds->bs, sector)) { if (bdrv_read(bmds->bs, sector, buf, - block_mig_state->sectors_per_block) < 0) { + BDRV_SECTORS_PER_DIRTY_CHUNK) < 0) { /* FIXME: add error handling */ } /* sector number and flags */ - qemu_put_be64(f, (sector << SECTOR_BITS) + qemu_put_be64(f, (sector << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK); /* device name */ @@ -347,14 +342,12 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) qemu_put_byte(f, len); qemu_put_buffer(f, (uint8_t *)bmds->bs->device_name, len); - qemu_put_buffer(f, buf, - (block_mig_state->sectors_per_block * - SECTOR_SIZE)); + qemu_put_buffer(f, buf, BLOCK_SIZE); bdrv_reset_dirty(bmds->bs, sector, - block_mig_state->sectors_per_block); + BDRV_SECTORS_PER_DIRTY_CHUNK); } - sector += block_mig_state->sectors_per_block; + sector += BDRV_SECTORS_PER_DIRTY_CHUNK; } } } @@ -465,14 +458,13 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) BlockDriverState *bs; uint8_t *buf; - block_mig_state->sectors_per_block = bdrv_get_sectors_per_chunk(); buf = qemu_malloc(BLOCK_SIZE); do { addr = qemu_get_be64(f); - flags = addr & ~SECTOR_MASK; - addr &= SECTOR_MASK; + flags = addr & ~BDRV_SECTOR_MASK; + addr >>= BDRV_SECTOR_BITS; if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) { /* get device name */ @@ -485,8 +477,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, buf, BLOCK_SIZE); if (bs != NULL) { - bdrv_write(bs, (addr >> SECTOR_BITS), - buf, block_mig_state->sectors_per_block); + bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK); } else { printf("Error unknown block device %s\n", device_name); /* FIXME: add error handling */ diff --git a/block.c b/block.c index 75ea22351..9ce6d8a21 100644 --- a/block.c +++ b/block.c @@ -41,10 +41,6 @@ #include #endif -#define SECTOR_BITS 9 -#define SECTOR_SIZE (1 << SECTOR_BITS) -#define SECTORS_PER_DIRTY_CHUNK 8 - static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque); @@ -386,7 +382,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, bdrv_delete(bs1); return ret; } - total_size = bdrv_getlength(bs1) >> SECTOR_BITS; + total_size = bdrv_getlength(bs1) >> BDRV_SECTOR_BITS; if (bs1->drv && bs1->drv->protocol_name) is_protocol = 1; @@ -473,7 +469,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, return ret; } if (drv->bdrv_getlength) { - bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; + bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; } #ifndef _WIN32 if (bs->is_temporary) { @@ -576,7 +572,7 @@ int bdrv_commit(BlockDriverState *bs) return -ENOTSUP; } - total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; + total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; for (i = 0; i < total_sectors;) { if (drv->bdrv_is_allocated(bs, i, 65536, &n)) { for(j = 0; j < n; j++) { @@ -647,8 +643,8 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num, { int64_t start, end; - start = sector_num / SECTORS_PER_DIRTY_CHUNK; - end = (sector_num + nb_sectors) / SECTORS_PER_DIRTY_CHUNK; + start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK; + end = (sector_num + nb_sectors) / BDRV_SECTORS_PER_DIRTY_CHUNK; for (; start <= end; start++) { bs->dirty_bitmap[start] = dirty; @@ -682,20 +678,20 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, int bdrv_pread(BlockDriverState *bs, int64_t offset, void *buf, int count1) { - uint8_t tmp_buf[SECTOR_SIZE]; + uint8_t tmp_buf[BDRV_SECTOR_SIZE]; int len, nb_sectors, count; int64_t sector_num; count = count1; /* first read to align to sector start */ - len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1); + len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1); if (len > count) len = count; - sector_num = offset >> SECTOR_BITS; + sector_num = offset >> BDRV_SECTOR_BITS; if (len > 0) { if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) return -EIO; - memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len); + memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len); count -= len; if (count == 0) return count1; @@ -704,12 +700,12 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, } /* read the sectors "in place" */ - nb_sectors = count >> SECTOR_BITS; + nb_sectors = count >> BDRV_SECTOR_BITS; if (nb_sectors > 0) { if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0) return -EIO; sector_num += nb_sectors; - len = nb_sectors << SECTOR_BITS; + len = nb_sectors << BDRV_SECTOR_BITS; buf += len; count -= len; } @@ -726,20 +722,20 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, int bdrv_pwrite(BlockDriverState *bs, int64_t offset, const void *buf, int count1) { - uint8_t tmp_buf[SECTOR_SIZE]; + uint8_t tmp_buf[BDRV_SECTOR_SIZE]; int len, nb_sectors, count; int64_t sector_num; count = count1; /* first write to align to sector start */ - len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1); + len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1); if (len > count) len = count; - sector_num = offset >> SECTOR_BITS; + sector_num = offset >> BDRV_SECTOR_BITS; if (len > 0) { if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) return -EIO; - memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len); + memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len); if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0) return -EIO; count -= len; @@ -750,12 +746,12 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, } /* write the sectors "in place" */ - nb_sectors = count >> SECTOR_BITS; + nb_sectors = count >> BDRV_SECTOR_BITS; if (nb_sectors > 0) { if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0) return -EIO; sector_num += nb_sectors; - len = nb_sectors << SECTOR_BITS; + len = nb_sectors << BDRV_SECTOR_BITS; buf += len; count -= len; } @@ -796,7 +792,7 @@ int64_t bdrv_getlength(BlockDriverState *bs) return -ENOMEDIUM; if (!drv->bdrv_getlength) { /* legacy mode */ - return bs->total_sectors * SECTOR_SIZE; + return bs->total_sectors * BDRV_SECTOR_SIZE; } return drv->bdrv_getlength(bs); } @@ -809,7 +805,7 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr) if (length < 0) length = 0; else - length = length >> SECTOR_BITS; + length = length >> BDRV_SECTOR_BITS; *nb_sectors_ptr = length; } @@ -1402,7 +1398,7 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, if (ret) { /* Update stats even though technically transfer has not happened. */ - bs->rd_bytes += (unsigned) nb_sectors * SECTOR_SIZE; + bs->rd_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE; bs->rd_ops ++; } @@ -1432,7 +1428,7 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, if (ret) { /* Update stats even though technically transfer has not happened. */ - bs->wr_bytes += (unsigned) nb_sectors * SECTOR_SIZE; + bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE; bs->wr_ops ++; } @@ -1973,8 +1969,8 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) int64_t i; uint8_t test; - bitmap_size = (bdrv_getlength(bs) >> SECTOR_BITS); - bitmap_size /= SECTORS_PER_DIRTY_CHUNK; + bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS); + bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK; bitmap_size++; bs->dirty_bitmap = qemu_mallocz(bitmap_size); @@ -1992,10 +1988,10 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) int bdrv_get_dirty(BlockDriverState *bs, int64_t sector) { - int64_t chunk = sector / (int64_t)SECTORS_PER_DIRTY_CHUNK; + int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK; if (bs->dirty_bitmap != NULL && - (sector << SECTOR_BITS) <= bdrv_getlength(bs)) { + (sector << BDRV_SECTOR_BITS) <= bdrv_getlength(bs)) { return bs->dirty_bitmap[chunk]; } else { return 0; @@ -2007,9 +2003,3 @@ void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, { set_dirty_bitmap(bs, cur_sector, nr_sectors, 0); } - -int bdrv_get_sectors_per_chunk(void) -{ - /* size must be 2^x */ - return SECTORS_PER_DIRTY_CHUNK; -} diff --git a/block.h b/block.h index 85d231df6..351371227 100644 --- a/block.h +++ b/block.h @@ -41,6 +41,10 @@ typedef struct QEMUSnapshotInfo { #define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB) +#define BDRV_SECTOR_BITS 9 +#define BDRV_SECTOR_SIZE (1 << BDRV_SECTOR_BITS) +#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1); + void bdrv_info(Monitor *mon); void bdrv_info_stats(Monitor *mon); @@ -188,9 +192,10 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size); +#define BDRV_SECTORS_PER_DIRTY_CHUNK 8 + void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable); int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); -int bdrv_get_sectors_per_chunk(void); #endif -- cgit v1.2.3-65-gdbad From c6d2283068026035a6468aae9dcde953bd7521ac Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:20 +0100 Subject: block migration: Cleanup dirty tracking code This switches the dirty bitmap to a true bitmap, reducing its footprint (specifically in caches). It moreover fixes off-by-one bugs in set_dirty_bitmap (nb_sectors+1 were marked) and bdrv_get_dirty (limit check allowed one sector behind end of drive). And is drops redundant dirty_tracking field from BlockDriverState. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block.c | 44 ++++++++++++++++++++++++-------------------- block_int.h | 3 +-- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/block.c b/block.c index 9ce6d8a21..853f0256a 100644 --- a/block.c +++ b/block.c @@ -642,12 +642,21 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int dirty) { int64_t start, end; + unsigned long val, idx, bit; start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK; - end = (sector_num + nb_sectors) / BDRV_SECTORS_PER_DIRTY_CHUNK; + end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK; for (; start <= end; start++) { - bs->dirty_bitmap[start] = dirty; + idx = start / (sizeof(unsigned long) * 8); + bit = start % (sizeof(unsigned long) * 8); + val = bs->dirty_bitmap[idx]; + if (dirty) { + val |= 1 << bit; + } else { + val &= ~(1 << bit); + } + bs->dirty_bitmap[idx] = val; } } @@ -668,7 +677,7 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, if (bdrv_check_request(bs, sector_num, nb_sectors)) return -EIO; - if (bs->dirty_tracking) { + if (bs->dirty_bitmap) { set_dirty_bitmap(bs, sector_num, nb_sectors, 1); } @@ -1218,7 +1227,7 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, if (bdrv_check_request(bs, sector_num, nb_sectors)) return -EIO; - if (bs->dirty_tracking) { + if (bs->dirty_bitmap) { set_dirty_bitmap(bs, sector_num, nb_sectors, 1); } @@ -1419,7 +1428,7 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, if (bdrv_check_request(bs, sector_num, nb_sectors)) return NULL; - if (bs->dirty_tracking) { + if (bs->dirty_bitmap) { set_dirty_bitmap(bs, sector_num, nb_sectors, 1); } @@ -1965,23 +1974,17 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) int64_t bitmap_size; if (enable) { - if (bs->dirty_tracking == 0) { - int64_t i; - uint8_t test; - - bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS); - bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK; - bitmap_size++; + if (!bs->dirty_bitmap) { + bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) + + BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1; + bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8; bs->dirty_bitmap = qemu_mallocz(bitmap_size); - - bs->dirty_tracking = enable; - for(i = 0; i < bitmap_size; i++) test = bs->dirty_bitmap[i]; } } else { - if (bs->dirty_tracking != 0) { + if (bs->dirty_bitmap) { qemu_free(bs->dirty_bitmap); - bs->dirty_tracking = enable; + bs->dirty_bitmap = NULL; } } } @@ -1990,9 +1993,10 @@ int bdrv_get_dirty(BlockDriverState *bs, int64_t sector) { int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK; - if (bs->dirty_bitmap != NULL && - (sector << BDRV_SECTOR_BITS) <= bdrv_getlength(bs)) { - return bs->dirty_bitmap[chunk]; + if (bs->dirty_bitmap && + (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) { + return bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] & + (1 << (chunk % (sizeof(unsigned long) * 8))); } else { return 0; } diff --git a/block_int.h b/block_int.h index 7ebe926f5..907e86410 100644 --- a/block_int.h +++ b/block_int.h @@ -168,8 +168,7 @@ struct BlockDriverState { int cyls, heads, secs, translation; int type; char device_name[32]; - int dirty_tracking; - uint8_t *dirty_bitmap; + unsigned long *dirty_bitmap; BlockDriverState *next; void *private; }; -- cgit v1.2.3-65-gdbad From 575a58d763fa31ab34b8b943b452c0fdb9f37190 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:20 +0100 Subject: block migration: Avoid large stack buffer Move a potentially large buffer from stack to heap. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/block-migration.c b/block-migration.c index 5aff5a718..a0dcdadb2 100644 --- a/block-migration.c +++ b/block-migration.c @@ -321,10 +321,12 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) static void blk_mig_save_dirty_blocks(QEMUFile *f) { BlkMigDevState *bmds; - uint8_t buf[BLOCK_SIZE]; + uint8_t *buf; int64_t sector; int len; + buf = qemu_malloc(BLOCK_SIZE); + for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { for (sector = 0; sector < bmds->cur_sector;) { if (bdrv_get_dirty(bmds->bs, sector)) { @@ -350,6 +352,8 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) sector += BDRV_SECTORS_PER_DIRTY_CHUNK; } } + + qemu_free(buf); } static void flush_blks(QEMUFile* f) @@ -458,8 +462,6 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) BlockDriverState *bs; uint8_t *buf; - buf = qemu_malloc(BLOCK_SIZE); - do { addr = qemu_get_be64(f); @@ -475,6 +477,8 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) bs = bdrv_find(device_name); + buf = qemu_malloc(BLOCK_SIZE); + qemu_get_buffer(f, buf, BLOCK_SIZE); if (bs != NULL) { bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK); @@ -482,14 +486,14 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) printf("Error unknown block device %s\n", device_name); /* FIXME: add error handling */ } + + qemu_free(buf); } else if (!(flags & BLK_MIG_FLAG_EOS)) { printf("Unknown flags\n"); /* FIXME: add error handling */ } } while (!(flags & BLK_MIG_FLAG_EOS)); - qemu_free(buf); - return 0; } -- cgit v1.2.3-65-gdbad From d11ecd3dd54fec1eaf132300701b219723256c49 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:20 +0100 Subject: block migration: Avoid indirection of block_mig_state No need to push block_mig_state to the heap and, thus, establish an indirection. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 91 +++++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 47 deletions(-) diff --git a/block-migration.c b/block-migration.c index a0dcdadb2..f6fac7396 100644 --- a/block-migration.c +++ b/block-migration.c @@ -73,7 +73,7 @@ typedef struct BlkMigState { int64_t print_completion; } BlkMigState; -static BlkMigState *block_mig_state = NULL; +static BlkMigState block_mig_state; static void blk_mig_read_cb(void *opaque, int ret) { @@ -82,17 +82,17 @@ static void blk_mig_read_cb(void *opaque, int ret) blk->ret = ret; /* insert at the end */ - if (block_mig_state->last_blk == NULL) { - block_mig_state->first_blk = blk; - block_mig_state->last_blk = blk; + if (block_mig_state.last_blk == NULL) { + block_mig_state.first_blk = blk; + block_mig_state.last_blk = blk; } else { - block_mig_state->last_blk->next = blk; - block_mig_state->last_blk = blk; + block_mig_state.last_blk->next = blk; + block_mig_state.last_blk = blk; } - block_mig_state->submitted--; - block_mig_state->read_done++; - assert(block_mig_state->submitted >= 0); + block_mig_state.submitted--; + block_mig_state.read_done++; + assert(block_mig_state.submitted >= 0); } static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) @@ -123,10 +123,10 @@ static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) return 1; } - if (cur_sector >= block_mig_state->print_completion) { + if (cur_sector >= block_mig_state.print_completion) { printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors); fflush(stdout); - block_mig_state->print_completion += + block_mig_state.print_completion += (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); } @@ -159,7 +159,7 @@ static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) } bdrv_reset_dirty(bms->bs, cur_sector, nr_sectors); - block_mig_state->submitted++; + block_mig_state.submitted++; return (bms->cur_sector >= total_sectors); } @@ -189,10 +189,10 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) return 1; } - if (cur_sector >= block_mig_state->print_completion) { + if (cur_sector >= block_mig_state.print_completion) { printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors); fflush(stdout); - block_mig_state->print_completion += + block_mig_state.print_completion += (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); } @@ -252,7 +252,7 @@ static void blk_mig_save_dev_info(QEMUFile *f, BlkMigDevState *bmds) static void set_dirty_tracking(int enable) { BlkMigDevState *bmds; - for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { + for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) { bdrv_set_dirty_tracking(bmds->bs, enable); } } @@ -268,7 +268,7 @@ static void init_blk_migration(QEMUFile *f) bmds->bs = bs; bmds->bulk_completed = 0; bmds->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; - bmds->shared_base = block_mig_state->shared_base; + bmds->shared_base = block_mig_state.shared_base; if (bmds->shared_base) { printf("Start migration for %s with shared base image\n", @@ -278,7 +278,7 @@ static void init_blk_migration(QEMUFile *f) } /* insert at the end */ - pbmds = &block_mig_state->bmds_first; + pbmds = &block_mig_state.bmds_first; while (*pbmds != NULL) { pbmds = &(*pbmds)->next; } @@ -293,7 +293,7 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) { BlkMigDevState *bmds; - for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { + for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) { if (bmds->bulk_completed == 0) { if (is_async) { if (mig_read_device_bulk(f, bmds) == 1) { @@ -311,7 +311,7 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) } /* we reached here means bulk is completed */ - block_mig_state->bulk_completed = 1; + block_mig_state.bulk_completed = 1; return 0; } @@ -327,7 +327,7 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) buf = qemu_malloc(BLOCK_SIZE); - for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { + for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) { for (sector = 0; sector < bmds->cur_sector;) { if (bdrv_get_dirty(bmds->bs, sector)) { if (bdrv_read(bmds->bs, sector, buf, @@ -360,10 +360,11 @@ static void flush_blks(QEMUFile* f) { BlkMigBlock *blk, *next; - dprintf("%s Enter submitted %d read_done %d transfered\n", __FUNCTION__, - submitted, read_done, transfered); + dprintf("%s Enter submitted %d read_done %d transferred %d\n", + __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done, + block_mig_state.transferred); - for (blk = block_mig_state->first_blk; + for (blk = block_mig_state.first_blk; blk != NULL && !qemu_file_rate_limit(f); blk = next) { send_blk(f, blk); @@ -372,30 +373,30 @@ static void flush_blks(QEMUFile* f) qemu_free(blk->buf); qemu_free(blk); - block_mig_state->read_done--; - block_mig_state->transferred++; - assert(block_mig_state->read_done >= 0); + block_mig_state.read_done--; + block_mig_state.transferred++; + assert(block_mig_state.read_done >= 0); } - block_mig_state->first_blk = blk; + block_mig_state.first_blk = blk; - if (block_mig_state->first_blk == NULL) { - block_mig_state->last_blk = NULL; + if (block_mig_state.first_blk == NULL) { + block_mig_state.last_blk = NULL; } - dprintf("%s Exit submitted %d read_done %d transferred%d\n", __FUNCTION__, - block_mig_state->submitted, block_mig_state->read_done, - block_mig_state->transferred); + dprintf("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__, + block_mig_state.submitted, block_mig_state.read_done, + block_mig_state.transferred); } static int is_stage2_completed(void) { BlkMigDevState *bmds; - if (block_mig_state->submitted > 0) { + if (block_mig_state.submitted > 0) { return 0; } - for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) { + for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) { if (bmds->bulk_completed == 0) { return 0; } @@ -406,10 +407,10 @@ static int is_stage2_completed(void) static int block_save_live(QEMUFile *f, int stage, void *opaque) { - dprintf("Enter save live stage %d submitted %d transferred %d\n", stage, - submitted, transferred); + dprintf("Enter save live stage %d submitted %d transferred %d\n", + stage, block_mig_state.submitted, block_mig_state.transferred); - if (block_mig_state->blk_enable != 1) { + if (block_mig_state.blk_enable != 1) { /* no need to migrate storage */ qemu_put_be64(f, BLK_MIG_FLAG_EOS); return 1; @@ -425,8 +426,8 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque) flush_blks(f); /* control the rate of transfer */ - while ((block_mig_state->submitted + - block_mig_state->read_done) * BLOCK_SIZE < + while ((block_mig_state.submitted + + block_mig_state.read_done) * BLOCK_SIZE < qemu_file_get_rate_limit(f)) { if (blk_mig_save_bulked_block(f, 1) == 0) { /* no more bulk blocks for now */ @@ -499,13 +500,11 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) static void block_set_params(int blk_enable, int shared_base, void *opaque) { - assert(opaque == block_mig_state); - - block_mig_state->blk_enable = blk_enable; - block_mig_state->shared_base = shared_base; + block_mig_state.blk_enable = blk_enable; + block_mig_state.shared_base = shared_base; /* shared base means that blk_enable = 1 */ - block_mig_state->blk_enable |= shared_base; + block_mig_state.blk_enable |= shared_base; } void blk_mig_info(void) @@ -523,8 +522,6 @@ void blk_mig_info(void) void blk_mig_init(void) { - block_mig_state = qemu_mallocz(sizeof(BlkMigState)); - register_savevm_live("block", 0, 1, block_set_params, block_save_live, - NULL, block_load, block_mig_state); + NULL, block_load, &block_mig_state); } -- cgit v1.2.3-65-gdbad From 3c095c3f802538cefb0fb7c87dcb39eddaadf13f Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:20 +0100 Subject: block migration: Drop dead code Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 24 ------------------------ block-migration.h | 2 +- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/block-migration.c b/block-migration.c index f6fac7396..f81cf35fb 100644 --- a/block-migration.c +++ b/block-migration.c @@ -59,11 +59,8 @@ typedef struct BlkMigBlock { } BlkMigBlock; typedef struct BlkMigState { - int bulk_completed; int blk_enable; int shared_base; - int no_dirty; - QEMUFile *load_file; BlkMigDevState *bmds_first; BlkMigBlock *first_blk; BlkMigBlock *last_blk; @@ -245,10 +242,6 @@ static void send_blk(QEMUFile *f, BlkMigBlock * blk) qemu_put_buffer(f, blk->buf, BLOCK_SIZE); } -static void blk_mig_save_dev_info(QEMUFile *f, BlkMigDevState *bmds) -{ -} - static void set_dirty_tracking(int enable) { BlkMigDevState *bmds; @@ -283,8 +276,6 @@ static void init_blk_migration(QEMUFile *f) pbmds = &(*pbmds)->next; } *pbmds = bmds; - - blk_mig_save_dev_info(f, bmds); } } } @@ -311,8 +302,6 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) } /* we reached here means bulk is completed */ - block_mig_state.bulk_completed = 1; - return 0; } @@ -507,19 +496,6 @@ static void block_set_params(int blk_enable, int shared_base, void *opaque) block_mig_state.blk_enable |= shared_base; } -void blk_mig_info(void) -{ - BlockDriverState *bs; - - for (bs = bdrv_first; bs != NULL; bs = bs->next) { - printf("Device %s\n", bs->device_name); - if (bs->type == BDRV_TYPE_HD) { - printf("device %s format %s\n", - bs->device_name, bs->drv->format_name); - } - } -} - void blk_mig_init(void) { register_savevm_live("block", 0, 1, block_set_params, block_save_live, diff --git a/block-migration.h b/block-migration.h index 39ee88988..a274d2d02 100644 --- a/block-migration.h +++ b/block-migration.h @@ -15,5 +15,5 @@ #define BLOCK_MIGRATION_H void blk_mig_init(void); -void blk_mig_info(void); + #endif /* BLOCK_MIGRATION_H */ -- cgit v1.2.3-65-gdbad From c616bbe1fd17ee633f2e8c4f96423399a85ca4a4 Mon Sep 17 00:00:00 2001 From: Pierre Riteau Date: Mon, 30 Nov 2009 18:21:20 +0100 Subject: Import a simple queue implementation from NetBSD Signed-off-by: Pierre Riteau Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- qemu-queue.h | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 4 deletions(-) diff --git a/qemu-queue.h b/qemu-queue.h index 8877efd7b..1d077458c 100644 --- a/qemu-queue.h +++ b/qemu-queue.h @@ -1,8 +1,9 @@ -/* $NetBSD: queue.h,v 1.45.14.1 2007/07/18 20:13:24 liamjfoy Exp $ */ +/* $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */ /* * Qemu version: Copy from netbsd, removed debug code, removed some of - * the implementations. Left in lists, tail queues and circular queues. + * the implementations. Left in lists, simple queues, tail queues and + * circular queues. */ /* @@ -40,8 +41,8 @@ #define QEMU_SYS_QUEUE_H_ /* - * This file defines three types of data structures: - * lists, tail queues, and circular queues. + * This file defines four types of data structures: + * lists, simple queues, tail queues, and circular queues. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked @@ -50,6 +51,13 @@ * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to @@ -139,6 +147,99 @@ struct { \ #define QLIST_NEXT(elm, field) ((elm)->field.le_next) +/* + * Simple queue definitions. + */ +#define QSIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define QSIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define QSIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define QSIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL)\ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + QSIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +#define QSIMPLEQ_FOREACH_SAFE(var, head, field, next) \ + for ((var) = ((head)->sqh_first); \ + (var) && ((next = ((var)->field.sqe_next)), 1); \ + (var) = (next)) + +#define QSIMPLEQ_CONCAT(head1, head2) do { \ + if (!QSIMPLEQ_EMPTY((head2))) { \ + *(head1)->sqh_last = (head2)->sqh_first; \ + (head1)->sqh_last = (head2)->sqh_last; \ + QSIMPLEQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +#define QSIMPLEQ_LAST(head, type, field) \ + (QSIMPLEQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->sqh_last) - offsetof(struct type, field)))) + +/* + * Simple queue access methods. + */ +#define QSIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define QSIMPLEQ_FIRST(head) ((head)->sqh_first) +#define QSIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + /* * Tail queue definitions. */ -- cgit v1.2.3-65-gdbad From 5e5328be14d4c2305411bec5993e909717e6f0a9 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:20 +0100 Subject: block migration: Switch device and block lists to QSIMPLEQ Based on the original patch by Pierre Riteau. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 57 +++++++++++++++++++++---------------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/block-migration.c b/block-migration.c index f81cf35fb..6ca48f4b3 100644 --- a/block-migration.c +++ b/block-migration.c @@ -14,6 +14,7 @@ #include "qemu-common.h" #include "block_int.h" #include "hw/hw.h" +#include "qemu-queue.h" #include "block-migration.h" #include @@ -41,10 +42,10 @@ typedef struct BlkMigDevState { BlockDriverState *bs; int bulk_completed; int shared_base; - struct BlkMigDevState *next; int64_t cur_sector; int64_t total_sectors; int64_t dirty; + QSIMPLEQ_ENTRY(BlkMigDevState) entry; } BlkMigDevState; typedef struct BlkMigBlock { @@ -55,15 +56,14 @@ typedef struct BlkMigBlock { QEMUIOVector qiov; BlockDriverAIOCB *aiocb; int ret; - struct BlkMigBlock *next; + QSIMPLEQ_ENTRY(BlkMigBlock) entry; } BlkMigBlock; typedef struct BlkMigState { int blk_enable; int shared_base; - BlkMigDevState *bmds_first; - BlkMigBlock *first_blk; - BlkMigBlock *last_blk; + QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list; + QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list; int submitted; int read_done; int transferred; @@ -78,14 +78,7 @@ static void blk_mig_read_cb(void *opaque, int ret) blk->ret = ret; - /* insert at the end */ - if (block_mig_state.last_blk == NULL) { - block_mig_state.first_blk = blk; - block_mig_state.last_blk = blk; - } else { - block_mig_state.last_blk->next = blk; - block_mig_state.last_blk = blk; - } + QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry); block_mig_state.submitted--; block_mig_state.read_done++; @@ -139,7 +132,6 @@ static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) bms->cur_sector = cur_sector + nr_sectors; blk->sector = cur_sector; blk->bmds = bms; - blk->next = NULL; blk->iov.iov_base = blk->buf; blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; @@ -245,14 +237,15 @@ static void send_blk(QEMUFile *f, BlkMigBlock * blk) static void set_dirty_tracking(int enable) { BlkMigDevState *bmds; - for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) { + + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { bdrv_set_dirty_tracking(bmds->bs, enable); } } static void init_blk_migration(QEMUFile *f) { - BlkMigDevState **pbmds, *bmds; + BlkMigDevState *bmds; BlockDriverState *bs; for (bs = bdrv_first; bs != NULL; bs = bs->next) { @@ -270,12 +263,7 @@ static void init_blk_migration(QEMUFile *f) printf("Start full migration for %s\n", bs->device_name); } - /* insert at the end */ - pbmds = &block_mig_state.bmds_first; - while (*pbmds != NULL) { - pbmds = &(*pbmds)->next; - } - *pbmds = bmds; + QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry); } } } @@ -284,7 +272,7 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) { BlkMigDevState *bmds; - for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) { + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { if (bmds->bulk_completed == 0) { if (is_async) { if (mig_read_device_bulk(f, bmds) == 1) { @@ -316,7 +304,7 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) buf = qemu_malloc(BLOCK_SIZE); - for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) { + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { for (sector = 0; sector < bmds->cur_sector;) { if (bdrv_get_dirty(bmds->bs, sector)) { if (bdrv_read(bmds->bs, sector, buf, @@ -347,18 +335,19 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) static void flush_blks(QEMUFile* f) { - BlkMigBlock *blk, *next; + BlkMigBlock *blk; dprintf("%s Enter submitted %d read_done %d transferred %d\n", __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done, block_mig_state.transferred); - for (blk = block_mig_state.first_blk; - blk != NULL && !qemu_file_rate_limit(f); - blk = next) { + while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) { + if (qemu_file_rate_limit(f)) { + break; + } send_blk(f, blk); - next = blk->next; + QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry); qemu_free(blk->buf); qemu_free(blk); @@ -366,11 +355,6 @@ static void flush_blks(QEMUFile* f) block_mig_state.transferred++; assert(block_mig_state.read_done >= 0); } - block_mig_state.first_blk = blk; - - if (block_mig_state.first_blk == NULL) { - block_mig_state.last_blk = NULL; - } dprintf("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done, @@ -385,7 +369,7 @@ static int is_stage2_completed(void) return 0; } - for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) { + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { if (bmds->bulk_completed == 0) { return 0; } @@ -498,6 +482,9 @@ static void block_set_params(int blk_enable, int shared_base, void *opaque) void blk_mig_init(void) { + QSIMPLEQ_INIT(&block_mig_state.bmds_list); + QSIMPLEQ_INIT(&block_mig_state.blk_list); + register_savevm_live("block", 0, 1, block_set_params, block_save_live, NULL, block_load, &block_mig_state); } -- cgit v1.2.3-65-gdbad From 69d63a97a194a70d305f7d3d6b9d8f2c3c5bfbf2 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:20 +0100 Subject: block migration: Initialize remaining BlkMigState fields In case we restart a migration, submitted, read_done, transferred, and print_completion need to be reinitialized to 0. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/block-migration.c b/block-migration.c index 6ca48f4b3..ec32ee27c 100644 --- a/block-migration.c +++ b/block-migration.c @@ -248,6 +248,11 @@ static void init_blk_migration(QEMUFile *f) BlkMigDevState *bmds; BlockDriverState *bs; + block_mig_state.submitted = 0; + block_mig_state.read_done = 0; + block_mig_state.transferred = 0; + block_mig_state.print_completion = 0; + for (bs = bdrv_first; bs != NULL; bs = bs->next) { if (bs->type == BDRV_TYPE_HD) { bmds = qemu_mallocz(sizeof(BlkMigDevState)); -- cgit v1.2.3-65-gdbad From b1d10856d687b449a0dc4eca3a8db41055e2d3b8 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:20 +0100 Subject: block migration: Clean up use of total_sectors We already save total_sectors in BlkMigDevState, let's use this value during the migration and avoid to recalculate it needlessly. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block-migration.c b/block-migration.c index ec32ee27c..2f89a4ee9 100644 --- a/block-migration.c +++ b/block-migration.c @@ -96,10 +96,10 @@ static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) blk->buf = qemu_malloc(BLOCK_SIZE); cur_sector = bms->cur_sector; - total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; + total_sectors = bms->total_sectors; if (bms->shared_base) { - while (cur_sector < bms->total_sectors && + while (cur_sector < total_sectors && !bdrv_is_allocated(bms->bs, cur_sector, MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { cur_sector += nr_sectors; @@ -165,7 +165,7 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) cur_sector = bmds->cur_sector; if (bmds->shared_base) { - while (cur_sector < bmds->total_sectors && + while (cur_sector < total_sectors && !bdrv_is_allocated(bmds->bs, cur_sector, MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { cur_sector += nr_sectors; -- cgit v1.2.3-65-gdbad From 57cce12d544e17fd42f1ccf9d669bf54a5f45b19 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:20 +0100 Subject: block migration: Consolidate mig_read_device_bulk into mig_save_device_bulk Both functions share a lot of code, so make them one. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 149 ++++++++++++++++++------------------------------------ 1 file changed, 50 insertions(+), 99 deletions(-) diff --git a/block-migration.c b/block-migration.c index 2f89a4ee9..99fe3331c 100644 --- a/block-migration.c +++ b/block-migration.c @@ -85,31 +85,25 @@ static void blk_mig_read_cb(void *opaque, int ret) assert(block_mig_state.submitted >= 0); } -static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) +static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds, int is_async) { - int nr_sectors; - int64_t total_sectors, cur_sector = 0; - BlockDriverState *bs = bms->bs; + int64_t total_sectors = bmds->total_sectors; + int64_t cur_sector = bmds->cur_sector; + BlockDriverState *bs = bmds->bs; + int len, nr_sectors; BlkMigBlock *blk; + uint8_t *tmp_buf; - blk = qemu_malloc(sizeof(BlkMigBlock)); - blk->buf = qemu_malloc(BLOCK_SIZE); - - cur_sector = bms->cur_sector; - total_sectors = bms->total_sectors; - - if (bms->shared_base) { + if (bmds->shared_base) { while (cur_sector < total_sectors && - !bdrv_is_allocated(bms->bs, cur_sector, - MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { + !bdrv_is_allocated(bs, cur_sector, MAX_IS_ALLOCATED_SEARCH, + &nr_sectors)) { cur_sector += nr_sectors; } } if (cur_sector >= total_sectors) { - bms->cur_sector = total_sectors; - qemu_free(blk->buf); - qemu_free(blk); + bmds->cur_sector = total_sectors; return 1; } @@ -120,101 +114,65 @@ static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms) (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); } + cur_sector &= ~((int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK - 1); + /* we are going to transfer a full block even if it is not allocated */ nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK; - cur_sector &= ~((int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK - 1); - if (total_sectors - cur_sector < BDRV_SECTORS_PER_DIRTY_CHUNK) { - nr_sectors = (total_sectors - cur_sector); + nr_sectors = total_sectors - cur_sector; } - bms->cur_sector = cur_sector + nr_sectors; - blk->sector = cur_sector; - blk->bmds = bms; + if (is_async) { + blk = qemu_malloc(sizeof(BlkMigBlock)); + blk->buf = qemu_malloc(BLOCK_SIZE); - blk->iov.iov_base = blk->buf; - blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; - qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); + bmds->cur_sector = cur_sector + nr_sectors; + blk->sector = cur_sector; + blk->bmds = bmds; - blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, - nr_sectors, blk_mig_read_cb, blk); + blk->iov.iov_base = blk->buf; + blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; + qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); - if (!blk->aiocb) { - printf("Error reading sector %" PRId64 "\n", cur_sector); - qemu_free(blk->buf); - qemu_free(blk); - return 0; - } - - bdrv_reset_dirty(bms->bs, cur_sector, nr_sectors); - block_mig_state.submitted++; - - return (bms->cur_sector >= total_sectors); -} + blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, + nr_sectors, blk_mig_read_cb, blk); -static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) -{ - int len, nr_sectors; - int64_t total_sectors = bmds->total_sectors, cur_sector = 0; - uint8_t *tmp_buf = NULL; - BlockDriverState *bs = bmds->bs; + if (!blk->aiocb) { + printf("Error reading sector %" PRId64 "\n", cur_sector); + qemu_free(blk->buf); + qemu_free(blk); + return 0; + } - tmp_buf = qemu_malloc(BLOCK_SIZE); + bdrv_reset_dirty(bs, cur_sector, nr_sectors); + block_mig_state.submitted++; - cur_sector = bmds->cur_sector; + } else { + tmp_buf = qemu_malloc(BLOCK_SIZE); - if (bmds->shared_base) { - while (cur_sector < total_sectors && - !bdrv_is_allocated(bmds->bs, cur_sector, - MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { - cur_sector += nr_sectors; + if (bdrv_read(bs, cur_sector, tmp_buf, nr_sectors) < 0) { + printf("Error reading sector %" PRId64 "\n", cur_sector); } - } - if (cur_sector >= total_sectors) { - bmds->cur_sector = total_sectors; - qemu_free(tmp_buf); - return 1; - } + bdrv_reset_dirty(bs, cur_sector, nr_sectors); - if (cur_sector >= block_mig_state.print_completion) { - printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors); - fflush(stdout); - block_mig_state.print_completion += - (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); - } + /* sector number and flags */ + qemu_put_be64(f, (cur_sector << BDRV_SECTOR_BITS) + | BLK_MIG_FLAG_DEVICE_BLOCK); - cur_sector &= ~((int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK - 1); + /* device name */ + len = strlen(bs->device_name); + qemu_put_byte(f, len); + qemu_put_buffer(f, (uint8_t *)bs->device_name, len); - /* we are going to transfer a full block even if it is not allocated */ - nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK; + qemu_put_buffer(f, tmp_buf, BLOCK_SIZE); - if (total_sectors - cur_sector < BDRV_SECTORS_PER_DIRTY_CHUNK) { - nr_sectors = (total_sectors - cur_sector); - } + bmds->cur_sector = cur_sector + BDRV_SECTORS_PER_DIRTY_CHUNK; - if (bdrv_read(bs, cur_sector, tmp_buf, nr_sectors) < 0) { - printf("Error reading sector %" PRId64 "\n", cur_sector); + qemu_free(tmp_buf); } - bdrv_reset_dirty(bs, cur_sector, nr_sectors); - - /* sector number and flags */ - qemu_put_be64(f, (cur_sector << BDRV_SECTOR_BITS) - | BLK_MIG_FLAG_DEVICE_BLOCK); - - /* device name */ - len = strlen(bs->device_name); - qemu_put_byte(f, len); - qemu_put_buffer(f, (uint8_t *)bs->device_name, len); - - qemu_put_buffer(f, tmp_buf, BLOCK_SIZE); - - bmds->cur_sector = cur_sector + BDRV_SECTORS_PER_DIRTY_CHUNK; - - qemu_free(tmp_buf); - return (bmds->cur_sector >= total_sectors); } @@ -279,16 +237,9 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { if (bmds->bulk_completed == 0) { - if (is_async) { - if (mig_read_device_bulk(f, bmds) == 1) { - /* completed bulk section for this device */ - bmds->bulk_completed = 1; - } - } else { - if (mig_save_device_bulk(f, bmds) == 1) { - /* completed bulk section for this device */ - bmds->bulk_completed = 1; - } + if (mig_save_device_bulk(f, bmds, is_async) == 1) { + /* completed bulk section for this device */ + bmds->bulk_completed = 1; } return 1; } -- cgit v1.2.3-65-gdbad From 13f0b67fd34e3cdae15b0fa37e81f6175682dcaf Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: block migration: Consolidate block transmission Based on the original patch by Pierre Riteau: Use a common blk_send function to transmit a block. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 104 ++++++++++++++++++++---------------------------------- 1 file changed, 39 insertions(+), 65 deletions(-) diff --git a/block-migration.c b/block-migration.c index 99fe3331c..81709aaf4 100644 --- a/block-migration.c +++ b/block-migration.c @@ -72,6 +72,22 @@ typedef struct BlkMigState { static BlkMigState block_mig_state; +static void blk_send(QEMUFile *f, BlkMigBlock * blk) +{ + int len; + + /* sector number and flags */ + qemu_put_be64(f, (blk->sector << BDRV_SECTOR_BITS) + | BLK_MIG_FLAG_DEVICE_BLOCK); + + /* device name */ + len = strlen(blk->bmds->bs->device_name); + qemu_put_byte(f, len); + qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len); + + qemu_put_buffer(f, blk->buf, BLOCK_SIZE); +} + static void blk_mig_read_cb(void *opaque, int ret) { BlkMigBlock *blk = opaque; @@ -90,9 +106,8 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds, int is_async) int64_t total_sectors = bmds->total_sectors; int64_t cur_sector = bmds->cur_sector; BlockDriverState *bs = bmds->bs; - int len, nr_sectors; BlkMigBlock *blk; - uint8_t *tmp_buf; + int nr_sectors; if (bmds->shared_base) { while (cur_sector < total_sectors && @@ -123,73 +138,40 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds, int is_async) nr_sectors = total_sectors - cur_sector; } - if (is_async) { - blk = qemu_malloc(sizeof(BlkMigBlock)); - blk->buf = qemu_malloc(BLOCK_SIZE); - - bmds->cur_sector = cur_sector + nr_sectors; - blk->sector = cur_sector; - blk->bmds = bmds; + blk = qemu_malloc(sizeof(BlkMigBlock)); + blk->buf = qemu_malloc(BLOCK_SIZE); + blk->bmds = bmds; + blk->sector = cur_sector; + if (is_async) { blk->iov.iov_base = blk->buf; blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); - if (!blk->aiocb) { printf("Error reading sector %" PRId64 "\n", cur_sector); qemu_free(blk->buf); qemu_free(blk); return 0; } - - bdrv_reset_dirty(bs, cur_sector, nr_sectors); block_mig_state.submitted++; - } else { - tmp_buf = qemu_malloc(BLOCK_SIZE); - - if (bdrv_read(bs, cur_sector, tmp_buf, nr_sectors) < 0) { + if (bdrv_read(bs, cur_sector, blk->buf, nr_sectors) < 0) { printf("Error reading sector %" PRId64 "\n", cur_sector); + return 0; } + blk_send(f, blk); - bdrv_reset_dirty(bs, cur_sector, nr_sectors); - - /* sector number and flags */ - qemu_put_be64(f, (cur_sector << BDRV_SECTOR_BITS) - | BLK_MIG_FLAG_DEVICE_BLOCK); - - /* device name */ - len = strlen(bs->device_name); - qemu_put_byte(f, len); - qemu_put_buffer(f, (uint8_t *)bs->device_name, len); - - qemu_put_buffer(f, tmp_buf, BLOCK_SIZE); - - bmds->cur_sector = cur_sector + BDRV_SECTORS_PER_DIRTY_CHUNK; - - qemu_free(tmp_buf); + qemu_free(blk->buf); + qemu_free(blk); } - return (bmds->cur_sector >= total_sectors); -} - -static void send_blk(QEMUFile *f, BlkMigBlock * blk) -{ - int len; - - /* sector number and flags */ - qemu_put_be64(f, (blk->sector << BDRV_SECTOR_BITS) - | BLK_MIG_FLAG_DEVICE_BLOCK); + bdrv_reset_dirty(bs, cur_sector, nr_sectors); + bmds->cur_sector = cur_sector + nr_sectors; - /* device name */ - len = strlen(blk->bmds->bs->device_name); - qemu_put_byte(f, len); - qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len); - - qemu_put_buffer(f, blk->buf, BLOCK_SIZE); + return (bmds->cur_sector >= total_sectors); } static void set_dirty_tracking(int enable) @@ -254,30 +236,22 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) static void blk_mig_save_dirty_blocks(QEMUFile *f) { BlkMigDevState *bmds; - uint8_t *buf; + BlkMigBlock blk; int64_t sector; - int len; - buf = qemu_malloc(BLOCK_SIZE); + blk.buf = qemu_malloc(BLOCK_SIZE); QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { for (sector = 0; sector < bmds->cur_sector;) { if (bdrv_get_dirty(bmds->bs, sector)) { - if (bdrv_read(bmds->bs, sector, buf, + if (bdrv_read(bmds->bs, sector, blk.buf, BDRV_SECTORS_PER_DIRTY_CHUNK) < 0) { + printf("Error reading sector %" PRId64 "\n", sector); /* FIXME: add error handling */ } - - /* sector number and flags */ - qemu_put_be64(f, (sector << BDRV_SECTOR_BITS) - | BLK_MIG_FLAG_DEVICE_BLOCK); - - /* device name */ - len = strlen(bmds->bs->device_name); - qemu_put_byte(f, len); - qemu_put_buffer(f, (uint8_t *)bmds->bs->device_name, len); - - qemu_put_buffer(f, buf, BLOCK_SIZE); + blk.bmds = bmds; + blk.sector = sector; + blk_send(f, &blk); bdrv_reset_dirty(bmds->bs, sector, BDRV_SECTORS_PER_DIRTY_CHUNK); @@ -286,7 +260,7 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) } } - qemu_free(buf); + qemu_free(blk.buf); } static void flush_blks(QEMUFile* f) @@ -301,7 +275,7 @@ static void flush_blks(QEMUFile* f) if (qemu_file_rate_limit(f)) { break; } - send_blk(f, blk); + blk_send(f, blk); QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry); qemu_free(blk->buf); -- cgit v1.2.3-65-gdbad From 4b640365c79c970d150beb940559b78709a042cb Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: block migration: Add error handling/propagation Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 57 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/block-migration.c b/block-migration.c index 81709aaf4..5997f9bc6 100644 --- a/block-migration.c +++ b/block-migration.c @@ -151,16 +151,12 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds, int is_async) blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); if (!blk->aiocb) { - printf("Error reading sector %" PRId64 "\n", cur_sector); - qemu_free(blk->buf); - qemu_free(blk); - return 0; + goto error; } block_mig_state.submitted++; } else { if (bdrv_read(bs, cur_sector, blk->buf, nr_sectors) < 0) { - printf("Error reading sector %" PRId64 "\n", cur_sector); - return 0; + goto error; } blk_send(f, blk); @@ -172,6 +168,13 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds, int is_async) bmds->cur_sector = cur_sector + nr_sectors; return (bmds->cur_sector >= total_sectors); + +error: + printf("Error reading sector %" PRId64 "\n", cur_sector); + qemu_file_set_error(f); + qemu_free(blk->buf); + qemu_free(blk); + return 0; } static void set_dirty_tracking(int enable) @@ -247,7 +250,9 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) if (bdrv_read(bmds->bs, sector, blk.buf, BDRV_SECTORS_PER_DIRTY_CHUNK) < 0) { printf("Error reading sector %" PRId64 "\n", sector); - /* FIXME: add error handling */ + qemu_file_set_error(f); + qemu_free(blk.buf); + return; } blk.bmds = bmds; blk.sector = sector; @@ -275,6 +280,10 @@ static void flush_blks(QEMUFile* f) if (qemu_file_rate_limit(f)) { break; } + if (blk->ret < 0) { + qemu_file_set_error(f); + break; + } blk_send(f, blk); QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry); @@ -328,6 +337,11 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque) flush_blks(f); + if (qemu_file_has_error(f)) { + set_dirty_tracking(0); + return 0; + } + /* control the rate of transfer */ while ((block_mig_state.submitted + block_mig_state.read_done) * BLOCK_SIZE < @@ -340,6 +354,11 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque) flush_blks(f); + if (qemu_file_has_error(f)) { + set_dirty_tracking(0); + return 0; + } + if (stage == 3) { while (blk_mig_save_bulked_block(f, 0) != 0) { /* empty */ @@ -350,6 +369,10 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque) /* stop track dirty blocks */ set_dirty_tracking(0); + if (qemu_file_has_error(f)) { + return 0; + } + printf("\nBlock migration completed\n"); } @@ -375,26 +398,28 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) { /* get device name */ len = qemu_get_byte(f); - qemu_get_buffer(f, (uint8_t *)device_name, len); device_name[len] = '\0'; bs = bdrv_find(device_name); + if (!bs) { + fprintf(stderr, "Error unknown block device %s\n", + device_name); + return -EINVAL; + } buf = qemu_malloc(BLOCK_SIZE); qemu_get_buffer(f, buf, BLOCK_SIZE); - if (bs != NULL) { - bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK); - } else { - printf("Error unknown block device %s\n", device_name); - /* FIXME: add error handling */ - } + bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK); qemu_free(buf); } else if (!(flags & BLK_MIG_FLAG_EOS)) { - printf("Unknown flags\n"); - /* FIXME: add error handling */ + fprintf(stderr, "Unknown flags\n"); + return -EINVAL; + } + if (qemu_file_has_error(f)) { + return -EIO; } } while (!(flags & BLK_MIG_FLAG_EOS)); -- cgit v1.2.3-65-gdbad From 9a743e5ba32f7a620baa0b3d3808e88d2433e861 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: ram migration: Stop loading on error Besides catching real errors, this also allows to interrrupt the qemu process during restore. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- vl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index ba5bd3d80..62427b8f9 100644 --- a/vl.c +++ b/vl.c @@ -3016,8 +3016,12 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) madvise(qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE, MADV_DONTNEED); } #endif - } else if (flags & RAM_SAVE_FLAG_PAGE) + } else if (flags & RAM_SAVE_FLAG_PAGE) { qemu_get_buffer(f, qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE); + } + if (qemu_file_has_error(f)) { + return -EIO; + } } while (!(flags & RAM_SAVE_FLAG_EOS)); return 0; -- cgit v1.2.3-65-gdbad From 4ec7fcc7da214d48d39b63fd2c6a4d19ac42ae04 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: live migration: Allow cleanup after cancellation or error Introduce qemu_savevm_state_cancel and inject a stage -1 to cancel a live migration. This gives the involved subsystems a chance to clean up dynamically allocated resources. Namely, the block migration layer can now free its device descriptors and pending blocks. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 36 ++++++++++++++++++++++++++++++------ migration.c | 1 + savevm.c | 19 +++++++++++++++++-- sysemu.h | 1 + vl.c | 5 +++++ 5 files changed, 54 insertions(+), 8 deletions(-) diff --git a/block-migration.c b/block-migration.c index 5997f9bc6..5274c5ec3 100644 --- a/block-migration.c +++ b/block-migration.c @@ -317,11 +317,37 @@ static int is_stage2_completed(void) return 1; } +static void blk_mig_cleanup(void) +{ + BlkMigDevState *bmds, *next_bmds; + BlkMigBlock *blk, *next_blk; + + QTAILQ_FOREACH_SAFE(bmds, &block_mig_state.dev_list, entry, next_bmds) { + QTAILQ_REMOVE(&block_mig_state.dev_list, bmds, entry); + qemu_free(bmds); + } + + QTAILQ_FOREACH_SAFE(blk, &block_mig_state.blk_list, entry, next_blk) { + QTAILQ_REMOVE(&block_mig_state.blk_list, blk, entry); + qemu_free(blk->buf); + qemu_free(blk); + } + + set_dirty_tracking(0); + + printf("\n"); +} + static int block_save_live(QEMUFile *f, int stage, void *opaque) { dprintf("Enter save live stage %d submitted %d transferred %d\n", stage, block_mig_state.submitted, block_mig_state.transferred); + if (stage < 0) { + blk_mig_cleanup(); + return 0; + } + if (block_mig_state.blk_enable != 1) { /* no need to migrate storage */ qemu_put_be64(f, BLK_MIG_FLAG_EOS); @@ -338,7 +364,7 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque) flush_blks(f); if (qemu_file_has_error(f)) { - set_dirty_tracking(0); + blk_mig_cleanup(); return 0; } @@ -355,7 +381,7 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque) flush_blks(f); if (qemu_file_has_error(f)) { - set_dirty_tracking(0); + blk_mig_cleanup(); return 0; } @@ -365,15 +391,13 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque) } blk_mig_save_dirty_blocks(f); - - /* stop track dirty blocks */ - set_dirty_tracking(0); + blk_mig_cleanup(); if (qemu_file_has_error(f)) { return 0; } - printf("\nBlock migration completed\n"); + printf("Block migration completed\n"); } qemu_put_be64(f, BLK_MIG_FLAG_EOS); diff --git a/migration.c b/migration.c index d7fb75676..f8a15fb48 100644 --- a/migration.c +++ b/migration.c @@ -324,6 +324,7 @@ void migrate_fd_cancel(MigrationState *mig_state) dprintf("cancelling migration\n"); s->state = MIG_STATE_CANCELLED; + qemu_savevm_state_cancel(s->file); migrate_fd_cleanup(s); } diff --git a/savevm.c b/savevm.c index 17a6c9705..9a7a78ecc 100644 --- a/savevm.c +++ b/savevm.c @@ -1299,8 +1299,10 @@ int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared) se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque); } - if (qemu_file_has_error(f)) + if (qemu_file_has_error(f)) { + qemu_savevm_state_cancel(f); return -EIO; + } return 0; } @@ -1324,8 +1326,10 @@ int qemu_savevm_state_iterate(QEMUFile *f) if (ret) return 1; - if (qemu_file_has_error(f)) + if (qemu_file_has_error(f)) { + qemu_savevm_state_cancel(f); return -EIO; + } return 0; } @@ -1374,6 +1378,17 @@ int qemu_savevm_state_complete(QEMUFile *f) return 0; } +void qemu_savevm_state_cancel(QEMUFile *f) +{ + SaveStateEntry *se; + + QTAILQ_FOREACH(se, &savevm_handlers, entry) { + if (se->save_live_state) { + se->save_live_state(f, -1, se->opaque); + } + } +} + int qemu_savevm_state(QEMUFile *f) { int saved_vm_running; diff --git a/sysemu.h b/sysemu.h index 70a2b044d..0149bd16c 100644 --- a/sysemu.h +++ b/sysemu.h @@ -65,6 +65,7 @@ void main_loop_wait(int timeout); int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared); int qemu_savevm_state_iterate(QEMUFile *f); int qemu_savevm_state_complete(QEMUFile *f); +void qemu_savevm_state_cancel(QEMUFile *f); int qemu_savevm_state(QEMUFile *f); int qemu_loadvm_state(QEMUFile *f); diff --git a/vl.c b/vl.c index 62427b8f9..f6c655b8d 100644 --- a/vl.c +++ b/vl.c @@ -2934,6 +2934,11 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) double bwidth = 0; uint64_t expected_time = 0; + if (stage < 0) { + cpu_physical_memory_set_dirty_tracking(0); + return 0; + } + if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) { qemu_file_set_error(f); return 0; -- cgit v1.2.3-65-gdbad From 82801d8f4f3fa7413647495d9823fb3144c31ddc Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: block migration: Report overall migration progress So far progress reporting only works for the first block device. Fix this by keeping an overall sum of sectors to be migratated, calculating the sum of all processed sectors, and finally basing the progress display on those values. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/block-migration.c b/block-migration.c index 5274c5ec3..15b76de9b 100644 --- a/block-migration.c +++ b/block-migration.c @@ -43,6 +43,7 @@ typedef struct BlkMigDevState { int bulk_completed; int shared_base; int64_t cur_sector; + int64_t completed_sectors; int64_t total_sectors; int64_t dirty; QSIMPLEQ_ENTRY(BlkMigDevState) entry; @@ -67,6 +68,7 @@ typedef struct BlkMigState { int submitted; int read_done; int transferred; + int64_t total_sector_sum; int64_t print_completion; } BlkMigState; @@ -118,16 +120,11 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds, int is_async) } if (cur_sector >= total_sectors) { - bmds->cur_sector = total_sectors; + bmds->cur_sector = bmds->completed_sectors = total_sectors; return 1; } - if (cur_sector >= block_mig_state.print_completion) { - printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors); - fflush(stdout); - block_mig_state.print_completion += - (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); - } + bmds->completed_sectors = cur_sector; cur_sector &= ~((int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK - 1); @@ -194,6 +191,7 @@ static void init_blk_migration(QEMUFile *f) block_mig_state.submitted = 0; block_mig_state.read_done = 0; block_mig_state.transferred = 0; + block_mig_state.total_sector_sum = 0; block_mig_state.print_completion = 0; for (bs = bdrv_first; bs != NULL; bs = bs->next) { @@ -202,8 +200,11 @@ static void init_blk_migration(QEMUFile *f) bmds->bs = bs; bmds->bulk_completed = 0; bmds->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; + bmds->completed_sectors = 0; bmds->shared_base = block_mig_state.shared_base; + block_mig_state.total_sector_sum += bmds->total_sectors; + if (bmds->shared_base) { printf("Start migration for %s with shared base image\n", bs->device_name); @@ -218,7 +219,9 @@ static void init_blk_migration(QEMUFile *f) static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) { + int64_t completed_sector_sum = 0; BlkMigDevState *bmds; + int ret = 0; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { if (bmds->bulk_completed == 0) { @@ -226,12 +229,23 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) /* completed bulk section for this device */ bmds->bulk_completed = 1; } - return 1; + completed_sector_sum += bmds->completed_sectors; + ret = 1; + break; + } else { + completed_sector_sum += bmds->completed_sectors; } } - /* we reached here means bulk is completed */ - return 0; + if (completed_sector_sum >= block_mig_state.print_completion) { + printf("Completed %" PRId64 " %%\r", + completed_sector_sum * 100 / block_mig_state.total_sector_sum); + fflush(stdout); + block_mig_state.print_completion += + (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); + } + + return ret; } #define MAX_NUM_BLOCKS 4 @@ -319,16 +333,16 @@ static int is_stage2_completed(void) static void blk_mig_cleanup(void) { - BlkMigDevState *bmds, *next_bmds; - BlkMigBlock *blk, *next_blk; + BlkMigDevState *bmds; + BlkMigBlock *blk; - QTAILQ_FOREACH_SAFE(bmds, &block_mig_state.dev_list, entry, next_bmds) { - QTAILQ_REMOVE(&block_mig_state.dev_list, bmds, entry); + while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) { + QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry); qemu_free(bmds); } - QTAILQ_FOREACH_SAFE(blk, &block_mig_state.blk_list, entry, next_blk) { - QTAILQ_REMOVE(&block_mig_state.blk_list, blk, entry); + while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) { + QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry); qemu_free(blk->buf); qemu_free(blk); } -- cgit v1.2.3-65-gdbad From f327aa0c608b4bae3c93f0fbd0afcfdd9c9635bc Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: live migration: Propagate output monitor to callback handler In order to allow proper progress reporting to the monitor that initiated the migration, forward the monitor reference through the migration layer down to SaveLiveStateHandler. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 2 +- hw/hw.h | 3 ++- migration-exec.c | 12 +++++++----- migration-fd.c | 9 +++++---- migration-tcp.c | 10 ++++++---- migration-unix.c | 10 ++++++---- migration.c | 30 ++++++++++++++++-------------- migration.h | 13 ++++++++----- savevm.c | 31 ++++++++++++++++--------------- sysemu.h | 10 +++++----- vl.c | 2 +- 11 files changed, 73 insertions(+), 59 deletions(-) diff --git a/block-migration.c b/block-migration.c index 15b76de9b..b56be7908 100644 --- a/block-migration.c +++ b/block-migration.c @@ -352,7 +352,7 @@ static void blk_mig_cleanup(void) printf("\n"); } -static int block_save_live(QEMUFile *f, int stage, void *opaque) +static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) { dprintf("Enter save live stage %d submitted %d transferred %d\n", stage, block_mig_state.submitted, block_mig_state.transferred); diff --git a/hw/hw.h b/hw/hw.h index 5f3499196..7b500f4e4 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -244,7 +244,8 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque); typedef void SaveStateHandler(QEMUFile *f, void *opaque); -typedef int SaveLiveStateHandler(QEMUFile *f, int stage, void *opaque); +typedef int SaveLiveStateHandler(Monitor *mon, QEMUFile *f, int stage, + void *opaque); typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); int register_savevm(const char *idstr, diff --git a/migration-exec.c b/migration-exec.c index c83066959..87f645b68 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -52,7 +52,8 @@ static int exec_close(FdMigrationState *s) return 0; } -MigrationState *exec_start_outgoing_migration(const char *command, +MigrationState *exec_start_outgoing_migration(Monitor *mon, + const char *command, int64_t bandwidth_limit, int detach, int blk, @@ -88,13 +89,14 @@ MigrationState *exec_start_outgoing_migration(const char *command, s->mig_state.blk = blk; s->mig_state.shared = inc; - + s->state = MIG_STATE_ACTIVE; - s->mon_resume = NULL; + s->mon = NULL; s->bandwidth_limit = bandwidth_limit; - if (!detach) - migrate_fd_monitor_suspend(s); + if (!detach) { + migrate_fd_monitor_suspend(s, mon); + } migrate_fd_connect(s); return &s->mig_state; diff --git a/migration-fd.c b/migration-fd.c index 587f9d8e8..ef7edbc5e 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -82,13 +82,14 @@ MigrationState *fd_start_outgoing_migration(Monitor *mon, s->mig_state.blk = blk; s->mig_state.shared = inc; - + s->state = MIG_STATE_ACTIVE; - s->mon_resume = NULL; + s->mon = NULL; s->bandwidth_limit = bandwidth_limit; - if (!detach) - migrate_fd_monitor_suspend(s); + if (!detach) { + migrate_fd_monitor_suspend(s, mon); + } migrate_fd_connect(s); return &s->mig_state; diff --git a/migration-tcp.c b/migration-tcp.c index efa7c74c6..b77ed8762 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -76,7 +76,8 @@ static void tcp_wait_for_connect(void *opaque) } } -MigrationState *tcp_start_outgoing_migration(const char *host_port, +MigrationState *tcp_start_outgoing_migration(Monitor *mon, + const char *host_port, int64_t bandwidth_limit, int detach, int blk, @@ -102,7 +103,7 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, s->mig_state.shared = inc; s->state = MIG_STATE_ACTIVE; - s->mon_resume = NULL; + s->mon = NULL; s->bandwidth_limit = bandwidth_limit; s->fd = socket(PF_INET, SOCK_STREAM, 0); if (s->fd == -1) { @@ -112,8 +113,9 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, socket_set_nonblock(s->fd); - if (!detach) - migrate_fd_monitor_suspend(s); + if (!detach) { + migrate_fd_monitor_suspend(s, mon); + } do { ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); diff --git a/migration-unix.c b/migration-unix.c index 25cd6d3d2..7dd787cd9 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -75,7 +75,8 @@ static void unix_wait_for_connect(void *opaque) } } -MigrationState *unix_start_outgoing_migration(const char *path, +MigrationState *unix_start_outgoing_migration(Monitor *mon, + const char *path, int64_t bandwidth_limit, int detach, int blk, @@ -101,7 +102,7 @@ MigrationState *unix_start_outgoing_migration(const char *path, s->mig_state.shared = inc; s->state = MIG_STATE_ACTIVE; - s->mon_resume = NULL; + s->mon = NULL; s->bandwidth_limit = bandwidth_limit; s->fd = socket(PF_UNIX, SOCK_STREAM, 0); if (s->fd < 0) { @@ -111,8 +112,9 @@ MigrationState *unix_start_outgoing_migration(const char *path, socket_set_nonblock(s->fd); - if (!detach) - migrate_fd_monitor_suspend(s); + if (!detach) { + migrate_fd_monitor_suspend(s, mon); + } do { ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); diff --git a/migration.c b/migration.c index f8a15fb48..f4d30222d 100644 --- a/migration.c +++ b/migration.c @@ -66,16 +66,16 @@ void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data) } if (strstart(uri, "tcp:", &p)) - s = tcp_start_outgoing_migration(p, max_throttle, detach, + s = tcp_start_outgoing_migration(mon, p, max_throttle, detach, (int)qdict_get_int(qdict, "blk"), (int)qdict_get_int(qdict, "inc")); #if !defined(WIN32) else if (strstart(uri, "exec:", &p)) - s = exec_start_outgoing_migration(p, max_throttle, detach, + s = exec_start_outgoing_migration(mon, p, max_throttle, detach, (int)qdict_get_int(qdict, "blk"), (int)qdict_get_int(qdict, "inc")); else if (strstart(uri, "unix:", &p)) - s = unix_start_outgoing_migration(p, max_throttle, detach, + s = unix_start_outgoing_migration(mon, p, max_throttle, detach, (int)qdict_get_int(qdict, "blk"), (int)qdict_get_int(qdict, "inc")); else if (strstart(uri, "fd:", &p)) @@ -190,14 +190,15 @@ void do_info_migrate(Monitor *mon) /* shared migration helpers */ -void migrate_fd_monitor_suspend(FdMigrationState *s) +void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon) { - s->mon_resume = cur_mon; - if (monitor_suspend(cur_mon) == 0) + s->mon = mon; + if (monitor_suspend(mon) == 0) { dprintf("suspending monitor\n"); - else - monitor_printf(cur_mon, "terminal does not allow synchronous " + } else { + monitor_printf(mon, "terminal does not allow synchronous " "migration, continuing detached\n"); + } } void migrate_fd_error(FdMigrationState *s) @@ -221,8 +222,9 @@ void migrate_fd_cleanup(FdMigrationState *s) close(s->fd); /* Don't resume monitor until we've flushed all of the buffers */ - if (s->mon_resume) - monitor_resume(s->mon_resume); + if (s->mon) { + monitor_resume(s->mon); + } s->fd = -1; } @@ -265,7 +267,7 @@ void migrate_fd_connect(FdMigrationState *s) migrate_fd_close); dprintf("beginning savevm\n"); - ret = qemu_savevm_state_begin(s->file, s->mig_state.blk, + ret = qemu_savevm_state_begin(s->mon, s->file, s->mig_state.blk, s->mig_state.shared); if (ret < 0) { dprintf("failed, %d\n", ret); @@ -286,7 +288,7 @@ void migrate_fd_put_ready(void *opaque) } dprintf("iterate\n"); - if (qemu_savevm_state_iterate(s->file) == 1) { + if (qemu_savevm_state_iterate(s->mon, s->file) == 1) { int state; int old_vm_running = vm_running; @@ -295,7 +297,7 @@ void migrate_fd_put_ready(void *opaque) qemu_aio_flush(); bdrv_flush_all(); - if ((qemu_savevm_state_complete(s->file)) < 0) { + if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) { if (old_vm_running) { vm_start(); } @@ -324,7 +326,7 @@ void migrate_fd_cancel(MigrationState *mig_state) dprintf("cancelling migration\n"); s->state = MIG_STATE_CANCELLED; - qemu_savevm_state_cancel(s->file); + qemu_savevm_state_cancel(s->mon, s->file); migrate_fd_cleanup(s); } diff --git a/migration.h b/migration.h index 56adf05e6..3f2b3df2b 100644 --- a/migration.h +++ b/migration.h @@ -42,7 +42,7 @@ struct FdMigrationState int64_t bandwidth_limit; QEMUFile *file; int fd; - Monitor *mon_resume; + Monitor *mon; int state; int (*get_error)(struct FdMigrationState*); int (*close)(struct FdMigrationState*); @@ -66,7 +66,8 @@ void do_info_migrate(Monitor *mon); int exec_start_incoming_migration(const char *host_port); -MigrationState *exec_start_outgoing_migration(const char *host_port, +MigrationState *exec_start_outgoing_migration(Monitor *mon, + const char *host_port, int64_t bandwidth_limit, int detach, int blk, @@ -74,7 +75,8 @@ MigrationState *exec_start_outgoing_migration(const char *host_port, int tcp_start_incoming_migration(const char *host_port); -MigrationState *tcp_start_outgoing_migration(const char *host_port, +MigrationState *tcp_start_outgoing_migration(Monitor *mon, + const char *host_port, int64_t bandwidth_limit, int detach, int blk, @@ -82,7 +84,8 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, int unix_start_incoming_migration(const char *path); -MigrationState *unix_start_outgoing_migration(const char *path, +MigrationState *unix_start_outgoing_migration(Monitor *mon, + const char *path, int64_t bandwidth_limit, int detach, int blk, @@ -97,7 +100,7 @@ MigrationState *fd_start_outgoing_migration(Monitor *mon, int blk, int inc); -void migrate_fd_monitor_suspend(FdMigrationState *s); +void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon); void migrate_fd_error(FdMigrationState *s); diff --git a/savevm.c b/savevm.c index 9a7a78ecc..db44ed607 100644 --- a/savevm.c +++ b/savevm.c @@ -1264,7 +1264,8 @@ static void vmstate_save(QEMUFile *f, SaveStateEntry *se) #define QEMU_VM_SECTION_END 0x03 #define QEMU_VM_SECTION_FULL 0x04 -int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared) +int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable, + int shared) { SaveStateEntry *se; @@ -1296,18 +1297,18 @@ int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared) qemu_put_be32(f, se->instance_id); qemu_put_be32(f, se->version_id); - se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque); + se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque); } if (qemu_file_has_error(f)) { - qemu_savevm_state_cancel(f); + qemu_savevm_state_cancel(mon, f); return -EIO; } return 0; } -int qemu_savevm_state_iterate(QEMUFile *f) +int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f) { SaveStateEntry *se; int ret = 1; @@ -1320,21 +1321,21 @@ int qemu_savevm_state_iterate(QEMUFile *f) qemu_put_byte(f, QEMU_VM_SECTION_PART); qemu_put_be32(f, se->section_id); - ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque); + ret &= !!se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque); } if (ret) return 1; if (qemu_file_has_error(f)) { - qemu_savevm_state_cancel(f); + qemu_savevm_state_cancel(mon, f); return -EIO; } return 0; } -int qemu_savevm_state_complete(QEMUFile *f) +int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f) { SaveStateEntry *se; @@ -1346,7 +1347,7 @@ int qemu_savevm_state_complete(QEMUFile *f) qemu_put_byte(f, QEMU_VM_SECTION_END); qemu_put_be32(f, se->section_id); - se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque); + se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque); } QTAILQ_FOREACH(se, &savevm_handlers, entry) { @@ -1378,18 +1379,18 @@ int qemu_savevm_state_complete(QEMUFile *f) return 0; } -void qemu_savevm_state_cancel(QEMUFile *f) +void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f) { SaveStateEntry *se; QTAILQ_FOREACH(se, &savevm_handlers, entry) { if (se->save_live_state) { - se->save_live_state(f, -1, se->opaque); + se->save_live_state(mon, f, -1, se->opaque); } } } -int qemu_savevm_state(QEMUFile *f) +static int qemu_savevm_state(Monitor *mon, QEMUFile *f) { int saved_vm_running; int ret; @@ -1399,17 +1400,17 @@ int qemu_savevm_state(QEMUFile *f) bdrv_flush_all(); - ret = qemu_savevm_state_begin(f, 0, 0); + ret = qemu_savevm_state_begin(mon, f, 0, 0); if (ret < 0) goto out; do { - ret = qemu_savevm_state_iterate(f); + ret = qemu_savevm_state_iterate(mon, f); if (ret < 0) goto out; } while (ret == 0); - ret = qemu_savevm_state_complete(f); + ret = qemu_savevm_state_complete(mon, f); out: if (qemu_file_has_error(f)) @@ -1698,7 +1699,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) monitor_printf(mon, "Could not open VM state file\n"); goto the_end; } - ret = qemu_savevm_state(f); + ret = qemu_savevm_state(mon, f); vm_state_size = qemu_ftell(f); qemu_fclose(f); if (ret < 0) { diff --git a/sysemu.h b/sysemu.h index 0149bd16c..e7819de9a 100644 --- a/sysemu.h +++ b/sysemu.h @@ -62,11 +62,11 @@ void qemu_announce_self(void); void main_loop_wait(int timeout); -int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared); -int qemu_savevm_state_iterate(QEMUFile *f); -int qemu_savevm_state_complete(QEMUFile *f); -void qemu_savevm_state_cancel(QEMUFile *f); -int qemu_savevm_state(QEMUFile *f); +int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable, + int shared); +int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f); +int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f); +void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f); int qemu_loadvm_state(QEMUFile *f); void qemu_errors_to_file(FILE *fp); diff --git a/vl.c b/vl.c index f6c655b8d..e9b75c9b8 100644 --- a/vl.c +++ b/vl.c @@ -2927,7 +2927,7 @@ uint64_t ram_bytes_total(void) return last_ram_offset; } -static int ram_save_live(QEMUFile *f, int stage, void *opaque) +static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) { ram_addr_t addr; uint64_t bytes_transferred_last; -- cgit v1.2.3-65-gdbad From 7184049ee6f51e84ed36b9c864850e82a255c31a Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: block migration: Fix outgoing progress output Report progress of an outgoing live migration to the monitor instead of stdout. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/block-migration.c b/block-migration.c index b56be7908..22d10f03c 100644 --- a/block-migration.c +++ b/block-migration.c @@ -15,6 +15,7 @@ #include "block_int.h" #include "hw/hw.h" #include "qemu-queue.h" +#include "monitor.h" #include "block-migration.h" #include @@ -103,7 +104,8 @@ static void blk_mig_read_cb(void *opaque, int ret) assert(block_mig_state.submitted >= 0); } -static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds, int is_async) +static int mig_save_device_bulk(Monitor *mon, QEMUFile *f, + BlkMigDevState *bmds, int is_async) { int64_t total_sectors = bmds->total_sectors; int64_t cur_sector = bmds->cur_sector; @@ -167,7 +169,7 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds, int is_async) return (bmds->cur_sector >= total_sectors); error: - printf("Error reading sector %" PRId64 "\n", cur_sector); + monitor_printf(mon, "Error reading sector %" PRId64 "\n", cur_sector); qemu_file_set_error(f); qemu_free(blk->buf); qemu_free(blk); @@ -183,7 +185,7 @@ static void set_dirty_tracking(int enable) } } -static void init_blk_migration(QEMUFile *f) +static void init_blk_migration(Monitor *mon, QEMUFile *f) { BlkMigDevState *bmds; BlockDriverState *bs; @@ -206,10 +208,12 @@ static void init_blk_migration(QEMUFile *f) block_mig_state.total_sector_sum += bmds->total_sectors; if (bmds->shared_base) { - printf("Start migration for %s with shared base image\n", - bs->device_name); + monitor_printf(mon, "Start migration for %s with shared base " + "image\n", + bs->device_name); } else { - printf("Start full migration for %s\n", bs->device_name); + monitor_printf(mon, "Start full migration for %s\n", + bs->device_name); } QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry); @@ -217,7 +221,7 @@ static void init_blk_migration(QEMUFile *f) } } -static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) +static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f, int is_async) { int64_t completed_sector_sum = 0; BlkMigDevState *bmds; @@ -225,7 +229,7 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { if (bmds->bulk_completed == 0) { - if (mig_save_device_bulk(f, bmds, is_async) == 1) { + if (mig_save_device_bulk(mon, f, bmds, is_async) == 1) { /* completed bulk section for this device */ bmds->bulk_completed = 1; } @@ -238,9 +242,10 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) } if (completed_sector_sum >= block_mig_state.print_completion) { - printf("Completed %" PRId64 " %%\r", - completed_sector_sum * 100 / block_mig_state.total_sector_sum); - fflush(stdout); + monitor_printf(mon, "Completed %" PRId64 " %%\r", + completed_sector_sum * 100 / + block_mig_state.total_sector_sum); + monitor_flush(mon); block_mig_state.print_completion += (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); } @@ -250,7 +255,7 @@ static int blk_mig_save_bulked_block(QEMUFile *f, int is_async) #define MAX_NUM_BLOCKS 4 -static void blk_mig_save_dirty_blocks(QEMUFile *f) +static void blk_mig_save_dirty_blocks(Monitor *mon, QEMUFile *f) { BlkMigDevState *bmds; BlkMigBlock blk; @@ -263,7 +268,8 @@ static void blk_mig_save_dirty_blocks(QEMUFile *f) if (bdrv_get_dirty(bmds->bs, sector)) { if (bdrv_read(bmds->bs, sector, blk.buf, BDRV_SECTORS_PER_DIRTY_CHUNK) < 0) { - printf("Error reading sector %" PRId64 "\n", sector); + monitor_printf(mon, "Error reading sector %" PRId64 "\n", + sector); qemu_file_set_error(f); qemu_free(blk.buf); return; @@ -331,7 +337,7 @@ static int is_stage2_completed(void) return 1; } -static void blk_mig_cleanup(void) +static void blk_mig_cleanup(Monitor *mon) { BlkMigDevState *bmds; BlkMigBlock *blk; @@ -349,7 +355,7 @@ static void blk_mig_cleanup(void) set_dirty_tracking(0); - printf("\n"); + monitor_printf(mon, "\n"); } static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) @@ -358,7 +364,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) stage, block_mig_state.submitted, block_mig_state.transferred); if (stage < 0) { - blk_mig_cleanup(); + blk_mig_cleanup(mon); return 0; } @@ -369,7 +375,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) } if (stage == 1) { - init_blk_migration(f); + init_blk_migration(mon, f); /* start track dirty blocks */ set_dirty_tracking(1); @@ -378,7 +384,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) flush_blks(f); if (qemu_file_has_error(f)) { - blk_mig_cleanup(); + blk_mig_cleanup(mon); return 0; } @@ -386,7 +392,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) while ((block_mig_state.submitted + block_mig_state.read_done) * BLOCK_SIZE < qemu_file_get_rate_limit(f)) { - if (blk_mig_save_bulked_block(f, 1) == 0) { + if (blk_mig_save_bulked_block(mon, f, 1) == 0) { /* no more bulk blocks for now */ break; } @@ -395,23 +401,23 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) flush_blks(f); if (qemu_file_has_error(f)) { - blk_mig_cleanup(); + blk_mig_cleanup(mon); return 0; } if (stage == 3) { - while (blk_mig_save_bulked_block(f, 0) != 0) { + while (blk_mig_save_bulked_block(mon, f, 0) != 0) { /* empty */ } - blk_mig_save_dirty_blocks(f); - blk_mig_cleanup(); + blk_mig_save_dirty_blocks(mon, f); + blk_mig_cleanup(mon); if (qemu_file_has_error(f)) { return 0; } - printf("Block migration completed\n"); + monitor_printf(mon, "Block migration completed\n"); } qemu_put_be64(f, BLK_MIG_FLAG_EOS); -- cgit v1.2.3-65-gdbad From 25f236433f5c791edce74228201254a1cc84f9a3 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: block migration: Report progress also via info migration Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 32 ++++++++++++++++++++++++++++++++ block-migration.h | 4 ++++ migration.c | 9 +++++++++ 3 files changed, 45 insertions(+) diff --git a/block-migration.c b/block-migration.c index 22d10f03c..7510923a8 100644 --- a/block-migration.c +++ b/block-migration.c @@ -91,6 +91,38 @@ static void blk_send(QEMUFile *f, BlkMigBlock * blk) qemu_put_buffer(f, blk->buf, BLOCK_SIZE); } +int blk_mig_active(void) +{ + return !QSIMPLEQ_EMPTY(&block_mig_state.bmds_list); +} + +uint64_t blk_mig_bytes_transferred(void) +{ + BlkMigDevState *bmds; + uint64_t sum = 0; + + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + sum += bmds->completed_sectors; + } + return sum << BDRV_SECTOR_BITS; +} + +uint64_t blk_mig_bytes_remaining(void) +{ + return blk_mig_bytes_total() - blk_mig_bytes_transferred(); +} + +uint64_t blk_mig_bytes_total(void) +{ + BlkMigDevState *bmds; + uint64_t sum = 0; + + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + sum += bmds->total_sectors; + } + return sum << BDRV_SECTOR_BITS; +} + static void blk_mig_read_cb(void *opaque, int ret) { BlkMigBlock *blk = opaque; diff --git a/block-migration.h b/block-migration.h index a274d2d02..ffa8ac0bd 100644 --- a/block-migration.h +++ b/block-migration.h @@ -15,5 +15,9 @@ #define BLOCK_MIGRATION_H void blk_mig_init(void); +int blk_mig_active(void); +uint64_t blk_mig_bytes_transferred(void); +uint64_t blk_mig_bytes_remaining(void); +uint64_t blk_mig_bytes_total(void); #endif /* BLOCK_MIGRATION_H */ diff --git a/migration.c b/migration.c index f4d30222d..d6a3e2615 100644 --- a/migration.c +++ b/migration.c @@ -18,6 +18,7 @@ #include "sysemu.h" #include "block.h" #include "qemu_socket.h" +#include "block-migration.h" //#define DEBUG_MIGRATION @@ -174,6 +175,14 @@ void do_info_migrate(Monitor *mon) monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n", ram_bytes_transferred() >> 10); monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n", ram_bytes_remaining() >> 10); monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n", ram_bytes_total() >> 10); + if (blk_mig_active()) { + monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n", + blk_mig_bytes_transferred() >> 10); + monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n", + blk_mig_bytes_remaining() >> 10); + monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n", + blk_mig_bytes_total() >> 10); + } break; case MIG_STATE_COMPLETED: monitor_printf(mon, "completed\n"); -- cgit v1.2.3-65-gdbad From 01e61e2d16b72aa3f18cd25123db069c06a3606c Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 1 Dec 2009 15:20:17 +0100 Subject: block migration: Add support for restore progress reporting Inject progress report in percentage into the block live stream. This can be read out and displayed easily on restore. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/block-migration.c b/block-migration.c index 7510923a8..a066f1924 100644 --- a/block-migration.c +++ b/block-migration.c @@ -23,6 +23,7 @@ #define BLK_MIG_FLAG_DEVICE_BLOCK 0x01 #define BLK_MIG_FLAG_EOS 0x02 +#define BLK_MIG_FLAG_PROGRESS 0x04 #define MAX_IS_ALLOCATED_SEARCH 65536 #define MAX_BLOCKS_READ 10000 @@ -70,7 +71,7 @@ typedef struct BlkMigState { int read_done; int transferred; int64_t total_sector_sum; - int64_t print_completion; + int prev_progress; } BlkMigState; static BlkMigState block_mig_state; @@ -226,7 +227,7 @@ static void init_blk_migration(Monitor *mon, QEMUFile *f) block_mig_state.read_done = 0; block_mig_state.transferred = 0; block_mig_state.total_sector_sum = 0; - block_mig_state.print_completion = 0; + block_mig_state.prev_progress = -1; for (bs = bdrv_first; bs != NULL; bs = bs->next) { if (bs->type == BDRV_TYPE_HD) { @@ -257,6 +258,7 @@ static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f, int is_async) { int64_t completed_sector_sum = 0; BlkMigDevState *bmds; + int progress; int ret = 0; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { @@ -273,13 +275,13 @@ static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f, int is_async) } } - if (completed_sector_sum >= block_mig_state.print_completion) { - monitor_printf(mon, "Completed %" PRId64 " %%\r", - completed_sector_sum * 100 / - block_mig_state.total_sector_sum); + progress = completed_sector_sum * 100 / block_mig_state.total_sector_sum; + if (progress != block_mig_state.prev_progress) { + block_mig_state.prev_progress = progress; + qemu_put_be64(f, (progress << BDRV_SECTOR_BITS) + | BLK_MIG_FLAG_PROGRESS); + monitor_printf(mon, "Completed %d %%\r", progress); monitor_flush(mon); - block_mig_state.print_completion += - (BDRV_SECTORS_PER_DIRTY_CHUNK * 10000); } return ret; @@ -445,6 +447,9 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) blk_mig_save_dirty_blocks(mon, f); blk_mig_cleanup(mon); + /* report completion */ + qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS); + if (qemu_file_has_error(f)) { return 0; } @@ -459,6 +464,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) static int block_load(QEMUFile *f, void *opaque, int version_id) { + static int banner_printed; int len, flags; char device_name[256]; int64_t addr; @@ -490,6 +496,14 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK); qemu_free(buf); + } else if (flags & BLK_MIG_FLAG_PROGRESS) { + if (!banner_printed) { + printf("Receiving block device images\n"); + banner_printed = 1; + } + printf("Completed %d %%%c", (int)addr, + (addr == 100) ? '\n' : '\r'); + fflush(stdout); } else if (!(flags & BLK_MIG_FLAG_EOS)) { fprintf(stderr, "Unknown flags\n"); return -EINVAL; -- cgit v1.2.3-65-gdbad From 23bd90d2f916f5a2e0a6ad00d26f3ff26144066d Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:22 +0100 Subject: block migration: Increase dirty chunk size to 1M 4K is too small for efficiently saving and restoring multi-GB block devices. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block.h b/block.h index 351371227..4a8b6283e 100644 --- a/block.h +++ b/block.h @@ -192,7 +192,7 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size); -#define BDRV_SECTORS_PER_DIRTY_CHUNK 8 +#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048 void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable); int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); -- cgit v1.2.3-65-gdbad From 792773b2255d25c6f5fe9dfa0ae200debab92de4 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 20:34:55 +0100 Subject: block migration: Skip zero-sized disks No need to migrate emptiness (risking divide by zero later on). Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/block-migration.c b/block-migration.c index a066f1924..258a88afc 100644 --- a/block-migration.c +++ b/block-migration.c @@ -222,6 +222,7 @@ static void init_blk_migration(Monitor *mon, QEMUFile *f) { BlkMigDevState *bmds; BlockDriverState *bs; + int64_t sectors; block_mig_state.submitted = 0; block_mig_state.read_done = 0; @@ -231,14 +232,19 @@ static void init_blk_migration(Monitor *mon, QEMUFile *f) for (bs = bdrv_first; bs != NULL; bs = bs->next) { if (bs->type == BDRV_TYPE_HD) { + sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; + if (sectors == 0) { + continue; + } + bmds = qemu_mallocz(sizeof(BlkMigDevState)); bmds->bs = bs; bmds->bulk_completed = 0; - bmds->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; + bmds->total_sectors = sectors; bmds->completed_sectors = 0; bmds->shared_base = block_mig_state.shared_base; - block_mig_state.total_sector_sum += bmds->total_sectors; + block_mig_state.total_sector_sum += sectors; if (bmds->shared_base) { monitor_printf(mon, "Start migration for %s with shared base " -- cgit v1.2.3-65-gdbad From 90697be8896ce364456b81d3ba7eaadd10b1766e Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 1 Dec 2009 15:19:55 +0100 Subject: live migration: Serialize vmstate saving in stage 2 The effect of this patch with current block migration is that its stage 2, ie. the first full walk-through of the block devices will be performed completely before RAM migration starts. This ensures that continuously changing RAM pages are not re-synchronized all the time while block migration is not completed. Future versions of block migration which will respect the specified downtime will generate a different pattern: After RAM migration has started as well, block migration may also continue to inject dirty blocks into the RAM stream once it detects that the number of pending blocks would extend the downtime unacceptably. Note that all this relies on the current registration order: block before RAM migration. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- savevm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/savevm.c b/savevm.c index db44ed607..aefe052cd 100644 --- a/savevm.c +++ b/savevm.c @@ -1321,7 +1321,14 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f) qemu_put_byte(f, QEMU_VM_SECTION_PART); qemu_put_be32(f, se->section_id); - ret &= !!se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque); + ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque); + if (!ret) { + /* Do not proceed to the next vmstate before this one reported + completion of the current stage. This serializes the migration + and reduces the probability that a faster changing state is + synchronized over and over again. */ + break; + } } if (ret) -- cgit v1.2.3-65-gdbad From b09417b9bcbde787a03cf38608cb897a52f12dd5 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 1 Dec 2009 15:24:18 +0100 Subject: qemu-opts: Release id on deletion The opts id is always allocated via qemu_strdup, so it need not be const, but it has to be released on opts deletion. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- qemu-option.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu-option.c b/qemu-option.c index 49efd392d..b00910900 100644 --- a/qemu-option.c +++ b/qemu-option.c @@ -481,7 +481,7 @@ struct QemuOpt { }; struct QemuOpts { - const char *id; + char *id; QemuOptsList *list; QTAILQ_HEAD(QemuOptHead, QemuOpt) head; QTAILQ_ENTRY(QemuOpts) next; @@ -686,6 +686,7 @@ void qemu_opts_del(QemuOpts *opts) qemu_opt_del(opt); } QTAILQ_REMOVE(&opts->list->head, opts, next); + qemu_free(opts->id); qemu_free(opts); } -- cgit v1.2.3-65-gdbad From 843079386eed4ae2dbe1be98383f185b7721411b Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 2 Dec 2009 11:29:38 +0100 Subject: ram migration: Properly reset statistics As we may do more than one migration (cancellation, live backup), reset bytes_transferred on stage 1. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index e9b75c9b8..78a4ec4d9 100644 --- a/vl.c +++ b/vl.c @@ -2897,7 +2897,7 @@ static int ram_save_block(QEMUFile *f) return found; } -static uint64_t bytes_transferred = 0; +static uint64_t bytes_transferred; static ram_addr_t ram_save_remaining(void) { @@ -2945,6 +2945,8 @@ static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) } if (stage == 1) { + bytes_transferred = 0; + /* Make sure all dirty bits are set */ for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) { if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) -- cgit v1.2.3-65-gdbad From f785009961c335a4c9c735b2bf96d5a0d2e5bde1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 27 Nov 2009 13:25:36 +0100 Subject: Rename DriveInfo.onerror to on_write_error Either rename variables and functions to refer to write errors (which is what they actually do) or introduce a parameter to distinguish reads and writes. Signed-off-by: Kevin Wolf Signed-off-by: Anthony Liguori --- hw/ide/core.c | 2 +- hw/scsi-disk.c | 3 ++- hw/virtio-blk.c | 2 +- sysemu.h | 6 ++++-- vl.c | 11 ++++++++--- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 7b1ff8f95..49bbdcde1 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -473,7 +473,7 @@ void ide_dma_error(IDEState *s) static int ide_handle_write_error(IDEState *s, int error, int op) { - BlockInterfaceErrorAction action = drive_get_onerror(s->bs); + BlockInterfaceErrorAction action = drive_get_on_error(s->bs, 0); if (action == BLOCK_ERR_IGNORE) return 0; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index c802ccdbd..67e300898 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -172,7 +172,8 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) static int scsi_handle_write_error(SCSIDiskReq *r, int error) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - BlockInterfaceErrorAction action = drive_get_onerror(s->qdev.dinfo->bdrv); + BlockInterfaceErrorAction action = + drive_get_on_error(s->qdev.dinfo->bdrv, 0); if (action == BLOCK_ERR_IGNORE) return 0; diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 42b766fa2..a93d20dfa 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -100,7 +100,7 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status) static int virtio_blk_handle_write_error(VirtIOBlockReq *req, int error) { - BlockInterfaceErrorAction action = drive_get_onerror(req->dev->bs); + BlockInterfaceErrorAction action = drive_get_on_error(req->dev->bs, 0); VirtIOBlock *s = req->dev; if (action == BLOCK_ERR_IGNORE) diff --git a/sysemu.h b/sysemu.h index e7819de9a..c79a019e7 100644 --- a/sysemu.h +++ b/sysemu.h @@ -180,7 +180,7 @@ typedef struct DriveInfo { int bus; int unit; QemuOpts *opts; - BlockInterfaceErrorAction onerror; + BlockInterfaceErrorAction on_write_error; char serial[BLOCK_SERIAL_STRLEN + 1]; QTAILQ_ENTRY(DriveInfo) next; } DriveInfo; @@ -197,7 +197,9 @@ extern DriveInfo *drive_get_by_id(const char *id); extern int drive_get_max_bus(BlockInterfaceType type); extern void drive_uninit(DriveInfo *dinfo); extern const char *drive_get_serial(BlockDriverState *bdrv); -extern BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv); + +extern BlockInterfaceErrorAction drive_get_on_error( + BlockDriverState *bdrv, int is_read); BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type); diff --git a/vl.c b/vl.c index 78a4ec4d9..b0a2e883d 100644 --- a/vl.c +++ b/vl.c @@ -1959,13 +1959,18 @@ const char *drive_get_serial(BlockDriverState *bdrv) return "\0"; } -BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv) +BlockInterfaceErrorAction drive_get_on_error( + BlockDriverState *bdrv, int is_read) { DriveInfo *dinfo; + if (is_read) { + return BLOCK_ERR_REPORT; + } + QTAILQ_FOREACH(dinfo, &drives, next) { if (dinfo->bdrv == bdrv) - return dinfo->onerror; + return dinfo->on_write_error; } return BLOCK_ERR_STOP_ENOSPC; @@ -2263,7 +2268,7 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque, dinfo->type = type; dinfo->bus = bus_id; dinfo->unit = unit_id; - dinfo->onerror = onerror; + dinfo->on_write_error = onerror; dinfo->opts = opts; if (serial) strncpy(dinfo->serial, serial, sizeof(serial)); -- cgit v1.2.3-65-gdbad From e9b2e81889d9877415710484b876ee57a42b0bcb Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 27 Nov 2009 13:25:37 +0100 Subject: Introduce rerror option for drives rerror controls the action to be taken when an error occurs while accessing the guest image file. It corresponds to werror which already controls the action take for write errors. This purely introduces parsing rerror command line option into the right structures, real support for it in the device emulation is added in the following patches. Signed-off-by: Kevin Wolf Signed-off-by: Anthony Liguori --- qemu-config.c | 3 +++ sysemu.h | 1 + vl.c | 59 ++++++++++++++++++++++++++++++++++++++++------------------- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/qemu-config.c b/qemu-config.c index 590fc052f..92b5363ec 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -64,6 +64,9 @@ QemuOptsList qemu_drive_opts = { },{ .name = "serial", .type = QEMU_OPT_STRING, + },{ + .name = "rerror", + .type = QEMU_OPT_STRING, },{ .name = "werror", .type = QEMU_OPT_STRING, diff --git a/sysemu.h b/sysemu.h index c79a019e7..efed771d0 100644 --- a/sysemu.h +++ b/sysemu.h @@ -180,6 +180,7 @@ typedef struct DriveInfo { int bus; int unit; QemuOpts *opts; + BlockInterfaceErrorAction on_read_error; BlockInterfaceErrorAction on_write_error; char serial[BLOCK_SERIAL_STRLEN + 1]; QTAILQ_ENTRY(DriveInfo) next; diff --git a/vl.c b/vl.c index b0a2e883d..3d64fc653 100644 --- a/vl.c +++ b/vl.c @@ -1964,16 +1964,12 @@ BlockInterfaceErrorAction drive_get_on_error( { DriveInfo *dinfo; - if (is_read) { - return BLOCK_ERR_REPORT; - } - QTAILQ_FOREACH(dinfo, &drives, next) { if (dinfo->bdrv == bdrv) - return dinfo->on_write_error; + return is_read ? dinfo->on_read_error : dinfo->on_write_error; } - return BLOCK_ERR_STOP_ENOSPC; + return is_read ? BLOCK_ERR_REPORT : BLOCK_ERR_STOP_ENOSPC; } static void bdrv_format_print(void *opaque, const char *name) @@ -1989,6 +1985,23 @@ void drive_uninit(DriveInfo *dinfo) qemu_free(dinfo); } +static int parse_block_error_action(const char *buf, int is_read) +{ + if (!strcmp(buf, "ignore")) { + return BLOCK_ERR_IGNORE; + } else if (!is_read && !strcmp(buf, "enospc")) { + return BLOCK_ERR_STOP_ENOSPC; + } else if (!strcmp(buf, "stop")) { + return BLOCK_ERR_STOP_ANY; + } else if (!strcmp(buf, "report")) { + return BLOCK_ERR_REPORT; + } else { + fprintf(stderr, "qemu: '%s' invalid %s error action\n", + buf, is_read ? "read" : "write"); + return -1; + } +} + DriveInfo *drive_init(QemuOpts *opts, void *opaque, int *fatal_error) { @@ -2008,7 +2021,8 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque, int cache; int aio = 0; int ro = 0; - int bdrv_flags, onerror; + int bdrv_flags; + int on_read_error, on_write_error; const char *devaddr; DriveInfo *dinfo; int snapshot = 0; @@ -2169,22 +2183,28 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque, } } - onerror = BLOCK_ERR_STOP_ENOSPC; + on_write_error = BLOCK_ERR_STOP_ENOSPC; if ((buf = qemu_opt_get(opts, "werror")) != NULL) { if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO) { fprintf(stderr, "werror is no supported by this format\n"); return NULL; } - if (!strcmp(buf, "ignore")) - onerror = BLOCK_ERR_IGNORE; - else if (!strcmp(buf, "enospc")) - onerror = BLOCK_ERR_STOP_ENOSPC; - else if (!strcmp(buf, "stop")) - onerror = BLOCK_ERR_STOP_ANY; - else if (!strcmp(buf, "report")) - onerror = BLOCK_ERR_REPORT; - else { - fprintf(stderr, "qemu: '%s' invalid write error action\n", buf); + + on_write_error = parse_block_error_action(buf, 0); + if (on_write_error < 0) { + return NULL; + } + } + + on_read_error = BLOCK_ERR_REPORT; + if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { + if (1) { + fprintf(stderr, "rerror is no supported by this format\n"); + return NULL; + } + + on_read_error = parse_block_error_action(buf, 1); + if (on_read_error < 0) { return NULL; } } @@ -2268,7 +2288,8 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque, dinfo->type = type; dinfo->bus = bus_id; dinfo->unit = unit_id; - dinfo->on_write_error = onerror; + dinfo->on_read_error = on_read_error; + dinfo->on_write_error = on_write_error; dinfo->opts = opts; if (serial) strncpy(dinfo->serial, serial, sizeof(serial)); -- cgit v1.2.3-65-gdbad