[x86] hv: Update all Hyper-V drivers to 3.4-rc1 (Closes: #661318)

svn path=/dists/sid/linux-2.6/; revision=18921
This commit is contained in:
Ben Hutchings 2012-04-09 00:47:41 +00:00
parent c31d2a0d11
commit 3121d09256
81 changed files with 19885 additions and 3 deletions

1
debian/changelog vendored
View File

@ -8,6 +8,7 @@ linux-2.6 (3.2.14-2) UNRELEASED; urgency=low
(Closes: #668036)
* TOMOYO: Fix mount flags checking order.
* drm/radeon/kms: fix fans after resume (Closes: #596741)
* [x86] hv: Update all Hyper-V drivers to 3.4-rc1 (Closes: #661318)
[ Jonathan Nieder ]
* [x86] ioat: fix size of 'completion' for Xen (Closes: #660554)

View File

@ -1,6 +1,7 @@
[abi]
abiname: 2
ignore-changes: module:drivers/net/wireless/ath/ath9k/*
module:drivers/hv/*
[base]
arches:

View File

@ -0,0 +1,60 @@
From: Ben Hutchings <ben@decadent.org.uk>
Date: Mon, 9 Apr 2012 00:51:37 +0100
Subject: [PATCH] nls: Avoid ABI change from improvement to utf8s_to_utf16s
It's easy to add a temporary wrapper for binary-compatibility.
---
fs/nls/nls_base.c | 13 ++++++++++++-
include/linux/nls.h | 4 +++-
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 0eb059e..91f145a 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -129,7 +129,7 @@ static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian)
}
}
-int utf8s_to_utf16s(const u8 *s, int len, enum utf16_endian endian,
+int utf8s_to_utf16s_new(const u8 *s, int len, enum utf16_endian endian,
wchar_t *pwcs, int maxlen)
{
u16 *op;
@@ -171,6 +171,17 @@ int utf8s_to_utf16s(const u8 *s, int len, enum utf16_endian endian,
}
EXPORT_SYMBOL(utf8s_to_utf16s);
+/* Binary-compatibility wrapper */
+#undef utf8s_to_utf16s
+int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs)
+{
+ /* Output length in code units is never longer than input
+ * length in bytes, so we can trivially set maxlen = len.
+ */
+ return utf8s_to_utf16s_new(s, len, UTF16_HOST_ENDIAN, pwcs, len);
+}
+EXPORT_SYMBOL(utf8s_to_utf16s);
+
static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian)
{
switch (endian) {
diff --git a/include/linux/nls.h b/include/linux/nls.h
index 5dc635f..6a2a00c 100644
--- a/include/linux/nls.h
+++ b/include/linux/nls.h
@@ -52,8 +52,10 @@ extern struct nls_table *load_nls_default(void);
extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen);
-extern int utf8s_to_utf16s(const u8 *s, int len,
+extern int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs);
+extern int utf8s_to_utf16s_new(const u8 *s, int len,
enum utf16_endian endian, wchar_t *pwcs, int maxlen);
+#define utf8s_to_utf16s utf8s_to_utf16s_new
extern int utf16s_to_utf8s(const wchar_t *pwcs, int len,
enum utf16_endian endian, u8 *s, int maxlen);
--
1.7.9.5

View File

@ -0,0 +1,164 @@
From: Alan Stern <stern@rowland.harvard.edu>
Date: Thu, 17 Nov 2011 16:42:19 -0500
Subject: [PATCH 01/77] NLS: improve UTF8 -> UTF16 string conversion routine
commit 0720a06a7518c9d0c0125bd5d1f3b6264c55c3dd upstream.
The utf8s_to_utf16s conversion routine needs to be improved. Unlike
its utf16s_to_utf8s sibling, it doesn't accept arguments specifying
the maximum length of the output buffer or the endianness of its
16-bit output.
This patch (as1501) adds the two missing arguments, and adjusts the
only two places in the kernel where the function is called. A
follow-on patch will add a third caller that does utilize the new
capabilities.
The two conversion routines are still annoyingly inconsistent in the
way they handle invalid byte combinations. But that's a subject for a
different patch.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/hv/hv_kvp.c | 10 ++++++----
fs/fat/namei_vfat.c | 3 ++-
fs/nls/nls_base.c | 43 +++++++++++++++++++++++++++++++++----------
include/linux/nls.h | 5 +++--
4 files changed, 44 insertions(+), 17 deletions(-)
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 89f5244..0e8343f 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -212,11 +212,13 @@ kvp_respond_to_host(char *key, char *value, int error)
* The windows host expects the key/value pair to be encoded
* in utf16.
*/
- keylen = utf8s_to_utf16s(key_name, strlen(key_name),
- (wchar_t *)kvp_data->data.key);
+ keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
+ (wchar_t *) kvp_data->data.key,
+ HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2);
kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */
- valuelen = utf8s_to_utf16s(value, strlen(value),
- (wchar_t *)kvp_data->data.value);
+ valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
+ (wchar_t *) kvp_data->data.value,
+ HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2);
kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */
kvp_data->data.value_type = REG_SZ; /* all our values are strings */
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index a87a656..c25cf15 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -512,7 +512,8 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
int charlen;
if (utf8) {
- *outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname);
+ *outlen = utf8s_to_utf16s(name, len, UTF16_HOST_ENDIAN,
+ (wchar_t *) outname, FAT_LFN_LEN + 2);
if (*outlen < 0)
return *outlen;
else if (*outlen > FAT_LFN_LEN)
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 44a88a9..0eb059e 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -114,34 +114,57 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxlen)
}
EXPORT_SYMBOL(utf32_to_utf8);
-int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs)
+static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian)
+{
+ switch (endian) {
+ default:
+ *s = (wchar_t) c;
+ break;
+ case UTF16_LITTLE_ENDIAN:
+ *s = __cpu_to_le16(c);
+ break;
+ case UTF16_BIG_ENDIAN:
+ *s = __cpu_to_be16(c);
+ break;
+ }
+}
+
+int utf8s_to_utf16s(const u8 *s, int len, enum utf16_endian endian,
+ wchar_t *pwcs, int maxlen)
{
u16 *op;
int size;
unicode_t u;
op = pwcs;
- while (*s && len > 0) {
+ while (len > 0 && maxlen > 0 && *s) {
if (*s & 0x80) {
size = utf8_to_utf32(s, len, &u);
if (size < 0)
return -EINVAL;
+ s += size;
+ len -= size;
if (u >= PLANE_SIZE) {
+ if (maxlen < 2)
+ break;
u -= PLANE_SIZE;
- *op++ = (wchar_t) (SURROGATE_PAIR |
- ((u >> 10) & SURROGATE_BITS));
- *op++ = (wchar_t) (SURROGATE_PAIR |
+ put_utf16(op++, SURROGATE_PAIR |
+ ((u >> 10) & SURROGATE_BITS),
+ endian);
+ put_utf16(op++, SURROGATE_PAIR |
SURROGATE_LOW |
- (u & SURROGATE_BITS));
+ (u & SURROGATE_BITS),
+ endian);
+ maxlen -= 2;
} else {
- *op++ = (wchar_t) u;
+ put_utf16(op++, u, endian);
+ maxlen--;
}
- s += size;
- len -= size;
} else {
- *op++ = *s++;
+ put_utf16(op++, *s++, endian);
len--;
+ maxlen--;
}
}
return op - pwcs;
diff --git a/include/linux/nls.h b/include/linux/nls.h
index d47beef..5dc635f 100644
--- a/include/linux/nls.h
+++ b/include/linux/nls.h
@@ -43,7 +43,7 @@ enum utf16_endian {
UTF16_BIG_ENDIAN
};
-/* nls.c */
+/* nls_base.c */
extern int register_nls(struct nls_table *);
extern int unregister_nls(struct nls_table *);
extern struct nls_table *load_nls(char *);
@@ -52,7 +52,8 @@ extern struct nls_table *load_nls_default(void);
extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen);
-extern int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs);
+extern int utf8s_to_utf16s(const u8 *s, int len,
+ enum utf16_endian endian, wchar_t *pwcs, int maxlen);
extern int utf16s_to_utf8s(const wchar_t *pwcs, int len,
enum utf16_endian endian, u8 *s, int maxlen);
--
1.7.9.5

View File

@ -0,0 +1,646 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 17 Nov 2011 08:47:29 -0800
Subject: [PATCH 02/77] HID: Move the hid-hyperv driver out of staging
commit b95f5bcb811e3905b5376f87789da8d097fee682 upstream.
The file hid-hyperv.c implements a hid compliant mouse driver for use on a
Hyper-V based system. This driver is currently in the staging area and as part
of the effort to move this driver out of staging, I had posted the driver code
for community review a few weeks ago. This current patch addresses all the
review comments I have gotten to date. All the relevant patches have already
been submitted to the staging tree as well.
As per Greg's suggestion, this patch does not get rid of the code from
the staging area. Once the mouse driver lands under the hid directory,
we will cleanup the staging directory.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
drivers/hid/Kconfig | 6 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-hyperv.c | 582 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 589 insertions(+)
create mode 100644 drivers/hid/hid-hyperv.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index d21f6d0..4c09210 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -646,6 +646,12 @@ config HID_ZYDACRON
---help---
Support for Zydacron remote control.
+config HYPERV_MOUSE
+ tristate "Microsoft Hyper-V mouse driver"
+ depends on HYPERV
+ ---help---
+ Select this option to enable the Hyper-V mouse driver.
+
endmenu
endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 1e0d2a6..fbb1ee6 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
+obj-$(CONFIG_HYPERV_MOUSE) += hid-hyperv.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
new file mode 100644
index 0000000..d503cbb
--- /dev/null
+++ b/drivers/hid/hid-hyperv.c
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 2009, Citrix Systems, Inc.
+ * Copyright (c) 2010, Microsoft Corporation.
+ * Copyright (c) 2011, Novell Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/completion.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/hiddev.h>
+#include <linux/hyperv.h>
+
+
+struct hv_input_dev_info {
+ unsigned int size;
+ unsigned short vendor;
+ unsigned short product;
+ unsigned short version;
+ unsigned short reserved[11];
+};
+
+/* The maximum size of a synthetic input message. */
+#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
+
+/*
+ * Current version
+ *
+ * History:
+ * Beta, RC < 2008/1/22 1,0
+ * RC > 2008/1/22 2,0
+ */
+#define SYNTHHID_INPUT_VERSION_MAJOR 2
+#define SYNTHHID_INPUT_VERSION_MINOR 0
+#define SYNTHHID_INPUT_VERSION (SYNTHHID_INPUT_VERSION_MINOR | \
+ (SYNTHHID_INPUT_VERSION_MAJOR << 16))
+
+
+#pragma pack(push, 1)
+/*
+ * Message types in the synthetic input protocol
+ */
+enum synthhid_msg_type {
+ SYNTH_HID_PROTOCOL_REQUEST,
+ SYNTH_HID_PROTOCOL_RESPONSE,
+ SYNTH_HID_INITIAL_DEVICE_INFO,
+ SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
+ SYNTH_HID_INPUT_REPORT,
+ SYNTH_HID_MAX
+};
+
+/*
+ * Basic message structures.
+ */
+struct synthhid_msg_hdr {
+ enum synthhid_msg_type type;
+ u32 size;
+};
+
+struct synthhid_msg {
+ struct synthhid_msg_hdr header;
+ char data[1]; /* Enclosed message */
+};
+
+union synthhid_version {
+ struct {
+ u16 minor_version;
+ u16 major_version;
+ };
+ u32 version;
+};
+
+/*
+ * Protocol messages
+ */
+struct synthhid_protocol_request {
+ struct synthhid_msg_hdr header;
+ union synthhid_version version_requested;
+};
+
+struct synthhid_protocol_response {
+ struct synthhid_msg_hdr header;
+ union synthhid_version version_requested;
+ unsigned char approved;
+};
+
+struct synthhid_device_info {
+ struct synthhid_msg_hdr header;
+ struct hv_input_dev_info hid_dev_info;
+ struct hid_descriptor hid_descriptor;
+};
+
+struct synthhid_device_info_ack {
+ struct synthhid_msg_hdr header;
+ unsigned char reserved;
+};
+
+struct synthhid_input_report {
+ struct synthhid_msg_hdr header;
+ char buffer[1];
+};
+
+#pragma pack(pop)
+
+#define INPUTVSC_SEND_RING_BUFFER_SIZE (10*PAGE_SIZE)
+#define INPUTVSC_RECV_RING_BUFFER_SIZE (10*PAGE_SIZE)
+
+
+enum pipe_prot_msg_type {
+ PIPE_MESSAGE_INVALID,
+ PIPE_MESSAGE_DATA,
+ PIPE_MESSAGE_MAXIMUM
+};
+
+
+struct pipe_prt_msg {
+ enum pipe_prot_msg_type type;
+ u32 size;
+ char data[1];
+};
+
+struct mousevsc_prt_msg {
+ enum pipe_prot_msg_type type;
+ u32 size;
+ union {
+ struct synthhid_protocol_request request;
+ struct synthhid_protocol_response response;
+ struct synthhid_device_info_ack ack;
+ };
+};
+
+/*
+ * Represents an mousevsc device
+ */
+struct mousevsc_dev {
+ struct hv_device *device;
+ bool init_complete;
+ bool connected;
+ struct mousevsc_prt_msg protocol_req;
+ struct mousevsc_prt_msg protocol_resp;
+ /* Synchronize the request/response if needed */
+ struct completion wait_event;
+ int dev_info_status;
+
+ struct hid_descriptor *hid_desc;
+ unsigned char *report_desc;
+ u32 report_desc_size;
+ struct hv_input_dev_info hid_dev_info;
+ struct hid_device *hid_device;
+};
+
+
+static struct mousevsc_dev *mousevsc_alloc_device(struct hv_device *device)
+{
+ struct mousevsc_dev *input_dev;
+
+ input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
+
+ if (!input_dev)
+ return NULL;
+
+ input_dev->device = device;
+ hv_set_drvdata(device, input_dev);
+ init_completion(&input_dev->wait_event);
+ input_dev->init_complete = false;
+
+ return input_dev;
+}
+
+static void mousevsc_free_device(struct mousevsc_dev *device)
+{
+ kfree(device->hid_desc);
+ kfree(device->report_desc);
+ hv_set_drvdata(device->device, NULL);
+ kfree(device);
+}
+
+static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
+ struct synthhid_device_info *device_info)
+{
+ int ret = 0;
+ struct hid_descriptor *desc;
+ struct mousevsc_prt_msg ack;
+
+ input_device->dev_info_status = -ENOMEM;
+
+ input_device->hid_dev_info = device_info->hid_dev_info;
+ desc = &device_info->hid_descriptor;
+ if (desc->bLength == 0)
+ goto cleanup;
+
+ input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
+
+ if (!input_device->hid_desc)
+ goto cleanup;
+
+ memcpy(input_device->hid_desc, desc, desc->bLength);
+
+ input_device->report_desc_size = desc->desc[0].wDescriptorLength;
+ if (input_device->report_desc_size == 0) {
+ input_device->dev_info_status = -EINVAL;
+ goto cleanup;
+ }
+
+ input_device->report_desc = kzalloc(input_device->report_desc_size,
+ GFP_ATOMIC);
+
+ if (!input_device->report_desc) {
+ input_device->dev_info_status = -ENOMEM;
+ goto cleanup;
+ }
+
+ memcpy(input_device->report_desc,
+ ((unsigned char *)desc) + desc->bLength,
+ desc->desc[0].wDescriptorLength);
+
+ /* Send the ack */
+ memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
+
+ ack.type = PIPE_MESSAGE_DATA;
+ ack.size = sizeof(struct synthhid_device_info_ack);
+
+ ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
+ ack.ack.header.size = 1;
+ ack.ack.reserved = 0;
+
+ ret = vmbus_sendpacket(input_device->device->channel,
+ &ack,
+ sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
+ sizeof(struct synthhid_device_info_ack),
+ (unsigned long)&ack,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+
+ if (!ret)
+ input_device->dev_info_status = 0;
+
+cleanup:
+ complete(&input_device->wait_event);
+
+ return;
+}
+
+static void mousevsc_on_receive(struct hv_device *device,
+ struct vmpacket_descriptor *packet)
+{
+ struct pipe_prt_msg *pipe_msg;
+ struct synthhid_msg *hid_msg;
+ struct mousevsc_dev *input_dev = hv_get_drvdata(device);
+ struct synthhid_input_report *input_report;
+
+ pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
+ (packet->offset8 << 3));
+
+ if (pipe_msg->type != PIPE_MESSAGE_DATA)
+ return;
+
+ hid_msg = (struct synthhid_msg *)pipe_msg->data;
+
+ switch (hid_msg->header.type) {
+ case SYNTH_HID_PROTOCOL_RESPONSE:
+ /*
+ * While it will be impossible for us to protect against
+ * malicious/buggy hypervisor/host, add a check here to
+ * ensure we don't corrupt memory.
+ */
+ if ((pipe_msg->size + sizeof(struct pipe_prt_msg)
+ - sizeof(unsigned char))
+ > sizeof(struct mousevsc_prt_msg)) {
+ WARN_ON(1);
+ break;
+ }
+
+ memcpy(&input_dev->protocol_resp, pipe_msg,
+ pipe_msg->size + sizeof(struct pipe_prt_msg) -
+ sizeof(unsigned char));
+ complete(&input_dev->wait_event);
+ break;
+
+ case SYNTH_HID_INITIAL_DEVICE_INFO:
+ WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
+
+ /*
+ * Parse out the device info into device attr,
+ * hid desc and report desc
+ */
+ mousevsc_on_receive_device_info(input_dev,
+ (struct synthhid_device_info *)pipe_msg->data);
+ break;
+ case SYNTH_HID_INPUT_REPORT:
+ input_report =
+ (struct synthhid_input_report *)pipe_msg->data;
+ if (!input_dev->init_complete)
+ break;
+ hid_input_report(input_dev->hid_device,
+ HID_INPUT_REPORT, input_report->buffer,
+ input_report->header.size, 1);
+ break;
+ default:
+ pr_err("unsupported hid msg type - type %d len %d",
+ hid_msg->header.type, hid_msg->header.size);
+ break;
+ }
+
+}
+
+static void mousevsc_on_channel_callback(void *context)
+{
+ const int packet_size = 0x100;
+ int ret;
+ struct hv_device *device = context;
+ u32 bytes_recvd;
+ u64 req_id;
+ struct vmpacket_descriptor *desc;
+ unsigned char *buffer;
+ int bufferlen = packet_size;
+
+ buffer = kmalloc(bufferlen, GFP_ATOMIC);
+ if (!buffer)
+ return;
+
+ do {
+ ret = vmbus_recvpacket_raw(device->channel, buffer,
+ bufferlen, &bytes_recvd, &req_id);
+
+ switch (ret) {
+ case 0:
+ if (bytes_recvd <= 0) {
+ kfree(buffer);
+ return;
+ }
+ desc = (struct vmpacket_descriptor *)buffer;
+
+ switch (desc->type) {
+ case VM_PKT_COMP:
+ break;
+
+ case VM_PKT_DATA_INBAND:
+ mousevsc_on_receive(device, desc);
+ break;
+
+ default:
+ pr_err("unhandled packet type %d, tid %llx len %d\n",
+ desc->type, req_id, bytes_recvd);
+ break;
+ }
+
+ break;
+
+ case -ENOBUFS:
+ kfree(buffer);
+ /* Handle large packet */
+ bufferlen = bytes_recvd;
+ buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
+
+ if (!buffer)
+ return;
+
+ break;
+ }
+ } while (1);
+
+}
+
+static int mousevsc_connect_to_vsp(struct hv_device *device)
+{
+ int ret = 0;
+ int t;
+ struct mousevsc_dev *input_dev = hv_get_drvdata(device);
+ struct mousevsc_prt_msg *request;
+ struct mousevsc_prt_msg *response;
+
+ request = &input_dev->protocol_req;
+ memset(request, 0, sizeof(struct mousevsc_prt_msg));
+
+ request->type = PIPE_MESSAGE_DATA;
+ request->size = sizeof(struct synthhid_protocol_request);
+ request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
+ request->request.header.size = sizeof(unsigned int);
+ request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
+
+ ret = vmbus_sendpacket(device->channel, request,
+ sizeof(struct pipe_prt_msg) -
+ sizeof(unsigned char) +
+ sizeof(struct synthhid_protocol_request),
+ (unsigned long)request,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (ret)
+ goto cleanup;
+
+ t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
+ if (!t) {
+ ret = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ response = &input_dev->protocol_resp;
+
+ if (!response->response.approved) {
+ pr_err("synthhid protocol request failed (version %d)\n",
+ SYNTHHID_INPUT_VERSION);
+ ret = -ENODEV;
+ goto cleanup;
+ }
+
+ t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
+ if (!t) {
+ ret = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ /*
+ * We should have gotten the device attr, hid desc and report
+ * desc at this point
+ */
+ ret = input_dev->dev_info_status;
+
+cleanup:
+ return ret;
+}
+
+static int mousevsc_hid_open(struct hid_device *hid)
+{
+ return 0;
+}
+
+static int mousevsc_hid_start(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void mousevsc_hid_close(struct hid_device *hid)
+{
+}
+
+static void mousevsc_hid_stop(struct hid_device *hid)
+{
+}
+
+static struct hid_ll_driver mousevsc_ll_driver = {
+ .open = mousevsc_hid_open,
+ .close = mousevsc_hid_close,
+ .start = mousevsc_hid_start,
+ .stop = mousevsc_hid_stop,
+};
+
+static struct hid_driver mousevsc_hid_driver;
+
+static int mousevsc_probe(struct hv_device *device,
+ const struct hv_vmbus_device_id *dev_id)
+{
+ int ret;
+ struct mousevsc_dev *input_dev;
+ struct hid_device *hid_dev;
+
+ input_dev = mousevsc_alloc_device(device);
+
+ if (!input_dev)
+ return -ENOMEM;
+
+ ret = vmbus_open(device->channel,
+ INPUTVSC_SEND_RING_BUFFER_SIZE,
+ INPUTVSC_RECV_RING_BUFFER_SIZE,
+ NULL,
+ 0,
+ mousevsc_on_channel_callback,
+ device
+ );
+
+ if (ret)
+ goto probe_err0;
+
+ ret = mousevsc_connect_to_vsp(device);
+
+ if (ret)
+ goto probe_err1;
+
+ /* workaround SA-167 */
+ if (input_dev->report_desc[14] == 0x25)
+ input_dev->report_desc[14] = 0x29;
+
+ hid_dev = hid_allocate_device();
+ if (IS_ERR(hid_dev)) {
+ ret = PTR_ERR(hid_dev);
+ goto probe_err1;
+ }
+
+ hid_dev->ll_driver = &mousevsc_ll_driver;
+ hid_dev->driver = &mousevsc_hid_driver;
+ hid_dev->bus = BUS_VIRTUAL;
+ hid_dev->vendor = input_dev->hid_dev_info.vendor;
+ hid_dev->product = input_dev->hid_dev_info.product;
+ hid_dev->version = input_dev->hid_dev_info.version;
+ input_dev->hid_device = hid_dev;
+
+ sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
+
+ ret = hid_parse_report(hid_dev, input_dev->report_desc,
+ input_dev->report_desc_size);
+
+ if (ret) {
+ hid_err(hid_dev, "parse failed\n");
+ goto probe_err2;
+ }
+
+ ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV);
+
+ if (ret) {
+ hid_err(hid_dev, "hw start failed\n");
+ goto probe_err2;
+ }
+
+ input_dev->connected = true;
+ input_dev->init_complete = true;
+
+ return ret;
+
+probe_err2:
+ hid_destroy_device(hid_dev);
+
+probe_err1:
+ vmbus_close(device->channel);
+
+probe_err0:
+ mousevsc_free_device(input_dev);
+
+ return ret;
+}
+
+
+static int mousevsc_remove(struct hv_device *dev)
+{
+ struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
+
+ vmbus_close(dev->channel);
+ hid_destroy_device(input_dev->hid_device);
+ mousevsc_free_device(input_dev);
+
+ return 0;
+}
+
+static const struct hv_vmbus_device_id id_table[] = {
+ /* Mouse guid */
+ { VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
+ 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(vmbus, id_table);
+
+static struct hv_driver mousevsc_drv = {
+ .name = KBUILD_MODNAME,
+ .id_table = id_table,
+ .probe = mousevsc_probe,
+ .remove = mousevsc_remove,
+};
+
+static int __init mousevsc_init(void)
+{
+ return vmbus_driver_register(&mousevsc_drv);
+}
+
+static void __exit mousevsc_exit(void)
+{
+ vmbus_driver_unregister(&mousevsc_drv);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
+module_init(mousevsc_init);
+module_exit(mousevsc_exit);
--
1.7.9.5

View File

@ -0,0 +1,147 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:40 -0800
Subject: [PATCH 03/77] Staging: hv: storvsc: Use mempools to allocate struct
storvsc_cmd_request
commit 4e03e697c5446146318cdb6344af0060541cbc1c upstream.
We intend to use the storage driver to manage the root device.
To avoid deadlocks, use mempools to allocate struct storvsc_cmd_request.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 30 +++++++++++++++++++++++++-----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index ae8c33e..6a255e9 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/hyperv.h>
+#include <linux/mempool.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
@@ -42,6 +43,7 @@
#include <scsi/scsi_dbg.h>
+#define STORVSC_MIN_BUF_NR 64
#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE;
@@ -287,6 +289,7 @@ struct storvsc_device {
struct hv_host_device {
struct hv_device *dev;
struct kmem_cache *request_pool;
+ mempool_t *request_mempool;
unsigned int port;
unsigned char path;
unsigned char target;
@@ -974,8 +977,10 @@ static int storvsc_remove(struct hv_device *dev)
storvsc_dev_remove(dev);
if (host_dev->request_pool) {
+ mempool_destroy(host_dev->request_mempool);
kmem_cache_destroy(host_dev->request_pool);
host_dev->request_pool = NULL;
+ host_dev->request_mempool = NULL;
}
return 0;
}
@@ -1120,7 +1125,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
scsi_done_fn(scmnd);
- kmem_cache_free(host_dev->request_pool, cmd_request);
+ mempool_free(cmd_request, host_dev->request_mempool);
}
static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
@@ -1176,12 +1181,13 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
request_size = sizeof(struct storvsc_cmd_request);
- cmd_request = kmem_cache_zalloc(host_dev->request_pool,
+ cmd_request = mempool_alloc(host_dev->request_mempool,
GFP_ATOMIC);
if (!cmd_request) {
scmnd->scsi_done = NULL;
return SCSI_MLQUEUE_DEVICE_BUSY;
}
+ memset(cmd_request, 0, sizeof(struct storvsc_cmd_request));
/* Setup the cmd request */
cmd_request->bounce_sgl_count = 0;
@@ -1235,8 +1241,8 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
if (!cmd_request->bounce_sgl) {
scmnd->scsi_done = NULL;
scmnd->host_scribble = NULL;
- kmem_cache_free(host_dev->request_pool,
- cmd_request);
+ mempool_free(cmd_request,
+ host_dev->request_mempool);
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1278,7 +1284,7 @@ retry_request:
destroy_bounce_buffer(cmd_request->bounce_sgl,
cmd_request->bounce_sgl_count);
- kmem_cache_free(host_dev->request_pool, cmd_request);
+ mempool_free(cmd_request, host_dev->request_mempool);
scmnd->scsi_done = NULL;
scmnd->host_scribble = NULL;
@@ -1348,6 +1354,7 @@ static int storvsc_probe(struct hv_device *device,
const struct hv_vmbus_device_id *dev_id)
{
int ret;
+ int number = STORVSC_MIN_BUF_NR;
struct Scsi_Host *host;
struct hv_host_device *host_dev;
bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
@@ -1376,8 +1383,19 @@ static int storvsc_probe(struct hv_device *device,
return -ENOMEM;
}
+ host_dev->request_mempool = mempool_create(number, mempool_alloc_slab,
+ mempool_free_slab,
+ host_dev->request_pool);
+
+ if (!host_dev->request_mempool) {
+ kmem_cache_destroy(host_dev->request_pool);
+ scsi_host_put(host);
+ return -ENOMEM;
+ }
+
stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
if (!stor_device) {
+ mempool_destroy(host_dev->request_mempool);
kmem_cache_destroy(host_dev->request_pool);
scsi_host_put(host);
return -ENOMEM;
@@ -1392,6 +1410,7 @@ static int storvsc_probe(struct hv_device *device,
stor_device->port_number = host->host_no;
ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size);
if (ret) {
+ mempool_destroy(host_dev->request_mempool);
kmem_cache_destroy(host_dev->request_pool);
scsi_host_put(host);
kfree(stor_device);
@@ -1431,6 +1450,7 @@ static int storvsc_probe(struct hv_device *device,
err_out:
storvsc_dev_remove(device);
+ mempool_destroy(host_dev->request_mempool);
kmem_cache_destroy(host_dev->request_pool);
scsi_host_put(host);
return -ENODEV;
--
1.7.9.5

View File

@ -0,0 +1,104 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:41 -0800
Subject: [PATCH 04/77] Staging: hv: storvsc: Cleanup error handling in the
probe function
commit 225ce6eab741d51d565f67ce9065c596c6535f25 upstream.
Cleanup error handling in the probe function.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 42 ++++++++++++++++++++++----------------
1 file changed, 24 insertions(+), 18 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 6a255e9..a72cc22 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -1388,17 +1388,14 @@ static int storvsc_probe(struct hv_device *device,
host_dev->request_pool);
if (!host_dev->request_mempool) {
- kmem_cache_destroy(host_dev->request_pool);
- scsi_host_put(host);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_out0;
}
stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
if (!stor_device) {
- mempool_destroy(host_dev->request_mempool);
- kmem_cache_destroy(host_dev->request_pool);
- scsi_host_put(host);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_out1;
}
stor_device->destroy = false;
@@ -1409,13 +1406,8 @@ static int storvsc_probe(struct hv_device *device,
stor_device->port_number = host->host_no;
ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size);
- if (ret) {
- mempool_destroy(host_dev->request_mempool);
- kmem_cache_destroy(host_dev->request_pool);
- scsi_host_put(host);
- kfree(stor_device);
- return ret;
- }
+ if (ret)
+ goto err_out2;
if (dev_is_ide)
storvsc_get_ide_info(device, &target, &path);
@@ -1435,7 +1427,7 @@ static int storvsc_probe(struct hv_device *device,
/* Register the HBA and start the scsi bus scan */
ret = scsi_add_host(host, &device->device);
if (ret != 0)
- goto err_out;
+ goto err_out3;
if (!dev_is_ide) {
scsi_scan_host(host);
@@ -1444,16 +1436,30 @@ static int storvsc_probe(struct hv_device *device,
ret = scsi_add_device(host, 0, target, 0);
if (ret) {
scsi_remove_host(host);
- goto err_out;
+ goto err_out3;
}
return 0;
-err_out:
+err_out3:
+ /*
+ * Once we have connected with the host, we would need to
+ * to invoke storvsc_dev_remove() to rollback this state and
+ * this call also frees up the stor_device; hence the jump around
+ * err_out2 label.
+ */
storvsc_dev_remove(device);
+ goto err_out1;
+
+err_out2:
+ kfree(stor_device);
+
+err_out1:
mempool_destroy(host_dev->request_mempool);
+
+err_out0:
kmem_cache_destroy(host_dev->request_pool);
scsi_host_put(host);
- return -ENODEV;
+ return ret;
}
/* The one and only one */
--
1.7.9.5

View File

@ -0,0 +1,32 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:42 -0800
Subject: [PATCH 05/77] Staging: hv: storvsc: Fixup the error when processing
SET_WINDOW command
commit 59e00e744d2413430ebaa09a5fdb61e9ad02a492 upstream.
Fixup the error when processing SET_WINDOW command.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index a72cc22..e16c7a3 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -1136,7 +1136,7 @@ static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
switch (scsi_op) {
/* smartd sends this command, which will offline the device */
case SET_WINDOW:
- scmnd->result = DID_ERROR << 16;
+ scmnd->result = ILLEGAL_REQUEST << 16;
allowed = false;
break;
default:
--
1.7.9.5

View File

@ -0,0 +1,79 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:43 -0800
Subject: [PATCH 06/77] Staging: hv: storvsc: Fix error handling
storvsc_host_reset()
commit a00e8224c19fa5ba3007da00d850865cbefcaabd upstream.
Fix error handling storvsc_host_reset(). I would like to thank
Long Li <longli@microsoft.com> for reporting this.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reported-by: Long Li <longli@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 20 ++++++--------------
1 file changed, 6 insertions(+), 14 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index e16c7a3..a145245 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -1019,7 +1019,7 @@ static int storvsc_host_reset(struct hv_device *device)
stor_device = get_out_stor_device(device);
if (!stor_device)
- return -ENODEV;
+ return FAILED;
request = &stor_device->reset_request;
vstor_packet = &request->vstor_packet;
@@ -1036,13 +1036,11 @@ static int storvsc_host_reset(struct hv_device *device)
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0)
- goto cleanup;
+ return FAILED;
t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ if (t == 0)
+ return TIMEOUT_ERROR;
/*
@@ -1050,8 +1048,7 @@ static int storvsc_host_reset(struct hv_device *device)
* should have been flushed out and return to us
*/
-cleanup:
- return ret;
+ return SUCCESS;
}
@@ -1060,16 +1057,11 @@ cleanup:
*/
static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
{
- int ret;
struct hv_host_device *host_dev =
(struct hv_host_device *)scmnd->device->host->hostdata;
struct hv_device *dev = host_dev->dev;
- ret = storvsc_host_reset(dev);
- if (ret != 0)
- return ret;
-
- return ret;
+ return storvsc_host_reset(dev);
}
--
1.7.9.5

View File

@ -0,0 +1,72 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:44 -0800
Subject: [PATCH 07/77] Staging: hv: storvsc: Use the accessor function
shost_priv()
commit 7f33f30a67cebbdaa938e34c5144424d2f0ce9cc upstream.
Use the accessor function shost_priv().
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index a145245..b21e85f 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -968,8 +968,7 @@ static int storvsc_remove(struct hv_device *dev)
{
struct storvsc_device *stor_device = hv_get_drvdata(dev);
struct Scsi_Host *host = stor_device->host;
- struct hv_host_device *host_dev =
- (struct hv_host_device *)host->hostdata;
+ struct hv_host_device *host_dev = shost_priv(host);
scsi_remove_host(host);
@@ -1057,8 +1056,7 @@ static int storvsc_host_reset(struct hv_device *device)
*/
static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
{
- struct hv_host_device *host_dev =
- (struct hv_host_device *)scmnd->device->host->hostdata;
+ struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
struct hv_device *dev = host_dev->dev;
return storvsc_host_reset(dev);
@@ -1073,8 +1071,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
struct storvsc_cmd_request *cmd_request =
(struct storvsc_cmd_request *)request->context;
struct scsi_cmnd *scmnd = cmd_request->cmd;
- struct hv_host_device *host_dev =
- (struct hv_host_device *)scmnd->device->host->hostdata;
+ struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
void (*scsi_done_fn)(struct scsi_cmnd *);
struct scsi_sense_hdr sense_hdr;
struct vmscsi_request *vm_srb;
@@ -1144,8 +1141,7 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
void (*done)(struct scsi_cmnd *))
{
int ret;
- struct hv_host_device *host_dev =
- (struct hv_host_device *)scmnd->device->host->hostdata;
+ struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
struct hv_device *dev = host_dev->dev;
struct hv_storvsc_request *request;
struct storvsc_cmd_request *cmd_request;
@@ -1359,7 +1355,7 @@ static int storvsc_probe(struct hv_device *device,
if (!host)
return -ENOMEM;
- host_dev = (struct hv_host_device *)host->hostdata;
+ host_dev = shost_priv(host);
memset(host_dev, 0, sizeof(struct hv_host_device));
host_dev->port = host->host_no;
--
1.7.9.5

View File

@ -0,0 +1,91 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:45 -0800
Subject: [PATCH 08/77] Staging: hv: storvsc: Use the unlocked version
queuecommand
commit bab445e12b45153282fb7d39143516e11987deaa upstream.
Use the unlocked version queuecommand.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 19 +++++--------------
1 file changed, 5 insertions(+), 14 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index b21e85f..827bc68 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -1137,11 +1137,10 @@ static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
/*
* storvsc_queuecommand - Initiate command processing
*/
-static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
- void (*done)(struct scsi_cmnd *))
+static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
{
int ret;
- struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
+ struct hv_host_device *host_dev = shost_priv(host);
struct hv_device *dev = host_dev->dev;
struct hv_storvsc_request *request;
struct storvsc_cmd_request *cmd_request;
@@ -1152,7 +1151,7 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
struct vmscsi_request *vm_srb;
if (storvsc_check_scsi_cmd(scmnd) == false) {
- done(scmnd);
+ scmnd->scsi_done(scmnd);
return 0;
}
@@ -1165,16 +1164,13 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
goto retry_request;
}
- scmnd->scsi_done = done;
-
request_size = sizeof(struct storvsc_cmd_request);
cmd_request = mempool_alloc(host_dev->request_mempool,
GFP_ATOMIC);
- if (!cmd_request) {
- scmnd->scsi_done = NULL;
+ if (!cmd_request)
return SCSI_MLQUEUE_DEVICE_BUSY;
- }
+
memset(cmd_request, 0, sizeof(struct storvsc_cmd_request));
/* Setup the cmd request */
@@ -1227,7 +1223,6 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
create_bounce_buffer(sgl, scsi_sg_count(scmnd),
scsi_bufflen(scmnd));
if (!cmd_request->bounce_sgl) {
- scmnd->scsi_done = NULL;
scmnd->host_scribble = NULL;
mempool_free(cmd_request,
host_dev->request_mempool);
@@ -1274,7 +1269,6 @@ retry_request:
mempool_free(cmd_request, host_dev->request_mempool);
- scmnd->scsi_done = NULL;
scmnd->host_scribble = NULL;
ret = SCSI_MLQUEUE_DEVICE_BUSY;
@@ -1283,9 +1277,6 @@ retry_request:
return ret;
}
-static DEF_SCSI_QCMD(storvsc_queuecommand)
-
-
/* Scsi driver */
static struct scsi_host_template scsi_driver = {
.module = THIS_MODULE,
--
1.7.9.5

View File

@ -0,0 +1,31 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:46 -0800
Subject: [PATCH 09/77] Staging: hv: storvsc: use the macro KBUILD_MODNAME
commit fafb0efc303a916f9902cbadddef3ea125720c1b upstream.
Use the macro KBUILD_MODNAME.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 827bc68..916f5d0 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -1444,7 +1444,7 @@ err_out0:
/* The one and only one */
static struct hv_driver storvsc_drv = {
- .name = "storvsc",
+ .name = KBUILD_MODNAME,
.id_table = id_table,
.probe = storvsc_probe,
.remove = storvsc_remove,
--
1.7.9.5

View File

@ -0,0 +1,32 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:47 -0800
Subject: [PATCH 10/77] Staging: hv: storvsc: Get rid of an unnecessary
forward declaration
commit a404c1ff5556fe29460c097a34d2abe10ddd6e0a upstream.
Get rid of an unnecessary forward declaration.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 916f5d0..4cdb417 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -236,8 +236,6 @@ struct vstor_packet {
#define STORVSC_MAX_CHANNELS 1
#define STORVSC_MAX_CMD_LEN 16
-struct hv_storvsc_request;
-
/* Matches Windows-end */
enum storvsc_request_type {
WRITE_TYPE,
--
1.7.9.5

View File

@ -0,0 +1,43 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:48 -0800
Subject: [PATCH 11/77] Staging: hv: storvsc: Upgrade the vmstor protocol
version
commit 2b9525f511791758b394643b61754a9688e0707d upstream.
In preparation for supporting hot add/remove of scsi devices,
upgrade the vmstor protocol version.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 4cdb417..9153641 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -80,7 +80,7 @@ MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
/* V1 Beta 0.1 */
/* V1 RC < 2008/1/31 1.0 */
/* V1 RC > 2008/1/31 2.0 */
-#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(2, 0)
+#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(4, 2)
@@ -106,7 +106,8 @@ enum vstor_packet_operation {
VSTOR_OPERATION_END_INITIALIZATION = 8,
VSTOR_OPERATION_QUERY_PROTOCOL_VERSION = 9,
VSTOR_OPERATION_QUERY_PROPERTIES = 10,
- VSTOR_OPERATION_MAXIMUM = 10
+ VSTOR_OPERATION_ENUMERATE_BUS = 11,
+ VSTOR_OPERATION_MAXIMUM = 11
};
/*
--
1.7.9.5

View File

@ -0,0 +1,79 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:49 -0800
Subject: [PATCH 12/77] Staging: hv: storvsc: Support hot add of scsi disks
commit 126757998a50659f79a3f1ff23fccfc40ff1bf5c upstream.
Support hot add of scsi disks.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 9153641..7c82d14 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -304,6 +304,30 @@ struct storvsc_cmd_request {
struct hv_storvsc_request request;
};
+struct storvsc_scan_work {
+ struct work_struct work;
+ struct Scsi_Host *host;
+ uint lun;
+};
+
+static void storvsc_bus_scan(struct work_struct *work)
+{
+ struct storvsc_scan_work *wrk;
+ int id, order_id;
+
+ wrk = container_of(work, struct storvsc_scan_work, work);
+ for (id = 0; id < wrk->host->max_id; ++id) {
+ if (wrk->host->reverse_ordering)
+ order_id = wrk->host->max_id - id - 1;
+ else
+ order_id = id;
+
+ scsi_scan_target(&wrk->host->shost_gendev, 0,
+ order_id, SCAN_WILD_CARD, 1);
+ }
+ kfree(wrk);
+}
+
static inline struct storvsc_device *get_out_stor_device(
struct hv_device *device)
{
@@ -551,11 +575,25 @@ static void storvsc_on_receive(struct hv_device *device,
struct vstor_packet *vstor_packet,
struct hv_storvsc_request *request)
{
+ struct storvsc_scan_work *work;
+ struct storvsc_device *stor_device;
+
switch (vstor_packet->operation) {
case VSTOR_OPERATION_COMPLETE_IO:
storvsc_on_io_completion(device, vstor_packet, request);
break;
+
case VSTOR_OPERATION_REMOVE_DEVICE:
+ case VSTOR_OPERATION_ENUMERATE_BUS:
+ stor_device = get_in_stor_device(device);
+ work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC);
+ if (!work)
+ return;
+
+ INIT_WORK(&work->work, storvsc_bus_scan);
+ work->host = stor_device->host;
+ schedule_work(&work->work);
+ break;
default:
break;
--
1.7.9.5

View File

@ -0,0 +1,89 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Tue, 8 Nov 2011 09:01:50 -0800
Subject: [PATCH 13/77] Staging: hv: storvsc: Support hot-removing of scsi
devices
commit b401731985bfa7c02e4e5673a151b29ae7180fce upstream.
Support hot-removing of scsi devices.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 45 ++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 7c82d14..0245143 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -328,6 +328,27 @@ static void storvsc_bus_scan(struct work_struct *work)
kfree(wrk);
}
+static void storvsc_remove_lun(struct work_struct *work)
+{
+ struct storvsc_scan_work *wrk;
+ struct scsi_device *sdev;
+
+ wrk = container_of(work, struct storvsc_scan_work, work);
+ if (!scsi_host_get(wrk->host))
+ goto done;
+
+ sdev = scsi_device_lookup(wrk->host, 0, 0, wrk->lun);
+
+ if (sdev) {
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ }
+ scsi_host_put(wrk->host);
+
+done:
+ kfree(wrk);
+}
+
static inline struct storvsc_device *get_out_stor_device(
struct hv_device *device)
{
@@ -1112,6 +1133,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
void (*scsi_done_fn)(struct scsi_cmnd *);
struct scsi_sense_hdr sense_hdr;
struct vmscsi_request *vm_srb;
+ struct storvsc_scan_work *wrk;
vm_srb = &request->vstor_packet.vm_srb;
if (cmd_request->bounce_sgl_count) {
@@ -1134,6 +1156,29 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
else
scmnd->result = vm_srb->scsi_status;
+ /*
+ * If the LUN is invalid; remove the device.
+ */
+ if (vm_srb->srb_status == 0x20) {
+ struct storvsc_device *stor_dev;
+ struct hv_device *dev = host_dev->dev;
+ struct Scsi_Host *host;
+
+ stor_dev = get_in_stor_device(dev);
+ host = stor_dev->host;
+
+ wrk = kmalloc(sizeof(struct storvsc_scan_work),
+ GFP_ATOMIC);
+ if (!wrk) {
+ scmnd->result = DID_TARGET_FAILURE << 16;
+ } else {
+ wrk->host = host;
+ wrk->lun = vm_srb->lun;
+ INIT_WORK(&wrk->work, storvsc_remove_lun);
+ schedule_work(&wrk->work);
+ }
+ }
+
if (scmnd->result) {
if (scsi_normalize_sense(scmnd->sense_buffer,
SCSI_SENSE_BUFFERSIZE, &sense_hdr))
--
1.7.9.5

View File

@ -0,0 +1,68 @@
From: Thomas Meyer <thomas@m3y3r.de>
Date: Sat, 12 Nov 2011 13:21:49 +0100
Subject: [PATCH 14/77] staging: hv: Use kmemdup rather than duplicating its
implementation
commit 27b7923035f737a7e6384d0084e34706ea068040 upstream.
Use kmemdup rather than duplicating its implementation
The semantic patch that makes this change is available
in scripts/coccinelle/api/memdup.cocci.
Signed-off-by: Thomas Meyer <thomas@m3y3r.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/hv_mouse.c | 4 +---
drivers/staging/hv/netvsc.c | 11 +++--------
2 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c
index ccd39c7..3689217 100644
--- a/drivers/staging/hv/hv_mouse.c
+++ b/drivers/staging/hv/hv_mouse.c
@@ -205,13 +205,11 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
desc = &device_info->hid_descriptor;
WARN_ON(desc->bLength == 0);
- input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
+ input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
if (!input_device->hid_desc)
goto cleanup;
- memcpy(input_device->hid_desc, desc, desc->bLength);
-
input_device->report_desc_size = desc->desc[0].wDescriptorLength;
if (input_device->report_desc_size == 0)
goto cleanup;
diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index b902579..28e69a6 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -230,19 +230,14 @@ static int netvsc_init_recv_buf(struct hv_device *device)
net_device->recv_section_cnt = init_packet->msg.
v1_msg.send_recv_buf_complete.num_sections;
- net_device->recv_section = kmalloc(net_device->recv_section_cnt
- * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL);
+ net_device->recv_section = kmemdup(init_packet->msg.v1_msg.send_recv_buf_complete.sections,
+ net_device->recv_section_cnt * sizeof(struct nvsp_1_receive_buffer_section),
+ GFP_KERNEL);
if (net_device->recv_section == NULL) {
ret = -EINVAL;
goto cleanup;
}
- memcpy(net_device->recv_section,
- init_packet->msg.v1_msg.
- send_recv_buf_complete.sections,
- net_device->recv_section_cnt *
- sizeof(struct nvsp_1_receive_buffer_section));
-
/*
* For 1st release, there should only be 1 section that represents the
* entire receive buffer
--
1.7.9.5

View File

@ -0,0 +1,32 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Mon, 24 Oct 2011 11:28:12 -0700
Subject: [PATCH 15/77] Staging: hv: vmbus: Support building the vmbus driver
as part of the kernel
commit 43d4e119f944a41a7694552353635ad9b2cd8b37 upstream.
Modify the way we initialize the vmbus driver so that all the hyper-v drivers
can be linked with the kernel and still ensure that the vmbus driver
is fully initialized before the drivers that depend upon the vmbus
driver attempt to initialize.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/hv/vmbus_drv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index d2d0a2a..05168eb 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -796,4 +796,4 @@ cleanup:
MODULE_LICENSE("GPL");
MODULE_VERSION(HV_DRV_VERSION);
-module_init(hv_acpi_init);
+subsys_initcall(hv_acpi_init);
--
1.7.9.5

View File

@ -0,0 +1,38 @@
From: Bart Van Assche <bvanassche@acm.org>
Date: Fri, 18 Nov 2011 18:40:52 +0100
Subject: [PATCH 16/77] hv: Add Kconfig menu entry
commit 124a6b4c4dae0317a0689a42ed0c68fabeb10c8d upstream.
Most of the drivers/*/Kconfig files define a menu entry. Define
a menu item for hv too such that it becomes uniform with e.g.
virtio for at least "make xconfig" and "make menuconfig" users.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Cc: James Bottomley <JBottomley@Parallels.com>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/hv/Kconfig | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig
index 9fa09ac..70f5dde 100644
--- a/drivers/hv/Kconfig
+++ b/drivers/hv/Kconfig
@@ -1,3 +1,5 @@
+menu "Microsoft Hyper-V guest support"
+
config HYPERV
tristate "Microsoft Hyper-V client drivers"
depends on X86 && ACPI && PCI
@@ -11,4 +13,4 @@ config HYPERV_UTILS
help
Select this option to enable the Hyper-V Utilities.
-
+endmenu
--
1.7.9.5

View File

@ -0,0 +1,656 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Fri, 25 Nov 2011 21:28:28 -0800
Subject: [PATCH 17/77] Staging: hv: mousevsc: Remove the mouse driver from
the staging tree
commit 045b1684bc21575793a099490938d197555eb128 upstream.
The mouse driver for Hyper-V is a HID compliant mouse driver.
Now that all relevant review comments have been addressed,
Jiri has agreed to merge this mouse driver into 3.3 hid.git.
This patch takes care of removing the mouse driver from the
staging area. Greg, if you can ack this patch, Jiri will proceed
with his merge.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
[bwh: Backported to 3.2, dropping the intermediate changes]
---
drivers/staging/hv/Kconfig | 6 -
drivers/staging/hv/Makefile | 1 -
drivers/staging/hv/hv_mouse.c | 597 -----------------------------------------
3 files changed, 604 deletions(-)
delete mode 100644 drivers/staging/hv/hv_mouse.c
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
index 072185e..6c0dc30 100644
--- a/drivers/staging/hv/Kconfig
+++ b/drivers/staging/hv/Kconfig
@@ -9,9 +9,3 @@ config HYPERV_NET
depends on HYPERV && NET
help
Select this option to enable the Hyper-V virtual network driver.
-
-config HYPERV_MOUSE
- tristate "Microsoft Hyper-V mouse driver"
- depends on HYPERV && HID
- help
- Select this option to enable the Hyper-V mouse driver.
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
index 0f55cee..fbe9a42 100644
--- a/drivers/staging/hv/Makefile
+++ b/drivers/staging/hv/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o
-obj-$(CONFIG_HYPERV_MOUSE) += hv_mouse.o
hv_storvsc-y := storvsc_drv.o
hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o
diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c
deleted file mode 100644
index 3689217..0000000
--- a/drivers/staging/hv/hv_mouse.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * Copyright (c) 2009, Citrix Systems, Inc.
- * Copyright (c) 2010, Microsoft Corporation.
- * Copyright (c) 2011, Novell Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/input.h>
-#include <linux/hid.h>
-#include <linux/hiddev.h>
-#include <linux/hyperv.h>
-
-
-struct hv_input_dev_info {
- unsigned int size;
- unsigned short vendor;
- unsigned short product;
- unsigned short version;
- unsigned short reserved[11];
-};
-
-/* The maximum size of a synthetic input message. */
-#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
-
-/*
- * Current version
- *
- * History:
- * Beta, RC < 2008/1/22 1,0
- * RC > 2008/1/22 2,0
- */
-#define SYNTHHID_INPUT_VERSION_MAJOR 2
-#define SYNTHHID_INPUT_VERSION_MINOR 0
-#define SYNTHHID_INPUT_VERSION (SYNTHHID_INPUT_VERSION_MINOR | \
- (SYNTHHID_INPUT_VERSION_MAJOR << 16))
-
-
-#pragma pack(push, 1)
-/*
- * Message types in the synthetic input protocol
- */
-enum synthhid_msg_type {
- SYNTH_HID_PROTOCOL_REQUEST,
- SYNTH_HID_PROTOCOL_RESPONSE,
- SYNTH_HID_INITIAL_DEVICE_INFO,
- SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
- SYNTH_HID_INPUT_REPORT,
- SYNTH_HID_MAX
-};
-
-/*
- * Basic message structures.
- */
-struct synthhid_msg_hdr {
- enum synthhid_msg_type type;
- u32 size;
-};
-
-struct synthhid_msg {
- struct synthhid_msg_hdr header;
- char data[1]; /* Enclosed message */
-};
-
-union synthhid_version {
- struct {
- u16 minor_version;
- u16 major_version;
- };
- u32 version;
-};
-
-/*
- * Protocol messages
- */
-struct synthhid_protocol_request {
- struct synthhid_msg_hdr header;
- union synthhid_version version_requested;
-};
-
-struct synthhid_protocol_response {
- struct synthhid_msg_hdr header;
- union synthhid_version version_requested;
- unsigned char approved;
-};
-
-struct synthhid_device_info {
- struct synthhid_msg_hdr header;
- struct hv_input_dev_info hid_dev_info;
- struct hid_descriptor hid_descriptor;
-};
-
-struct synthhid_device_info_ack {
- struct synthhid_msg_hdr header;
- unsigned char reserved;
-};
-
-struct synthhid_input_report {
- struct synthhid_msg_hdr header;
- char buffer[1];
-};
-
-#pragma pack(pop)
-
-#define INPUTVSC_SEND_RING_BUFFER_SIZE (10*PAGE_SIZE)
-#define INPUTVSC_RECV_RING_BUFFER_SIZE (10*PAGE_SIZE)
-
-#define NBITS(x) (((x)/BITS_PER_LONG)+1)
-
-enum pipe_prot_msg_type {
- PIPE_MESSAGE_INVALID,
- PIPE_MESSAGE_DATA,
- PIPE_MESSAGE_MAXIMUM
-};
-
-
-struct pipe_prt_msg {
- enum pipe_prot_msg_type type;
- u32 size;
- char data[1];
-};
-
-struct mousevsc_prt_msg {
- enum pipe_prot_msg_type type;
- u32 size;
- union {
- struct synthhid_protocol_request request;
- struct synthhid_protocol_response response;
- struct synthhid_device_info_ack ack;
- };
-};
-
-/*
- * Represents an mousevsc device
- */
-struct mousevsc_dev {
- struct hv_device *device;
- unsigned char init_complete;
- struct mousevsc_prt_msg protocol_req;
- struct mousevsc_prt_msg protocol_resp;
- /* Synchronize the request/response if needed */
- struct completion wait_event;
- int dev_info_status;
-
- struct hid_descriptor *hid_desc;
- unsigned char *report_desc;
- u32 report_desc_size;
- struct hv_input_dev_info hid_dev_info;
- int connected;
- struct hid_device *hid_device;
-};
-
-
-static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
-{
- struct mousevsc_dev *input_dev;
-
- input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
-
- if (!input_dev)
- return NULL;
-
- input_dev->device = device;
- hv_set_drvdata(device, input_dev);
- init_completion(&input_dev->wait_event);
-
- return input_dev;
-}
-
-static void free_input_device(struct mousevsc_dev *device)
-{
- kfree(device->hid_desc);
- kfree(device->report_desc);
- hv_set_drvdata(device->device, NULL);
- kfree(device);
-}
-
-
-static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
- struct synthhid_device_info *device_info)
-{
- int ret = 0;
- struct hid_descriptor *desc;
- struct mousevsc_prt_msg ack;
-
- /* Assume success for now */
- input_device->dev_info_status = 0;
-
- memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
- sizeof(struct hv_input_dev_info));
-
- desc = &device_info->hid_descriptor;
- WARN_ON(desc->bLength == 0);
-
- input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
-
- if (!input_device->hid_desc)
- goto cleanup;
-
- input_device->report_desc_size = desc->desc[0].wDescriptorLength;
- if (input_device->report_desc_size == 0)
- goto cleanup;
- input_device->report_desc = kzalloc(input_device->report_desc_size,
- GFP_ATOMIC);
-
- if (!input_device->report_desc)
- goto cleanup;
-
- memcpy(input_device->report_desc,
- ((unsigned char *)desc) + desc->bLength,
- desc->desc[0].wDescriptorLength);
-
- /* Send the ack */
- memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
-
- ack.type = PIPE_MESSAGE_DATA;
- ack.size = sizeof(struct synthhid_device_info_ack);
-
- ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
- ack.ack.header.size = 1;
- ack.ack.reserved = 0;
-
- ret = vmbus_sendpacket(input_device->device->channel,
- &ack,
- sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
- sizeof(struct synthhid_device_info_ack),
- (unsigned long)&ack,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0)
- goto cleanup;
-
- complete(&input_device->wait_event);
-
- return;
-
-cleanup:
- kfree(input_device->hid_desc);
- input_device->hid_desc = NULL;
-
- kfree(input_device->report_desc);
- input_device->report_desc = NULL;
-
- input_device->dev_info_status = -1;
- complete(&input_device->wait_event);
-}
-
-static void mousevsc_on_receive(struct hv_device *device,
- struct vmpacket_descriptor *packet)
-{
- struct pipe_prt_msg *pipe_msg;
- struct synthhid_msg *hid_msg;
- struct mousevsc_dev *input_dev = hv_get_drvdata(device);
- struct synthhid_input_report *input_report;
-
- pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
- (packet->offset8 << 3));
-
- if (pipe_msg->type != PIPE_MESSAGE_DATA)
- return;
-
- hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
-
- switch (hid_msg->header.type) {
- case SYNTH_HID_PROTOCOL_RESPONSE:
- memcpy(&input_dev->protocol_resp, pipe_msg,
- pipe_msg->size + sizeof(struct pipe_prt_msg) -
- sizeof(unsigned char));
- complete(&input_dev->wait_event);
- break;
-
- case SYNTH_HID_INITIAL_DEVICE_INFO:
- WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
-
- /*
- * Parse out the device info into device attr,
- * hid desc and report desc
- */
- mousevsc_on_receive_device_info(input_dev,
- (struct synthhid_device_info *)&pipe_msg->data[0]);
- break;
- case SYNTH_HID_INPUT_REPORT:
- input_report =
- (struct synthhid_input_report *)&pipe_msg->data[0];
- if (!input_dev->init_complete)
- break;
- hid_input_report(input_dev->hid_device,
- HID_INPUT_REPORT, input_report->buffer,
- input_report->header.size, 1);
- break;
- default:
- pr_err("unsupported hid msg type - type %d len %d",
- hid_msg->header.type, hid_msg->header.size);
- break;
- }
-
-}
-
-static void mousevsc_on_channel_callback(void *context)
-{
- const int packetSize = 0x100;
- int ret = 0;
- struct hv_device *device = (struct hv_device *)context;
-
- u32 bytes_recvd;
- u64 req_id;
- unsigned char packet[0x100];
- struct vmpacket_descriptor *desc;
- unsigned char *buffer = packet;
- int bufferlen = packetSize;
-
-
- do {
- ret = vmbus_recvpacket_raw(device->channel, buffer,
- bufferlen, &bytes_recvd, &req_id);
-
- if (ret == 0) {
- if (bytes_recvd > 0) {
- desc = (struct vmpacket_descriptor *)buffer;
-
- switch (desc->type) {
- case VM_PKT_COMP:
- break;
-
- case VM_PKT_DATA_INBAND:
- mousevsc_on_receive(
- device, desc);
- break;
-
- default:
- pr_err("unhandled packet type %d, tid %llx len %d\n",
- desc->type,
- req_id,
- bytes_recvd);
- break;
- }
-
- /* reset */
- if (bufferlen > packetSize) {
- kfree(buffer);
-
- buffer = packet;
- bufferlen = packetSize;
- }
- } else {
- if (bufferlen > packetSize) {
- kfree(buffer);
-
- buffer = packet;
- bufferlen = packetSize;
- }
- break;
- }
- } else if (ret == -ENOBUFS) {
- /* Handle large packet */
- bufferlen = bytes_recvd;
- buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
-
- if (buffer == NULL) {
- buffer = packet;
- bufferlen = packetSize;
- break;
- }
- }
- } while (1);
-
- return;
-}
-
-static int mousevsc_connect_to_vsp(struct hv_device *device)
-{
- int ret = 0;
- int t;
- struct mousevsc_dev *input_dev = hv_get_drvdata(device);
- struct mousevsc_prt_msg *request;
- struct mousevsc_prt_msg *response;
-
-
- request = &input_dev->protocol_req;
-
- memset(request, 0, sizeof(struct mousevsc_prt_msg));
-
- request->type = PIPE_MESSAGE_DATA;
- request->size = sizeof(struct synthhid_protocol_request);
-
- request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
- request->request.header.size = sizeof(unsigned int);
- request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
-
-
- ret = vmbus_sendpacket(device->channel, request,
- sizeof(struct pipe_prt_msg) -
- sizeof(unsigned char) +
- sizeof(struct synthhid_protocol_request),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0)
- goto cleanup;
-
- t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- response = &input_dev->protocol_resp;
-
- if (!response->response.approved) {
- pr_err("synthhid protocol request failed (version %d)",
- SYNTHHID_INPUT_VERSION);
- ret = -ENODEV;
- goto cleanup;
- }
-
- t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- /*
- * We should have gotten the device attr, hid desc and report
- * desc at this point
- */
- if (input_dev->dev_info_status)
- ret = -ENOMEM;
-
-cleanup:
-
- return ret;
-}
-
-static int mousevsc_hid_open(struct hid_device *hid)
-{
- return 0;
-}
-
-static void mousevsc_hid_close(struct hid_device *hid)
-{
-}
-
-static struct hid_ll_driver mousevsc_ll_driver = {
- .open = mousevsc_hid_open,
- .close = mousevsc_hid_close,
-};
-
-static struct hid_driver mousevsc_hid_driver;
-
-static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
-{
- struct hid_device *hid_dev;
- struct mousevsc_dev *input_device = hv_get_drvdata(dev);
-
- hid_dev = hid_allocate_device();
- if (IS_ERR(hid_dev))
- return;
-
- hid_dev->ll_driver = &mousevsc_ll_driver;
- hid_dev->driver = &mousevsc_hid_driver;
-
- if (hid_parse_report(hid_dev, packet, len))
- return;
-
- hid_dev->bus = BUS_VIRTUAL;
- hid_dev->vendor = input_device->hid_dev_info.vendor;
- hid_dev->product = input_device->hid_dev_info.product;
- hid_dev->version = input_device->hid_dev_info.version;
-
- sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
-
- if (!hidinput_connect(hid_dev, 0)) {
- hid_dev->claimed |= HID_CLAIMED_INPUT;
-
- input_device->connected = 1;
-
- }
-
- input_device->hid_device = hid_dev;
-}
-
-static int mousevsc_on_device_add(struct hv_device *device)
-{
- int ret = 0;
- struct mousevsc_dev *input_dev;
-
- input_dev = alloc_input_device(device);
-
- if (!input_dev)
- return -ENOMEM;
-
- input_dev->init_complete = false;
-
- ret = vmbus_open(device->channel,
- INPUTVSC_SEND_RING_BUFFER_SIZE,
- INPUTVSC_RECV_RING_BUFFER_SIZE,
- NULL,
- 0,
- mousevsc_on_channel_callback,
- device
- );
-
- if (ret != 0) {
- free_input_device(input_dev);
- return ret;
- }
-
-
- ret = mousevsc_connect_to_vsp(device);
-
- if (ret != 0) {
- vmbus_close(device->channel);
- free_input_device(input_dev);
- return ret;
- }
-
-
- /* workaround SA-167 */
- if (input_dev->report_desc[14] == 0x25)
- input_dev->report_desc[14] = 0x29;
-
- reportdesc_callback(device, input_dev->report_desc,
- input_dev->report_desc_size);
-
- input_dev->init_complete = true;
-
- return ret;
-}
-
-static int mousevsc_probe(struct hv_device *dev,
- const struct hv_vmbus_device_id *dev_id)
-{
-
- return mousevsc_on_device_add(dev);
-
-}
-
-static int mousevsc_remove(struct hv_device *dev)
-{
- struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
-
- vmbus_close(dev->channel);
-
- if (input_dev->connected) {
- hidinput_disconnect(input_dev->hid_device);
- input_dev->connected = 0;
- hid_destroy_device(input_dev->hid_device);
- }
-
- free_input_device(input_dev);
-
- return 0;
-}
-
-static const struct hv_vmbus_device_id id_table[] = {
- /* Mouse guid */
- { VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
- 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
- { },
-};
-
-MODULE_DEVICE_TABLE(vmbus, id_table);
-
-static struct hv_driver mousevsc_drv = {
- .name = "mousevsc",
- .id_table = id_table,
- .probe = mousevsc_probe,
- .remove = mousevsc_remove,
-};
-
-static int __init mousevsc_init(void)
-{
- return vmbus_driver_register(&mousevsc_drv);
-}
-
-static void __exit mousevsc_exit(void)
-{
- vmbus_driver_unregister(&mousevsc_drv);
-}
-
-MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
-module_init(mousevsc_init);
-module_exit(mousevsc_exit);
--
1.7.9.5

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Wed, 30 Nov 2011 07:19:07 -0800
Subject: [PATCH 19/77] net/hyperv: Fix long lines in netvsc.c
commit c18132005e711c07523d8c6602e5b2266ab9a0f2 upstream.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/net/hyperv/netvsc.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 28e69a6..4a807e4 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -230,9 +230,11 @@ static int netvsc_init_recv_buf(struct hv_device *device)
net_device->recv_section_cnt = init_packet->msg.
v1_msg.send_recv_buf_complete.num_sections;
- net_device->recv_section = kmemdup(init_packet->msg.v1_msg.send_recv_buf_complete.sections,
- net_device->recv_section_cnt * sizeof(struct nvsp_1_receive_buffer_section),
- GFP_KERNEL);
+ net_device->recv_section = kmemdup(
+ init_packet->msg.v1_msg.send_recv_buf_complete.sections,
+ net_device->recv_section_cnt *
+ sizeof(struct nvsp_1_receive_buffer_section),
+ GFP_KERNEL);
if (net_device->recv_section == NULL) {
ret = -EINVAL;
goto cleanup;
--
1.7.9.5

View File

@ -0,0 +1,163 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Wed, 30 Nov 2011 07:19:08 -0800
Subject: [PATCH 20/77] net/hyperv: Add support for promiscuous mode setting
commit d426b2e3d91f8ec3203f8852e7ad0153b5dfdf71 upstream.
Add code to accept promiscuous mode setting, and pass it to
RNDIS filter.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/net/hyperv/hyperv_net.h | 24 +++++++++++++++++++
drivers/net/hyperv/netvsc_drv.c | 46 ++++++++++++++++++++++++++++++++++---
drivers/net/hyperv/rndis_filter.c | 23 +------------------
3 files changed, 68 insertions(+), 25 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index ac1ec84..49b131f 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -87,6 +87,27 @@ struct netvsc_device_info {
int ring_size;
};
+enum rndis_device_state {
+ RNDIS_DEV_UNINITIALIZED = 0,
+ RNDIS_DEV_INITIALIZING,
+ RNDIS_DEV_INITIALIZED,
+ RNDIS_DEV_DATAINITIALIZED,
+};
+
+struct rndis_device {
+ struct netvsc_device *net_dev;
+
+ enum rndis_device_state state;
+ bool link_state;
+ atomic_t new_req_id;
+
+ spinlock_t request_lock;
+ struct list_head req_list;
+
+ unsigned char hw_mac_adr[ETH_ALEN];
+};
+
+
/* Interface */
int netvsc_device_add(struct hv_device *device, void *additional_info);
int netvsc_device_remove(struct hv_device *device);
@@ -109,6 +130,9 @@ int rndis_filter_receive(struct hv_device *dev,
int rndis_filter_send(struct hv_device *dev,
struct hv_netvsc_packet *pkt);
+int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
+
+
#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
#define NVSP_PROTOCOL_VERSION_1 2
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 93b0e91..b69c3a4 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -56,11 +56,51 @@ static int ring_size = 128;
module_param(ring_size, int, S_IRUGO);
MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
-/* no-op so the netdev core doesn't return -EINVAL when modifying the the
- * multicast address list in SIOCADDMULTI. hv is setup to get all multicast
- * when it calls RndisFilterOnOpen() */
+struct set_multicast_work {
+ struct work_struct work;
+ struct net_device *net;
+};
+
+static void do_set_multicast(struct work_struct *w)
+{
+ struct set_multicast_work *swk =
+ container_of(w, struct set_multicast_work, work);
+ struct net_device *net = swk->net;
+
+ struct net_device_context *ndevctx = netdev_priv(net);
+ struct netvsc_device *nvdev;
+ struct rndis_device *rdev;
+
+ nvdev = hv_get_drvdata(ndevctx->device_ctx);
+ if (nvdev == NULL)
+ return;
+
+ rdev = nvdev->extension;
+ if (rdev == NULL)
+ return;
+
+ if (net->flags & IFF_PROMISC)
+ rndis_filter_set_packet_filter(rdev,
+ NDIS_PACKET_TYPE_PROMISCUOUS);
+ else
+ rndis_filter_set_packet_filter(rdev,
+ NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_DIRECTED);
+
+ kfree(w);
+}
+
static void netvsc_set_multicast_list(struct net_device *net)
{
+ struct set_multicast_work *swk =
+ kmalloc(sizeof(struct set_multicast_work), GFP_ATOMIC);
+ if (swk == NULL)
+ return;
+
+ swk->net = net;
+ INIT_WORK(&swk->work, do_set_multicast);
+ schedule_work(&swk->work);
}
static int netvsc_open(struct net_device *net)
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index bafccb3..418e7aa 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -30,26 +30,6 @@
#include "hyperv_net.h"
-enum rndis_device_state {
- RNDIS_DEV_UNINITIALIZED = 0,
- RNDIS_DEV_INITIALIZING,
- RNDIS_DEV_INITIALIZED,
- RNDIS_DEV_DATAINITIALIZED,
-};
-
-struct rndis_device {
- struct netvsc_device *net_dev;
-
- enum rndis_device_state state;
- bool link_state;
- atomic_t new_req_id;
-
- spinlock_t request_lock;
- struct list_head req_list;
-
- unsigned char hw_mac_adr[ETH_ALEN];
-};
-
struct rndis_request {
struct list_head list_ent;
struct completion wait_event;
@@ -522,8 +502,7 @@ static int rndis_filter_query_device_link_status(struct rndis_device *dev)
return ret;
}
-static int rndis_filter_set_packet_filter(struct rndis_device *dev,
- u32 new_filter)
+int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
{
struct rndis_request *request;
struct rndis_set_request *set;
--
1.7.9.5

View File

@ -0,0 +1,65 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 1 Dec 2011 04:59:16 -0800
Subject: [PATCH 21/77] Staging: hv: storvsc: Disable clustering
commit 039db52de9c5682ee10a3cd69f2d76db40b1dee0 upstream.
Disable clustering, since the host side on Hyper-V requires that
each I/O element not exceed the page size. As part of this
cleanup, get rid of the function to merge bvecs, as the primary
reason for this function was to avoid having an element exceed
the page size.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 0245143..9153f98 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -798,13 +798,6 @@ static int storvsc_device_alloc(struct scsi_device *sdevice)
return 0;
}
-static int storvsc_merge_bvec(struct request_queue *q,
- struct bvec_merge_data *bmd, struct bio_vec *bvec)
-{
- /* checking done by caller. */
- return bvec->bv_len;
-}
-
static int storvsc_device_configure(struct scsi_device *sdevice)
{
scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
@@ -812,8 +805,6 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
- blk_queue_merge_bvec(sdevice->request_queue, storvsc_merge_bvec);
-
blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
return 0;
@@ -1375,14 +1366,7 @@ static struct scsi_host_template scsi_driver = {
/* no use setting to 0 since ll_blk_rw reset it to 1 */
/* currently 32 */
.sg_tablesize = MAX_MULTIPAGE_BUFFER_COUNT,
- /*
- * ENABLE_CLUSTERING allows mutiple physically contig bio_vecs to merge
- * into 1 sg element. If set, we must limit the max_segment_size to
- * PAGE_SIZE, otherwise we may get 1 sg element that represents
- * multiple
- */
- /* physically contig pfns (ie sg[x].length > PAGE_SIZE). */
- .use_clustering = ENABLE_CLUSTERING,
+ .use_clustering = DISABLE_CLUSTERING,
/* Make sure we dont get a sg segment crosses a page boundary */
.dma_boundary = PAGE_SIZE-1,
};
--
1.7.9.5

View File

@ -0,0 +1,36 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 1 Dec 2011 04:59:17 -0800
Subject: [PATCH 22/77] Staging: hv: storvsc: Cleanup storvsc_device_alloc()
commit 2781866484624fabbe373b95cfd20d44d2c9a69e upstream.
The code in storvsc_device_alloc() is not needed as this would be
done by default. Get rid of it. We still keep the function as we use
this hook to allocate per-LUN memory pools in a later patch.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 9153f98..14ecb69 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -790,11 +790,6 @@ static void storvsc_get_ide_info(struct hv_device *dev, int *target, int *path)
static int storvsc_device_alloc(struct scsi_device *sdevice)
{
- /*
- * This enables luns to be located sparsely. Otherwise, we may not
- * discovered them.
- */
- sdevice->sdev_bflags |= BLIST_SPARSELUN | BLIST_LARGELUN;
return 0;
}
--
1.7.9.5

View File

@ -0,0 +1,40 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 1 Dec 2011 04:59:18 -0800
Subject: [PATCH 23/77] Staging: hv: storvsc: Fix a bug in
storvsc_command_completion()
commit a768a76d55c2798bbd86b81f50ef740312d69935 upstream.
Fix a bug in storvsc_command_completion() that leaks memory when scatter/gather
lists are used on the "write" side.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 14ecb69..8dafe52 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -1123,13 +1123,12 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
vm_srb = &request->vstor_packet.vm_srb;
if (cmd_request->bounce_sgl_count) {
- if (vm_srb->data_in == READ_TYPE) {
+ if (vm_srb->data_in == READ_TYPE)
copy_from_bounce_buffer(scsi_sglist(scmnd),
cmd_request->bounce_sgl,
scsi_sg_count(scmnd));
- destroy_bounce_buffer(cmd_request->bounce_sgl,
+ destroy_bounce_buffer(cmd_request->bounce_sgl,
cmd_request->bounce_sgl_count);
- }
}
/*
--
1.7.9.5

View File

@ -0,0 +1,68 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 1 Dec 2011 04:59:19 -0800
Subject: [PATCH 24/77] Staging: hv: storvsc: Fix a bug in
copy_from_bounce_buffer()
commit 10c43dd4c4403d35fc6477d547aa3a38b466b310 upstream.
Fix a bug in copy_from_bounce_buffer().
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 8dafe52..c22de06 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -880,7 +880,8 @@ cleanup:
/* Assume the original sgl has enough room */
static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count)
+ unsigned int orig_sgl_count,
+ unsigned int bounce_sgl_count)
{
int i;
int j = 0;
@@ -921,6 +922,24 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
kunmap_atomic((void *)bounce_addr, KM_IRQ0);
j++;
+ /*
+ * It is possible that the number of elements
+ * in the bounce buffer may not be equal to
+ * the number of elements in the original
+ * scatter list. Handle this correctly.
+ */
+
+ if (j == bounce_sgl_count) {
+ /*
+ * We are done; cleanup and return.
+ */
+ kunmap_atomic((void *)(dest_addr -
+ orig_sgl[i].offset),
+ KM_IRQ0);
+ local_irq_restore(flags);
+ return total_copied;
+ }
+
/* if we need to use another bounce buffer */
if (destlen || i != orig_sgl_count - 1)
bounce_addr =
@@ -1126,7 +1145,8 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
if (vm_srb->data_in == READ_TYPE)
copy_from_bounce_buffer(scsi_sglist(scmnd),
cmd_request->bounce_sgl,
- scsi_sg_count(scmnd));
+ scsi_sg_count(scmnd),
+ cmd_request->bounce_sgl_count);
destroy_bounce_buffer(cmd_request->bounce_sgl,
cmd_request->bounce_sgl_count);
}
--
1.7.9.5

View File

@ -0,0 +1,264 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 1 Dec 2011 04:59:20 -0800
Subject: [PATCH 25/77] Staging: hv: storvsc: Implement per device memory
pools
commit ce3e301c442f7beffd049908a007697753766cf7 upstream.
The current code implemented a per-HBA memory pool mechanism. For IDE disks
managed by this driver, there is a one to one correspondance between the
block device and the associated virtual HBA and since currently only IDE devices
can be the boot device, this addressed the deadlock issues that were raised during
the review process. This patch implements a per-lun memory pool mechanism.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 106 ++++++++++++++++++++++----------------
1 file changed, 62 insertions(+), 44 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index c22de06..18f8771 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -285,10 +285,13 @@ struct storvsc_device {
struct hv_storvsc_request reset_request;
};
-struct hv_host_device {
- struct hv_device *dev;
+struct stor_mem_pools {
struct kmem_cache *request_pool;
mempool_t *request_mempool;
+};
+
+struct hv_host_device {
+ struct hv_device *dev;
unsigned int port;
unsigned char path;
unsigned char target;
@@ -790,7 +793,48 @@ static void storvsc_get_ide_info(struct hv_device *dev, int *target, int *path)
static int storvsc_device_alloc(struct scsi_device *sdevice)
{
+ struct stor_mem_pools *memp;
+ int number = STORVSC_MIN_BUF_NR;
+
+ memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL);
+ if (!memp)
+ return -ENOMEM;
+
+ memp->request_pool =
+ kmem_cache_create(dev_name(&sdevice->sdev_dev),
+ sizeof(struct storvsc_cmd_request), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+
+ if (!memp->request_pool)
+ goto err0;
+
+ memp->request_mempool = mempool_create(number, mempool_alloc_slab,
+ mempool_free_slab,
+ memp->request_pool);
+
+ if (!memp->request_mempool)
+ goto err1;
+
+ sdevice->hostdata = memp;
+
return 0;
+
+err1:
+ kmem_cache_destroy(memp->request_pool);
+
+err0:
+ kfree(memp);
+ return -ENOMEM;
+}
+
+static void storvsc_device_destroy(struct scsi_device *sdevice)
+{
+ struct stor_mem_pools *memp = sdevice->hostdata;
+
+ mempool_destroy(memp->request_mempool);
+ kmem_cache_destroy(memp->request_pool);
+ kfree(memp);
+ sdevice->hostdata = NULL;
}
static int storvsc_device_configure(struct scsi_device *sdevice)
@@ -1031,19 +1075,13 @@ static int storvsc_remove(struct hv_device *dev)
{
struct storvsc_device *stor_device = hv_get_drvdata(dev);
struct Scsi_Host *host = stor_device->host;
- struct hv_host_device *host_dev = shost_priv(host);
scsi_remove_host(host);
scsi_host_put(host);
storvsc_dev_remove(dev);
- if (host_dev->request_pool) {
- mempool_destroy(host_dev->request_mempool);
- kmem_cache_destroy(host_dev->request_pool);
- host_dev->request_pool = NULL;
- host_dev->request_mempool = NULL;
- }
+
return 0;
}
@@ -1139,6 +1177,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
struct scsi_sense_hdr sense_hdr;
struct vmscsi_request *vm_srb;
struct storvsc_scan_work *wrk;
+ struct stor_mem_pools *memp = scmnd->device->hostdata;
vm_srb = &request->vstor_packet.vm_srb;
if (cmd_request->bounce_sgl_count) {
@@ -1201,7 +1240,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
scsi_done_fn(scmnd);
- mempool_free(cmd_request, host_dev->request_mempool);
+ mempool_free(cmd_request, memp->request_mempool);
}
static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
@@ -1236,6 +1275,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
struct scatterlist *sgl;
unsigned int sg_count = 0;
struct vmscsi_request *vm_srb;
+ struct stor_mem_pools *memp = scmnd->device->hostdata;
if (storvsc_check_scsi_cmd(scmnd) == false) {
scmnd->scsi_done(scmnd);
@@ -1253,7 +1293,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
request_size = sizeof(struct storvsc_cmd_request);
- cmd_request = mempool_alloc(host_dev->request_mempool,
+ cmd_request = mempool_alloc(memp->request_mempool,
GFP_ATOMIC);
if (!cmd_request)
return SCSI_MLQUEUE_DEVICE_BUSY;
@@ -1312,7 +1352,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
if (!cmd_request->bounce_sgl) {
scmnd->host_scribble = NULL;
mempool_free(cmd_request,
- host_dev->request_mempool);
+ memp->request_mempool);
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1354,7 +1394,7 @@ retry_request:
destroy_bounce_buffer(cmd_request->bounce_sgl,
cmd_request->bounce_sgl_count);
- mempool_free(cmd_request, host_dev->request_mempool);
+ mempool_free(cmd_request, memp->request_mempool);
scmnd->host_scribble = NULL;
@@ -1372,6 +1412,7 @@ static struct scsi_host_template scsi_driver = {
.queuecommand = storvsc_queuecommand,
.eh_host_reset_handler = storvsc_host_reset_handler,
.slave_alloc = storvsc_device_alloc,
+ .slave_destroy = storvsc_device_destroy,
.slave_configure = storvsc_device_configure,
.cmd_per_lun = 1,
/* 64 max_queue * 1 target */
@@ -1413,7 +1454,6 @@ static int storvsc_probe(struct hv_device *device,
const struct hv_vmbus_device_id *dev_id)
{
int ret;
- int number = STORVSC_MIN_BUF_NR;
struct Scsi_Host *host;
struct hv_host_device *host_dev;
bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
@@ -1432,29 +1472,11 @@ static int storvsc_probe(struct hv_device *device,
host_dev->port = host->host_no;
host_dev->dev = device;
- host_dev->request_pool =
- kmem_cache_create(dev_name(&device->device),
- sizeof(struct storvsc_cmd_request), 0,
- SLAB_HWCACHE_ALIGN, NULL);
-
- if (!host_dev->request_pool) {
- scsi_host_put(host);
- return -ENOMEM;
- }
-
- host_dev->request_mempool = mempool_create(number, mempool_alloc_slab,
- mempool_free_slab,
- host_dev->request_pool);
-
- if (!host_dev->request_mempool) {
- ret = -ENOMEM;
- goto err_out0;
- }
stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
if (!stor_device) {
ret = -ENOMEM;
- goto err_out1;
+ goto err_out0;
}
stor_device->destroy = false;
@@ -1466,7 +1488,7 @@ static int storvsc_probe(struct hv_device *device,
stor_device->port_number = host->host_no;
ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size);
if (ret)
- goto err_out2;
+ goto err_out1;
if (dev_is_ide)
storvsc_get_ide_info(device, &target, &path);
@@ -1486,7 +1508,7 @@ static int storvsc_probe(struct hv_device *device,
/* Register the HBA and start the scsi bus scan */
ret = scsi_add_host(host, &device->device);
if (ret != 0)
- goto err_out3;
+ goto err_out2;
if (!dev_is_ide) {
scsi_scan_host(host);
@@ -1495,28 +1517,24 @@ static int storvsc_probe(struct hv_device *device,
ret = scsi_add_device(host, 0, target, 0);
if (ret) {
scsi_remove_host(host);
- goto err_out3;
+ goto err_out2;
}
return 0;
-err_out3:
+err_out2:
/*
* Once we have connected with the host, we would need to
* to invoke storvsc_dev_remove() to rollback this state and
* this call also frees up the stor_device; hence the jump around
- * err_out2 label.
+ * err_out1 label.
*/
storvsc_dev_remove(device);
- goto err_out1;
-
-err_out2:
- kfree(stor_device);
+ goto err_out0;
err_out1:
- mempool_destroy(host_dev->request_mempool);
+ kfree(stor_device);
err_out0:
- kmem_cache_destroy(host_dev->request_pool);
scsi_host_put(host);
return ret;
}
--
1.7.9.5

View File

@ -0,0 +1,29 @@
From: Greg Kroah-Hartman <gregkh@suse.de>
Date: Thu, 1 Dec 2011 10:38:42 -0800
Subject: [PATCH 26/77] Staging: hv: update TODO file
commit 0c9d19646249e0124f1d82fb939e5ba76cb1af3c upstream.
Hank is no longer at Microsoft, so remove his email address as it
bounces.
Cc: KY Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/TODO | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/staging/hv/TODO b/drivers/staging/hv/TODO
index fd080cb..dea7d92 100644
--- a/drivers/staging/hv/TODO
+++ b/drivers/staging/hv/TODO
@@ -2,5 +2,4 @@ TODO:
- audit the scsi driver
Please send patches for this code to Greg Kroah-Hartman <gregkh@suse.de>,
-Hank Janssen <hjanssen@microsoft.com>, Haiyang Zhang <haiyangz@microsoft.com>,
-K. Y. Srinivasan <kys@microsoft.com>
+Haiyang Zhang <haiyangz@microsoft.com>, and K. Y. Srinivasan <kys@microsoft.com>
--
1.7.9.5

View File

@ -0,0 +1,34 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Wed, 30 Nov 2011 08:52:23 -0800
Subject: [PATCH 27/77] HID: hv_mouse: Properly add the hid device
commit 74c4fb058083b47571a4f76dcfce95085f2d8098 upstream.
We need to properly add the hid device to correctly initialize the sysfs state.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reported-by: Fuzhou Chen <fuzhouch@microsoft.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
drivers/hid/hid-hyperv.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index d503cbb..0c33ae9 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -506,6 +506,10 @@ static int mousevsc_probe(struct hv_device *device,
sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
+ ret = hid_add_device(hid_dev);
+ if (ret)
+ goto probe_err1;
+
ret = hid_parse_report(hid_dev, input_dev->report_desc,
input_dev->report_desc_size);
--
1.7.9.5

View File

@ -0,0 +1,65 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Wed, 7 Dec 2011 07:15:52 -0800
Subject: [PATCH 28/77] Staging: hv: storvsc: Fix a bug in
create_bounce_buffer()
commit 6e8087a4fae41ae1518babbf1ef46f105d702bfd upstream.
Set the length field of the scatter gather elements correctly when we create
the bounce buffer. When we use the bounce buffer for a "write" operation,
the act of copying to the bounce buffer, correctly deals with this issue.
However, on the "read" side, the current code was not correctly setting
the buffer length. Fix this bug. Note that when we copy from the bounce
buffer (for the read case), the amount we copy is controlled by the original
scatter gather list given to the driver.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reported-by: Dadok Milan <dadok@kvados.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/hv/storvsc_drv.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 18f8771..eb853f7 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -893,12 +893,14 @@ static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
unsigned int sg_count,
- unsigned int len)
+ unsigned int len,
+ int write)
{
int i;
int num_pages;
struct scatterlist *bounce_sgl;
struct page *page_buf;
+ unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
@@ -910,7 +912,7 @@ static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
page_buf = alloc_page(GFP_ATOMIC);
if (!page_buf)
goto cleanup;
- sg_set_page(&bounce_sgl[i], page_buf, 0, 0);
+ sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
}
return bounce_sgl;
@@ -1348,7 +1350,8 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
cmd_request->bounce_sgl =
create_bounce_buffer(sgl, scsi_sg_count(scmnd),
- scsi_bufflen(scmnd));
+ scsi_bufflen(scmnd),
+ vm_srb->data_in);
if (!cmd_request->bounce_sgl) {
scmnd->host_scribble = NULL;
mempool_free(cmd_request,
--
1.7.9.5

View File

@ -0,0 +1,131 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Fri, 2 Dec 2011 11:56:25 -0800
Subject: [PATCH 29/77] net/hyperv: Fix the stop/wake queue mechanism
commit 1d06825b0ede541f63b5577435abd2fc649a9b5e upstream.
The ring buffer is only used to pass meta data for outbound packets. The
actual payload is accessed by DMA from the host. So the stop/wake queue
mechanism based on counting and comparing number of pages sent v.s. number
of pages in the ring buffer is wrong. Also, there is a race condition in
the stop/wake queue calls, which can stop xmit queue forever.
The new stop/wake queue mechanism is based on the actual bytes used by
outbound packets in the ring buffer. The check for number of outstanding
sends after stop queue prevents the race condition that can cause wake
queue happening earlier than stop queue.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reported-by: Long Li <longli@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/net/hyperv/netvsc.c | 14 +++++++++++---
drivers/net/hyperv/netvsc_drv.c | 24 +-----------------------
2 files changed, 12 insertions(+), 26 deletions(-)
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 4a807e4..b6ac152 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -435,6 +435,9 @@ static void netvsc_send_completion(struct hv_device *device,
nvsc_packet->completion.send.send_completion_ctx);
atomic_dec(&net_device->num_outstanding_sends);
+
+ if (netif_queue_stopped(ndev))
+ netif_wake_queue(ndev);
} else {
netdev_err(ndev, "Unknown send completion packet type- "
"%d received!!\n", nvsp_packet->hdr.msg_type);
@@ -485,11 +488,16 @@ int netvsc_send(struct hv_device *device,
}
- if (ret != 0)
+ if (ret == 0) {
+ atomic_inc(&net_device->num_outstanding_sends);
+ } else if (ret == -EAGAIN) {
+ netif_stop_queue(ndev);
+ if (atomic_read(&net_device->num_outstanding_sends) < 1)
+ netif_wake_queue(ndev);
+ } else {
netdev_err(ndev, "Unable to send packet %p ret %d\n",
packet, ret);
- else
- atomic_inc(&net_device->num_outstanding_sends);
+ }
return ret;
}
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index b69c3a4..7da85eb 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -43,15 +43,10 @@
struct net_device_context {
/* point back to our device context */
struct hv_device *device_ctx;
- atomic_t avail;
struct delayed_work dwork;
};
-#define PACKET_PAGES_LOWATER 8
-/* Need this many pages to handle worst case fragmented packet */
-#define PACKET_PAGES_HIWATER (MAX_SKB_FRAGS + 2)
-
static int ring_size = 128;
module_param(ring_size, int, S_IRUGO);
MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
@@ -144,18 +139,8 @@ static void netvsc_xmit_completion(void *context)
kfree(packet);
- if (skb) {
- struct net_device *net = skb->dev;
- struct net_device_context *net_device_ctx = netdev_priv(net);
- unsigned int num_pages = skb_shinfo(skb)->nr_frags + 2;
-
+ if (skb)
dev_kfree_skb_any(skb);
-
- atomic_add(num_pages, &net_device_ctx->avail);
- if (atomic_read(&net_device_ctx->avail) >=
- PACKET_PAGES_HIWATER)
- netif_wake_queue(net);
- }
}
static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
@@ -167,8 +152,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
/* Add 1 for skb->data and additional one for RNDIS */
num_pages = skb_shinfo(skb)->nr_frags + 1 + 1;
- if (num_pages > atomic_read(&net_device_ctx->avail))
- return NETDEV_TX_BUSY;
/* Allocate a netvsc packet based on # of frags. */
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
@@ -218,10 +201,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
if (ret == 0) {
net->stats.tx_bytes += skb->len;
net->stats.tx_packets++;
-
- atomic_sub(num_pages, &net_device_ctx->avail);
- if (atomic_read(&net_device_ctx->avail) < PACKET_PAGES_LOWATER)
- netif_stop_queue(net);
} else {
/* we are shutting down or bus overloaded, just drop packet */
net->stats.tx_dropped++;
@@ -391,7 +370,6 @@ static int netvsc_probe(struct hv_device *dev,
net_device_ctx = netdev_priv(net);
net_device_ctx->device_ctx = dev;
- atomic_set(&net_device_ctx->avail, ring_size);
hv_set_drvdata(dev, net);
INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp);
--
1.7.9.5

View File

@ -0,0 +1,31 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Mon, 12 Dec 2011 09:29:16 -0800
Subject: [PATCH 30/77] Drivers: hv: Fix a memory leak
commit 8b8ee6753154dd6cfe397e0d29fe7f90a8adb50b upstream.
There was a memory leak in a failure path in vmbus_process_offer().
Fix it.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/hv/channel_mgmt.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 12b85ff..b91af50 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -287,6 +287,7 @@ static void vmbus_process_offer(struct work_struct *work)
spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
list_del(&newchannel->listentry);
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ kfree(newchannel->device_obj);
free_channel(newchannel);
} else {
--
1.7.9.5

View File

@ -0,0 +1,94 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Mon, 12 Dec 2011 09:29:17 -0800
Subject: [PATCH 31/77] Drivers: hv: Make the vmbus driver unloadable
commit 93e5bd06a95343c701361fa009cdc5a653d6ec8e upstream.
It turns out that the vmbus driver can be made unloadable. Make it
unloadable.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/hv/channel_mgmt.c | 11 +++++++++++
drivers/hv/hv.c | 3 +++
drivers/hv/hyperv_vmbus.h | 1 +
drivers/hv/vmbus_drv.c | 11 +++++++++++
4 files changed, 26 insertions(+)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index b91af50..36484db 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -223,6 +223,17 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
vmbus_device_unregister(channel->device_obj);
}
+void vmbus_free_channels(void)
+{
+ struct vmbus_channel *channel;
+
+ list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
+ vmbus_device_unregister(channel->device_obj);
+ kfree(channel->device_obj);
+ free_channel(channel);
+ }
+}
+
/*
* vmbus_process_offer - Process the offer by creating a channel/device
* associated with this offer
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 0fb100e..f8a77d0 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -237,6 +237,9 @@ void hv_cleanup(void)
{
union hv_x64_msr_hypercall_contents hypercall_msr;
+ /* Reset our OS id */
+ wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
+
kfree(hv_context.signal_event_buffer);
hv_context.signal_event_buffer = NULL;
hv_context.signal_event_param = NULL;
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 0aee112..6d7d286 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -611,6 +611,7 @@ void vmbus_device_unregister(struct hv_device *device_obj);
struct vmbus_channel *relid2channel(u32 relid);
+void vmbus_free_channels(void);
/* Connection interface */
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 05168eb..a220e57 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -792,8 +792,19 @@ cleanup:
return ret;
}
+static void __exit vmbus_exit(void)
+{
+
+ free_irq(irq, hv_acpi_dev);
+ vmbus_free_channels();
+ bus_unregister(&hv_bus);
+ hv_cleanup();
+ acpi_bus_unregister_driver(&vmbus_acpi_driver);
+}
+
MODULE_LICENSE("GPL");
MODULE_VERSION(HV_DRV_VERSION);
subsys_initcall(hv_acpi_init);
+module_exit(vmbus_exit);
--
1.7.9.5

View File

@ -0,0 +1,35 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Mon, 12 Dec 2011 09:29:18 -0800
Subject: [PATCH 32/77] Drivers: hv: Get rid of an unnecessary check in hv.c
commit 175cad266774d09c57a62c65baa6b4e1edafdf3a upstream.
In preparation for eventually supporting kexec in Linux VMs on Hyper-V,
get rid of an unnecessary check in hv_init().
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/hv/hv.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index f8a77d0..12aa97f 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -164,11 +164,6 @@ int hv_init(void)
max_leaf = query_hypervisor_info();
- rdmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
-
- if (hv_context.guestid != 0)
- goto cleanup;
-
/* Write our OS info */
wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
hv_context.guestid = HV_LINUX_GUEST_ID;
--
1.7.9.5

View File

@ -0,0 +1,221 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Thu, 15 Dec 2011 13:45:15 -0800
Subject: [PATCH 33/77] net/hyperv: Remove unnecessary kmap_atomic in netvsc
driver
commit 453263421f88b4a7e508c2e7b639c97e99c5b118 upstream.
__get_free_pages() doesn't return HI memory, so the memory is always mapped.
kmap_atomic() is not necessary here. This patch removes the kmap_atomic()
calls and related code for locking and page manipulation.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/net/hyperv/hyperv_net.h | 6 ++---
drivers/net/hyperv/netvsc.c | 53 +++----------------------------------
drivers/net/hyperv/netvsc_drv.c | 22 ++-------------
drivers/net/hyperv/rndis_filter.c | 21 ++-------------
4 files changed, 10 insertions(+), 92 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 49b131f..ff1b520 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -39,9 +39,6 @@ struct xferpage_packet {
u32 count;
};
-/* The number of pages which are enough to cover jumbo frame buffer. */
-#define NETVSC_PACKET_MAXPAGE 4
-
/*
* Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame
* within the RNDIS
@@ -77,8 +74,9 @@ struct hv_netvsc_packet {
u32 total_data_buflen;
/* Points to the send/receive buffer where the ethernet frame is */
+ void *data;
u32 page_buf_cnt;
- struct hv_page_buffer page_buf[NETVSC_PACKET_MAXPAGE];
+ struct hv_page_buffer page_buf[0];
};
struct netvsc_device_info {
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index b6ac152..bab627f 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -603,12 +603,10 @@ static void netvsc_receive(struct hv_device *device,
struct vmtransfer_page_packet_header *vmxferpage_packet;
struct nvsp_message *nvsp_packet;
struct hv_netvsc_packet *netvsc_packet = NULL;
- unsigned long start;
- unsigned long end, end_virtual;
/* struct netvsc_driver *netvscDriver; */
struct xferpage_packet *xferpage_packet = NULL;
- int i, j;
- int count = 0, bytes_remain = 0;
+ int i;
+ int count = 0;
unsigned long flags;
struct net_device *ndev;
@@ -717,53 +715,10 @@ static void netvsc_receive(struct hv_device *device,
netvsc_packet->completion.recv.recv_completion_tid =
vmxferpage_packet->d.trans_id;
+ netvsc_packet->data = (void *)((unsigned long)net_device->
+ recv_buf + vmxferpage_packet->ranges[i].byte_offset);
netvsc_packet->total_data_buflen =
vmxferpage_packet->ranges[i].byte_count;
- netvsc_packet->page_buf_cnt = 1;
-
- netvsc_packet->page_buf[0].len =
- vmxferpage_packet->ranges[i].byte_count;
-
- start = virt_to_phys((void *)((unsigned long)net_device->
- recv_buf + vmxferpage_packet->ranges[i].byte_offset));
-
- netvsc_packet->page_buf[0].pfn = start >> PAGE_SHIFT;
- end_virtual = (unsigned long)net_device->recv_buf
- + vmxferpage_packet->ranges[i].byte_offset
- + vmxferpage_packet->ranges[i].byte_count - 1;
- end = virt_to_phys((void *)end_virtual);
-
- /* Calculate the page relative offset */
- netvsc_packet->page_buf[0].offset =
- vmxferpage_packet->ranges[i].byte_offset &
- (PAGE_SIZE - 1);
- if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) {
- /* Handle frame across multiple pages: */
- netvsc_packet->page_buf[0].len =
- (netvsc_packet->page_buf[0].pfn <<
- PAGE_SHIFT)
- + PAGE_SIZE - start;
- bytes_remain = netvsc_packet->total_data_buflen -
- netvsc_packet->page_buf[0].len;
- for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) {
- netvsc_packet->page_buf[j].offset = 0;
- if (bytes_remain <= PAGE_SIZE) {
- netvsc_packet->page_buf[j].len =
- bytes_remain;
- bytes_remain = 0;
- } else {
- netvsc_packet->page_buf[j].len =
- PAGE_SIZE;
- bytes_remain -= PAGE_SIZE;
- }
- netvsc_packet->page_buf[j].pfn =
- virt_to_phys((void *)(end_virtual -
- bytes_remain)) >> PAGE_SHIFT;
- netvsc_packet->page_buf_cnt++;
- if (bytes_remain == 0)
- break;
- }
- }
/* Pass it to the upper layer */
rndis_filter_receive(device, netvsc_packet);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 7da85eb..b7cbd12 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -251,9 +251,6 @@ int netvsc_recv_callback(struct hv_device *device_obj,
{
struct net_device *net = dev_get_drvdata(&device_obj->device);
struct sk_buff *skb;
- void *data;
- int i;
- unsigned long flags;
struct netvsc_device *net_device;
net_device = hv_get_drvdata(device_obj);
@@ -272,27 +269,12 @@ int netvsc_recv_callback(struct hv_device *device_obj,
return 0;
}
- /* for kmap_atomic */
- local_irq_save(flags);
-
/*
* Copy to skb. This copy is needed here since the memory pointed by
* hv_netvsc_packet cannot be deallocated
*/
- for (i = 0; i < packet->page_buf_cnt; i++) {
- data = kmap_atomic(pfn_to_page(packet->page_buf[i].pfn),
- KM_IRQ1);
- data = (void *)(unsigned long)data +
- packet->page_buf[i].offset;
-
- memcpy(skb_put(skb, packet->page_buf[i].len), data,
- packet->page_buf[i].len);
-
- kunmap_atomic((void *)((unsigned long)data -
- packet->page_buf[i].offset), KM_IRQ1);
- }
-
- local_irq_restore(flags);
+ memcpy(skb_put(skb, packet->total_data_buflen), packet->data,
+ packet->total_data_buflen);
skb->protocol = eth_type_trans(skb, net);
skb->ip_summed = CHECKSUM_NONE;
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 418e7aa..da181f9 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -309,7 +309,6 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
{
struct rndis_packet *rndis_pkt;
u32 data_offset;
- int i;
rndis_pkt = &msg->msg.pkt;
@@ -322,17 +321,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
pkt->total_data_buflen -= data_offset;
- pkt->page_buf[0].offset += data_offset;
- pkt->page_buf[0].len -= data_offset;
-
- /* Drop the 0th page, if rndis data go beyond page boundary */
- if (pkt->page_buf[0].offset >= PAGE_SIZE) {
- pkt->page_buf[1].offset = pkt->page_buf[0].offset - PAGE_SIZE;
- pkt->page_buf[1].len -= pkt->page_buf[1].offset;
- pkt->page_buf_cnt--;
- for (i = 0; i < pkt->page_buf_cnt; i++)
- pkt->page_buf[i] = pkt->page_buf[i+1];
- }
+ pkt->data = (void *)((unsigned long)pkt->data + data_offset);
pkt->is_data_pkt = true;
@@ -367,11 +356,7 @@ int rndis_filter_receive(struct hv_device *dev,
return -ENODEV;
}
- rndis_hdr = (struct rndis_message *)kmap_atomic(
- pfn_to_page(pkt->page_buf[0].pfn), KM_IRQ0);
-
- rndis_hdr = (void *)((unsigned long)rndis_hdr +
- pkt->page_buf[0].offset);
+ rndis_hdr = pkt->data;
/* Make sure we got a valid rndis message */
if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
@@ -387,8 +372,6 @@ int rndis_filter_receive(struct hv_device *dev,
sizeof(struct rndis_message) :
rndis_hdr->msg_len);
- kunmap_atomic(rndis_hdr - pkt->page_buf[0].offset, KM_IRQ0);
-
dump_rndis_message(dev, &rndis_msg);
switch (rndis_msg.ndis_msg_type) {
--
1.7.9.5

View File

@ -0,0 +1,284 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Thu, 15 Dec 2011 13:45:16 -0800
Subject: [PATCH 34/77] net/hyperv: Add NETVSP protocol version negotiation
commit f157e78de5923dfb209355f3005ce1b5d64f7998 upstream.
Automatically negotiate the highest protocol version mutually recognized by
both host and guest.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/net/hyperv/hyperv_net.h | 101 ++++++++++++++++++++++++++++++++++++---
drivers/net/hyperv/netvsc.c | 82 ++++++++++++++++++++-----------
2 files changed, 149 insertions(+), 34 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index ff1b520..2877670 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -134,8 +134,7 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
#define NVSP_PROTOCOL_VERSION_1 2
-#define NVSP_MIN_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1
-#define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1
+#define NVSP_PROTOCOL_VERSION_2 0x30002
enum {
NVSP_MSG_TYPE_NONE = 0,
@@ -160,11 +159,36 @@ enum {
NVSP_MSG1_TYPE_SEND_RNDIS_PKT,
NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE,
- /*
- * This should be set to the number of messages for the version with
- * the maximum number of messages.
- */
- NVSP_NUM_MSG_PER_VERSION = 9,
+ /* Version 2 messages */
+ NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF,
+ NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF_COMP,
+ NVSP_MSG2_TYPE_REVOKE_CHIMNEY_DELEGATED_BUF,
+
+ NVSP_MSG2_TYPE_RESUME_CHIMNEY_RX_INDICATION,
+
+ NVSP_MSG2_TYPE_TERMINATE_CHIMNEY,
+ NVSP_MSG2_TYPE_TERMINATE_CHIMNEY_COMP,
+
+ NVSP_MSG2_TYPE_INDICATE_CHIMNEY_EVENT,
+
+ NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT,
+ NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT_COMP,
+
+ NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ,
+ NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ_COMP,
+
+ NVSP_MSG2_TYPE_ALLOC_RXBUF,
+ NVSP_MSG2_TYPE_ALLOC_RXBUF_COMP,
+
+ NVSP_MSG2_TYPE_FREE_RXBUF,
+
+ NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT,
+ NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT_COMP,
+
+ NVSP_MSG2_TYPE_SEND_NDIS_CONFIG,
+
+ NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE,
+ NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP,
};
enum {
@@ -175,6 +199,7 @@ enum {
NVSP_STAT_PROTOCOL_TOO_OLD,
NVSP_STAT_INVALID_RNDIS_PKT,
NVSP_STAT_BUSY,
+ NVSP_STAT_PROTOCOL_UNSUPPORTED,
NVSP_STAT_MAX,
};
@@ -359,9 +384,69 @@ union nvsp_1_message_uber {
send_rndis_pkt_complete;
} __packed;
+
+/*
+ * Network VSP protocol version 2 messages:
+ */
+struct nvsp_2_vsc_capability {
+ union {
+ u64 data;
+ struct {
+ u64 vmq:1;
+ u64 chimney:1;
+ u64 sriov:1;
+ u64 ieee8021q:1;
+ u64 correlation_id:1;
+ };
+ };
+} __packed;
+
+struct nvsp_2_send_ndis_config {
+ u32 mtu;
+ u32 reserved;
+ struct nvsp_2_vsc_capability capability;
+} __packed;
+
+/* Allocate receive buffer */
+struct nvsp_2_alloc_rxbuf {
+ /* Allocation ID to match the allocation request and response */
+ u32 alloc_id;
+
+ /* Length of the VM shared memory receive buffer that needs to
+ * be allocated
+ */
+ u32 len;
+} __packed;
+
+/* Allocate receive buffer complete */
+struct nvsp_2_alloc_rxbuf_comp {
+ /* The NDIS_STATUS code for buffer allocation */
+ u32 status;
+
+ u32 alloc_id;
+
+ /* GPADL handle for the allocated receive buffer */
+ u32 gpadl_handle;
+
+ /* Receive buffer ID */
+ u64 recv_buf_id;
+} __packed;
+
+struct nvsp_2_free_rxbuf {
+ u64 recv_buf_id;
+} __packed;
+
+union nvsp_2_message_uber {
+ struct nvsp_2_send_ndis_config send_ndis_config;
+ struct nvsp_2_alloc_rxbuf alloc_rxbuf;
+ struct nvsp_2_alloc_rxbuf_comp alloc_rxbuf_comp;
+ struct nvsp_2_free_rxbuf free_rxbuf;
+} __packed;
+
union nvsp_all_messages {
union nvsp_message_init_uber init_msg;
union nvsp_1_message_uber v1_msg;
+ union nvsp_2_message_uber v2_msg;
} __packed;
/* ALL Messages */
@@ -391,6 +476,8 @@ struct nvsp_message {
struct netvsc_device {
struct hv_device *dev;
+ u32 nvsp_version;
+
atomic_t num_outstanding_sends;
bool destroy;
/*
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index bab627f..46828b4 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -28,6 +28,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
+#include <linux/if_ether.h>
#include "hyperv_net.h"
@@ -260,27 +261,18 @@ exit:
}
-static int netvsc_connect_vsp(struct hv_device *device)
+/* Negotiate NVSP protocol version */
+static int negotiate_nvsp_ver(struct hv_device *device,
+ struct netvsc_device *net_device,
+ struct nvsp_message *init_packet,
+ u32 nvsp_ver)
{
int ret, t;
- struct netvsc_device *net_device;
- struct nvsp_message *init_packet;
- int ndis_version;
- struct net_device *ndev;
-
- net_device = get_outbound_net_device(device);
- if (!net_device)
- return -ENODEV;
- ndev = net_device->ndev;
-
- init_packet = &net_device->channel_init_pkt;
memset(init_packet, 0, sizeof(struct nvsp_message));
init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT;
- init_packet->msg.init_msg.init.min_protocol_ver =
- NVSP_MIN_PROTOCOL_VERSION;
- init_packet->msg.init_msg.init.max_protocol_ver =
- NVSP_MAX_PROTOCOL_VERSION;
+ init_packet->msg.init_msg.init.min_protocol_ver = nvsp_ver;
+ init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver;
/* Send the init request */
ret = vmbus_sendpacket(device->channel, init_packet,
@@ -290,26 +282,62 @@ static int netvsc_connect_vsp(struct hv_device *device)
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0)
- goto cleanup;
+ return ret;
t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ if (t == 0)
+ return -ETIMEDOUT;
if (init_packet->msg.init_msg.init_complete.status !=
- NVSP_STAT_SUCCESS) {
- ret = -EINVAL;
- goto cleanup;
- }
+ NVSP_STAT_SUCCESS)
+ return -EINVAL;
- if (init_packet->msg.init_msg.init_complete.
- negotiated_protocol_ver != NVSP_PROTOCOL_VERSION_1) {
+ if (nvsp_ver != NVSP_PROTOCOL_VERSION_2)
+ return 0;
+
+ /* NVSPv2 only: Send NDIS config */
+ memset(init_packet, 0, sizeof(struct nvsp_message));
+ init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG;
+ init_packet->msg.v2_msg.send_ndis_config.mtu = ETH_DATA_LEN;
+
+ ret = vmbus_sendpacket(device->channel, init_packet,
+ sizeof(struct nvsp_message),
+ (unsigned long)init_packet,
+ VM_PKT_DATA_INBAND, 0);
+
+ return ret;
+}
+
+static int netvsc_connect_vsp(struct hv_device *device)
+{
+ int ret;
+ struct netvsc_device *net_device;
+ struct nvsp_message *init_packet;
+ int ndis_version;
+ struct net_device *ndev;
+
+ net_device = get_outbound_net_device(device);
+ if (!net_device)
+ return -ENODEV;
+ ndev = net_device->ndev;
+
+ init_packet = &net_device->channel_init_pkt;
+
+ /* Negotiate the latest NVSP protocol supported */
+ if (negotiate_nvsp_ver(device, net_device, init_packet,
+ NVSP_PROTOCOL_VERSION_2) == 0) {
+ net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2;
+ } else if (negotiate_nvsp_ver(device, net_device, init_packet,
+ NVSP_PROTOCOL_VERSION_1) == 0) {
+ net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1;
+ } else {
ret = -EPROTO;
goto cleanup;
}
+
+ pr_debug("Negotiated NVSP version:%x\n", net_device->nvsp_version);
+
/* Send the ndis version */
memset(init_packet, 0, sizeof(struct nvsp_message));
--
1.7.9.5

View File

@ -0,0 +1,213 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Thu, 15 Dec 2011 13:45:17 -0800
Subject: [PATCH 35/77] net/hyperv: Add support for jumbo frame up to 64KB
commit 4d447c9a6ebc0142d320f075c5bac6d202a79fd4 upstream.
Allow the user set the MTU up to 65536 for Linux guests running on
Hyper-V 2008 R2 or later.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/net/hyperv/hyperv_net.h | 8 ++---
drivers/net/hyperv/netvsc.c | 6 ++--
drivers/net/hyperv/netvsc_drv.c | 70 ++++++++++++++++++++++++++++++++++-----
include/linux/hyperv.h | 2 +-
4 files changed, 68 insertions(+), 18 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 2877670..dec5836 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -456,12 +456,9 @@ struct nvsp_message {
} __packed;
+#define NETVSC_MTU 65536
-
-/* #define NVSC_MIN_PROTOCOL_VERSION 1 */
-/* #define NVSC_MAX_PROTOCOL_VERSION 1 */
-
-#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024) /* 1MB */
+#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*2) /* 2MB */
#define NETVSC_RECEIVE_BUFFER_ID 0xcafe
@@ -479,6 +476,7 @@ struct netvsc_device {
u32 nvsp_version;
atomic_t num_outstanding_sends;
+ bool start_remove;
bool destroy;
/*
* List of free preallocated hv_netvsc_packet to represent receive
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 46828b4..8965b45 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -42,7 +42,7 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
if (!net_device)
return NULL;
-
+ net_device->start_remove = false;
net_device->destroy = false;
net_device->dev = device;
net_device->ndev = ndev;
@@ -299,7 +299,7 @@ static int negotiate_nvsp_ver(struct hv_device *device,
/* NVSPv2 only: Send NDIS config */
memset(init_packet, 0, sizeof(struct nvsp_message));
init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG;
- init_packet->msg.v2_msg.send_ndis_config.mtu = ETH_DATA_LEN;
+ init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu;
ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
@@ -464,7 +464,7 @@ static void netvsc_send_completion(struct hv_device *device,
atomic_dec(&net_device->num_outstanding_sends);
- if (netif_queue_stopped(ndev))
+ if (netif_queue_stopped(ndev) && !net_device->start_remove)
netif_wake_queue(ndev);
} else {
netdev_err(ndev, "Unknown send completion packet type- "
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index b7cbd12..462d05f 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -148,10 +148,12 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
struct net_device_context *net_device_ctx = netdev_priv(net);
struct hv_netvsc_packet *packet;
int ret;
- unsigned int i, num_pages;
+ unsigned int i, num_pages, npg_data;
- /* Add 1 for skb->data and additional one for RNDIS */
- num_pages = skb_shinfo(skb)->nr_frags + 1 + 1;
+ /* Add multipage for skb->data and additional one for RNDIS */
+ npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1)
+ >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1;
+ num_pages = skb_shinfo(skb)->nr_frags + npg_data + 1;
/* Allocate a netvsc packet based on # of frags. */
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
@@ -174,21 +176,36 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
packet->page_buf_cnt = num_pages;
/* Initialize it from the skb */
- packet->total_data_buflen = skb->len;
+ packet->total_data_buflen = skb->len;
/* Start filling in the page buffers starting after RNDIS buffer. */
packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
packet->page_buf[1].offset
= (unsigned long)skb->data & (PAGE_SIZE - 1);
- packet->page_buf[1].len = skb_headlen(skb);
+ if (npg_data == 1)
+ packet->page_buf[1].len = skb_headlen(skb);
+ else
+ packet->page_buf[1].len = PAGE_SIZE
+ - packet->page_buf[1].offset;
+
+ for (i = 2; i <= npg_data; i++) {
+ packet->page_buf[i].pfn = virt_to_phys(skb->data
+ + PAGE_SIZE * (i-1)) >> PAGE_SHIFT;
+ packet->page_buf[i].offset = 0;
+ packet->page_buf[i].len = PAGE_SIZE;
+ }
+ if (npg_data > 1)
+ packet->page_buf[npg_data].len = (((unsigned long)skb->data
+ + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1;
/* Additional fragments are after SKB data */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
- packet->page_buf[i+2].pfn = page_to_pfn(skb_frag_page(f));
- packet->page_buf[i+2].offset = f->page_offset;
- packet->page_buf[i+2].len = skb_frag_size(f);
+ packet->page_buf[i+npg_data+1].pfn =
+ page_to_pfn(skb_frag_page(f));
+ packet->page_buf[i+npg_data+1].offset = f->page_offset;
+ packet->page_buf[i+npg_data+1].len = skb_frag_size(f);
}
/* Set the completion routine */
@@ -300,6 +317,39 @@ static void netvsc_get_drvinfo(struct net_device *net,
strcpy(info->fw_version, "N/A");
}
+static int netvsc_change_mtu(struct net_device *ndev, int mtu)
+{
+ struct net_device_context *ndevctx = netdev_priv(ndev);
+ struct hv_device *hdev = ndevctx->device_ctx;
+ struct netvsc_device *nvdev = hv_get_drvdata(hdev);
+ struct netvsc_device_info device_info;
+ int limit = ETH_DATA_LEN;
+
+ if (nvdev == NULL || nvdev->destroy)
+ return -ENODEV;
+
+ if (nvdev->nvsp_version == NVSP_PROTOCOL_VERSION_2)
+ limit = NETVSC_MTU;
+
+ if (mtu < 68 || mtu > limit)
+ return -EINVAL;
+
+ nvdev->start_remove = true;
+ cancel_delayed_work_sync(&ndevctx->dwork);
+ netif_stop_queue(ndev);
+ rndis_filter_device_remove(hdev);
+
+ ndev->mtu = mtu;
+
+ ndevctx->device_ctx = hdev;
+ hv_set_drvdata(hdev, ndev);
+ device_info.ring_size = ring_size;
+ rndis_filter_device_add(hdev, &device_info);
+ netif_wake_queue(ndev);
+
+ return 0;
+}
+
static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = netvsc_get_drvinfo,
.get_link = ethtool_op_get_link,
@@ -310,7 +360,7 @@ static const struct net_device_ops device_ops = {
.ndo_stop = netvsc_close,
.ndo_start_xmit = netvsc_start_xmit,
.ndo_set_rx_mode = netvsc_set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
+ .ndo_change_mtu = netvsc_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
};
@@ -403,6 +453,8 @@ static int netvsc_remove(struct hv_device *dev)
return 0;
}
+ net_device->start_remove = true;
+
ndev_ctx = netdev_priv(net);
cancel_delayed_work_sync(&ndev_ctx->dwork);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 12ec328..62b908e 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -35,7 +35,7 @@
#include <linux/mod_devicetable.h>
-#define MAX_PAGE_BUFFER_COUNT 16
+#define MAX_PAGE_BUFFER_COUNT 18
#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
#pragma pack(push, 1)
--
1.7.9.5

View File

@ -0,0 +1,47 @@
From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
Date: Tue, 24 Jan 2012 10:21:28 +0000
Subject: [PATCH 36/77] net/hyperv: fix possible memory leak in
do_set_multicast()
commit c11bf1c8baff170fa478adc04964da519d160e62 upstream.
do_set_multicast() may not free the memory malloc in
netvsc_set_multicast_list().
Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/netvsc_drv.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 462d05f..1a1ca6c 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -68,11 +68,11 @@ static void do_set_multicast(struct work_struct *w)
nvdev = hv_get_drvdata(ndevctx->device_ctx);
if (nvdev == NULL)
- return;
+ goto out;
rdev = nvdev->extension;
if (rdev == NULL)
- return;
+ goto out;
if (net->flags & IFF_PROMISC)
rndis_filter_set_packet_filter(rdev,
@@ -83,6 +83,7 @@ static void do_set_multicast(struct work_struct *w)
NDIS_PACKET_TYPE_ALL_MULTICAST |
NDIS_PACKET_TYPE_DIRECTED);
+out:
kfree(w);
}
--
1.7.9.5

View File

@ -0,0 +1,127 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Sun, 8 Jan 2012 10:12:18 -0800
Subject: [PATCH 37/77] drivers: hv: Get rid of some unnecessary code
commit 2897a563a55442379e5e59ec68c229a7f27fb7c6 upstream.
The current code unnecessarily limits the number of offers we handle.
Get rid of this limitation. As part of this cleanup, also get rid of an
unused define - MAX_MSG_TYPES.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/hv/channel_mgmt.c | 87 ---------------------------------------------
1 file changed, 87 deletions(-)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 36484db..9ffbfc5 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -37,81 +37,6 @@ struct vmbus_channel_message_table_entry {
void (*message_handler)(struct vmbus_channel_message_header *msg);
};
-#define MAX_MSG_TYPES 4
-#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 8
-
-static const uuid_le
- supported_device_classes[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
- /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
- /* Storage - SCSI */
- {
- .b = {
- 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
- 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
- }
- },
-
- /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
- /* Network */
- {
- .b = {
- 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
- 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
- }
- },
-
- /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
- /* Input */
- {
- .b = {
- 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
- 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
- }
- },
-
- /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
- /* IDE */
- {
- .b = {
- 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
- 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
- }
- },
- /* 0E0B6031-5213-4934-818B-38D90CED39DB */
- /* Shutdown */
- {
- .b = {
- 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
- 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
- }
- },
- /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
- /* TimeSync */
- {
- .b = {
- 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
- 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
- }
- },
- /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
- /* Heartbeat */
- {
- .b = {
- 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
- 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
- }
- },
- /* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
- /* KVP */
- {
- .b = {
- 0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
- 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6
- }
- },
-
-};
-
/**
* vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
@@ -321,20 +246,8 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
struct vmbus_channel *newchannel;
uuid_le *guidtype;
uuid_le *guidinstance;
- int i;
- int fsupported = 0;
offer = (struct vmbus_channel_offer_channel *)hdr;
- for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
- if (!uuid_le_cmp(offer->offer.if_type,
- supported_device_classes[i])) {
- fsupported = 1;
- break;
- }
- }
-
- if (!fsupported)
- return;
guidtype = &offer->offer.if_type;
guidinstance = &offer->offer.if_instance;
--
1.7.9.5

View File

@ -0,0 +1,32 @@
From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
Date: Sun, 29 Jan 2012 22:14:02 +0000
Subject: [PATCH 38/77] net/hyperv: rx_bytes should account the ether header
size
commit 48c3883999cb06246911e29356d194f96f1c75ef upstream.
skb->len after call eth_type_trans() does not include the ether
header size, but rx_bytes should account it.
Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/netvsc_drv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 1a1ca6c..9dccc7a 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -298,7 +298,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
skb->ip_summed = CHECKSUM_NONE;
net->stats.rx_packets++;
- net->stats.rx_bytes += skb->len;
+ net->stats.rx_bytes += packet->total_data_buflen;
/*
* Pass the skb back up. Network stack will deallocate the skb when it
--
1.7.9.5

View File

@ -0,0 +1,32 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Wed, 18 Jan 2012 08:57:14 -0800
Subject: [PATCH 39/77] HID: hyperv: Properly disconnect the input device
commit c1c454b8691cc95aa83f19273ed7845914c70e83 upstream.
When we unload the mouse driver, properly disconnect the input device.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reported-by: Fuzhou Chen <fuzhouch@microsoft.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
drivers/hid/hid-hyperv.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 0c33ae9..4066324 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -548,6 +548,7 @@ static int mousevsc_remove(struct hv_device *dev)
struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
vmbus_close(dev->channel);
+ hid_hw_stop(input_dev->hid_device);
hid_destroy_device(input_dev->hid_device);
mousevsc_free_device(input_dev);
--
1.7.9.5

View File

@ -0,0 +1,68 @@
From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
Date: Wed, 1 Feb 2012 20:17:23 +0000
Subject: [PATCH 40/77] net/hyperv: fix the issue that large packets be
dropped under bridge
commit 4b8a8bc9249f144803d840f2f7608ee9bbf1ea51 upstream.
The packets with size larger than 1452 will be dropped by bridge
which with two hyperv netdevice ports. This cause by hyperv netvsc
driver always copy the trailer padding to the data packet, and then
the skb received from netdevice may include wrong skb->len (20 bytes
larger than the real size normally). The captured packet may like
this:
Ethernet II, Src: Microsof_00:00:07 (00:15:5d:00:00:07),
Dst: HewlettP_00:00:4e (00:1f:29:00:00:4e)
Destination: HewlettP_e6:00:4e (00:1f:29:00:00:4e)
Source: Microsof_f6:6d:07 (00:15:5d:f6:6d:07)
Type: IP (0x0800)
Trailer: 1415161718191A1B1C1D1E1F20212223
Frame check sequence: 0x24252627 [incorrect, should be 0x7c2e5a5e]
The following command help to reproduction it, and the ping ICMP
packets will be dropped by bridge.
$ ping ip -s 1453
This patch fixed it by removing the trailer padding from the data
packet.
Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/rndis_filter.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index da181f9..dc2e384 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -321,6 +321,25 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
pkt->total_data_buflen -= data_offset;
+
+ /*
+ * Make sure we got a valid RNDIS message, now total_data_buflen
+ * should be the data packet size plus the trailer padding size
+ */
+ if (pkt->total_data_buflen < rndis_pkt->data_len) {
+ netdev_err(dev->net_dev->ndev, "rndis message buffer "
+ "overflow detected (got %u, min %u)"
+ "...dropping this message!\n",
+ pkt->total_data_buflen, rndis_pkt->data_len);
+ return;
+ }
+
+ /*
+ * Remove the rndis trailer padding from rndis packet message
+ * rndis_pkt->data_len tell us the real data length, we only copy
+ * the data packet to the stack, without the rndis trailer padding
+ */
+ pkt->total_data_buflen = rndis_pkt->data_len;
pkt->data = (void *)((unsigned long)pkt->data + data_offset);
pkt->is_data_pkt = true;
--
1.7.9.5

View File

@ -0,0 +1,60 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Thu, 2 Feb 2012 07:17:59 +0000
Subject: [PATCH 41/77] net/hyperv: Use netif_tx_disable() instead of
netif_stop_queue() when necessary
commit 0a282538cc1977655004cdb2eb25dd2b63f20637 upstream.
For code path not on the xmit, use netif_tx_disable() instead of
netif_stop_queue() to ensure other CPUs are not doing xmit.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/netvsc_drv.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 9dccc7a..69193fc 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -123,7 +123,7 @@ static int netvsc_close(struct net_device *net)
struct hv_device *device_obj = net_device_ctx->device_ctx;
int ret;
- netif_stop_queue(net);
+ netif_tx_disable(net);
ret = rndis_filter_close(device_obj);
if (ret != 0)
@@ -256,7 +256,7 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
} else {
netif_carrier_off(net);
- netif_stop_queue(net);
+ netif_tx_disable(net);
}
}
@@ -337,7 +337,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
nvdev->start_remove = true;
cancel_delayed_work_sync(&ndevctx->dwork);
- netif_stop_queue(ndev);
+ netif_tx_disable(ndev);
rndis_filter_device_remove(hdev);
ndev->mtu = mtu;
@@ -460,7 +460,7 @@ static int netvsc_remove(struct hv_device *dev)
cancel_delayed_work_sync(&ndev_ctx->dwork);
/* Stop outbound asap */
- netif_stop_queue(net);
+ netif_tx_disable(net);
unregister_netdev(net);
--
1.7.9.5

View File

@ -0,0 +1,87 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Thu, 2 Feb 2012 07:18:00 +0000
Subject: [PATCH 42/77] net/hyperv: Fix the page buffer when an RNDIS message
goes beyond page boundary
commit c31c151b1c4a29da4dc92212aa8648fb4f8557b9 upstream.
There is a possible data corruption if an RNDIS message goes beyond page
boundary in the sending code path. This patch fixes the problem.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/netvsc_drv.c | 8 ++++----
drivers/net/hyperv/rndis_filter.c | 13 +++++++++++++
include/linux/hyperv.h | 2 +-
3 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 69193fc..466c58a 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -151,10 +151,10 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
int ret;
unsigned int i, num_pages, npg_data;
- /* Add multipage for skb->data and additional one for RNDIS */
+ /* Add multipages for skb->data and additional 2 for RNDIS */
npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1)
>> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1;
- num_pages = skb_shinfo(skb)->nr_frags + npg_data + 1;
+ num_pages = skb_shinfo(skb)->nr_frags + npg_data + 2;
/* Allocate a netvsc packet based on # of frags. */
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
@@ -173,8 +173,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
sizeof(struct hv_netvsc_packet) +
(num_pages * sizeof(struct hv_page_buffer));
- /* Setup the rndis header */
- packet->page_buf_cnt = num_pages;
+ /* If the rndis msg goes beyond 1 page, we will add 1 later */
+ packet->page_buf_cnt = num_pages - 1;
/* Initialize it from the skb */
packet->total_data_buflen = skb->len;
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index dc2e384..133b7fb 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -797,6 +797,19 @@ int rndis_filter_send(struct hv_device *dev,
(unsigned long)rndisMessage & (PAGE_SIZE-1);
pkt->page_buf[0].len = rndisMessageSize;
+ /* Add one page_buf if the rndis msg goes beyond page boundary */
+ if (pkt->page_buf[0].offset + rndisMessageSize > PAGE_SIZE) {
+ int i;
+ for (i = pkt->page_buf_cnt; i > 1; i--)
+ pkt->page_buf[i] = pkt->page_buf[i-1];
+ pkt->page_buf_cnt++;
+ pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset;
+ pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong)
+ rndisMessage + pkt->page_buf[0].len)) >> PAGE_SHIFT;
+ pkt->page_buf[1].offset = 0;
+ pkt->page_buf[1].len = rndisMessageSize - pkt->page_buf[0].len;
+ }
+
/* Save the packet send completion and context */
filterPacket->completion = pkt->completion.send.send_completion;
filterPacket->completion_ctx =
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 62b908e..0ae065a 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -35,7 +35,7 @@
#include <linux/mod_devicetable.h>
-#define MAX_PAGE_BUFFER_COUNT 18
+#define MAX_PAGE_BUFFER_COUNT 19
#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
#pragma pack(push, 1)
--
1.7.9.5

View File

@ -0,0 +1,68 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Fri, 27 Jan 2012 15:55:57 -0800
Subject: [PATCH 43/77] drivers: hv: kvp: Add/cleanup connector defines
commit 4f03a2c934894f30a64d397df8c7c4de129c5b30 upstream.
The current KVP code carries some private connector related defines.
Update connector.h to have all the KVP defines. As part of this patch
get rid of some unused defines.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hv/hv_kvp.h | 3 ---
include/linux/connector.h | 1 +
tools/hv/hv_kvp_daemon.c | 4 ----
3 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/drivers/hv/hv_kvp.h b/drivers/hv/hv_kvp.h
index 9b765d7..c2c5bba 100644
--- a/drivers/hv/hv_kvp.h
+++ b/drivers/hv/hv_kvp.h
@@ -107,9 +107,6 @@
* the KVP user-mode component.
*/
-#define CN_KVP_VAL 0x1 /* This supports queries from the kernel */
-#define CN_KVP_USER_VAL 0x2 /* This supports queries from the user */
-
enum hv_ku_op {
KVP_REGISTER = 0, /* Register the user mode component */
KVP_KERNEL_GET, /* Kernel is requesting the value */
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 3c9c54f..7638407 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -43,6 +43,7 @@
#define CN_IDX_DRBD 0x8
#define CN_VAL_DRBD 0x1
#define CN_KVP_IDX 0x9 /* HyperV KVP */
+#define CN_KVP_VAL 0x1 /* queries from the kernel */
#define CN_NETLINK_USERS 10 /* Highest index + 1 */
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 11224ed..2b6a2d9 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -40,15 +40,11 @@
#include <syslog.h>
/*
- * KYS: TODO. Need to register these in the kernel.
*
* The following definitions are shared with the in-kernel component; do not
* change any of this without making the corresponding changes in
* the KVP kernel component.
*/
-#define CN_KVP_IDX 0x9 /* MSFT KVP functionality */
-#define CN_KVP_VAL 0x1 /* This supports queries from the kernel */
-#define CN_KVP_USER_VAL 0x2 /* This supports queries from the user */
/*
* KVP protocol: The user mode component first registers with the
--
1.7.9.5

View File

@ -0,0 +1,420 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Fri, 27 Jan 2012 15:55:58 -0800
Subject: [PATCH 44/77] drivers: hv: kvp: Move the contents of hv_kvp.h to
hyperv.h
commit 2939437ce8f2de07237eb2bcce29b6a699bfe799 upstream.
In preparation for consolidating all KVP related defines into a single header file
that both the kernel and user level components can use, move the contents of
hv_kvp.h into hyperv.h.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hv/hv_kvp.c | 2 -
drivers/hv/hv_kvp.h | 181 ------------------------------------------------
drivers/hv/hv_util.c | 3 -
include/linux/hyperv.h | 165 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 165 insertions(+), 186 deletions(-)
delete mode 100644 drivers/hv/hv_kvp.h
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 0e8343f..4a6971e 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -28,8 +28,6 @@
#include <linux/workqueue.h>
#include <linux/hyperv.h>
-#include "hv_kvp.h"
-
/*
diff --git a/drivers/hv/hv_kvp.h b/drivers/hv/hv_kvp.h
deleted file mode 100644
index c2c5bba..0000000
--- a/drivers/hv/hv_kvp.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * An implementation of HyperV key value pair (KVP) functionality for Linux.
- *
- *
- * Copyright (C) 2010, Novell, Inc.
- * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
- * This program 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-#ifndef _KVP_H
-#define _KVP_H_
-
-/*
- * Maximum value size - used for both key names and value data, and includes
- * any applicable NULL terminators.
- *
- * Note: This limit is somewhat arbitrary, but falls easily within what is
- * supported for all native guests (back to Win 2000) and what is reasonable
- * for the IC KVP exchange functionality. Note that Windows Me/98/95 are
- * limited to 255 character key names.
- *
- * MSDN recommends not storing data values larger than 2048 bytes in the
- * registry.
- *
- * Note: This value is used in defining the KVP exchange message - this value
- * cannot be modified without affecting the message size and compatibility.
- */
-
-/*
- * bytes, including any null terminators
- */
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048)
-
-
-/*
- * Maximum key size - the registry limit for the length of an entry name
- * is 256 characters, including the null terminator
- */
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512)
-
-/*
- * In Linux, we implement the KVP functionality in two components:
- * 1) The kernel component which is packaged as part of the hv_utils driver
- * is responsible for communicating with the host and responsible for
- * implementing the host/guest protocol. 2) A user level daemon that is
- * responsible for data gathering.
- *
- * Host/Guest Protocol: The host iterates over an index and expects the guest
- * to assign a key name to the index and also return the value corresponding to
- * the key. The host will have atmost one KVP transaction outstanding at any
- * given point in time. The host side iteration stops when the guest returns
- * an error. Microsoft has specified the following mapping of key names to
- * host specified index:
- *
- * Index Key Name
- * 0 FullyQualifiedDomainName
- * 1 IntegrationServicesVersion
- * 2 NetworkAddressIPv4
- * 3 NetworkAddressIPv6
- * 4 OSBuildNumber
- * 5 OSName
- * 6 OSMajorVersion
- * 7 OSMinorVersion
- * 8 OSVersion
- * 9 ProcessorArchitecture
- *
- * The Windows host expects the Key Name and Key Value to be encoded in utf16.
- *
- * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
- * data gathering functionality in a user mode daemon. The user level daemon
- * is also responsible for binding the key name to the index as well. The
- * kernel and user-level daemon communicate using a connector channel.
- *
- * The user mode component first registers with the
- * the kernel component. Subsequently, the kernel component requests, data
- * for the specified keys. In response to this message the user mode component
- * fills in the value corresponding to the specified key. We overload the
- * sequence field in the cn_msg header to define our KVP message types.
- *
- *
- * The kernel component simply acts as a conduit for communication between the
- * Windows host and the user-level daemon. The kernel component passes up the
- * index received from the Host to the user-level daemon. If the index is
- * valid (supported), the corresponding key as well as its
- * value (both are strings) is returned. If the index is invalid
- * (not supported), a NULL key string is returned.
- */
-
-/*
- *
- * The following definitions are shared with the user-mode component; do not
- * change any of this without making the corresponding changes in
- * the KVP user-mode component.
- */
-
-enum hv_ku_op {
- KVP_REGISTER = 0, /* Register the user mode component */
- KVP_KERNEL_GET, /* Kernel is requesting the value */
- KVP_KERNEL_SET, /* Kernel is providing the value */
- KVP_USER_GET, /* User is requesting the value */
- KVP_USER_SET /* User is providing the value */
-};
-
-struct hv_ku_msg {
- __u32 kvp_index; /* Key index */
- __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
- __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
-};
-
-
-
-
-#ifdef __KERNEL__
-
-/*
- * Registry value types.
- */
-
-#define REG_SZ 1
-
-enum hv_kvp_exchg_op {
- KVP_OP_GET = 0,
- KVP_OP_SET,
- KVP_OP_DELETE,
- KVP_OP_ENUMERATE,
- KVP_OP_COUNT /* Number of operations, must be last. */
-};
-
-enum hv_kvp_exchg_pool {
- KVP_POOL_EXTERNAL = 0,
- KVP_POOL_GUEST,
- KVP_POOL_AUTO,
- KVP_POOL_AUTO_EXTERNAL,
- KVP_POOL_AUTO_INTERNAL,
- KVP_POOL_COUNT /* Number of pools, must be last. */
-};
-
-struct hv_kvp_hdr {
- u8 operation;
- u8 pool;
-};
-
-struct hv_kvp_exchg_msg_value {
- u32 value_type;
- u32 key_size;
- u32 value_size;
- u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
- u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
-};
-
-struct hv_kvp_msg_enumerate {
- u32 index;
- struct hv_kvp_exchg_msg_value data;
-};
-
-struct hv_kvp_msg {
- struct hv_kvp_hdr kvp_hdr;
- struct hv_kvp_msg_enumerate kvp_data;
-};
-
-int hv_kvp_init(struct hv_util_service *);
-void hv_kvp_deinit(void);
-void hv_kvp_onchannelcallback(void *);
-
-#endif /* __KERNEL__ */
-#endif /* _KVP_H */
-
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 55d58f2..dbb8b8e 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -28,9 +28,6 @@
#include <linux/reboot.h>
#include <linux/hyperv.h>
-#include "hv_kvp.h"
-
-
static void shutdown_onchannelcallback(void *context);
static struct hv_util_service util_shutdown = {
.util_cb = shutdown_onchannelcallback,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 0ae065a..c445ead 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -25,6 +25,166 @@
#ifndef _HYPERV_H
#define _HYPERV_H
+#include <linux/types.h>
+
+/*
+ * An implementation of HyperV key value pair (KVP) functionality for Linux.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ */
+
+/*
+ * Maximum value size - used for both key names and value data, and includes
+ * any applicable NULL terminators.
+ *
+ * Note: This limit is somewhat arbitrary, but falls easily within what is
+ * supported for all native guests (back to Win 2000) and what is reasonable
+ * for the IC KVP exchange functionality. Note that Windows Me/98/95 are
+ * limited to 255 character key names.
+ *
+ * MSDN recommends not storing data values larger than 2048 bytes in the
+ * registry.
+ *
+ * Note: This value is used in defining the KVP exchange message - this value
+ * cannot be modified without affecting the message size and compatibility.
+ */
+
+/*
+ * bytes, including any null terminators
+ */
+#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048)
+
+
+/*
+ * Maximum key size - the registry limit for the length of an entry name
+ * is 256 characters, including the null terminator
+ */
+
+#define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512)
+
+/*
+ * In Linux, we implement the KVP functionality in two components:
+ * 1) The kernel component which is packaged as part of the hv_utils driver
+ * is responsible for communicating with the host and responsible for
+ * implementing the host/guest protocol. 2) A user level daemon that is
+ * responsible for data gathering.
+ *
+ * Host/Guest Protocol: The host iterates over an index and expects the guest
+ * to assign a key name to the index and also return the value corresponding to
+ * the key. The host will have atmost one KVP transaction outstanding at any
+ * given point in time. The host side iteration stops when the guest returns
+ * an error. Microsoft has specified the following mapping of key names to
+ * host specified index:
+ *
+ * Index Key Name
+ * 0 FullyQualifiedDomainName
+ * 1 IntegrationServicesVersion
+ * 2 NetworkAddressIPv4
+ * 3 NetworkAddressIPv6
+ * 4 OSBuildNumber
+ * 5 OSName
+ * 6 OSMajorVersion
+ * 7 OSMinorVersion
+ * 8 OSVersion
+ * 9 ProcessorArchitecture
+ *
+ * The Windows host expects the Key Name and Key Value to be encoded in utf16.
+ *
+ * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
+ * data gathering functionality in a user mode daemon. The user level daemon
+ * is also responsible for binding the key name to the index as well. The
+ * kernel and user-level daemon communicate using a connector channel.
+ *
+ * The user mode component first registers with the
+ * the kernel component. Subsequently, the kernel component requests, data
+ * for the specified keys. In response to this message the user mode component
+ * fills in the value corresponding to the specified key. We overload the
+ * sequence field in the cn_msg header to define our KVP message types.
+ *
+ *
+ * The kernel component simply acts as a conduit for communication between the
+ * Windows host and the user-level daemon. The kernel component passes up the
+ * index received from the Host to the user-level daemon. If the index is
+ * valid (supported), the corresponding key as well as its
+ * value (both are strings) is returned. If the index is invalid
+ * (not supported), a NULL key string is returned.
+ */
+
+/*
+ *
+ * The following definitions are shared with the user-mode component; do not
+ * change any of this without making the corresponding changes in
+ * the KVP user-mode component.
+ */
+
+enum hv_ku_op {
+ KVP_REGISTER = 0, /* Register the user mode component */
+ KVP_KERNEL_GET, /* Kernel is requesting the value */
+ KVP_KERNEL_SET, /* Kernel is providing the value */
+ KVP_USER_GET, /* User is requesting the value */
+ KVP_USER_SET /* User is providing the value */
+};
+
+struct hv_ku_msg {
+ __u32 kvp_index; /* Key index */
+ __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
+ __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
+};
+
+
+
+
+#ifdef __KERNEL__
+
+/*
+ * Registry value types.
+ */
+
+#define REG_SZ 1
+
+enum hv_kvp_exchg_op {
+ KVP_OP_GET = 0,
+ KVP_OP_SET,
+ KVP_OP_DELETE,
+ KVP_OP_ENUMERATE,
+ KVP_OP_COUNT /* Number of operations, must be last. */
+};
+
+enum hv_kvp_exchg_pool {
+ KVP_POOL_EXTERNAL = 0,
+ KVP_POOL_GUEST,
+ KVP_POOL_AUTO,
+ KVP_POOL_AUTO_EXTERNAL,
+ KVP_POOL_AUTO_INTERNAL,
+ KVP_POOL_COUNT /* Number of pools, must be last. */
+};
+
+struct hv_kvp_hdr {
+ u8 operation;
+ u8 pool;
+};
+
+struct hv_kvp_exchg_msg_value {
+ u32 value_type;
+ u32 key_size;
+ u32 value_size;
+ u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+};
+
+struct hv_kvp_msg_enumerate {
+ u32 index;
+ struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg {
+ struct hv_kvp_hdr kvp_hdr;
+ struct hv_kvp_msg_enumerate kvp_data;
+};
+
#include <linux/scatterlist.h>
#include <linux/list.h>
#include <linux/uuid.h>
@@ -870,4 +1030,9 @@ struct hyperv_service_callback {
extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *,
struct icmsg_negotiate *, u8 *);
+int hv_kvp_init(struct hv_util_service *);
+void hv_kvp_deinit(void);
+void hv_kvp_onchannelcallback(void *);
+
+#endif /* __KERNEL__ */
#endif /* _HYPERV_H */
--
1.7.9.5

View File

@ -0,0 +1,140 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Sun, 5 Feb 2012 12:13:08 +0000
Subject: [PATCH 45/77] net/hyperv: Convert camel cased variables in
rndis_filter.c to lower cases
commit 5fccab3b66d53883a97fc65e0c33f3ebf74e8ff9 upstream.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Jesper Juhl <jj@chaosbits.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/rndis_filter.c | 60 ++++++++++++++++++-------------------
1 file changed, 30 insertions(+), 30 deletions(-)
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 133b7fb..a60e5e2 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -758,66 +758,66 @@ int rndis_filter_open(struct hv_device *dev)
int rndis_filter_close(struct hv_device *dev)
{
- struct netvsc_device *netDevice = hv_get_drvdata(dev);
+ struct netvsc_device *nvdev = hv_get_drvdata(dev);
- if (!netDevice)
+ if (!nvdev)
return -EINVAL;
- return rndis_filter_close_device(netDevice->extension);
+ return rndis_filter_close_device(nvdev->extension);
}
int rndis_filter_send(struct hv_device *dev,
struct hv_netvsc_packet *pkt)
{
int ret;
- struct rndis_filter_packet *filterPacket;
- struct rndis_message *rndisMessage;
- struct rndis_packet *rndisPacket;
- u32 rndisMessageSize;
+ struct rndis_filter_packet *filter_pkt;
+ struct rndis_message *rndis_msg;
+ struct rndis_packet *rndis_pkt;
+ u32 rndis_msg_size;
/* Add the rndis header */
- filterPacket = (struct rndis_filter_packet *)pkt->extension;
+ filter_pkt = (struct rndis_filter_packet *)pkt->extension;
- memset(filterPacket, 0, sizeof(struct rndis_filter_packet));
+ memset(filter_pkt, 0, sizeof(struct rndis_filter_packet));
- rndisMessage = &filterPacket->msg;
- rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet);
+ rndis_msg = &filter_pkt->msg;
+ rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
- rndisMessage->ndis_msg_type = REMOTE_NDIS_PACKET_MSG;
- rndisMessage->msg_len = pkt->total_data_buflen +
- rndisMessageSize;
+ rndis_msg->ndis_msg_type = REMOTE_NDIS_PACKET_MSG;
+ rndis_msg->msg_len = pkt->total_data_buflen +
+ rndis_msg_size;
- rndisPacket = &rndisMessage->msg.pkt;
- rndisPacket->data_offset = sizeof(struct rndis_packet);
- rndisPacket->data_len = pkt->total_data_buflen;
+ rndis_pkt = &rndis_msg->msg.pkt;
+ rndis_pkt->data_offset = sizeof(struct rndis_packet);
+ rndis_pkt->data_len = pkt->total_data_buflen;
pkt->is_data_pkt = true;
- pkt->page_buf[0].pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT;
+ pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT;
pkt->page_buf[0].offset =
- (unsigned long)rndisMessage & (PAGE_SIZE-1);
- pkt->page_buf[0].len = rndisMessageSize;
+ (unsigned long)rndis_msg & (PAGE_SIZE-1);
+ pkt->page_buf[0].len = rndis_msg_size;
/* Add one page_buf if the rndis msg goes beyond page boundary */
- if (pkt->page_buf[0].offset + rndisMessageSize > PAGE_SIZE) {
+ if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) {
int i;
for (i = pkt->page_buf_cnt; i > 1; i--)
pkt->page_buf[i] = pkt->page_buf[i-1];
pkt->page_buf_cnt++;
pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset;
pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong)
- rndisMessage + pkt->page_buf[0].len)) >> PAGE_SHIFT;
+ rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT;
pkt->page_buf[1].offset = 0;
- pkt->page_buf[1].len = rndisMessageSize - pkt->page_buf[0].len;
+ pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len;
}
/* Save the packet send completion and context */
- filterPacket->completion = pkt->completion.send.send_completion;
- filterPacket->completion_ctx =
+ filter_pkt->completion = pkt->completion.send.send_completion;
+ filter_pkt->completion_ctx =
pkt->completion.send.send_completion_ctx;
/* Use ours */
pkt->completion.send.send_completion = rndis_filter_send_completion;
- pkt->completion.send.send_completion_ctx = filterPacket;
+ pkt->completion.send.send_completion_ctx = filter_pkt;
ret = netvsc_send(dev, pkt);
if (ret != 0) {
@@ -826,9 +826,9 @@ int rndis_filter_send(struct hv_device *dev,
* above
*/
pkt->completion.send.send_completion =
- filterPacket->completion;
+ filter_pkt->completion;
pkt->completion.send.send_completion_ctx =
- filterPacket->completion_ctx;
+ filter_pkt->completion_ctx;
}
return ret;
@@ -836,10 +836,10 @@ int rndis_filter_send(struct hv_device *dev,
static void rndis_filter_send_completion(void *ctx)
{
- struct rndis_filter_packet *filterPacket = ctx;
+ struct rndis_filter_packet *filter_pkt = ctx;
/* Pass it back to the original handler */
- filterPacket->completion(filterPacket->completion_ctx);
+ filter_pkt->completion(filter_pkt->completion_ctx);
}
--
1.7.9.5

View File

@ -0,0 +1,40 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Sun, 5 Feb 2012 12:13:09 +0000
Subject: [PATCH 46/77] net/hyperv: Correct the assignment in
netvsc_recv_callback()
commit 6f4c44460750dd4eb9926a58ab1ad0ceacef8284 upstream.
The first assignment to variable "net" is wrong, but overridden by the
latter assignments. So the bug isn't manifested.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/netvsc_drv.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 466c58a..0ae7a1a 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -267,13 +267,10 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
int netvsc_recv_callback(struct hv_device *device_obj,
struct hv_netvsc_packet *packet)
{
- struct net_device *net = dev_get_drvdata(&device_obj->device);
+ struct net_device *net;
struct sk_buff *skb;
- struct netvsc_device *net_device;
-
- net_device = hv_get_drvdata(device_obj);
- net = net_device->ndev;
+ net = ((struct netvsc_device *)hv_get_drvdata(device_obj))->ndev;
if (!net) {
netdev_err(net, "got receive callback but net device"
" not initialized yet\n");
--
1.7.9.5

View File

@ -0,0 +1,33 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Sun, 5 Feb 2012 12:13:10 +0000
Subject: [PATCH 47/77] net/hyperv: Remove the unnecessary memset in
rndis_filter_send()
commit bce60806de882cf15ad3a80a51e9878863a8fced upstream.
The memory has been allocated by kzalloc, so it's unnecessary to memset
again.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/rndis_filter.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index a60e5e2..136efd8 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -778,8 +778,6 @@ int rndis_filter_send(struct hv_device *dev,
/* Add the rndis header */
filter_pkt = (struct rndis_filter_packet *)pkt->extension;
- memset(filter_pkt, 0, sizeof(struct rndis_filter_packet));
-
rndis_msg = &filter_pkt->msg;
rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
--
1.7.9.5

View File

@ -0,0 +1,170 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:37:54 -0800
Subject: [PATCH 48/77] Staging: hv: storvsc: Cleanup some comments
commit 09f0355f0612520820ae4b2c342a26e048bef6e7 upstream.
Use consistent format for comments and get rid of some unnecessary
comments.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 57 +++++++++++++++++---------------------
1 file changed, 26 insertions(+), 31 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index eb853f7..1633b03 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -50,8 +50,10 @@ static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE;
module_param(storvsc_ringbuffer_size, int, S_IRUGO);
MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
-/* to alert the user that structure sizes may be mismatched even though the */
-/* protocol versions match. */
+/*
+ * To alert the user that structure sizes may be mismatched even though the
+ * protocol versions match.
+ */
#define REVISION_STRING(REVISION_) #REVISION_
@@ -68,26 +70,36 @@ MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
} \
} while (0)
-/* Major/minor macros. Minor version is in LSB, meaning that earlier flat */
-/* version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). */
+/*
+ * Major/minor macros. Minor version is in LSB, meaning that earlier flat
+ * version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1).
+ */
+
#define VMSTOR_PROTOCOL_MAJOR(VERSION_) (((VERSION_) >> 8) & 0xff)
#define VMSTOR_PROTOCOL_MINOR(VERSION_) (((VERSION_)) & 0xff)
#define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \
(((MINOR_) & 0xff)))
#define VMSTOR_INVALID_PROTOCOL_VERSION (-1)
-/* Version history: */
-/* V1 Beta 0.1 */
-/* V1 RC < 2008/1/31 1.0 */
-/* V1 RC > 2008/1/31 2.0 */
+/*
+ * Version history:
+ * V1 Beta: 0.1
+ * V1 RC < 2008/1/31: 1.0
+ * V1 RC > 2008/1/31: 2.0
+ * Win7: 4.2
+ */
+
#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(4, 2)
-/* This will get replaced with the max transfer length that is possible on */
-/* the host adapter. */
-/* The max transfer length will be published when we offer a vmbus channel. */
+/*
+ * This will get replaced with the max transfer length that is possible on
+ * the host adapter.
+ * The max transfer length will be published when we offer a vmbus channel.
+ */
+
#define MAX_TRANSFER_LENGTH 0x40000
#define DEFAULT_PACKET_SIZE (sizeof(struct vmdata_gpa_direct) + \
sizeof(struct vstor_packet) + \
@@ -211,18 +223,19 @@ struct vstor_packet {
};
} __packed;
-/* Packet flags */
/*
+ * Packet Flags:
+ *
* This flag indicates that the server should send back a completion for this
* packet.
*/
+
#define REQUEST_COMPLETION_FLAG 0x1
/* This is the set of flags that the vsc can set in any packets it sends */
#define VSC_LEGAL_FLAGS (REQUEST_COMPLETION_FLAG)
-/* Defines */
#define STORVSC_MAX_IO_REQUESTS 128
@@ -674,7 +687,6 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
memset(&props, 0, sizeof(struct vmstorage_channel_properties));
- /* Open the channel */
ret = vmbus_open(device->channel,
ring_size,
ring_size,
@@ -1154,9 +1166,6 @@ static int storvsc_host_reset(struct hv_device *device)
}
-/*
- * storvsc_host_reset_handler - Reset the scsi HBA
- */
static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
{
struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
@@ -1166,9 +1175,6 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
}
-/*
- * storvsc_command_completion - Command completion processing
- */
static void storvsc_command_completion(struct hv_storvsc_request *request)
{
struct storvsc_cmd_request *cmd_request =
@@ -1262,9 +1268,6 @@ static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
return allowed;
}
-/*
- * storvsc_queuecommand - Initiate command processing
- */
static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
{
int ret;
@@ -1407,7 +1410,6 @@ retry_request:
return ret;
}
-/* Scsi driver */
static struct scsi_host_template scsi_driver = {
.module = THIS_MODULE,
.name = "storvsc_host_t",
@@ -1448,11 +1450,6 @@ static const struct hv_vmbus_device_id id_table[] = {
MODULE_DEVICE_TABLE(vmbus, id_table);
-
-/*
- * storvsc_probe - Add a new device for this driver
- */
-
static int storvsc_probe(struct hv_device *device,
const struct hv_vmbus_device_id *dev_id)
{
@@ -1542,8 +1539,6 @@ err_out0:
return ret;
}
-/* The one and only one */
-
static struct hv_driver storvsc_drv = {
.name = KBUILD_MODNAME,
.id_table = id_table,
--
1.7.9.5

View File

@ -0,0 +1,80 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:37:55 -0800
Subject: [PATCH 49/77] Staging: hv: storvsc: Cleanup storvsc_probe()
commit 59d22950b274182b006e4071d6690bfbc94d7267 upstream.
Cleanup storvsc_probe(). As part of this cleanup, get rid of
storvsc_get_ide_info() by inlining the necessary code.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 30 ++++++++----------------------
1 file changed, 8 insertions(+), 22 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 1633b03..7561d29 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -791,18 +791,6 @@ static int storvsc_do_io(struct hv_device *device,
return ret;
}
-static void storvsc_get_ide_info(struct hv_device *dev, int *target, int *path)
-{
- *target =
- dev->dev_instance.b[5] << 8 | dev->dev_instance.b[4];
-
- *path =
- dev->dev_instance.b[3] << 24 |
- dev->dev_instance.b[2] << 16 |
- dev->dev_instance.b[1] << 8 | dev->dev_instance.b[0];
-}
-
-
static int storvsc_device_alloc(struct scsi_device *sdevice)
{
struct stor_mem_pools *memp;
@@ -1457,7 +1445,6 @@ static int storvsc_probe(struct hv_device *device,
struct Scsi_Host *host;
struct hv_host_device *host_dev;
bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
- int path = 0;
int target = 0;
struct storvsc_device *stor_device;
@@ -1490,9 +1477,6 @@ static int storvsc_probe(struct hv_device *device,
if (ret)
goto err_out1;
- if (dev_is_ide)
- storvsc_get_ide_info(device, &target, &path);
-
host_dev->path = stor_device->path_id;
host_dev->target = stor_device->target_id;
@@ -1512,12 +1496,14 @@ static int storvsc_probe(struct hv_device *device,
if (!dev_is_ide) {
scsi_scan_host(host);
- return 0;
- }
- ret = scsi_add_device(host, 0, target, 0);
- if (ret) {
- scsi_remove_host(host);
- goto err_out2;
+ } else {
+ target = (device->dev_instance.b[5] << 8 |
+ device->dev_instance.b[4]);
+ ret = scsi_add_device(host, 0, target, 0);
+ if (ret) {
+ scsi_remove_host(host);
+ goto err_out2;
+ }
}
return 0;
--
1.7.9.5

View File

@ -0,0 +1,129 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:37:56 -0800
Subject: [PATCH 50/77] Staging: hv: storvsc: Cleanup storvsc_queuecommand()
commit c77b63b639f52b2e92d0bbaa94f33a78939f3e7c upstream.
Cleanup storvsc_queuecommand(). As part of this cleanup, rename the function to
check if the scsi command can be sent to the host, consolidate error recovery
and get rid of some dead code.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 48 +++++++++++++++++---------------------
1 file changed, 22 insertions(+), 26 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 7561d29..71e50c3 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -1239,13 +1239,16 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
mempool_free(cmd_request, memp->request_mempool);
}
-static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
+static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd)
{
bool allowed = true;
u8 scsi_op = scmnd->cmnd[0];
switch (scsi_op) {
- /* smartd sends this command, which will offline the device */
+ /*
+ * smartd sends this command and the host does not handle
+ * this. So, don't send it.
+ */
case SET_WINDOW:
scmnd->result = ILLEGAL_REQUEST << 16;
allowed = false;
@@ -1270,32 +1273,26 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
struct vmscsi_request *vm_srb;
struct stor_mem_pools *memp = scmnd->device->hostdata;
- if (storvsc_check_scsi_cmd(scmnd) == false) {
+ if (!storvsc_scsi_cmd_ok(scmnd)) {
scmnd->scsi_done(scmnd);
return 0;
}
- /* If retrying, no need to prep the cmd */
- if (scmnd->host_scribble) {
-
- cmd_request =
- (struct storvsc_cmd_request *)scmnd->host_scribble;
-
- goto retry_request;
- }
-
request_size = sizeof(struct storvsc_cmd_request);
cmd_request = mempool_alloc(memp->request_mempool,
GFP_ATOMIC);
+
+ /*
+ * We might be invoked in an interrupt context; hence
+ * mempool_alloc() can fail.
+ */
if (!cmd_request)
return SCSI_MLQUEUE_DEVICE_BUSY;
memset(cmd_request, 0, sizeof(struct storvsc_cmd_request));
/* Setup the cmd request */
- cmd_request->bounce_sgl_count = 0;
- cmd_request->bounce_sgl = NULL;
cmd_request->cmd = scmnd;
scmnd->host_scribble = (unsigned char *)cmd_request;
@@ -1344,11 +1341,8 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
scsi_bufflen(scmnd),
vm_srb->data_in);
if (!cmd_request->bounce_sgl) {
- scmnd->host_scribble = NULL;
- mempool_free(cmd_request,
- memp->request_mempool);
-
- return SCSI_MLQUEUE_HOST_BUSY;
+ ret = SCSI_MLQUEUE_HOST_BUSY;
+ goto queue_error;
}
cmd_request->bounce_sgl_count =
@@ -1377,24 +1371,26 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT;
}
-retry_request:
/* Invokes the vsc to start an IO */
ret = storvsc_do_io(dev, &cmd_request->request);
if (ret == -EAGAIN) {
/* no more space */
- if (cmd_request->bounce_sgl_count)
+ if (cmd_request->bounce_sgl_count) {
destroy_bounce_buffer(cmd_request->bounce_sgl,
cmd_request->bounce_sgl_count);
- mempool_free(cmd_request, memp->request_mempool);
-
- scmnd->host_scribble = NULL;
-
- ret = SCSI_MLQUEUE_DEVICE_BUSY;
+ ret = SCSI_MLQUEUE_DEVICE_BUSY;
+ goto queue_error;
+ }
}
+ return 0;
+
+queue_error:
+ mempool_free(cmd_request, memp->request_mempool);
+ scmnd->host_scribble = NULL;
return ret;
}
--
1.7.9.5

View File

@ -0,0 +1,85 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:37:57 -0800
Subject: [PATCH 51/77] Staging: hv: storvsc: Introduce defines for srb status
codes
commit 160463204f541cea112fd4d68422f297bd98ec51 upstream.
Introduce defines for srb status codes.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 71e50c3..979f25b 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -257,6 +257,16 @@ enum storvsc_request_type {
UNKNOWN_TYPE,
};
+/*
+ * SRB status codes and masks; a subset of the codes used here.
+ */
+
+#define SRB_STATUS_AUTOSENSE_VALID 0x80
+#define SRB_STATUS_INVALID_LUN 0x20
+#define SRB_STATUS_SUCCESS 0x01
+#define SRB_STATUS_ERROR 0x04
+
+
struct hv_storvsc_request {
struct hv_device *device;
@@ -561,7 +571,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) ||
(stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) {
vstor_packet->vm_srb.scsi_status = 0;
- vstor_packet->vm_srb.srb_status = 0x1;
+ vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS;
}
@@ -572,7 +582,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
vstor_packet->vm_srb.sense_info_length;
if (vstor_packet->vm_srb.scsi_status != 0 ||
- vstor_packet->vm_srb.srb_status != 1){
+ vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS){
dev_warn(&device->device,
"cmd 0x%x scsi status 0x%x srb status 0x%x\n",
stor_pkt->vm_srb.cdb[0],
@@ -582,7 +592,8 @@ static void storvsc_on_io_completion(struct hv_device *device,
if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
/* CHECK_CONDITION */
- if (vstor_packet->vm_srb.srb_status & 0x80) {
+ if (vstor_packet->vm_srb.srb_status &
+ SRB_STATUS_AUTOSENSE_VALID) {
/* autosense data available */
dev_warn(&device->device,
"stor pkt %p autosense data valid - len %d\n",
@@ -1191,7 +1202,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
* error recovery strategies would have already been
* deployed on the host side.
*/
- if (vm_srb->srb_status == 0x4)
+ if (vm_srb->srb_status == SRB_STATUS_ERROR)
scmnd->result = DID_TARGET_FAILURE << 16;
else
scmnd->result = vm_srb->scsi_status;
@@ -1199,7 +1210,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
/*
* If the LUN is invalid; remove the device.
*/
- if (vm_srb->srb_status == 0x20) {
+ if (vm_srb->srb_status == SRB_STATUS_INVALID_LUN) {
struct storvsc_device *stor_dev;
struct hv_device *dev = host_dev->dev;
struct Scsi_Host *host;
--
1.7.9.5

View File

@ -0,0 +1,51 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:37:58 -0800
Subject: [PATCH 52/77] Staging: hv: storvsc: Cleanup
storvsc_host_reset_handler()
commit 4b270c8b23722128adedb5694097aea367284ce1 upstream.
Cleanup storvsc_host_reset_handler() by getting rid of storvsc_host_reset().
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 979f25b..8340387 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -1122,8 +1122,11 @@ static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
return 0;
}
-static int storvsc_host_reset(struct hv_device *device)
+static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
{
+ struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
+ struct hv_device *device = host_dev->dev;
+
struct storvsc_device *stor_device;
struct hv_storvsc_request *request;
struct vstor_packet *vstor_packet;
@@ -1165,15 +1168,6 @@ static int storvsc_host_reset(struct hv_device *device)
}
-static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
-{
- struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
- struct hv_device *dev = host_dev->dev;
-
- return storvsc_host_reset(dev);
-}
-
-
static void storvsc_command_completion(struct hv_storvsc_request *request)
{
struct storvsc_cmd_request *cmd_request =
--
1.7.9.5

View File

@ -0,0 +1,65 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:37:59 -0800
Subject: [PATCH 53/77] Staging: hv: storvsc: Move and cleanup
storvsc_remove()
commit ddcbf65e484c3473d3e808718ddb6c8166822c4c upstream.
Relocate the storvsc_remove() function to a different location in the file
and invoke scsi_host_put() only after all the cleanup.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 28 ++++++++++++----------------
1 file changed, 12 insertions(+), 16 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 8340387..e0e471c 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -1083,22 +1083,6 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
return total_copied;
}
-
-static int storvsc_remove(struct hv_device *dev)
-{
- struct storvsc_device *stor_device = hv_get_drvdata(dev);
- struct Scsi_Host *host = stor_device->host;
-
- scsi_remove_host(host);
-
- scsi_host_put(host);
-
- storvsc_dev_remove(dev);
-
- return 0;
-}
-
-
static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
sector_t capacity, int *info)
{
@@ -1526,6 +1510,18 @@ err_out0:
return ret;
}
+static int storvsc_remove(struct hv_device *dev)
+{
+ struct storvsc_device *stor_device = hv_get_drvdata(dev);
+ struct Scsi_Host *host = stor_device->host;
+
+ scsi_remove_host(host);
+ storvsc_dev_remove(dev);
+ scsi_host_put(host);
+
+ return 0;
+}
+
static struct hv_driver storvsc_drv = {
.name = KBUILD_MODNAME,
.id_table = id_table,
--
1.7.9.5

View File

@ -0,0 +1,53 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:38:00 -0800
Subject: [PATCH 54/77] Staging: hv: storvsc: Add a comment to explain
life-cycle management
commit a8c18c573bf896f81dbcd68fdb81d81d4200dcad upstream.
Add a comment to explain life-cycle management and fix format issue.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index e0e471c..204b3ca 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -375,6 +375,21 @@ done:
kfree(wrk);
}
+/*
+ * We can get incoming messages from the host that are not in response to
+ * messages that we have sent out. An example of this would be messages
+ * received by the guest to notify dynamic addition/removal of LUNs. To
+ * deal with potential race conditions where the driver may be in the
+ * midst of being unloaded when we might receive an unsolicited message
+ * from the host, we have implemented a mechanism to gurantee sequential
+ * consistency:
+ *
+ * 1) Once the device is marked as being destroyed, we will fail all
+ * outgoing messages.
+ * 2) We permit incoming messages when the device is being destroyed,
+ * only to properly account for messages already sent out.
+ */
+
static inline struct storvsc_device *get_out_stor_device(
struct hv_device *device)
{
@@ -569,7 +584,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
*/
if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) ||
- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) {
+ (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) {
vstor_packet->vm_srb.scsi_status = 0;
vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS;
}
--
1.7.9.5

View File

@ -0,0 +1,706 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:38:01 -0800
Subject: [PATCH 55/77] Staging: hv: storvsc: Get rid of the on_io_completion
in hv_storvsc_request
commit 2707388c7c5c6edf4e646a9013f6b7aa195fb174 upstream.
Get rid of the on_io_completion field in struct hv_storvsc_request. As part of this
relocate the bounce buffer handling code (to avoid having forward declarations).
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 630 +++++++++++++++++++-------------------
1 file changed, 313 insertions(+), 317 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 204b3ca..7c9fa19 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -276,7 +276,6 @@ struct hv_storvsc_request {
unsigned char *sense_buffer;
void *context;
- void (*on_io_completion)(struct hv_storvsc_request *request);
struct hv_multipage_buffer data_buffer;
struct vstor_packet vstor_packet;
@@ -436,6 +435,227 @@ get_in_err:
}
+static void destroy_bounce_buffer(struct scatterlist *sgl,
+ unsigned int sg_count)
+{
+ int i;
+ struct page *page_buf;
+
+ for (i = 0; i < sg_count; i++) {
+ page_buf = sg_page((&sgl[i]));
+ if (page_buf != NULL)
+ __free_page(page_buf);
+ }
+
+ kfree(sgl);
+}
+
+static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
+{
+ int i;
+
+ /* No need to check */
+ if (sg_count < 2)
+ return -1;
+
+ /* We have at least 2 sg entries */
+ for (i = 0; i < sg_count; i++) {
+ if (i == 0) {
+ /* make sure 1st one does not have hole */
+ if (sgl[i].offset + sgl[i].length != PAGE_SIZE)
+ return i;
+ } else if (i == sg_count - 1) {
+ /* make sure last one does not have hole */
+ if (sgl[i].offset != 0)
+ return i;
+ } else {
+ /* make sure no hole in the middle */
+ if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0)
+ return i;
+ }
+ }
+ return -1;
+}
+
+static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
+ unsigned int sg_count,
+ unsigned int len,
+ int write)
+{
+ int i;
+ int num_pages;
+ struct scatterlist *bounce_sgl;
+ struct page *page_buf;
+ unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
+
+ num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
+
+ bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC);
+ if (!bounce_sgl)
+ return NULL;
+
+ for (i = 0; i < num_pages; i++) {
+ page_buf = alloc_page(GFP_ATOMIC);
+ if (!page_buf)
+ goto cleanup;
+ sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
+ }
+
+ return bounce_sgl;
+
+cleanup:
+ destroy_bounce_buffer(bounce_sgl, num_pages);
+ return NULL;
+}
+
+/* Assume the original sgl has enough room */
+static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
+ struct scatterlist *bounce_sgl,
+ unsigned int orig_sgl_count,
+ unsigned int bounce_sgl_count)
+{
+ int i;
+ int j = 0;
+ unsigned long src, dest;
+ unsigned int srclen, destlen, copylen;
+ unsigned int total_copied = 0;
+ unsigned long bounce_addr = 0;
+ unsigned long dest_addr = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ for (i = 0; i < orig_sgl_count; i++) {
+ dest_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
+ KM_IRQ0) + orig_sgl[i].offset;
+ dest = dest_addr;
+ destlen = orig_sgl[i].length;
+
+ if (bounce_addr == 0)
+ bounce_addr =
+ (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
+ KM_IRQ0);
+
+ while (destlen) {
+ src = bounce_addr + bounce_sgl[j].offset;
+ srclen = bounce_sgl[j].length - bounce_sgl[j].offset;
+
+ copylen = min(srclen, destlen);
+ memcpy((void *)dest, (void *)src, copylen);
+
+ total_copied += copylen;
+ bounce_sgl[j].offset += copylen;
+ destlen -= copylen;
+ dest += copylen;
+
+ if (bounce_sgl[j].offset == bounce_sgl[j].length) {
+ /* full */
+ kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ j++;
+
+ /*
+ * It is possible that the number of elements
+ * in the bounce buffer may not be equal to
+ * the number of elements in the original
+ * scatter list. Handle this correctly.
+ */
+
+ if (j == bounce_sgl_count) {
+ /*
+ * We are done; cleanup and return.
+ */
+ kunmap_atomic((void *)(dest_addr -
+ orig_sgl[i].offset),
+ KM_IRQ0);
+ local_irq_restore(flags);
+ return total_copied;
+ }
+
+ /* if we need to use another bounce buffer */
+ if (destlen || i != orig_sgl_count - 1)
+ bounce_addr =
+ (unsigned long)kmap_atomic(
+ sg_page((&bounce_sgl[j])), KM_IRQ0);
+ } else if (destlen == 0 && i == orig_sgl_count - 1) {
+ /* unmap the last bounce that is < PAGE_SIZE */
+ kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ }
+ }
+
+ kunmap_atomic((void *)(dest_addr - orig_sgl[i].offset),
+ KM_IRQ0);
+ }
+
+ local_irq_restore(flags);
+
+ return total_copied;
+}
+
+/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */
+static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
+ struct scatterlist *bounce_sgl,
+ unsigned int orig_sgl_count)
+{
+ int i;
+ int j = 0;
+ unsigned long src, dest;
+ unsigned int srclen, destlen, copylen;
+ unsigned int total_copied = 0;
+ unsigned long bounce_addr = 0;
+ unsigned long src_addr = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ for (i = 0; i < orig_sgl_count; i++) {
+ src_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
+ KM_IRQ0) + orig_sgl[i].offset;
+ src = src_addr;
+ srclen = orig_sgl[i].length;
+
+ if (bounce_addr == 0)
+ bounce_addr =
+ (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
+ KM_IRQ0);
+
+ while (srclen) {
+ /* assume bounce offset always == 0 */
+ dest = bounce_addr + bounce_sgl[j].length;
+ destlen = PAGE_SIZE - bounce_sgl[j].length;
+
+ copylen = min(srclen, destlen);
+ memcpy((void *)dest, (void *)src, copylen);
+
+ total_copied += copylen;
+ bounce_sgl[j].length += copylen;
+ srclen -= copylen;
+ src += copylen;
+
+ if (bounce_sgl[j].length == PAGE_SIZE) {
+ /* full..move to next entry */
+ kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ j++;
+
+ /* if we need to use another bounce buffer */
+ if (srclen || i != orig_sgl_count - 1)
+ bounce_addr =
+ (unsigned long)kmap_atomic(
+ sg_page((&bounce_sgl[j])), KM_IRQ0);
+
+ } else if (srclen == 0 && i == orig_sgl_count - 1) {
+ /* unmap the last bounce that is < PAGE_SIZE */
+ kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ }
+ }
+
+ kunmap_atomic((void *)(src_addr - orig_sgl[i].offset), KM_IRQ0);
+ }
+
+ local_irq_restore(flags);
+
+ return total_copied;
+}
+
static int storvsc_channel_init(struct hv_device *device)
{
struct storvsc_device *stor_device;
@@ -562,24 +782,101 @@ cleanup:
return ret;
}
-static void storvsc_on_io_completion(struct hv_device *device,
- struct vstor_packet *vstor_packet,
- struct hv_storvsc_request *request)
+
+static void storvsc_command_completion(struct hv_storvsc_request *request)
{
- struct storvsc_device *stor_device;
- struct vstor_packet *stor_pkt;
+ struct storvsc_cmd_request *cmd_request =
+ (struct storvsc_cmd_request *)request->context;
+ struct scsi_cmnd *scmnd = cmd_request->cmd;
+ struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
+ void (*scsi_done_fn)(struct scsi_cmnd *);
+ struct scsi_sense_hdr sense_hdr;
+ struct vmscsi_request *vm_srb;
+ struct storvsc_scan_work *wrk;
+ struct stor_mem_pools *memp = scmnd->device->hostdata;
- stor_device = hv_get_drvdata(device);
- stor_pkt = &request->vstor_packet;
+ vm_srb = &request->vstor_packet.vm_srb;
+ if (cmd_request->bounce_sgl_count) {
+ if (vm_srb->data_in == READ_TYPE)
+ copy_from_bounce_buffer(scsi_sglist(scmnd),
+ cmd_request->bounce_sgl,
+ scsi_sg_count(scmnd),
+ cmd_request->bounce_sgl_count);
+ destroy_bounce_buffer(cmd_request->bounce_sgl,
+ cmd_request->bounce_sgl_count);
+ }
/*
- * The current SCSI handling on the host side does
- * not correctly handle:
- * INQUIRY command with page code parameter set to 0x80
- * MODE_SENSE command with cmd[2] == 0x1c
- *
- * Setup srb and scsi status so this won't be fatal.
- * We do this so we can distinguish truly fatal failues
+ * If there is an error; offline the device since all
+ * error recovery strategies would have already been
+ * deployed on the host side.
+ */
+ if (vm_srb->srb_status == SRB_STATUS_ERROR)
+ scmnd->result = DID_TARGET_FAILURE << 16;
+ else
+ scmnd->result = vm_srb->scsi_status;
+
+ /*
+ * If the LUN is invalid; remove the device.
+ */
+ if (vm_srb->srb_status == SRB_STATUS_INVALID_LUN) {
+ struct storvsc_device *stor_dev;
+ struct hv_device *dev = host_dev->dev;
+ struct Scsi_Host *host;
+
+ stor_dev = get_in_stor_device(dev);
+ host = stor_dev->host;
+
+ wrk = kmalloc(sizeof(struct storvsc_scan_work),
+ GFP_ATOMIC);
+ if (!wrk) {
+ scmnd->result = DID_TARGET_FAILURE << 16;
+ } else {
+ wrk->host = host;
+ wrk->lun = vm_srb->lun;
+ INIT_WORK(&wrk->work, storvsc_remove_lun);
+ schedule_work(&wrk->work);
+ }
+ }
+
+ if (scmnd->result) {
+ if (scsi_normalize_sense(scmnd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+ scsi_print_sense_hdr("storvsc", &sense_hdr);
+ }
+
+ scsi_set_resid(scmnd,
+ request->data_buffer.len -
+ vm_srb->data_transfer_length);
+
+ scsi_done_fn = scmnd->scsi_done;
+
+ scmnd->host_scribble = NULL;
+ scmnd->scsi_done = NULL;
+
+ scsi_done_fn(scmnd);
+
+ mempool_free(cmd_request, memp->request_mempool);
+}
+
+static void storvsc_on_io_completion(struct hv_device *device,
+ struct vstor_packet *vstor_packet,
+ struct hv_storvsc_request *request)
+{
+ struct storvsc_device *stor_device;
+ struct vstor_packet *stor_pkt;
+
+ stor_device = hv_get_drvdata(device);
+ stor_pkt = &request->vstor_packet;
+
+ /*
+ * The current SCSI handling on the host side does
+ * not correctly handle:
+ * INQUIRY command with page code parameter set to 0x80
+ * MODE_SENSE command with cmd[2] == 0x1c
+ *
+ * Setup srb and scsi status so this won't be fatal.
+ * We do this so we can distinguish truly fatal failues
* (srb status == 0x4) and off-line the device in that case.
*/
@@ -625,7 +922,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
stor_pkt->vm_srb.data_transfer_length =
vstor_packet->vm_srb.data_transfer_length;
- request->on_io_completion(request);
+ storvsc_command_completion(request);
if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
stor_device->drain_notify)
@@ -875,229 +1172,6 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
return 0;
}
-static void destroy_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count)
-{
- int i;
- struct page *page_buf;
-
- for (i = 0; i < sg_count; i++) {
- page_buf = sg_page((&sgl[i]));
- if (page_buf != NULL)
- __free_page(page_buf);
- }
-
- kfree(sgl);
-}
-
-static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
-{
- int i;
-
- /* No need to check */
- if (sg_count < 2)
- return -1;
-
- /* We have at least 2 sg entries */
- for (i = 0; i < sg_count; i++) {
- if (i == 0) {
- /* make sure 1st one does not have hole */
- if (sgl[i].offset + sgl[i].length != PAGE_SIZE)
- return i;
- } else if (i == sg_count - 1) {
- /* make sure last one does not have hole */
- if (sgl[i].offset != 0)
- return i;
- } else {
- /* make sure no hole in the middle */
- if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0)
- return i;
- }
- }
- return -1;
-}
-
-static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count,
- unsigned int len,
- int write)
-{
- int i;
- int num_pages;
- struct scatterlist *bounce_sgl;
- struct page *page_buf;
- unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
-
- num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
-
- bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC);
- if (!bounce_sgl)
- return NULL;
-
- for (i = 0; i < num_pages; i++) {
- page_buf = alloc_page(GFP_ATOMIC);
- if (!page_buf)
- goto cleanup;
- sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
- }
-
- return bounce_sgl;
-
-cleanup:
- destroy_bounce_buffer(bounce_sgl, num_pages);
- return NULL;
-}
-
-
-/* Assume the original sgl has enough room */
-static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count,
- unsigned int bounce_sgl_count)
-{
- int i;
- int j = 0;
- unsigned long src, dest;
- unsigned int srclen, destlen, copylen;
- unsigned int total_copied = 0;
- unsigned long bounce_addr = 0;
- unsigned long dest_addr = 0;
- unsigned long flags;
-
- local_irq_save(flags);
-
- for (i = 0; i < orig_sgl_count; i++) {
- dest_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
- KM_IRQ0) + orig_sgl[i].offset;
- dest = dest_addr;
- destlen = orig_sgl[i].length;
-
- if (bounce_addr == 0)
- bounce_addr =
- (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
- KM_IRQ0);
-
- while (destlen) {
- src = bounce_addr + bounce_sgl[j].offset;
- srclen = bounce_sgl[j].length - bounce_sgl[j].offset;
-
- copylen = min(srclen, destlen);
- memcpy((void *)dest, (void *)src, copylen);
-
- total_copied += copylen;
- bounce_sgl[j].offset += copylen;
- destlen -= copylen;
- dest += copylen;
-
- if (bounce_sgl[j].offset == bounce_sgl[j].length) {
- /* full */
- kunmap_atomic((void *)bounce_addr, KM_IRQ0);
- j++;
-
- /*
- * It is possible that the number of elements
- * in the bounce buffer may not be equal to
- * the number of elements in the original
- * scatter list. Handle this correctly.
- */
-
- if (j == bounce_sgl_count) {
- /*
- * We are done; cleanup and return.
- */
- kunmap_atomic((void *)(dest_addr -
- orig_sgl[i].offset),
- KM_IRQ0);
- local_irq_restore(flags);
- return total_copied;
- }
-
- /* if we need to use another bounce buffer */
- if (destlen || i != orig_sgl_count - 1)
- bounce_addr =
- (unsigned long)kmap_atomic(
- sg_page((&bounce_sgl[j])), KM_IRQ0);
- } else if (destlen == 0 && i == orig_sgl_count - 1) {
- /* unmap the last bounce that is < PAGE_SIZE */
- kunmap_atomic((void *)bounce_addr, KM_IRQ0);
- }
- }
-
- kunmap_atomic((void *)(dest_addr - orig_sgl[i].offset),
- KM_IRQ0);
- }
-
- local_irq_restore(flags);
-
- return total_copied;
-}
-
-
-/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */
-static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count)
-{
- int i;
- int j = 0;
- unsigned long src, dest;
- unsigned int srclen, destlen, copylen;
- unsigned int total_copied = 0;
- unsigned long bounce_addr = 0;
- unsigned long src_addr = 0;
- unsigned long flags;
-
- local_irq_save(flags);
-
- for (i = 0; i < orig_sgl_count; i++) {
- src_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
- KM_IRQ0) + orig_sgl[i].offset;
- src = src_addr;
- srclen = orig_sgl[i].length;
-
- if (bounce_addr == 0)
- bounce_addr =
- (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
- KM_IRQ0);
-
- while (srclen) {
- /* assume bounce offset always == 0 */
- dest = bounce_addr + bounce_sgl[j].length;
- destlen = PAGE_SIZE - bounce_sgl[j].length;
-
- copylen = min(srclen, destlen);
- memcpy((void *)dest, (void *)src, copylen);
-
- total_copied += copylen;
- bounce_sgl[j].length += copylen;
- srclen -= copylen;
- src += copylen;
-
- if (bounce_sgl[j].length == PAGE_SIZE) {
- /* full..move to next entry */
- kunmap_atomic((void *)bounce_addr, KM_IRQ0);
- j++;
-
- /* if we need to use another bounce buffer */
- if (srclen || i != orig_sgl_count - 1)
- bounce_addr =
- (unsigned long)kmap_atomic(
- sg_page((&bounce_sgl[j])), KM_IRQ0);
-
- } else if (srclen == 0 && i == orig_sgl_count - 1) {
- /* unmap the last bounce that is < PAGE_SIZE */
- kunmap_atomic((void *)bounce_addr, KM_IRQ0);
- }
- }
-
- kunmap_atomic((void *)(src_addr - orig_sgl[i].offset), KM_IRQ0);
- }
-
- local_irq_restore(flags);
-
- return total_copied;
-}
-
static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
sector_t capacity, int *info)
{
@@ -1166,83 +1240,6 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
return SUCCESS;
}
-
-static void storvsc_command_completion(struct hv_storvsc_request *request)
-{
- struct storvsc_cmd_request *cmd_request =
- (struct storvsc_cmd_request *)request->context;
- struct scsi_cmnd *scmnd = cmd_request->cmd;
- struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
- void (*scsi_done_fn)(struct scsi_cmnd *);
- struct scsi_sense_hdr sense_hdr;
- struct vmscsi_request *vm_srb;
- struct storvsc_scan_work *wrk;
- struct stor_mem_pools *memp = scmnd->device->hostdata;
-
- vm_srb = &request->vstor_packet.vm_srb;
- if (cmd_request->bounce_sgl_count) {
- if (vm_srb->data_in == READ_TYPE)
- copy_from_bounce_buffer(scsi_sglist(scmnd),
- cmd_request->bounce_sgl,
- scsi_sg_count(scmnd),
- cmd_request->bounce_sgl_count);
- destroy_bounce_buffer(cmd_request->bounce_sgl,
- cmd_request->bounce_sgl_count);
- }
-
- /*
- * If there is an error; offline the device since all
- * error recovery strategies would have already been
- * deployed on the host side.
- */
- if (vm_srb->srb_status == SRB_STATUS_ERROR)
- scmnd->result = DID_TARGET_FAILURE << 16;
- else
- scmnd->result = vm_srb->scsi_status;
-
- /*
- * If the LUN is invalid; remove the device.
- */
- if (vm_srb->srb_status == SRB_STATUS_INVALID_LUN) {
- struct storvsc_device *stor_dev;
- struct hv_device *dev = host_dev->dev;
- struct Scsi_Host *host;
-
- stor_dev = get_in_stor_device(dev);
- host = stor_dev->host;
-
- wrk = kmalloc(sizeof(struct storvsc_scan_work),
- GFP_ATOMIC);
- if (!wrk) {
- scmnd->result = DID_TARGET_FAILURE << 16;
- } else {
- wrk->host = host;
- wrk->lun = vm_srb->lun;
- INIT_WORK(&wrk->work, storvsc_remove_lun);
- schedule_work(&wrk->work);
- }
- }
-
- if (scmnd->result) {
- if (scsi_normalize_sense(scmnd->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr))
- scsi_print_sense_hdr("storvsc", &sense_hdr);
- }
-
- scsi_set_resid(scmnd,
- request->data_buffer.len -
- vm_srb->data_transfer_length);
-
- scsi_done_fn = scmnd->scsi_done;
-
- scmnd->host_scribble = NULL;
- scmnd->scsi_done = NULL;
-
- scsi_done_fn(scmnd);
-
- mempool_free(cmd_request, memp->request_mempool);
-}
-
static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd)
{
bool allowed = true;
@@ -1318,7 +1315,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
break;
}
- request->on_io_completion = storvsc_command_completion;
request->context = cmd_request;/* scmnd; */
vm_srb->port_number = host_dev->port;
--
1.7.9.5

View File

@ -0,0 +1,51 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:38:02 -0800
Subject: [PATCH 56/77] Staging: hv: storvsc: Rename the context field in
hv_storvsc_request
commit 93a1bf4dd018af2a4931b916dd46fdfb963fa4ad upstream.
Rename the context field in hv_storvsc_request. As part of this change
fix the type of this field.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 7c9fa19..0515707 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -275,7 +275,7 @@ struct hv_storvsc_request {
struct completion wait_event;
unsigned char *sense_buffer;
- void *context;
+ struct storvsc_cmd_request *cmd;
struct hv_multipage_buffer data_buffer;
struct vstor_packet vstor_packet;
@@ -785,8 +785,7 @@ cleanup:
static void storvsc_command_completion(struct hv_storvsc_request *request)
{
- struct storvsc_cmd_request *cmd_request =
- (struct storvsc_cmd_request *)request->context;
+ struct storvsc_cmd_request *cmd_request = request->cmd;
struct scsi_cmnd *scmnd = cmd_request->cmd;
struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
void (*scsi_done_fn)(struct scsi_cmnd *);
@@ -1315,7 +1314,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
break;
}
- request->context = cmd_request;/* scmnd; */
+ request->cmd = cmd_request;
vm_srb->port_number = host_dev->port;
vm_srb->path_id = scmnd->device->channel;
--
1.7.9.5

View File

@ -0,0 +1,195 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:38:03 -0800
Subject: [PATCH 57/77] Staging: hv: storvsc: Miscellaneous cleanup of storvsc
driver
commit c649114a5d99eb10e58f977f82018b1d77191aa7 upstream.
Miscellaneous cleanup of storvsc driver - get rid of unnecessary defines and
use fixed size types for structures used for communication with the host.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 94 ++++++++++++++++----------------------
1 file changed, 39 insertions(+), 55 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 0515707..da71294 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -43,32 +43,18 @@
#include <scsi/scsi_dbg.h>
+/*
+ * We setup a mempool to allocate request structures for this driver
+ * on a per-lun basis. The following define specifies the number of
+ * elements in the pool.
+ */
+
#define STORVSC_MIN_BUF_NR 64
-#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
-static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE;
+static int storvsc_ringbuffer_size = (20 * PAGE_SIZE);
module_param(storvsc_ringbuffer_size, int, S_IRUGO);
MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
-/*
- * To alert the user that structure sizes may be mismatched even though the
- * protocol versions match.
- */
-
-
-#define REVISION_STRING(REVISION_) #REVISION_
-#define FILL_VMSTOR_REVISION(RESULT_LVALUE_) \
- do { \
- char *revision_string \
- = REVISION_STRING($Rev : 6 $) + 6; \
- RESULT_LVALUE_ = 0; \
- while (*revision_string >= '0' \
- && *revision_string <= '9') { \
- RESULT_LVALUE_ *= 10; \
- RESULT_LVALUE_ += *revision_string - '0'; \
- revision_string++; \
- } \
- } while (0)
/*
* Major/minor macros. Minor version is in LSB, meaning that earlier flat
@@ -79,7 +65,6 @@ MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
#define VMSTOR_PROTOCOL_MINOR(VERSION_) (((VERSION_)) & 0xff)
#define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \
(((MINOR_) & 0xff)))
-#define VMSTOR_INVALID_PROTOCOL_VERSION (-1)
/*
* Version history:
@@ -136,26 +121,26 @@ enum vstor_packet_operation {
#define MAX_DATA_BUF_LEN_WITH_PADDING 0x14
struct vmscsi_request {
- unsigned short length;
- unsigned char srb_status;
- unsigned char scsi_status;
+ u16 length;
+ u8 srb_status;
+ u8 scsi_status;
- unsigned char port_number;
- unsigned char path_id;
- unsigned char target_id;
- unsigned char lun;
+ u8 port_number;
+ u8 path_id;
+ u8 target_id;
+ u8 lun;
- unsigned char cdb_length;
- unsigned char sense_info_length;
- unsigned char data_in;
- unsigned char reserved;
+ u8 cdb_length;
+ u8 sense_info_length;
+ u8 data_in;
+ u8 reserved;
- unsigned int data_transfer_length;
+ u32 data_transfer_length;
union {
- unsigned char cdb[CDB16GENERIC_LENGTH];
- unsigned char sense_data[SENSE_BUFFER_SIZE];
- unsigned char reserved_array[MAX_DATA_BUF_LEN_WITH_PADDING];
+ u8 cdb[CDB16GENERIC_LENGTH];
+ u8 sense_data[SENSE_BUFFER_SIZE];
+ u8 reserved_array[MAX_DATA_BUF_LEN_WITH_PADDING];
};
} __attribute((packed));
@@ -165,18 +150,21 @@ struct vmscsi_request {
* properties of the channel.
*/
struct vmstorage_channel_properties {
- unsigned short protocol_version;
- unsigned char path_id;
- unsigned char target_id;
+ u16 protocol_version;
+ u8 path_id;
+ u8 target_id;
/* Note: port number is only really known on the client side */
- unsigned int port_number;
- unsigned int flags;
- unsigned int max_transfer_bytes;
+ u32 port_number;
+ u32 flags;
+ u32 max_transfer_bytes;
- /* This id is unique for each channel and will correspond with */
- /* vendor specific data in the inquirydata */
- unsigned long long unique_id;
+ /*
+ * This id is unique for each channel and will correspond with
+ * vendor specific data in the inquiry data.
+ */
+
+ u64 unique_id;
} __packed;
/* This structure is sent during the storage protocol negotiations. */
@@ -189,6 +177,7 @@ struct vmstorage_protocol_version {
* (See FILL_VMSTOR_REVISION macro above). Mismatch does not
* definitely indicate incompatibility--but it does indicate mismatched
* builds.
+ * This is only used on the windows side. Just set it to 0.
*/
unsigned short revision;
} __packed;
@@ -202,10 +191,10 @@ struct vstor_packet {
enum vstor_packet_operation operation;
/* Flags - see below for values */
- unsigned int flags;
+ u32 flags;
/* Status of the request returned from the server side. */
- unsigned int status;
+ u32 status;
/* Data payload area */
union {
@@ -232,11 +221,6 @@ struct vstor_packet {
#define REQUEST_COMPLETION_FLAG 0x1
-/* This is the set of flags that the vsc can set in any packets it sends */
-#define VSC_LEGAL_FLAGS (REQUEST_COMPLETION_FLAG)
-
-
-
#define STORVSC_MAX_IO_REQUESTS 128
/*
@@ -252,7 +236,7 @@ struct vstor_packet {
/* Matches Windows-end */
enum storvsc_request_type {
- WRITE_TYPE,
+ WRITE_TYPE = 0,
READ_TYPE,
UNKNOWN_TYPE,
};
@@ -704,7 +688,7 @@ static int storvsc_channel_init(struct hv_device *device)
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT;
- FILL_VMSTOR_REVISION(vstor_packet->version.revision);
+ vstor_packet->version.revision = 0;
ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
--
1.7.9.5

View File

@ -0,0 +1,84 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:38:04 -0800
Subject: [PATCH 58/77] Staging: hv: storvsc: Cleanup the code for generating
protocol version
commit 85904a5e553f343243e5cf59f150174159e2e5ea upstream.
Cleanup the code for generating protocol version.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index da71294..629edd1 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -61,10 +61,13 @@ MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
* version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1).
*/
-#define VMSTOR_PROTOCOL_MAJOR(VERSION_) (((VERSION_) >> 8) & 0xff)
-#define VMSTOR_PROTOCOL_MINOR(VERSION_) (((VERSION_)) & 0xff)
-#define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \
- (((MINOR_) & 0xff)))
+static inline u16 storvsc_get_version(u8 major, u8 minor)
+{
+ u16 version;
+
+ version = ((major << 8) | minor);
+ return version;
+}
/*
* Version history:
@@ -74,9 +77,8 @@ MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
* Win7: 4.2
*/
-#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(4, 2)
-
-
+#define VMSTOR_CURRENT_MAJOR 4
+#define VMSTOR_CURRENT_MINOR 2
/*
@@ -170,7 +172,7 @@ struct vmstorage_channel_properties {
/* This structure is sent during the storage protocol negotiations. */
struct vmstorage_protocol_version {
/* Major (MSW) and minor (LSW) version numbers. */
- unsigned short major_minor;
+ u16 major_minor;
/*
* Revision number is auto-incremented whenever this file is changed
@@ -179,7 +181,7 @@ struct vmstorage_protocol_version {
* builds.
* This is only used on the windows side. Just set it to 0.
*/
- unsigned short revision;
+ u16 revision;
} __packed;
/* Channel Property Flags */
@@ -687,7 +689,12 @@ static int storvsc_channel_init(struct hv_device *device)
vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
- vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT;
+ vstor_packet->version.major_minor =
+ storvsc_get_version(VMSTOR_CURRENT_MAJOR, VMSTOR_CURRENT_MINOR);
+
+ /*
+ * The revision number is only used in Windows; set it to 0.
+ */
vstor_packet->version.revision = 0;
ret = vmbus_sendpacket(device->channel, vstor_packet,
--
1.7.9.5

View File

@ -0,0 +1,69 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:38:05 -0800
Subject: [PATCH 59/77] Staging: hv: storvsc: Cleanup some protocol related
constants
commit 6b2f949559b26448cc6d161d62341281db42c909 upstream.
Cleanup some protocol related constants.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 629edd1..9f07458 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -114,13 +114,9 @@ enum vstor_packet_operation {
* this remains the same across the write regardless of 32/64 bit
* note: it's patterned off the SCSI_PASS_THROUGH structure
*/
-#define CDB16GENERIC_LENGTH 0x10
-
-#ifndef SENSE_BUFFER_SIZE
-#define SENSE_BUFFER_SIZE 0x12
-#endif
-
-#define MAX_DATA_BUF_LEN_WITH_PADDING 0x14
+#define STORVSC_MAX_CMD_LEN 0x10
+#define STORVSC_SENSE_BUFFER_SIZE 0x12
+#define STORVSC_MAX_BUF_LEN_WITH_PADDING 0x14
struct vmscsi_request {
u16 length;
@@ -140,9 +136,9 @@ struct vmscsi_request {
u32 data_transfer_length;
union {
- u8 cdb[CDB16GENERIC_LENGTH];
- u8 sense_data[SENSE_BUFFER_SIZE];
- u8 reserved_array[MAX_DATA_BUF_LEN_WITH_PADDING];
+ u8 cdb[STORVSC_MAX_CMD_LEN];
+ u8 sense_data[STORVSC_SENSE_BUFFER_SIZE];
+ u8 reserved_array[STORVSC_MAX_BUF_LEN_WITH_PADDING];
};
} __attribute((packed));
@@ -234,7 +230,6 @@ struct vstor_packet {
#define STORVSC_MAX_LUNS_PER_TARGET 64
#define STORVSC_MAX_TARGETS 1
#define STORVSC_MAX_CHANNELS 1
-#define STORVSC_MAX_CMD_LEN 16
/* Matches Windows-end */
enum storvsc_request_type {
@@ -1074,7 +1069,7 @@ static int storvsc_do_io(struct hv_device *device,
vstor_packet->vm_srb.length = sizeof(struct vmscsi_request);
- vstor_packet->vm_srb.sense_info_length = SENSE_BUFFER_SIZE;
+ vstor_packet->vm_srb.sense_info_length = STORVSC_SENSE_BUFFER_SIZE;
vstor_packet->vm_srb.data_transfer_length =
--
1.7.9.5

View File

@ -0,0 +1,40 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:38:06 -0800
Subject: [PATCH 60/77] Staging: hv: storvsc: Get rid of some unused defines
commit 410c52ed66cabd1837a87b37348d92a17f01c199 upstream.
Get rid of some unused defines.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 9f07458..d34e3ca 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -81,18 +81,6 @@ static inline u16 storvsc_get_version(u8 major, u8 minor)
#define VMSTOR_CURRENT_MINOR 2
-/*
- * This will get replaced with the max transfer length that is possible on
- * the host adapter.
- * The max transfer length will be published when we offer a vmbus channel.
- */
-
-#define MAX_TRANSFER_LENGTH 0x40000
-#define DEFAULT_PACKET_SIZE (sizeof(struct vmdata_gpa_direct) + \
- sizeof(struct vstor_packet) + \
- sizesizeof(u64) * (MAX_TRANSFER_LENGTH / PAGE_SIZE)))
-
-
/* Packet structure describing virtual storage requests. */
enum vstor_packet_operation {
VSTOR_OPERATION_COMPLETE_IO = 1,
--
1.7.9.5

View File

@ -0,0 +1,241 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:38:07 -0800
Subject: [PATCH 61/77] Staging: hv: storvsc: Consolidate the request
structure
commit 61eaffc91d375e02bc12c2c831478841f5ce4757 upstream.
Consolidate the request structure by getting rid of struct hv_storvsc_request.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 65 ++++++++++++++++----------------------
1 file changed, 27 insertions(+), 38 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index d34e3ca..9ccc1c4 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -236,17 +236,20 @@ enum storvsc_request_type {
#define SRB_STATUS_ERROR 0x04
+struct storvsc_cmd_request {
+ struct list_head entry;
+ struct scsi_cmnd *cmd;
+
+ unsigned int bounce_sgl_count;
+ struct scatterlist *bounce_sgl;
-struct hv_storvsc_request {
struct hv_device *device;
/* Synchronize the request/response if needed */
struct completion wait_event;
unsigned char *sense_buffer;
- struct storvsc_cmd_request *cmd;
struct hv_multipage_buffer data_buffer;
-
struct vstor_packet vstor_packet;
};
@@ -272,8 +275,8 @@ struct storvsc_device {
unsigned char target_id;
/* Used for vsc/vsp channel reset process */
- struct hv_storvsc_request init_request;
- struct hv_storvsc_request reset_request;
+ struct storvsc_cmd_request init_request;
+ struct storvsc_cmd_request reset_request;
};
struct stor_mem_pools {
@@ -288,16 +291,6 @@ struct hv_host_device {
unsigned char target;
};
-struct storvsc_cmd_request {
- struct list_head entry;
- struct scsi_cmnd *cmd;
-
- unsigned int bounce_sgl_count;
- struct scatterlist *bounce_sgl;
-
- struct hv_storvsc_request request;
-};
-
struct storvsc_scan_work {
struct work_struct work;
struct Scsi_Host *host;
@@ -628,7 +621,7 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
static int storvsc_channel_init(struct hv_device *device)
{
struct storvsc_device *stor_device;
- struct hv_storvsc_request *request;
+ struct storvsc_cmd_request *request;
struct vstor_packet *vstor_packet;
int ret, t;
@@ -643,7 +636,7 @@ static int storvsc_channel_init(struct hv_device *device)
* Now, initiate the vsc/vsp initialization protocol on the open
* channel
*/
- memset(request, 0, sizeof(struct hv_storvsc_request));
+ memset(request, 0, sizeof(struct storvsc_cmd_request));
init_completion(&request->wait_event);
vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
@@ -757,9 +750,8 @@ cleanup:
}
-static void storvsc_command_completion(struct hv_storvsc_request *request)
+static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
{
- struct storvsc_cmd_request *cmd_request = request->cmd;
struct scsi_cmnd *scmnd = cmd_request->cmd;
struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
void (*scsi_done_fn)(struct scsi_cmnd *);
@@ -768,7 +760,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
struct storvsc_scan_work *wrk;
struct stor_mem_pools *memp = scmnd->device->hostdata;
- vm_srb = &request->vstor_packet.vm_srb;
+ vm_srb = &cmd_request->vstor_packet.vm_srb;
if (cmd_request->bounce_sgl_count) {
if (vm_srb->data_in == READ_TYPE)
copy_from_bounce_buffer(scsi_sglist(scmnd),
@@ -819,7 +811,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
}
scsi_set_resid(scmnd,
- request->data_buffer.len -
+ cmd_request->data_buffer.len -
vm_srb->data_transfer_length);
scsi_done_fn = scmnd->scsi_done;
@@ -834,7 +826,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
static void storvsc_on_io_completion(struct hv_device *device,
struct vstor_packet *vstor_packet,
- struct hv_storvsc_request *request)
+ struct storvsc_cmd_request *request)
{
struct storvsc_device *stor_device;
struct vstor_packet *stor_pkt;
@@ -906,7 +898,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
static void storvsc_on_receive(struct hv_device *device,
struct vstor_packet *vstor_packet,
- struct hv_storvsc_request *request)
+ struct storvsc_cmd_request *request)
{
struct storvsc_scan_work *work;
struct storvsc_device *stor_device;
@@ -940,7 +932,7 @@ static void storvsc_on_channel_callback(void *context)
u32 bytes_recvd;
u64 request_id;
unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)];
- struct hv_storvsc_request *request;
+ struct storvsc_cmd_request *request;
int ret;
@@ -954,7 +946,7 @@ static void storvsc_on_channel_callback(void *context)
&bytes_recvd, &request_id);
if (ret == 0 && bytes_recvd > 0) {
- request = (struct hv_storvsc_request *)
+ request = (struct storvsc_cmd_request *)
(unsigned long)request_id;
if ((request == &stor_device->init_request) ||
@@ -1036,7 +1028,7 @@ static int storvsc_dev_remove(struct hv_device *device)
}
static int storvsc_do_io(struct hv_device *device,
- struct hv_storvsc_request *request)
+ struct storvsc_cmd_request *request)
{
struct storvsc_device *stor_device;
struct vstor_packet *vstor_packet;
@@ -1174,7 +1166,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
struct hv_device *device = host_dev->dev;
struct storvsc_device *stor_device;
- struct hv_storvsc_request *request;
+ struct storvsc_cmd_request *request;
struct vstor_packet *vstor_packet;
int ret, t;
@@ -1238,7 +1230,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
int ret;
struct hv_host_device *host_dev = shost_priv(host);
struct hv_device *dev = host_dev->dev;
- struct hv_storvsc_request *request;
struct storvsc_cmd_request *cmd_request;
unsigned int request_size = 0;
int i;
@@ -1271,8 +1262,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
scmnd->host_scribble = (unsigned char *)cmd_request;
- request = &cmd_request->request;
- vm_srb = &request->vstor_packet.vm_srb;
+ vm_srb = &cmd_request->vstor_packet.vm_srb;
/* Build the SRB */
@@ -1288,7 +1278,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
break;
}
- request->cmd = cmd_request;
vm_srb->port_number = host_dev->port;
vm_srb->path_id = scmnd->device->channel;
@@ -1299,10 +1288,10 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length);
- request->sense_buffer = scmnd->sense_buffer;
+ cmd_request->sense_buffer = scmnd->sense_buffer;
- request->data_buffer.len = scsi_bufflen(scmnd);
+ cmd_request->data_buffer.len = scsi_bufflen(scmnd);
if (scsi_sg_count(scmnd)) {
sgl = (struct scatterlist *)scsi_sglist(scmnd);
sg_count = scsi_sg_count(scmnd);
@@ -1331,21 +1320,21 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
sg_count = cmd_request->bounce_sgl_count;
}
- request->data_buffer.offset = sgl[0].offset;
+ cmd_request->data_buffer.offset = sgl[0].offset;
for (i = 0; i < sg_count; i++)
- request->data_buffer.pfn_array[i] =
+ cmd_request->data_buffer.pfn_array[i] =
page_to_pfn(sg_page((&sgl[i])));
} else if (scsi_sglist(scmnd)) {
- request->data_buffer.offset =
+ cmd_request->data_buffer.offset =
virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1);
- request->data_buffer.pfn_array[0] =
+ cmd_request->data_buffer.pfn_array[0] =
virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT;
}
/* Invokes the vsc to start an IO */
- ret = storvsc_do_io(dev, &cmd_request->request);
+ ret = storvsc_do_io(dev, cmd_request);
if (ret == -EAGAIN) {
/* no more space */
--
1.7.9.5

View File

@ -0,0 +1,136 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 12 Jan 2012 12:38:08 -0800
Subject: [PATCH 62/77] Staging: hv: storvsc: Consolidate all the wire
protocol definitions
commit af9584b82df77751710db45043cf8d7d7740056d upstream.
Consolidate all definitions that support communication with the host.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/staging/hv/storvsc_drv.c | 83 +++++++++++++++++++++-----------------
1 file changed, 47 insertions(+), 36 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 9ccc1c4..695ffc3 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -42,33 +42,13 @@
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_dbg.h>
-
-/*
- * We setup a mempool to allocate request structures for this driver
- * on a per-lun basis. The following define specifies the number of
- * elements in the pool.
- */
-
-#define STORVSC_MIN_BUF_NR 64
-static int storvsc_ringbuffer_size = (20 * PAGE_SIZE);
-
-module_param(storvsc_ringbuffer_size, int, S_IRUGO);
-MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
-
-
/*
- * Major/minor macros. Minor version is in LSB, meaning that earlier flat
- * version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1).
+ * All wire protocol details (storage protocol between the guest and the host)
+ * are consolidated here.
+ *
+ * Begin protocol definitions.
*/
-static inline u16 storvsc_get_version(u8 major, u8 minor)
-{
- u16 version;
-
- version = ((major << 8) | minor);
- return version;
-}
-
/*
* Version history:
* V1 Beta: 0.1
@@ -207,18 +187,6 @@ struct vstor_packet {
#define REQUEST_COMPLETION_FLAG 0x1
-#define STORVSC_MAX_IO_REQUESTS 128
-
-/*
- * In Hyper-V, each port/path/target maps to 1 scsi host adapter. In
- * reality, the path/target is not used (ie always set to 0) so our
- * scsi host adapter essentially has 1 bus with 1 target that contains
- * up to 256 luns.
- */
-#define STORVSC_MAX_LUNS_PER_TARGET 64
-#define STORVSC_MAX_TARGETS 1
-#define STORVSC_MAX_CHANNELS 1
-
/* Matches Windows-end */
enum storvsc_request_type {
WRITE_TYPE = 0,
@@ -235,6 +203,36 @@ enum storvsc_request_type {
#define SRB_STATUS_SUCCESS 0x01
#define SRB_STATUS_ERROR 0x04
+/*
+ * This is the end of Protocol specific defines.
+ */
+
+
+/*
+ * We setup a mempool to allocate request structures for this driver
+ * on a per-lun basis. The following define specifies the number of
+ * elements in the pool.
+ */
+
+#define STORVSC_MIN_BUF_NR 64
+static int storvsc_ringbuffer_size = (20 * PAGE_SIZE);
+
+module_param(storvsc_ringbuffer_size, int, S_IRUGO);
+MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
+
+#define STORVSC_MAX_IO_REQUESTS 128
+
+/*
+ * In Hyper-V, each port/path/target maps to 1 scsi host adapter. In
+ * reality, the path/target is not used (ie always set to 0) so our
+ * scsi host adapter essentially has 1 bus with 1 target that contains
+ * up to 256 luns.
+ */
+#define STORVSC_MAX_LUNS_PER_TARGET 64
+#define STORVSC_MAX_TARGETS 1
+#define STORVSC_MAX_CHANNELS 1
+
+
struct storvsc_cmd_request {
struct list_head entry;
@@ -337,6 +335,19 @@ done:
}
/*
+ * Major/minor macros. Minor version is in LSB, meaning that earlier flat
+ * version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1).
+ */
+
+static inline u16 storvsc_get_version(u8 major, u8 minor)
+{
+ u16 version;
+
+ version = ((major << 8) | minor);
+ return version;
+}
+
+/*
* We can get incoming messages from the host that are not in response to
* messages that we have sent out. An example of this would be messages
* received by the guest to notify dynamic addition/removal of LUNs. To
--
1.7.9.5

View File

@ -0,0 +1,73 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 2 Feb 2012 16:56:48 -0800
Subject: [PATCH 63/77] drivers: hv: Cleanup the kvp related state in hyperv.h
commit 59a084a70afa0678bda2a23a7bc7cc59664945c7 upstream.
Now cleanup the hyperv.h with regards to KVP definitions.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/linux/hyperv.h | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index c445ead..dd0e3ee 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -137,7 +137,6 @@ struct hv_ku_msg {
-#ifdef __KERNEL__
/*
* Registry value types.
@@ -163,28 +162,30 @@ enum hv_kvp_exchg_pool {
};
struct hv_kvp_hdr {
- u8 operation;
- u8 pool;
-};
+ __u8 operation;
+ __u8 pool;
+ __u16 pad;
+} __attribute__((packed));
struct hv_kvp_exchg_msg_value {
- u32 value_type;
- u32 key_size;
- u32 value_size;
- u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
- u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
-};
+ __u32 value_type;
+ __u32 key_size;
+ __u32 value_size;
+ __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+} __attribute__((packed));
struct hv_kvp_msg_enumerate {
- u32 index;
+ __u32 index;
struct hv_kvp_exchg_msg_value data;
-};
+} __attribute__((packed));
struct hv_kvp_msg {
struct hv_kvp_hdr kvp_hdr;
struct hv_kvp_msg_enumerate kvp_data;
-};
+} __attribute__((packed));
+#ifdef __KERNEL__
#include <linux/scatterlist.h>
#include <linux/list.h>
#include <linux/uuid.h>
--
1.7.9.5

View File

@ -0,0 +1,78 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 2 Feb 2012 16:56:49 -0800
Subject: [PATCH 64/77] tools: hv: Use hyperv.h to get the KVP definitions
commit eab6af71f0b83a7f62b9c48be5b2c0a82a86fad3 upstream.
Now use hyperv.h to get the KVP defines in the KVP user-mode code.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
tools/hv/hv_kvp_daemon.c | 28 +---------------------------
1 file changed, 1 insertion(+), 27 deletions(-)
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 2b6a2d9..b75523c 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -34,17 +34,12 @@
#include <errno.h>
#include <arpa/inet.h>
#include <linux/connector.h>
+#include <linux/hyperv.h>
#include <linux/netlink.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <syslog.h>
-/*
- *
- * The following definitions are shared with the in-kernel component; do not
- * change any of this without making the corresponding changes in
- * the KVP kernel component.
- */
/*
* KVP protocol: The user mode component first registers with the
@@ -56,25 +51,8 @@
* We use this infrastructure for also supporting queries from user mode
* application for state that may be maintained in the KVP kernel component.
*
- * XXXKYS: Have a shared header file between the user and kernel (TODO)
*/
-enum kvp_op {
- KVP_REGISTER = 0, /* Register the user mode component*/
- KVP_KERNEL_GET, /*Kernel is requesting the value for the specified key*/
- KVP_KERNEL_SET, /*Kernel is providing the value for the specified key*/
- KVP_USER_GET, /*User is requesting the value for the specified key*/
- KVP_USER_SET /*User is providing the value for the specified key*/
-};
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE 512
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE 2048
-
-struct hv_ku_msg {
- __u32 kvp_index;
- __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
- __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
-};
enum key_index {
FullyQualifiedDomainName = 0,
@@ -89,10 +67,6 @@ enum key_index {
ProcessorArchitecture
};
-/*
- * End of shared definitions.
- */
-
static char kvp_send_buffer[4096];
static char kvp_recv_buffer[4096];
static struct sockaddr_nl addr;
--
1.7.9.5

View File

@ -0,0 +1,258 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 2 Feb 2012 16:56:50 -0800
Subject: [PATCH 65/77] drivers: hv: kvp: Cleanup the kernel/user protocol
commit 2640335438ca4d7b139e114dae5f0d80e740e106 upstream.
Now, cleanup the user/kernel KVP protocol by using the same structure
definition that is used for host/guest KVP protocol. This simplifies the code.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hv/hv_kvp.c | 41 +++++++++++++++++++++++++----------------
include/linux/hyperv.h | 30 +++++-------------------------
tools/hv/hv_kvp_daemon.c | 30 +++++++++++++++---------------
3 files changed, 45 insertions(+), 56 deletions(-)
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 4a6971e..0ef4c1f 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -71,15 +71,20 @@ kvp_register(void)
{
struct cn_msg *msg;
+ struct hv_kvp_msg *kvp_msg;
+ char *version;
- msg = kzalloc(sizeof(*msg) + strlen(HV_DRV_VERSION) + 1 , GFP_ATOMIC);
+ msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg), GFP_ATOMIC);
if (msg) {
+ kvp_msg = (struct hv_kvp_msg *)msg->data;
+ version = kvp_msg->body.kvp_version;
msg->id.idx = CN_KVP_IDX;
msg->id.val = CN_KVP_VAL;
- msg->seq = KVP_REGISTER;
- strcpy(msg->data, HV_DRV_VERSION);
- msg->len = strlen(HV_DRV_VERSION) + 1;
+
+ kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER;
+ strcpy(version, HV_DRV_VERSION);
+ msg->len = sizeof(struct hv_kvp_msg);
cn_netlink_send(msg, 0, GFP_ATOMIC);
kfree(msg);
}
@@ -101,23 +106,24 @@ kvp_work_func(struct work_struct *dummy)
static void
kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
- struct hv_ku_msg *message;
+ struct hv_kvp_msg *message;
+ struct hv_kvp_msg_enumerate *data;
- message = (struct hv_ku_msg *)msg->data;
- if (msg->seq == KVP_REGISTER) {
+ message = (struct hv_kvp_msg *)msg->data;
+ if (message->kvp_hdr.operation == KVP_OP_REGISTER) {
pr_info("KVP: user-mode registering done.\n");
kvp_register();
}
- if (msg->seq == KVP_USER_SET) {
+ if (message->kvp_hdr.operation == KVP_OP_ENUMERATE) {
+ data = &message->body.kvp_enum_data;
/*
* Complete the transaction by forwarding the key value
* to the host. But first, cancel the timeout.
*/
if (cancel_delayed_work_sync(&kvp_work))
- kvp_respond_to_host(message->kvp_key,
- message->kvp_value,
- !strlen(message->kvp_key));
+ kvp_respond_to_host(data->data.key, data->data.value,
+ !strlen(data->data.key));
}
}
@@ -125,6 +131,7 @@ static void
kvp_send_key(struct work_struct *dummy)
{
struct cn_msg *msg;
+ struct hv_kvp_msg *message;
int index = kvp_transaction.index;
msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
@@ -132,9 +139,11 @@ kvp_send_key(struct work_struct *dummy)
if (msg) {
msg->id.idx = CN_KVP_IDX;
msg->id.val = CN_KVP_VAL;
- msg->seq = KVP_KERNEL_GET;
- ((struct hv_ku_msg *)msg->data)->kvp_index = index;
- msg->len = sizeof(struct hv_ku_msg);
+
+ message = (struct hv_kvp_msg *)msg->data;
+ message->kvp_hdr.operation = KVP_OP_ENUMERATE;
+ message->body.kvp_enum_data.index = index;
+ msg->len = sizeof(struct hv_kvp_msg);
cn_netlink_send(msg, 0, GFP_ATOMIC);
kfree(msg);
}
@@ -191,7 +200,7 @@ kvp_respond_to_host(char *key, char *value, int error)
kvp_msg = (struct hv_kvp_msg *)
&recv_buffer[sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
- kvp_data = &kvp_msg->kvp_data;
+ kvp_data = &kvp_msg->body.kvp_enum_data;
key_name = key;
/*
@@ -266,7 +275,7 @@ void hv_kvp_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
- kvp_data = &kvp_msg->kvp_data;
+ kvp_data = &kvp_msg->body.kvp_enum_data;
/*
* We only support the "get" operation on
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index dd0e3ee..e57a6c6 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -113,30 +113,6 @@
* (not supported), a NULL key string is returned.
*/
-/*
- *
- * The following definitions are shared with the user-mode component; do not
- * change any of this without making the corresponding changes in
- * the KVP user-mode component.
- */
-
-enum hv_ku_op {
- KVP_REGISTER = 0, /* Register the user mode component */
- KVP_KERNEL_GET, /* Kernel is requesting the value */
- KVP_KERNEL_SET, /* Kernel is providing the value */
- KVP_USER_GET, /* User is requesting the value */
- KVP_USER_SET /* User is providing the value */
-};
-
-struct hv_ku_msg {
- __u32 kvp_index; /* Key index */
- __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
- __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
-};
-
-
-
-
/*
* Registry value types.
@@ -149,6 +125,7 @@ enum hv_kvp_exchg_op {
KVP_OP_SET,
KVP_OP_DELETE,
KVP_OP_ENUMERATE,
+ KVP_OP_REGISTER,
KVP_OP_COUNT /* Number of operations, must be last. */
};
@@ -182,7 +159,10 @@ struct hv_kvp_msg_enumerate {
struct hv_kvp_msg {
struct hv_kvp_hdr kvp_hdr;
- struct hv_kvp_msg_enumerate kvp_data;
+ union {
+ struct hv_kvp_msg_enumerate kvp_enum_data;
+ char kvp_version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ } body;
} __attribute__((packed));
#ifdef __KERNEL__
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index b75523c..4ebf703 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -302,7 +302,7 @@ int main(void)
struct pollfd pfd;
struct nlmsghdr *incoming_msg;
struct cn_msg *incoming_cn_msg;
- struct hv_ku_msg *hv_msg;
+ struct hv_kvp_msg *hv_msg;
char *p;
char *key_value;
char *key_name;
@@ -340,9 +340,11 @@ int main(void)
message = (struct cn_msg *)kvp_send_buffer;
message->id.idx = CN_KVP_IDX;
message->id.val = CN_KVP_VAL;
- message->seq = KVP_REGISTER;
+
+ hv_msg = (struct hv_kvp_msg *)message->data;
+ hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
message->ack = 0;
- message->len = 0;
+ message->len = sizeof(struct hv_kvp_msg);
len = netlink_send(fd, message);
if (len < 0) {
@@ -368,14 +370,15 @@ int main(void)
incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
+ hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
- switch (incoming_cn_msg->seq) {
- case KVP_REGISTER:
+ switch (hv_msg->kvp_hdr.operation) {
+ case KVP_OP_REGISTER:
/*
* Driver is registering with us; stash away the version
* information.
*/
- p = (char *)incoming_cn_msg->data;
+ p = (char *)hv_msg->body.kvp_version;
lic_version = malloc(strlen(p) + 1);
if (lic_version) {
strcpy(lic_version, p);
@@ -386,17 +389,15 @@ int main(void)
}
continue;
- case KVP_KERNEL_GET:
- break;
default:
- continue;
+ break;
}
- hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data;
- key_name = (char *)hv_msg->kvp_key;
- key_value = (char *)hv_msg->kvp_value;
+ hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
+ key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
+ key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
- switch (hv_msg->kvp_index) {
+ switch (hv_msg->body.kvp_enum_data.index) {
case FullyQualifiedDomainName:
kvp_get_domain_name(key_value,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
@@ -456,9 +457,8 @@ int main(void)
incoming_cn_msg->id.idx = CN_KVP_IDX;
incoming_cn_msg->id.val = CN_KVP_VAL;
- incoming_cn_msg->seq = KVP_USER_SET;
incoming_cn_msg->ack = 0;
- incoming_cn_msg->len = sizeof(struct hv_ku_msg);
+ incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
len = netlink_send(fd, incoming_cn_msg);
if (len < 0) {
--
1.7.9.5

View File

@ -0,0 +1,65 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Thu, 2 Feb 2012 16:56:51 -0800
Subject: [PATCH 66/77] drivers: hv: Increase the number of VCPUs supported in
the guest
commit 14c1bf8a8920f36f6e0603a2ff920b48eec14387 upstream.
The current code arbirarily limited the number of CPUs the guest could have.
Change that so that we can support the maximum number of CPUs the guest can
support. While we use NR_CPUS to size the per-cpu state all we are allocating
based on NR_CPUS are the pointers to per-cpu state that will be allocatted in
the context of the initializing CPU. This patch triggers a checkpatch warning
for the usage of NR_CPU and since all we are allocating a couple of pointers
per CPU, it should be ok.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hv/hv.c | 4 ++--
drivers/hv/hyperv_vmbus.h | 5 ++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 12aa97f..15956bd 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -155,9 +155,9 @@ int hv_init(void)
union hv_x64_msr_hypercall_contents hypercall_msr;
void *virtaddr = NULL;
- memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS);
+ memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
memset(hv_context.synic_message_page, 0,
- sizeof(void *) * MAX_NUM_CPUS);
+ sizeof(void *) * NR_CPUS);
if (!query_hypervisor_presence())
goto cleanup;
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 6d7d286..699f0d8 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -457,7 +457,6 @@ static const uuid_le VMBUS_SERVICE_ID = {
},
};
-#define MAX_NUM_CPUS 32
struct hv_input_signal_event_buffer {
@@ -483,8 +482,8 @@ struct hv_context {
/* 8-bytes aligned of the buffer above */
struct hv_input_signal_event *signal_event_param;
- void *synic_message_page[MAX_NUM_CPUS];
- void *synic_event_page[MAX_NUM_CPUS];
+ void *synic_message_page[NR_CPUS];
+ void *synic_event_page[NR_CPUS];
};
extern struct hv_context hv_context;
--
1.7.9.5

View File

@ -0,0 +1,40 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Wed, 7 Mar 2012 10:02:00 +0000
Subject: [PATCH 68/77] net/hyperv: Use the built-in macro KBUILD_MODNAME for
this driver
commit d31b20fcc89efa8c5d3f5ea2720e08a286b69a36 upstream.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Cc: Olaf Hering <olaf@aepfle.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/netvsc_drv.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 0ae7a1a..217dfed 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -310,7 +310,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
static void netvsc_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, "hv_netvsc");
+ strcpy(info->driver, KBUILD_MODNAME);
strcpy(info->version, HV_DRV_VERSION);
strcpy(info->fw_version, "N/A");
}
@@ -482,7 +482,7 @@ MODULE_DEVICE_TABLE(vmbus, id_table);
/* The one and only one */
static struct hv_driver netvsc_drv = {
- .name = "netvsc",
+ .name = KBUILD_MODNAME,
.id_table = id_table,
.probe = netvsc_probe,
.remove = netvsc_remove,
--
1.7.9.5

View File

@ -0,0 +1,94 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Mon, 12 Mar 2012 10:20:49 +0000
Subject: [PATCH 69/77] net/hyperv: Fix data corruption in
rndis_filter_receive()
commit ef31bef6216db76950c38f1993b45953402f4c63 upstream.
Limiting the memcpy to be the sizeof(struct rndis_message) can truncate
the message if there are Per-Packet-Info or Out-of-Band data.
In my earlier patch (commit 45326342), the unnecessary kmap_atomic and
kunmap_atomic surrounding this memcpy have been removed because the memory
in the receive buffer is always mapped. This memcpy is not necessary
either. To fix the bug, I removed the memcpy.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/rndis_filter.c | 33 +++++++++------------------------
1 file changed, 9 insertions(+), 24 deletions(-)
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 136efd8..0c3d7d9 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -352,8 +352,7 @@ int rndis_filter_receive(struct hv_device *dev,
{
struct netvsc_device *net_dev = hv_get_drvdata(dev);
struct rndis_device *rndis_dev;
- struct rndis_message rndis_msg;
- struct rndis_message *rndis_hdr;
+ struct rndis_message *rndis_msg;
struct net_device *ndev;
if (!net_dev)
@@ -375,46 +374,32 @@ int rndis_filter_receive(struct hv_device *dev,
return -ENODEV;
}
- rndis_hdr = pkt->data;
-
- /* Make sure we got a valid rndis message */
- if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
- (rndis_hdr->msg_len > sizeof(struct rndis_message))) {
- netdev_err(ndev, "incoming rndis message buffer overflow "
- "detected (got %u, max %zu)..marking it an error!\n",
- rndis_hdr->msg_len,
- sizeof(struct rndis_message));
- }
+ rndis_msg = pkt->data;
- memcpy(&rndis_msg, rndis_hdr,
- (rndis_hdr->msg_len > sizeof(struct rndis_message)) ?
- sizeof(struct rndis_message) :
- rndis_hdr->msg_len);
+ dump_rndis_message(dev, rndis_msg);
- dump_rndis_message(dev, &rndis_msg);
-
- switch (rndis_msg.ndis_msg_type) {
+ switch (rndis_msg->ndis_msg_type) {
case REMOTE_NDIS_PACKET_MSG:
/* data msg */
- rndis_filter_receive_data(rndis_dev, &rndis_msg, pkt);
+ rndis_filter_receive_data(rndis_dev, rndis_msg, pkt);
break;
case REMOTE_NDIS_INITIALIZE_CMPLT:
case REMOTE_NDIS_QUERY_CMPLT:
case REMOTE_NDIS_SET_CMPLT:
/* completion msgs */
- rndis_filter_receive_response(rndis_dev, &rndis_msg);
+ rndis_filter_receive_response(rndis_dev, rndis_msg);
break;
case REMOTE_NDIS_INDICATE_STATUS_MSG:
/* notification msgs */
- rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg);
+ rndis_filter_receive_indicate_status(rndis_dev, rndis_msg);
break;
default:
netdev_err(ndev,
"unhandled rndis message (type %u len %u)\n",
- rndis_msg.ndis_msg_type,
- rndis_msg.msg_len);
+ rndis_msg->ndis_msg_type,
+ rndis_msg->msg_len);
break;
}
--
1.7.9.5

View File

@ -0,0 +1,250 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Mon, 12 Mar 2012 10:20:50 +0000
Subject: [PATCH 70/77] net/hyperv: Add support for vlan trunking from guests
commit 1f5f3a75e216fe771b8d6805e0bb2f43595a6ee1 upstream.
With this feature, a Linux guest can now configure multiple vlans through
a single synthetic NIC on Win8 Hyper-V host.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/hyperv_net.h | 34 ++++++++++++++++++++-
drivers/net/hyperv/netvsc.c | 3 +-
drivers/net/hyperv/netvsc_drv.c | 8 +++--
drivers/net/hyperv/rndis_filter.c | 60 +++++++++++++++++++++++++++++++++++++
4 files changed, 101 insertions(+), 4 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index dec5836..c358245 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -49,6 +49,7 @@ struct hv_netvsc_packet {
struct hv_device *device;
bool is_data_pkt;
+ u16 vlan_tci;
/*
* Valid only for receives when we break a xfer page packet
@@ -926,9 +927,40 @@ struct rndis_oobd {
struct rndis_per_packet_info {
u32 size;
u32 type;
- u32 per_pkt_info_offset;
+ u32 ppi_offset;
+};
+
+enum ndis_per_pkt_info_type {
+ TCPIP_CHKSUM_PKTINFO,
+ IPSEC_PKTINFO,
+ TCP_LARGESEND_PKTINFO,
+ CLASSIFICATION_HANDLE_PKTINFO,
+ NDIS_RESERVED,
+ SG_LIST_PKTINFO,
+ IEEE_8021Q_INFO,
+ ORIGINAL_PKTINFO,
+ PACKET_CANCEL_ID,
+ ORIGINAL_NET_BUFLIST,
+ CACHED_NET_BUFLIST,
+ SHORT_PKT_PADINFO,
+ MAX_PER_PKT_INFO
+};
+
+struct ndis_pkt_8021q_info {
+ union {
+ struct {
+ u32 pri:3; /* User Priority */
+ u32 cfi:1; /* Canonical Format ID */
+ u32 vlanid:12; /* VLAN ID */
+ u32 reserved:16;
+ };
+ u32 value;
+ };
};
+#define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
+ sizeof(struct ndis_pkt_8021q_info))
+
/* Format of Information buffer passed in a SetRequest for the OID */
/* OID_GEN_RNDIS_CONFIG_PARAMETER. */
struct rndis_config_parameter_info {
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 8965b45..d025c83 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -300,6 +300,7 @@ static int negotiate_nvsp_ver(struct hv_device *device,
memset(init_packet, 0, sizeof(struct nvsp_message));
init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG;
init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu;
+ init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1;
ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
@@ -341,7 +342,7 @@ static int netvsc_connect_vsp(struct hv_device *device)
/* Send the ndis version */
memset(init_packet, 0, sizeof(struct nvsp_message));
- ndis_version = 0x00050000;
+ ndis_version = 0x00050001;
init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER;
init_packet->msg.v1_msg.
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 217dfed..0f8e834 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -159,7 +159,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
/* Allocate a netvsc packet based on # of frags. */
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
(num_pages * sizeof(struct hv_page_buffer)) +
- sizeof(struct rndis_filter_packet), GFP_ATOMIC);
+ sizeof(struct rndis_filter_packet) +
+ NDIS_VLAN_PPI_SIZE, GFP_ATOMIC);
if (!packet) {
/* out of memory, drop packet */
netdev_err(net, "unable to allocate hv_netvsc_packet\n");
@@ -169,6 +170,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
return NETDEV_TX_BUSY;
}
+ packet->vlan_tci = skb->vlan_tci;
+
packet->extension = (void *)(unsigned long)packet +
sizeof(struct hv_netvsc_packet) +
(num_pages * sizeof(struct hv_page_buffer));
@@ -293,6 +296,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
skb->protocol = eth_type_trans(skb, net);
skb->ip_summed = CHECKSUM_NONE;
+ skb->vlan_tci = packet->vlan_tci;
net->stats.rx_packets++;
net->stats.rx_bytes += packet->total_data_buflen;
@@ -407,7 +411,7 @@ static int netvsc_probe(struct hv_device *dev,
/* TODO: Add GSO and Checksum offload */
net->hw_features = NETIF_F_SG;
- net->features = NETIF_F_SG;
+ net->features = NETIF_F_SG | NETIF_F_HW_VLAN_TX;
SET_ETHTOOL_OPS(net, &ethtool_ops);
SET_NETDEV_DEV(net, &dev->device);
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 0c3d7d9..d6be64b 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -26,6 +26,7 @@
#include <linux/io.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
+#include <linux/if_vlan.h>
#include "hyperv_net.h"
@@ -303,12 +304,39 @@ static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
}
}
+/*
+ * Get the Per-Packet-Info with the specified type
+ * return NULL if not found.
+ */
+static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
+{
+ struct rndis_per_packet_info *ppi;
+ int len;
+
+ if (rpkt->per_pkt_info_offset == 0)
+ return NULL;
+
+ ppi = (struct rndis_per_packet_info *)((ulong)rpkt +
+ rpkt->per_pkt_info_offset);
+ len = rpkt->per_pkt_info_len;
+
+ while (len > 0) {
+ if (ppi->type == type)
+ return (void *)((ulong)ppi + ppi->ppi_offset);
+ len -= ppi->size;
+ ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size);
+ }
+
+ return NULL;
+}
+
static void rndis_filter_receive_data(struct rndis_device *dev,
struct rndis_message *msg,
struct hv_netvsc_packet *pkt)
{
struct rndis_packet *rndis_pkt;
u32 data_offset;
+ struct ndis_pkt_8021q_info *vlan;
rndis_pkt = &msg->msg.pkt;
@@ -344,6 +372,14 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
pkt->is_data_pkt = true;
+ vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
+ if (vlan) {
+ pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
+ (vlan->pri << VLAN_PRIO_SHIFT);
+ } else {
+ pkt->vlan_tci = 0;
+ }
+
netvsc_recv_callback(dev->net_dev->dev, pkt);
}
@@ -759,12 +795,15 @@ int rndis_filter_send(struct hv_device *dev,
struct rndis_message *rndis_msg;
struct rndis_packet *rndis_pkt;
u32 rndis_msg_size;
+ bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT;
/* Add the rndis header */
filter_pkt = (struct rndis_filter_packet *)pkt->extension;
rndis_msg = &filter_pkt->msg;
rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
+ if (isvlan)
+ rndis_msg_size += NDIS_VLAN_PPI_SIZE;
rndis_msg->ndis_msg_type = REMOTE_NDIS_PACKET_MSG;
rndis_msg->msg_len = pkt->total_data_buflen +
@@ -772,8 +811,29 @@ int rndis_filter_send(struct hv_device *dev,
rndis_pkt = &rndis_msg->msg.pkt;
rndis_pkt->data_offset = sizeof(struct rndis_packet);
+ if (isvlan)
+ rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE;
rndis_pkt->data_len = pkt->total_data_buflen;
+ if (isvlan) {
+ struct rndis_per_packet_info *ppi;
+ struct ndis_pkt_8021q_info *vlan;
+
+ rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
+ rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE;
+
+ ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt +
+ rndis_pkt->per_pkt_info_offset);
+ ppi->size = NDIS_VLAN_PPI_SIZE;
+ ppi->type = IEEE_8021Q_INFO;
+ ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
+
+ vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi +
+ ppi->ppi_offset);
+ vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK;
+ vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+ }
+
pkt->is_data_pkt = true;
pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT;
pkt->page_buf[0].offset =
--
1.7.9.5

View File

@ -0,0 +1,109 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Sat, 10 Mar 2012 15:32:08 -0800
Subject: [PATCH 71/77] Drivers: hv: Add new message types to enhance KVP
commit e485ceac9ebd43901ef0ce13622385d509e072e7 upstream.
Add additional KVP (Key Value Pair) protocol messages to
enhance KVP functionality for Linux guests on Hyper-V. As part of this,
patch define an explicit version negoitiation message.
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hv/hv_kvp.c | 5 +++--
include/linux/hyperv.h | 30 +++++++++++++++++++++++++++---
tools/hv/hv_kvp_daemon.c | 2 +-
3 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 0ef4c1f..779109b 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -78,7 +78,7 @@ kvp_register(void)
if (msg) {
kvp_msg = (struct hv_kvp_msg *)msg->data;
- version = kvp_msg->body.kvp_version;
+ version = kvp_msg->body.kvp_register.version;
msg->id.idx = CN_KVP_IDX;
msg->id.val = CN_KVP_VAL;
@@ -122,7 +122,8 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
* to the host. But first, cancel the timeout.
*/
if (cancel_delayed_work_sync(&kvp_work))
- kvp_respond_to_host(data->data.key, data->data.value,
+ kvp_respond_to_host(data->data.key,
+ data->data.value,
!strlen(data->data.key));
}
}
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index e57a6c6..a2d8c54 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -149,7 +149,11 @@ struct hv_kvp_exchg_msg_value {
__u32 key_size;
__u32 value_size;
__u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
- __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+ union {
+ __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+ __u32 value_u32;
+ __u64 value_u64;
+ };
} __attribute__((packed));
struct hv_kvp_msg_enumerate {
@@ -157,11 +161,31 @@ struct hv_kvp_msg_enumerate {
struct hv_kvp_exchg_msg_value data;
} __attribute__((packed));
+struct hv_kvp_msg_get {
+ struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg_set {
+ struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg_delete {
+ __u32 key_size;
+ __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+};
+
+struct hv_kvp_register {
+ __u8 version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+};
+
struct hv_kvp_msg {
struct hv_kvp_hdr kvp_hdr;
union {
- struct hv_kvp_msg_enumerate kvp_enum_data;
- char kvp_version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ struct hv_kvp_msg_get kvp_get;
+ struct hv_kvp_msg_set kvp_set;
+ struct hv_kvp_msg_delete kvp_delete;
+ struct hv_kvp_msg_enumerate kvp_enum_data;
+ struct hv_kvp_register kvp_register;
} body;
} __attribute__((packed));
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 4ebf703..00d3f7c 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -378,7 +378,7 @@ int main(void)
* Driver is registering with us; stash away the version
* information.
*/
- p = (char *)hv_msg->body.kvp_version;
+ p = (char *)hv_msg->body.kvp_register.version;
lic_version = malloc(strlen(p) + 1);
if (lic_version) {
strcpy(lic_version, p);
--
1.7.9.5

View File

@ -0,0 +1,53 @@
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Wed, 14 Mar 2012 08:53:34 +0000
Subject: [PATCH 72/77] net/hyperv: fix erroneous NETDEV_TX_BUSY use
commit bb6d5e76fb4fba9aa36726db41404512f3286c0f upstream.
A driver start_xmit() method cannot free skb and return NETDEV_TX_BUSY,
since caller is going to reuse freed skb.
This is mostly a revert of commit bf769375c (staging: hv: fix the return
status of netvsc_start_xmit())
In fact netif_tx_stop_queue() / netif_stop_queue() is needed before
returning NETDEV_TX_BUSY or you can trigger a ksoftirqd fatal loop.
In case of memory allocation error, only safe way is to drop the packet
and return NETDEV_TX_OK
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/netvsc_drv.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 0f8e834..2517d20 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -167,7 +167,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
dev_kfree_skb(skb);
net->stats.tx_dropped++;
- return NETDEV_TX_BUSY;
+ return NETDEV_TX_OK;
}
packet->vlan_tci = skb->vlan_tci;
@@ -229,7 +229,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
dev_kfree_skb_any(skb);
}
- return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK;
+ return NETDEV_TX_OK;
}
/*
--
1.7.9.5

View File

@ -0,0 +1,401 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Fri, 16 Mar 2012 08:02:25 -0700
Subject: [PATCH 73/77] Drivers: hv: Support the newly introduced KVP messages
in the driver
commit fa3d5b85c681518b6e4ec515814dcb2d5b702b89 upstream.
Support the newly defined KVP message types. It turns out that the host
pushes a set of standard key value pairs as soon as the guest opens the KVP channel.
Since we cannot handle these tuples until the user level daemon loads up, defer
reading the KVP channel until the user level daemon is launched.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hv/hv_kvp.c | 218 +++++++++++++++++++++++++++++++++++-----------
include/linux/hyperv.h | 2 +
tools/hv/hv_kvp_daemon.c | 7 ++
3 files changed, 176 insertions(+), 51 deletions(-)
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 779109b..cfe60b0 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -42,9 +42,10 @@
static struct {
bool active; /* transaction status - active or not */
int recv_len; /* number of bytes received. */
- int index; /* current index */
+ struct hv_kvp_msg *kvp_msg; /* current message */
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
+ void *kvp_context; /* for the channel callback */
} kvp_transaction;
static void kvp_send_key(struct work_struct *dummy);
@@ -110,12 +111,15 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
struct hv_kvp_msg_enumerate *data;
message = (struct hv_kvp_msg *)msg->data;
- if (message->kvp_hdr.operation == KVP_OP_REGISTER) {
+ switch (message->kvp_hdr.operation) {
+ case KVP_OP_REGISTER:
pr_info("KVP: user-mode registering done.\n");
kvp_register();
- }
+ kvp_transaction.active = false;
+ hv_kvp_onchannelcallback(kvp_transaction.kvp_context);
+ break;
- if (message->kvp_hdr.operation == KVP_OP_ENUMERATE) {
+ default:
data = &message->body.kvp_enum_data;
/*
* Complete the transaction by forwarding the key value
@@ -133,21 +137,104 @@ kvp_send_key(struct work_struct *dummy)
{
struct cn_msg *msg;
struct hv_kvp_msg *message;
- int index = kvp_transaction.index;
+ struct hv_kvp_msg *in_msg;
+ __u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation;
+ __u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool;
+ __u32 val32;
+ __u64 val64;
msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
+ if (!msg)
+ return;
- if (msg) {
- msg->id.idx = CN_KVP_IDX;
- msg->id.val = CN_KVP_VAL;
+ msg->id.idx = CN_KVP_IDX;
+ msg->id.val = CN_KVP_VAL;
- message = (struct hv_kvp_msg *)msg->data;
- message->kvp_hdr.operation = KVP_OP_ENUMERATE;
- message->body.kvp_enum_data.index = index;
- msg->len = sizeof(struct hv_kvp_msg);
- cn_netlink_send(msg, 0, GFP_ATOMIC);
- kfree(msg);
+ message = (struct hv_kvp_msg *)msg->data;
+ message->kvp_hdr.operation = operation;
+ message->kvp_hdr.pool = pool;
+ in_msg = kvp_transaction.kvp_msg;
+
+ /*
+ * The key/value strings sent from the host are encoded in
+ * in utf16; convert it to utf8 strings.
+ * The host assures us that the utf16 strings will not exceed
+ * the max lengths specified. We will however, reserve room
+ * for the string terminating character - in the utf16s_utf8s()
+ * function we limit the size of the buffer where the converted
+ * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee
+ * that the strings can be properly terminated!
+ */
+
+ switch (message->kvp_hdr.operation) {
+ case KVP_OP_SET:
+ switch (in_msg->body.kvp_set.data.value_type) {
+ case REG_SZ:
+ /*
+ * The value is a string - utf16 encoding.
+ */
+ message->body.kvp_set.data.value_size =
+ utf16s_to_utf8s(
+ (wchar_t *)in_msg->body.kvp_set.data.value,
+ in_msg->body.kvp_set.data.value_size,
+ UTF16_LITTLE_ENDIAN,
+ message->body.kvp_set.data.value,
+ HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1;
+ break;
+
+ case REG_U32:
+ /*
+ * The value is a 32 bit scalar.
+ * We save this as a utf8 string.
+ */
+ val32 = in_msg->body.kvp_set.data.value_u32;
+ message->body.kvp_set.data.value_size =
+ sprintf(message->body.kvp_set.data.value,
+ "%d", val32) + 1;
+ break;
+
+ case REG_U64:
+ /*
+ * The value is a 64 bit scalar.
+ * We save this as a utf8 string.
+ */
+ val64 = in_msg->body.kvp_set.data.value_u64;
+ message->body.kvp_set.data.value_size =
+ sprintf(message->body.kvp_set.data.value,
+ "%llu", val64) + 1;
+ break;
+
+ }
+ case KVP_OP_GET:
+ message->body.kvp_set.data.key_size =
+ utf16s_to_utf8s(
+ (wchar_t *)in_msg->body.kvp_set.data.key,
+ in_msg->body.kvp_set.data.key_size,
+ UTF16_LITTLE_ENDIAN,
+ message->body.kvp_set.data.key,
+ HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
+ break;
+
+ case KVP_OP_DELETE:
+ message->body.kvp_delete.key_size =
+ utf16s_to_utf8s(
+ (wchar_t *)in_msg->body.kvp_delete.key,
+ in_msg->body.kvp_delete.key_size,
+ UTF16_LITTLE_ENDIAN,
+ message->body.kvp_delete.key,
+ HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
+ break;
+
+ case KVP_OP_ENUMERATE:
+ message->body.kvp_enum_data.index =
+ in_msg->body.kvp_enum_data.index;
+ break;
}
+
+ msg->len = sizeof(struct hv_kvp_msg);
+ cn_netlink_send(msg, 0, GFP_ATOMIC);
+ kfree(msg);
+
return;
}
@@ -159,10 +246,11 @@ static void
kvp_respond_to_host(char *key, char *value, int error)
{
struct hv_kvp_msg *kvp_msg;
- struct hv_kvp_msg_enumerate *kvp_data;
+ struct hv_kvp_exchg_msg_value *kvp_data;
char *key_name;
struct icmsg_hdr *icmsghdrp;
- int keylen, valuelen;
+ int keylen = 0;
+ int valuelen = 0;
u32 buf_len;
struct vmbus_channel *channel;
u64 req_id;
@@ -189,6 +277,9 @@ kvp_respond_to_host(char *key, char *value, int error)
kvp_transaction.active = false;
+ icmsghdrp = (struct icmsg_hdr *)
+ &recv_buffer[sizeof(struct vmbuspipe_hdr)];
+
if (channel->onchannel_callback == NULL)
/*
* We have raced with util driver being unloaded;
@@ -196,41 +287,66 @@ kvp_respond_to_host(char *key, char *value, int error)
*/
return;
- icmsghdrp = (struct icmsg_hdr *)
- &recv_buffer[sizeof(struct vmbuspipe_hdr)];
- kvp_msg = (struct hv_kvp_msg *)
- &recv_buffer[sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
- kvp_data = &kvp_msg->body.kvp_enum_data;
- key_name = key;
/*
* If the error parameter is set, terminate the host's enumeration.
*/
if (error) {
/*
- * We don't support this index or the we have timedout;
+ * Something failed or the we have timedout;
* terminate the host-side iteration by returning an error.
*/
icmsghdrp->status = HV_E_FAIL;
goto response_done;
}
+ icmsghdrp->status = HV_S_OK;
+
+ kvp_msg = (struct hv_kvp_msg *)
+ &recv_buffer[sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ switch (kvp_transaction.kvp_msg->kvp_hdr.operation) {
+ case KVP_OP_GET:
+ kvp_data = &kvp_msg->body.kvp_get.data;
+ goto copy_value;
+
+ case KVP_OP_SET:
+ case KVP_OP_DELETE:
+ goto response_done;
+
+ default:
+ break;
+ }
+
+ kvp_data = &kvp_msg->body.kvp_enum_data.data;
+ key_name = key;
+
/*
* The windows host expects the key/value pair to be encoded
- * in utf16.
+ * in utf16. Ensure that the key/value size reported to the host
+ * will be less than or equal to the MAX size (including the
+ * terminating character).
*/
keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
- (wchar_t *) kvp_data->data.key,
- HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2);
- kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */
+ (wchar_t *) kvp_data->key,
+ (HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2);
+ kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */
+
+copy_value:
valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
- (wchar_t *) kvp_data->data.value,
- HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2);
- kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */
+ (wchar_t *) kvp_data->value,
+ (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2);
+ kvp_data->value_size = 2*(valuelen + 1); /* utf16 encoding */
- kvp_data->data.value_type = REG_SZ; /* all our values are strings */
- icmsghdrp->status = HV_S_OK;
+ /*
+ * If the utf8s to utf16s conversion failed; notify host
+ * of the error.
+ */
+ if ((keylen < 0) || (valuelen < 0))
+ icmsghdrp->status = HV_E_FAIL;
+
+ kvp_data->value_type = REG_SZ; /* all our values are strings */
response_done:
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
@@ -257,11 +373,18 @@ void hv_kvp_onchannelcallback(void *context)
u64 requestid;
struct hv_kvp_msg *kvp_msg;
- struct hv_kvp_msg_enumerate *kvp_data;
struct icmsg_hdr *icmsghdrp;
struct icmsg_negotiate *negop = NULL;
+ if (kvp_transaction.active) {
+ /*
+ * We will defer processing this callback once
+ * the current transaction is complete.
+ */
+ kvp_transaction.kvp_context = context;
+ return;
+ }
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
@@ -276,29 +399,16 @@ void hv_kvp_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
- kvp_data = &kvp_msg->body.kvp_enum_data;
-
- /*
- * We only support the "get" operation on
- * "KVP_POOL_AUTO" pool.
- */
-
- if ((kvp_msg->kvp_hdr.pool != KVP_POOL_AUTO) ||
- (kvp_msg->kvp_hdr.operation !=
- KVP_OP_ENUMERATE)) {
- icmsghdrp->status = HV_E_FAIL;
- goto callback_done;
- }
-
/*
* Stash away this global state for completing the
* transaction; note transactions are serialized.
*/
+
kvp_transaction.recv_len = recvlen;
kvp_transaction.recv_channel = channel;
kvp_transaction.recv_req_id = requestid;
kvp_transaction.active = true;
- kvp_transaction.index = kvp_data->index;
+ kvp_transaction.kvp_msg = kvp_msg;
/*
* Get the information from the
@@ -316,8 +426,6 @@ void hv_kvp_onchannelcallback(void *context)
}
-callback_done:
-
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
@@ -338,6 +446,14 @@ hv_kvp_init(struct hv_util_service *srv)
return err;
recv_buffer = srv->recv_buffer;
+ /*
+ * When this driver loads, the user level daemon that
+ * processes the host requests may not yet be running.
+ * Defer processing channel callbacks until the daemon
+ * has registered.
+ */
+ kvp_transaction.active = true;
+
return 0;
}
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index a2d8c54..e88a979 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -119,6 +119,8 @@
*/
#define REG_SZ 1
+#define REG_U32 4
+#define REG_U64 8
enum hv_kvp_exchg_op {
KVP_OP_GET = 0,
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 00d3f7c..a98878c 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -389,10 +389,16 @@ int main(void)
}
continue;
+ case KVP_OP_SET:
+ case KVP_OP_GET:
+ case KVP_OP_DELETE:
default:
break;
}
+ if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
+ goto kvp_done;
+
hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
@@ -454,6 +460,7 @@ int main(void)
* already in the receive buffer. Update the cn_msg header to
* reflect the key value that has been added to the message
*/
+kvp_done:
incoming_cn_msg->id.idx = CN_KVP_IDX;
incoming_cn_msg->id.val = CN_KVP_VAL;
--
1.7.9.5

View File

@ -0,0 +1,339 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Fri, 16 Mar 2012 08:02:26 -0700
Subject: [PATCH 74/77] Tools: hv: Fully support the new KVP verbs in the user
level daemon
commit db425334e5bb7fa65bbbd7bea9d79842f65bcf45 upstream.
Now fully support the new KVP messages in the user level daemon. Hyper-V defines
multiple persistent pools to which the host can write/read/modify KVP tuples.
In this patch we implement a file for each specified pool, where the KVP tuples
will be stored in the guest.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
tools/hv/hv_kvp_daemon.c | 281 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 280 insertions(+), 1 deletion(-)
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index a98878c..2fb9c3d 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -39,7 +39,8 @@
#include <ifaddrs.h>
#include <netdb.h>
#include <syslog.h>
-
+#include <sys/stat.h>
+#include <fcntl.h>
/*
* KVP protocol: The user mode component first registers with the
@@ -79,6 +80,250 @@ static char *os_build;
static char *lic_version;
static struct utsname uts_buf;
+
+#define MAX_FILE_NAME 100
+#define ENTRIES_PER_BLOCK 50
+
+struct kvp_record {
+ __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+};
+
+struct kvp_file_state {
+ int fd;
+ int num_blocks;
+ struct kvp_record *records;
+ int num_records;
+ __u8 fname[MAX_FILE_NAME];
+};
+
+static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
+
+static void kvp_acquire_lock(int pool)
+{
+ struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
+ fl.l_pid = getpid();
+
+ if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
+ syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
+ exit(-1);
+ }
+}
+
+static void kvp_release_lock(int pool)
+{
+ struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
+ fl.l_pid = getpid();
+
+ if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
+ perror("fcntl");
+ syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
+ exit(-1);
+ }
+}
+
+static void kvp_update_file(int pool)
+{
+ FILE *filep;
+ size_t bytes_written;
+
+ /*
+ * We are going to write our in-memory registry out to
+ * disk; acquire the lock first.
+ */
+ kvp_acquire_lock(pool);
+
+ filep = fopen(kvp_file_info[pool].fname, "w");
+ if (!filep) {
+ kvp_release_lock(pool);
+ syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
+ exit(-1);
+ }
+
+ bytes_written = fwrite(kvp_file_info[pool].records,
+ sizeof(struct kvp_record),
+ kvp_file_info[pool].num_records, filep);
+
+ fflush(filep);
+ kvp_release_lock(pool);
+}
+
+static int kvp_file_init(void)
+{
+ int ret, fd;
+ FILE *filep;
+ size_t records_read;
+ __u8 *fname;
+ struct kvp_record *record;
+ struct kvp_record *readp;
+ int num_blocks;
+ int i;
+ int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
+
+ if (access("/var/opt/hyperv", F_OK)) {
+ if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
+ syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
+ exit(-1);
+ }
+ }
+
+ for (i = 0; i < KVP_POOL_COUNT; i++) {
+ fname = kvp_file_info[i].fname;
+ records_read = 0;
+ num_blocks = 1;
+ sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
+ fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
+
+ if (fd == -1)
+ return 1;
+
+
+ filep = fopen(fname, "r");
+ if (!filep)
+ return 1;
+
+ record = malloc(alloc_unit * num_blocks);
+ if (record == NULL) {
+ fclose(filep);
+ return 1;
+ }
+ while (!feof(filep)) {
+ readp = &record[records_read];
+ records_read += fread(readp, sizeof(struct kvp_record),
+ ENTRIES_PER_BLOCK,
+ filep);
+
+ if (!feof(filep)) {
+ /*
+ * We have more data to read.
+ */
+ num_blocks++;
+ record = realloc(record, alloc_unit *
+ num_blocks);
+ if (record == NULL) {
+ fclose(filep);
+ return 1;
+ }
+ continue;
+ }
+ break;
+ }
+ kvp_file_info[i].fd = fd;
+ kvp_file_info[i].num_blocks = num_blocks;
+ kvp_file_info[i].records = record;
+ kvp_file_info[i].num_records = records_read;
+ fclose(filep);
+
+ }
+
+ return 0;
+}
+
+static int kvp_key_delete(int pool, __u8 *key, int key_size)
+{
+ int i;
+ int j, k;
+ int num_records = kvp_file_info[pool].num_records;
+ struct kvp_record *record = kvp_file_info[pool].records;
+
+ for (i = 0; i < num_records; i++) {
+ if (memcmp(key, record[i].key, key_size))
+ continue;
+ /*
+ * Found a match; just move the remaining
+ * entries up.
+ */
+ if (i == num_records) {
+ kvp_file_info[pool].num_records--;
+ kvp_update_file(pool);
+ return 0;
+ }
+
+ j = i;
+ k = j + 1;
+ for (; k < num_records; k++) {
+ strcpy(record[j].key, record[k].key);
+ strcpy(record[j].value, record[k].value);
+ j++;
+ }
+
+ kvp_file_info[pool].num_records--;
+ kvp_update_file(pool);
+ return 0;
+ }
+ return 1;
+}
+
+static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
+ int value_size)
+{
+ int i;
+ int j, k;
+ int num_records = kvp_file_info[pool].num_records;
+ struct kvp_record *record = kvp_file_info[pool].records;
+ int num_blocks = kvp_file_info[pool].num_blocks;
+
+ if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
+ (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
+ return 1;
+
+ for (i = 0; i < num_records; i++) {
+ if (memcmp(key, record[i].key, key_size))
+ continue;
+ /*
+ * Found a match; just update the value -
+ * this is the modify case.
+ */
+ memcpy(record[i].value, value, value_size);
+ kvp_update_file(pool);
+ return 0;
+ }
+
+ /*
+ * Need to add a new entry;
+ */
+ if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
+ /* Need to allocate a larger array for reg entries. */
+ record = realloc(record, sizeof(struct kvp_record) *
+ ENTRIES_PER_BLOCK * (num_blocks + 1));
+
+ if (record == NULL)
+ return 1;
+ kvp_file_info[pool].num_blocks++;
+
+ }
+ memcpy(record[i].value, value, value_size);
+ memcpy(record[i].key, key, key_size);
+ kvp_file_info[pool].records = record;
+ kvp_file_info[pool].num_records++;
+ kvp_update_file(pool);
+ return 0;
+}
+
+static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
+ int value_size)
+{
+ int i;
+ int num_records = kvp_file_info[pool].num_records;
+ struct kvp_record *record = kvp_file_info[pool].records;
+
+ if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
+ (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
+ return 1;
+
+ for (i = 0; i < num_records; i++) {
+ if (memcmp(key, record[i].key, key_size))
+ continue;
+ /*
+ * Found a match; just copy the value out.
+ */
+ memcpy(value, record[i].value, value_size);
+ return 0;
+ }
+
+ return 1;
+}
+
void kvp_get_os_info(void)
{
FILE *file;
@@ -315,6 +560,11 @@ int main(void)
*/
kvp_get_os_info();
+ if (kvp_file_init()) {
+ syslog(LOG_ERR, "Failed to initialize the pools");
+ exit(-1);
+ }
+
fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (fd < 0) {
syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
@@ -389,9 +639,38 @@ int main(void)
}
continue;
+ /*
+ * The current protocol with the kernel component uses a
+ * NULL key name to pass an error condition.
+ * For the SET, GET and DELETE operations,
+ * use the existing protocol to pass back error.
+ */
+
case KVP_OP_SET:
+ if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
+ hv_msg->body.kvp_set.data.key,
+ hv_msg->body.kvp_set.data.key_size,
+ hv_msg->body.kvp_set.data.value,
+ hv_msg->body.kvp_set.data.value_size))
+ strcpy(hv_msg->body.kvp_set.data.key, "");
+ break;
+
case KVP_OP_GET:
+ if (kvp_get_value(hv_msg->kvp_hdr.pool,
+ hv_msg->body.kvp_set.data.key,
+ hv_msg->body.kvp_set.data.key_size,
+ hv_msg->body.kvp_set.data.value,
+ hv_msg->body.kvp_set.data.value_size))
+ strcpy(hv_msg->body.kvp_set.data.key, "");
+ break;
+
case KVP_OP_DELETE:
+ if (kvp_key_delete(hv_msg->kvp_hdr.pool,
+ hv_msg->body.kvp_delete.key,
+ hv_msg->body.kvp_delete.key_size))
+ strcpy(hv_msg->body.kvp_delete.key, "");
+ break;
+
default:
break;
}
--
1.7.9.5

View File

@ -0,0 +1,237 @@
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Fri, 16 Mar 2012 08:02:27 -0700
Subject: [PATCH 75/77] Tools: hv: Support enumeration from all the pools
commit adc80ae60eae24a43a357bf5b30fb496f34aa605 upstream.
We have only supported enumeration only from the AUTO pool. Now support
enumeration from all the available pools.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hv/hv_kvp.c | 7 +--
include/linux/hyperv.h | 1 +
tools/hv/hv_kvp_daemon.c | 124 +++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 122 insertions(+), 10 deletions(-)
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index cfe60b0..6186025 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -289,14 +289,15 @@ kvp_respond_to_host(char *key, char *value, int error)
/*
- * If the error parameter is set, terminate the host's enumeration.
+ * If the error parameter is set, terminate the host's enumeration
+ * on this pool.
*/
if (error) {
/*
* Something failed or the we have timedout;
- * terminate the host-side iteration by returning an error.
+ * terminate the current host-side iteration.
*/
- icmsghdrp->status = HV_E_FAIL;
+ icmsghdrp->status = HV_S_CONT;
goto response_done;
}
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index e88a979..5852545 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -952,6 +952,7 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
#define HV_S_OK 0x00000000
#define HV_E_FAIL 0x80004005
+#define HV_S_CONT 0x80070103
#define HV_ERROR_NOT_SUPPORTED 0x80070032
#define HV_ERROR_MACHINE_LOCKED 0x800704F7
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 2fb9c3d..146fd61 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -148,6 +148,51 @@ static void kvp_update_file(int pool)
kvp_release_lock(pool);
}
+static void kvp_update_mem_state(int pool)
+{
+ FILE *filep;
+ size_t records_read = 0;
+ struct kvp_record *record = kvp_file_info[pool].records;
+ struct kvp_record *readp;
+ int num_blocks = kvp_file_info[pool].num_blocks;
+ int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
+
+ kvp_acquire_lock(pool);
+
+ filep = fopen(kvp_file_info[pool].fname, "r");
+ if (!filep) {
+ kvp_release_lock(pool);
+ syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
+ exit(-1);
+ }
+ while (!feof(filep)) {
+ readp = &record[records_read];
+ records_read += fread(readp, sizeof(struct kvp_record),
+ ENTRIES_PER_BLOCK * num_blocks,
+ filep);
+
+ if (!feof(filep)) {
+ /*
+ * We have more data to read.
+ */
+ num_blocks++;
+ record = realloc(record, alloc_unit * num_blocks);
+
+ if (record == NULL) {
+ syslog(LOG_ERR, "malloc failed");
+ exit(-1);
+ }
+ continue;
+ }
+ break;
+ }
+
+ kvp_file_info[pool].num_blocks = num_blocks;
+ kvp_file_info[pool].records = record;
+ kvp_file_info[pool].num_records = records_read;
+
+ kvp_release_lock(pool);
+}
static int kvp_file_init(void)
{
int ret, fd;
@@ -223,8 +268,16 @@ static int kvp_key_delete(int pool, __u8 *key, int key_size)
{
int i;
int j, k;
- int num_records = kvp_file_info[pool].num_records;
- struct kvp_record *record = kvp_file_info[pool].records;
+ int num_records;
+ struct kvp_record *record;
+
+ /*
+ * First update the in-memory state.
+ */
+ kvp_update_mem_state(pool);
+
+ num_records = kvp_file_info[pool].num_records;
+ record = kvp_file_info[pool].records;
for (i = 0; i < num_records; i++) {
if (memcmp(key, record[i].key, key_size))
@@ -259,14 +312,23 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
{
int i;
int j, k;
- int num_records = kvp_file_info[pool].num_records;
- struct kvp_record *record = kvp_file_info[pool].records;
- int num_blocks = kvp_file_info[pool].num_blocks;
+ int num_records;
+ struct kvp_record *record;
+ int num_blocks;
if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
return 1;
+ /*
+ * First update the in-memory state.
+ */
+ kvp_update_mem_state(pool);
+
+ num_records = kvp_file_info[pool].num_records;
+ record = kvp_file_info[pool].records;
+ num_blocks = kvp_file_info[pool].num_blocks;
+
for (i = 0; i < num_records; i++) {
if (memcmp(key, record[i].key, key_size))
continue;
@@ -304,13 +366,21 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
int value_size)
{
int i;
- int num_records = kvp_file_info[pool].num_records;
- struct kvp_record *record = kvp_file_info[pool].records;
+ int num_records;
+ struct kvp_record *record;
if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
return 1;
+ /*
+ * First update the in-memory state.
+ */
+ kvp_update_mem_state(pool);
+
+ num_records = kvp_file_info[pool].num_records;
+ record = kvp_file_info[pool].records;
+
for (i = 0; i < num_records; i++) {
if (memcmp(key, record[i].key, key_size))
continue;
@@ -324,6 +394,31 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
return 1;
}
+static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
+ __u8 *value, int value_size)
+{
+ struct kvp_record *record;
+
+ /*
+ * First update our in-memory database.
+ */
+ kvp_update_mem_state(pool);
+ record = kvp_file_info[pool].records;
+
+ if (index >= kvp_file_info[pool].num_records) {
+ /*
+ * This is an invalid index; terminate enumeration;
+ * - a NULL value will do the trick.
+ */
+ strcpy(value, "");
+ return;
+ }
+
+ memcpy(key, record[index].key, key_size);
+ memcpy(value, record[index].value, value_size);
+}
+
+
void kvp_get_os_info(void)
{
FILE *file;
@@ -678,6 +773,21 @@ int main(void)
if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
goto kvp_done;
+ /*
+ * If the pool is KVP_POOL_AUTO, dynamically generate
+ * both the key and the value; if not read from the
+ * appropriate pool.
+ */
+ if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) {
+ kvp_pool_enumerate(hv_msg->kvp_hdr.pool,
+ hv_msg->body.kvp_enum_data.index,
+ hv_msg->body.kvp_enum_data.data.key,
+ HV_KVP_EXCHANGE_MAX_KEY_SIZE,
+ hv_msg->body.kvp_enum_data.data.value,
+ HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
+ goto kvp_done;
+ }
+
hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
--
1.7.9.5

View File

@ -0,0 +1,46 @@
From: Haiyang Zhang <haiyangz@microsoft.com>
Date: Mon, 19 Mar 2012 17:27:06 -0400
Subject: [PATCH 76/77] net/hyperv: Fix the code handling tx busy
commit da24e906cbfc08171d24a2b7cf66fad565fdd121 upstream.
Instead of dropping the packet, we keep the skb buffer, and return
NETDEV_TX_BUSY to let upper layer retry send. This will not cause
endless loop, because the host is taking data away from ring buffer,
and we have called the stop_queue before returning NETDEV_TX_BUSY.
The stop_queue was called in the function netvsc_send() in file
netvsc.c, then it returns to rndis_filter_send(), which returns to
netvsc_start_xmit() in file netvsc_drv.c. So the NETDEV_TX_BUSY is
indeed returned AFTER queue is stopped.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/hyperv/netvsc_drv.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 2517d20..dd29478 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -223,13 +223,10 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
net->stats.tx_bytes += skb->len;
net->stats.tx_packets++;
} else {
- /* we are shutting down or bus overloaded, just drop packet */
- net->stats.tx_dropped++;
kfree(packet);
- dev_kfree_skb_any(skb);
}
- return NETDEV_TX_OK;
+ return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK;
}
/*
--
1.7.9.5

View File

@ -0,0 +1,144 @@
From: Cong Wang <amwang@redhat.com>
Date: Fri, 25 Nov 2011 23:14:24 +0800
Subject: [PATCH 77/77] hv: remove the second argument of k[un]map_atomic()
commit 86cbce4de23f26f1aee8df789d30b0f1ba78c967 upstream.
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Cong Wang <amwang@redhat.com>
[bwh: Adjust filename to apply after move to drivers/scsi; apply changes
from Linux's merge commit 9f3938346a5c1fa504647670edb5fea5756cfb00.]
---
drivers/scsi/storvsc_drv.c | 52 ++++++++++++++++++++++----------------------
1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 695ffc3..83a1972 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -481,6 +481,19 @@ cleanup:
return NULL;
}
+/* Disgusting wrapper functions */
+static inline unsigned long sg_kmap_atomic(struct scatterlist *sgl, int idx)
+{
+ void *addr = kmap_atomic(sg_page(sgl + idx));
+ return (unsigned long)addr;
+}
+
+static inline void sg_kunmap_atomic(unsigned long addr)
+{
+ kunmap_atomic((void *)addr);
+}
+
+
/* Assume the original sgl has enough room */
static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
struct scatterlist *bounce_sgl,
@@ -499,15 +512,12 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
local_irq_save(flags);
for (i = 0; i < orig_sgl_count; i++) {
- dest_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
- KM_IRQ0) + orig_sgl[i].offset;
+ dest_addr = sg_kmap_atomic(orig_sgl,i) + orig_sgl[i].offset;
dest = dest_addr;
destlen = orig_sgl[i].length;
if (bounce_addr == 0)
- bounce_addr =
- (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
- KM_IRQ0);
+ bounce_addr = sg_kmap_atomic(bounce_sgl,j);
while (destlen) {
src = bounce_addr + bounce_sgl[j].offset;
@@ -523,7 +533,7 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
if (bounce_sgl[j].offset == bounce_sgl[j].length) {
/* full */
- kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ sg_kunmap_atomic(bounce_addr);
j++;
/*
@@ -537,26 +547,21 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
/*
* We are done; cleanup and return.
*/
- kunmap_atomic((void *)(dest_addr -
- orig_sgl[i].offset),
- KM_IRQ0);
+ sg_kunmap_atomic(dest_addr - orig_sgl[i].offset);
local_irq_restore(flags);
return total_copied;
}
/* if we need to use another bounce buffer */
if (destlen || i != orig_sgl_count - 1)
- bounce_addr =
- (unsigned long)kmap_atomic(
- sg_page((&bounce_sgl[j])), KM_IRQ0);
+ bounce_addr = sg_kmap_atomic(bounce_sgl,j);
} else if (destlen == 0 && i == orig_sgl_count - 1) {
/* unmap the last bounce that is < PAGE_SIZE */
- kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ sg_kunmap_atomic(bounce_addr);
}
}
- kunmap_atomic((void *)(dest_addr - orig_sgl[i].offset),
- KM_IRQ0);
+ sg_kunmap_atomic(dest_addr - orig_sgl[i].offset);
}
local_irq_restore(flags);
@@ -581,15 +586,12 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
local_irq_save(flags);
for (i = 0; i < orig_sgl_count; i++) {
- src_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
- KM_IRQ0) + orig_sgl[i].offset;
+ src_addr = sg_kmap_atomic(orig_sgl,i) + orig_sgl[i].offset;
src = src_addr;
srclen = orig_sgl[i].length;
if (bounce_addr == 0)
- bounce_addr =
- (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
- KM_IRQ0);
+ bounce_addr = sg_kmap_atomic(bounce_sgl,j);
while (srclen) {
/* assume bounce offset always == 0 */
@@ -606,22 +608,20 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
if (bounce_sgl[j].length == PAGE_SIZE) {
/* full..move to next entry */
- kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ sg_kunmap_atomic(bounce_addr);
j++;
/* if we need to use another bounce buffer */
if (srclen || i != orig_sgl_count - 1)
- bounce_addr =
- (unsigned long)kmap_atomic(
- sg_page((&bounce_sgl[j])), KM_IRQ0);
+ bounce_addr = sg_kmap_atomic(bounce_sgl,j);
} else if (srclen == 0 && i == orig_sgl_count - 1) {
/* unmap the last bounce that is < PAGE_SIZE */
- kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ sg_kunmap_atomic(bounce_addr);
}
}
- kunmap_atomic((void *)(src_addr - orig_sgl[i].offset), KM_IRQ0);
+ sg_kunmap_atomic(src_addr - orig_sgl[i].offset);
}
local_irq_restore(flags);
--
1.7.9.5

View File

@ -89,11 +89,91 @@
# Temporary, until the Xen regression is fixed
+ debian/revert-x86-ioapic-Add-register-level-checks-to-detec.patch
# Temporary, until the next ABI bump
+ debian/revert-rtc-Provide-flag-for-rtc-devices-that-don-t-s.patch
+ bugfix/all/net-fix-proc-net-dev-regression.patch
+ bugfix/arm/ARM-orion5x-Fix-GPIO-enable-bits-for-MPP9.patch
+ bugfix/x86/drm-i915-mask-transcoder-select-bits-before-setting-.patch
+ bugfix/all/TOMOYO-Fix-mount-flags-checking-order.patch
+ bugfix/all/drm-radeon-kms-fix-fans-after-resume.patch
# Update all Hyper-V drivers to 3.4-rc1 (no longer staging)
+ features/x86/hyperv/0001-NLS-improve-UTF8-UTF16-string-conversion-routine.patch
+ features/x86/hyperv/0002-HID-Move-the-hid-hyperv-driver-out-of-staging.patch
+ features/x86/hyperv/0003-Staging-hv-storvsc-Use-mempools-to-allocate-struct-s.patch
+ features/x86/hyperv/0004-Staging-hv-storvsc-Cleanup-error-handling-in-the-pro.patch
+ features/x86/hyperv/0005-Staging-hv-storvsc-Fixup-the-error-when-processing-S.patch
+ features/x86/hyperv/0006-Staging-hv-storvsc-Fix-error-handling-storvsc_host_r.patch
+ features/x86/hyperv/0007-Staging-hv-storvsc-Use-the-accessor-function-shost_p.patch
+ features/x86/hyperv/0008-Staging-hv-storvsc-Use-the-unlocked-version-queuecom.patch
+ features/x86/hyperv/0009-Staging-hv-storvsc-use-the-macro-KBUILD_MODNAME.patch
+ features/x86/hyperv/0010-Staging-hv-storvsc-Get-rid-of-an-unnecessary-forward.patch
+ features/x86/hyperv/0011-Staging-hv-storvsc-Upgrade-the-vmstor-protocol-versi.patch
+ features/x86/hyperv/0012-Staging-hv-storvsc-Support-hot-add-of-scsi-disks.patch
+ features/x86/hyperv/0013-Staging-hv-storvsc-Support-hot-removing-of-scsi-devi.patch
+ features/x86/hyperv/0014-staging-hv-Use-kmemdup-rather-than-duplicating-its-i.patch
+ features/x86/hyperv/0015-Staging-hv-vmbus-Support-building-the-vmbus-driver-a.patch
+ features/x86/hyperv/0016-hv-Add-Kconfig-menu-entry.patch
+ features/x86/hyperv/0017-Staging-hv-mousevsc-Remove-the-mouse-driver-from-the.patch
+ features/x86/hyperv/0018-staging-hv-move-hv_netvsc-out-of-staging-area.patch
+ features/x86/hyperv/0019-net-hyperv-Fix-long-lines-in-netvsc.c.patch
+ features/x86/hyperv/0020-net-hyperv-Add-support-for-promiscuous-mode-setting.patch
+ features/x86/hyperv/0021-Staging-hv-storvsc-Disable-clustering.patch
+ features/x86/hyperv/0022-Staging-hv-storvsc-Cleanup-storvsc_device_alloc.patch
+ features/x86/hyperv/0023-Staging-hv-storvsc-Fix-a-bug-in-storvsc_command_comp.patch
+ features/x86/hyperv/0024-Staging-hv-storvsc-Fix-a-bug-in-copy_from_bounce_buf.patch
+ features/x86/hyperv/0025-Staging-hv-storvsc-Implement-per-device-memory-pools.patch
+ features/x86/hyperv/0026-Staging-hv-update-TODO-file.patch
+ features/x86/hyperv/0027-HID-hv_mouse-Properly-add-the-hid-device.patch
+ features/x86/hyperv/0028-Staging-hv-storvsc-Fix-a-bug-in-create_bounce_buffer.patch
+ features/x86/hyperv/0029-net-hyperv-Fix-the-stop-wake-queue-mechanism.patch
+ features/x86/hyperv/0030-Drivers-hv-Fix-a-memory-leak.patch
+ features/x86/hyperv/0031-Drivers-hv-Make-the-vmbus-driver-unloadable.patch
+ features/x86/hyperv/0032-Drivers-hv-Get-rid-of-an-unnecessary-check-in-hv.c.patch
+ features/x86/hyperv/0033-net-hyperv-Remove-unnecessary-kmap_atomic-in-netvsc-.patch
+ features/x86/hyperv/0034-net-hyperv-Add-NETVSP-protocol-version-negotiation.patch
+ features/x86/hyperv/0035-net-hyperv-Add-support-for-jumbo-frame-up-to-64KB.patch
+ features/x86/hyperv/0036-net-hyperv-fix-possible-memory-leak-in-do_set_multic.patch
+ features/x86/hyperv/0037-drivers-hv-Get-rid-of-some-unnecessary-code.patch
+ features/x86/hyperv/0038-net-hyperv-rx_bytes-should-account-the-ether-header-.patch
+ features/x86/hyperv/0039-HID-hyperv-Properly-disconnect-the-input-device.patch
+ features/x86/hyperv/0040-net-hyperv-fix-the-issue-that-large-packets-be-dropp.patch
+ features/x86/hyperv/0041-net-hyperv-Use-netif_tx_disable-instead-of-netif_sto.patch
+ features/x86/hyperv/0042-net-hyperv-Fix-the-page-buffer-when-an-RNDIS-message.patch
+ features/x86/hyperv/0043-drivers-hv-kvp-Add-cleanup-connector-defines.patch
+ features/x86/hyperv/0044-drivers-hv-kvp-Move-the-contents-of-hv_kvp.h-to-hype.patch
+ features/x86/hyperv/0045-net-hyperv-Convert-camel-cased-variables-in-rndis_fi.patch
+ features/x86/hyperv/0046-net-hyperv-Correct-the-assignment-in-netvsc_recv_cal.patch
+ features/x86/hyperv/0047-net-hyperv-Remove-the-unnecessary-memset-in-rndis_fi.patch
+ features/x86/hyperv/0048-Staging-hv-storvsc-Cleanup-some-comments.patch
+ features/x86/hyperv/0049-Staging-hv-storvsc-Cleanup-storvsc_probe.patch
+ features/x86/hyperv/0050-Staging-hv-storvsc-Cleanup-storvsc_queuecommand.patch
+ features/x86/hyperv/0051-Staging-hv-storvsc-Introduce-defines-for-srb-status-.patch
+ features/x86/hyperv/0052-Staging-hv-storvsc-Cleanup-storvsc_host_reset_handle.patch
+ features/x86/hyperv/0053-Staging-hv-storvsc-Move-and-cleanup-storvsc_remove.patch
+ features/x86/hyperv/0054-Staging-hv-storvsc-Add-a-comment-to-explain-life-cyc.patch
+ features/x86/hyperv/0055-Staging-hv-storvsc-Get-rid-of-the-on_io_completion-i.patch
+ features/x86/hyperv/0056-Staging-hv-storvsc-Rename-the-context-field-in-hv_st.patch
+ features/x86/hyperv/0057-Staging-hv-storvsc-Miscellaneous-cleanup-of-storvsc-.patch
+ features/x86/hyperv/0058-Staging-hv-storvsc-Cleanup-the-code-for-generating-p.patch
+ features/x86/hyperv/0059-Staging-hv-storvsc-Cleanup-some-protocol-related-con.patch
+ features/x86/hyperv/0060-Staging-hv-storvsc-Get-rid-of-some-unused-defines.patch
+ features/x86/hyperv/0061-Staging-hv-storvsc-Consolidate-the-request-structure.patch
+ features/x86/hyperv/0062-Staging-hv-storvsc-Consolidate-all-the-wire-protocol.patch
+ features/x86/hyperv/0063-drivers-hv-Cleanup-the-kvp-related-state-in-hyperv.h.patch
+ features/x86/hyperv/0064-tools-hv-Use-hyperv.h-to-get-the-KVP-definitions.patch
+ features/x86/hyperv/0065-drivers-hv-kvp-Cleanup-the-kernel-user-protocol.patch
+ features/x86/hyperv/0066-drivers-hv-Increase-the-number-of-VCPUs-supported-in.patch
+ features/x86/hyperv/0067-Staging-hv-storvsc-Move-the-storage-driver-out-of-th.patch
+ features/x86/hyperv/0068-net-hyperv-Use-the-built-in-macro-KBUILD_MODNAME-for.patch
+ features/x86/hyperv/0069-net-hyperv-Fix-data-corruption-in-rndis_filter_recei.patch
+ features/x86/hyperv/0070-net-hyperv-Add-support-for-vlan-trunking-from-guests.patch
+ features/x86/hyperv/0071-Drivers-hv-Add-new-message-types-to-enhance-KVP.patch
+ features/x86/hyperv/0072-net-hyperv-fix-erroneous-NETDEV_TX_BUSY-use.patch
+ features/x86/hyperv/0073-Drivers-hv-Support-the-newly-introduced-KVP-messages.patch
+ features/x86/hyperv/0074-Tools-hv-Fully-support-the-new-KVP-verbs-in-the-user.patch
+ features/x86/hyperv/0075-Tools-hv-Support-enumeration-from-all-the-pools.patch
+ features/x86/hyperv/0076-net-hyperv-Fix-the-code-handling-tx-busy.patch
+ features/x86/hyperv/0077-hv-remove-the-second-argument-of-k-un-map_atomic.patch
# Temporary, until the next ABI bump
+ debian/revert-rtc-Provide-flag-for-rtc-devices-that-don-t-s.patch
+ debian/nls-Avoid-ABI-change-from-improvement-to-utf8s_to_ut.patch