summaryrefslogtreecommitdiff
path: root/drivers/staging/hv
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/hv')
-rw-r--r--drivers/staging/hv/Kconfig4
-rw-r--r--drivers/staging/hv/Makefile2
-rw-r--r--drivers/staging/hv/blkvsc.c102
-rw-r--r--drivers/staging/hv/blkvsc_drv.c1465
-rw-r--r--drivers/staging/hv/channel.c230
-rw-r--r--drivers/staging/hv/channel.h112
-rw-r--r--drivers/staging/hv/channel_mgmt.c201
-rw-r--r--drivers/staging/hv/channel_mgmt.h320
-rw-r--r--drivers/staging/hv/connection.c108
-rw-r--r--drivers/staging/hv/hv.c111
-rw-r--r--drivers/staging/hv/hv.h140
-rw-r--r--drivers/staging/hv/hv_api.h910
-rw-r--r--drivers/staging/hv/hv_kvp.c20
-rw-r--r--drivers/staging/hv/hv_mouse.c502
-rw-r--r--drivers/staging/hv/hv_timesource.c3
-rw-r--r--drivers/staging/hv/hv_util.c81
-rw-r--r--drivers/staging/hv/hyperv.h944
-rw-r--r--drivers/staging/hv/hyperv_net.h (renamed from drivers/staging/hv/rndis.h)422
-rw-r--r--drivers/staging/hv/hyperv_storage.h (renamed from drivers/staging/hv/vstorage.h)144
-rw-r--r--drivers/staging/hv/hyperv_vmbus.h631
-rw-r--r--drivers/staging/hv/logging.h98
-rw-r--r--drivers/staging/hv/netvsc.c901
-rw-r--r--drivers/staging/hv/netvsc.h332
-rw-r--r--drivers/staging/hv/netvsc_api.h116
-rw-r--r--drivers/staging/hv/netvsc_drv.c190
-rw-r--r--drivers/staging/hv/ring_buffer.c526
-rw-r--r--drivers/staging/hv/ring_buffer.h102
-rw-r--r--drivers/staging/hv/rndis_filter.c187
-rw-r--r--drivers/staging/hv/rndis_filter.h55
-rw-r--r--drivers/staging/hv/storvsc.c547
-rw-r--r--drivers/staging/hv/storvsc_api.h110
-rw-r--r--drivers/staging/hv/storvsc_drv.c967
-rw-r--r--drivers/staging/hv/utils.h120
-rw-r--r--drivers/staging/hv/version_info.h48
-rw-r--r--drivers/staging/hv/vmbus.h51
-rw-r--r--drivers/staging/hv/vmbus_api.h139
-rw-r--r--drivers/staging/hv/vmbus_channel_interface.h89
-rw-r--r--drivers/staging/hv/vmbus_drv.c1090
-rw-r--r--drivers/staging/hv/vmbus_packet_format.h161
-rw-r--r--drivers/staging/hv/vmbus_private.h134
40 files changed, 4786 insertions, 7629 deletions
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
index d41f380d188f..5e0c9f6c7457 100644
--- a/drivers/staging/hv/Kconfig
+++ b/drivers/staging/hv/Kconfig
@@ -1,6 +1,6 @@
config HYPERV
tristate "Microsoft Hyper-V client drivers"
- depends on X86 && m
+ depends on X86 && ACPI && PCI && m
default n
help
Select this option to run Linux as a Hyper-V client operating
@@ -31,7 +31,7 @@ config HYPERV_NET
config HYPERV_UTILS
tristate "Microsoft Hyper-V Utilities driver"
- depends on CONNECTOR
+ depends on CONNECTOR && NLS
default HYPERV
help
Select this option to enable the Hyper-V Utilities.
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
index abeb2f7ef4e2..30046743a0b4 100644
--- a/drivers/staging/hv/Makefile
+++ b/drivers/staging/hv/Makefile
@@ -9,6 +9,6 @@ hv_vmbus-y := vmbus_drv.o \
hv.o connection.o channel.o \
channel_mgmt.o ring_buffer.o
hv_storvsc-y := storvsc_drv.o storvsc.o
-hv_blkvsc-y := blkvsc_drv.o blkvsc.o
+hv_blkvsc-y := blkvsc_drv.o storvsc.o
hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o
hv_utils-y := hv_util.o hv_kvp.o
diff --git a/drivers/staging/hv/blkvsc.c b/drivers/staging/hv/blkvsc.c
deleted file mode 100644
index 7c8729bc8329..000000000000
--- a/drivers/staging/hv/blkvsc.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include "hv_api.h"
-#include "storvsc.c"
-
-static const char *g_blk_driver_name = "blkvsc";
-
-/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
-static const struct hv_guid g_blk_device_type = {
- .data = {
- 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
- 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
- }
-};
-
-static int blk_vsc_on_device_add(struct hv_device *device, void *additional_info)
-{
- struct storvsc_device_info *device_info;
- int ret = 0;
-
- device_info = (struct storvsc_device_info *)additional_info;
-
- ret = stor_vsc_on_device_add(device, additional_info);
- if (ret != 0)
- return ret;
-
- /*
- * We need to use the device instance guid to set the path and target
- * id. For IDE devices, the device instance id is formatted as
- * <bus id> * - <device id> - 8899 - 000000000000.
- */
- device_info->path_id = device->dev_instance.data[3] << 24 |
- device->dev_instance.data[2] << 16 |
- device->dev_instance.data[1] << 8 |
- device->dev_instance.data[0];
-
- device_info->target_id = device->dev_instance.data[5] << 8 |
- device->dev_instance.data[4];
-
- return ret;
-}
-
-int blk_vsc_initialize(struct hv_driver *driver)
-{
- struct storvsc_driver_object *stor_driver;
- int ret = 0;
-
- stor_driver = (struct storvsc_driver_object *)driver;
-
- /* Make sure we are at least 2 pages since 1 page is used for control */
- /* ASSERT(stor_driver->RingBufferSize >= (PAGE_SIZE << 1)); */
-
- driver->name = g_blk_driver_name;
- memcpy(&driver->dev_type, &g_blk_device_type, sizeof(struct hv_guid));
-
- stor_driver->request_ext_size = sizeof(struct storvsc_request_extension);
-
- /*
- * Divide the ring buffer data size (which is 1 page less than the ring
- * buffer size since that page is reserved for the ring buffer indices)
- * by the max request size (which is
- * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
- */
- stor_driver->max_outstanding_req_per_channel =
- ((stor_driver->ring_buffer_size - PAGE_SIZE) /
- ALIGN(MAX_MULTIPAGE_BUFFER_PACKET +
- sizeof(struct vstor_packet) + sizeof(u64),
- sizeof(u64)));
-
- DPRINT_INFO(BLKVSC, "max io outstd %u",
- stor_driver->max_outstanding_req_per_channel);
-
- /* Setup the dispatch table */
- stor_driver->base.dev_add = blk_vsc_on_device_add;
- stor_driver->base.dev_rm = stor_vsc_on_device_remove;
- stor_driver->base.cleanup = stor_vsc_on_cleanup;
- stor_driver->on_io_request = stor_vsc_on_io_request;
-
- return ret;
-}
diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c
index 68ad17d67098..46daade7a9e2 100644
--- a/drivers/staging/hv/blkvsc_drv.c
+++ b/drivers/staging/hv/blkvsc_drv.c
@@ -17,6 +17,7 @@
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
*/
#include <linux/init.h>
#include <linux/module.h>
@@ -25,17 +26,14 @@
#include <linux/major.h>
#include <linux/delay.h>
#include <linux/hdreg.h>
-#include <linux/mutex.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dbg.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "version_info.h"
-#include "vmbus.h"
-#include "storvsc_api.h"
+
+#include "hyperv.h"
+#include "hyperv_storage.h"
#define BLKVSC_MINORS 64
@@ -46,6 +44,12 @@ enum blkvsc_device_type {
DVD_TYPE,
};
+enum blkvsc_op_type {
+ DO_INQUIRY,
+ DO_CAPACITY,
+ DO_FLUSH,
+};
+
/*
* This request ties the struct request and struct
* blkvsc_request/hv_storvsc_request together A struct request may be
@@ -72,9 +76,6 @@ struct blkvsc_request {
/* The group this request is part of. Maybe null */
struct blkvsc_request_group *group;
- wait_queue_head_t wevent;
- int cond;
-
int write;
sector_t sector_start;
unsigned long sector_count;
@@ -84,12 +85,6 @@ struct blkvsc_request {
unsigned char cmnd[MAX_COMMAND_SIZE];
struct hv_storvsc_request request;
- /*
- * !!!DO NOT ADD ANYTHING BELOW HERE!!! Otherwise, memory can overlap,
- * because - The extension buffer falls right here and is pointed to by
- * request.Extension;
- * Which sounds like a horrible idea, who designed this?
- */
};
/* Per device structure */
@@ -106,7 +101,6 @@ struct block_device_context {
unsigned int device_id_len;
int num_outstanding_reqs;
int shutting_down;
- int media_not_present;
unsigned int sector_size;
sector_t capacity;
unsigned int port;
@@ -115,515 +109,314 @@ struct block_device_context {
int users;
};
+static const char *drv_name = "blkvsc";
-/* Static decl */
-static DEFINE_MUTEX(blkvsc_mutex);
-static int blkvsc_probe(struct device *dev);
-static int blkvsc_remove(struct device *device);
-static void blkvsc_shutdown(struct device *device);
+/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
+static const struct hv_guid dev_type = {
+ .data = {
+ 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
+ 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
+ }
+};
-static int blkvsc_open(struct block_device *bdev, fmode_t mode);
-static int blkvsc_release(struct gendisk *disk, fmode_t mode);
-static unsigned int blkvsc_check_events(struct gendisk *gd,
- unsigned int clearing);
-static int blkvsc_revalidate_disk(struct gendisk *gd);
-static int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg);
-static int blkvsc_ioctl(struct block_device *bd, fmode_t mode,
- unsigned cmd, unsigned long argument);
-static void blkvsc_request(struct request_queue *queue);
+/*
+ * There is a circular dependency involving blkvsc_request_completion()
+ * and blkvsc_do_request().
+ */
static void blkvsc_request_completion(struct hv_storvsc_request *request);
-static int blkvsc_do_request(struct block_device_context *blkdev,
- struct request *req);
-static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req,
- void (*request_completion)(struct hv_storvsc_request *));
-static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req);
-static void blkvsc_cmd_completion(struct hv_storvsc_request *request);
-static int blkvsc_do_inquiry(struct block_device_context *blkdev);
-static int blkvsc_do_read_capacity(struct block_device_context *blkdev);
-static int blkvsc_do_read_capacity16(struct block_device_context *blkdev);
-static int blkvsc_do_flush(struct block_device_context *blkdev);
-static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev);
-static int blkvsc_do_pending_reqs(struct block_device_context *blkdev);
static int blkvsc_ringbuffer_size = BLKVSC_RING_BUFFER_SIZE;
+
module_param(blkvsc_ringbuffer_size, int, S_IRUGO);
MODULE_PARM_DESC(ring_size, "Ring buffer size (in bytes)");
-/* The one and only one */
-static struct storvsc_driver_object g_blkvsc_drv;
-
-static const struct block_device_operations block_ops = {
- .owner = THIS_MODULE,
- .open = blkvsc_open,
- .release = blkvsc_release,
- .check_events = blkvsc_check_events,
- .revalidate_disk = blkvsc_revalidate_disk,
- .getgeo = blkvsc_getgeo,
- .ioctl = blkvsc_ioctl,
-};
-
/*
- * blkvsc_drv_init - BlkVsc driver initialization.
+ * There is a circular dependency involving blkvsc_probe()
+ * and block_ops.
*/
-static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
-{
- struct storvsc_driver_object *storvsc_drv_obj = &g_blkvsc_drv;
- struct hv_driver *drv = &g_blkvsc_drv.base;
- int ret;
+static int blkvsc_probe(struct hv_device *dev);
- storvsc_drv_obj->ring_buffer_size = blkvsc_ringbuffer_size;
+static int blkvsc_device_add(struct hv_device *device,
+ void *additional_info)
+{
+ struct storvsc_device_info *device_info;
+ int ret = 0;
- drv->priv = storvsc_drv_obj;
+ device_info = (struct storvsc_device_info *)additional_info;
- /* Callback to client driver to complete the initialization */
- drv_init(&storvsc_drv_obj->base);
+ device_info->ring_buffer_size = blkvsc_ringbuffer_size;
- drv->driver.name = storvsc_drv_obj->base.name;
+ ret = storvsc_dev_add(device, additional_info);
+ if (ret != 0)
+ return ret;
- drv->driver.probe = blkvsc_probe;
- drv->driver.remove = blkvsc_remove;
- drv->driver.shutdown = blkvsc_shutdown;
+ /*
+ * We need to use the device instance guid to set the path and target
+ * id. For IDE devices, the device instance id is formatted as
+ * <bus id> * - <device id> - 8899 - 000000000000.
+ */
+ device_info->path_id = device->dev_instance.data[3] << 24 |
+ device->dev_instance.data[2] << 16 |
+ device->dev_instance.data[1] << 8 |
+ device->dev_instance.data[0];
- /* The driver belongs to vmbus */
- ret = vmbus_child_driver_register(&drv->driver);
+ device_info->target_id = device->dev_instance.data[5] << 8 |
+ device->dev_instance.data[4];
return ret;
}
-static int blkvsc_drv_exit_cb(struct device *dev, void *data)
-{
- struct device **curr = (struct device **)data;
- *curr = dev;
- return 1; /* stop iterating */
-}
-
-static void blkvsc_drv_exit(void)
+static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req,
+ void (*request_completion)(struct hv_storvsc_request *))
{
- struct storvsc_driver_object *storvsc_drv_obj = &g_blkvsc_drv;
- struct hv_driver *drv = &g_blkvsc_drv.base;
- struct device *current_dev;
+ struct block_device_context *blkdev = blkvsc_req->dev;
+ struct hv_storvsc_request *storvsc_req;
+ struct vmscsi_request *vm_srb;
int ret;
- while (1) {
- current_dev = NULL;
-
- /* Get the device */
- ret = driver_for_each_device(&drv->driver, NULL,
- (void *) &current_dev,
- blkvsc_drv_exit_cb);
-
- if (ret)
- DPRINT_WARN(BLKVSC_DRV,
- "driver_for_each_device returned %d", ret);
-
-
- if (current_dev == NULL)
- break;
-
- /* Initiate removal from the top-down */
- device_unregister(current_dev);
- }
-
- if (storvsc_drv_obj->base.cleanup)
- storvsc_drv_obj->base.cleanup(&storvsc_drv_obj->base);
- vmbus_child_driver_unregister(&drv->driver);
-
- return;
-}
+ storvsc_req = &blkvsc_req->request;
+ vm_srb = &storvsc_req->vstor_packet.vm_srb;
-/*
- * blkvsc_probe - Add a new device for this driver
- */
-static int blkvsc_probe(struct device *device)
-{
- struct hv_driver *drv =
- drv_to_hv_drv(device->driver);
- struct storvsc_driver_object *storvsc_drv_obj =
- drv->priv;
- struct hv_device *device_obj = device_to_hv_device(device);
+ vm_srb->data_in = blkvsc_req->write ? WRITE_TYPE : READ_TYPE;
- struct block_device_context *blkdev = NULL;
- struct storvsc_device_info device_info;
- int major = 0;
- int devnum = 0;
- int ret = 0;
- static int ide0_registered;
- static int ide1_registered;
+ storvsc_req->on_io_completion = request_completion;
+ storvsc_req->context = blkvsc_req;
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_probe - enter");
+ vm_srb->port_number = blkdev->port;
+ vm_srb->path_id = blkdev->path;
+ vm_srb->target_id = blkdev->target;
+ vm_srb->lun = 0; /* this is not really used at all */
- if (!storvsc_drv_obj->base.dev_add) {
- DPRINT_ERR(BLKVSC_DRV, "OnDeviceAdd() not set");
- ret = -1;
- goto Cleanup;
- }
+ vm_srb->cdb_length = blkvsc_req->cmd_len;
- blkdev = kzalloc(sizeof(struct block_device_context), GFP_KERNEL);
- if (!blkdev) {
- ret = -ENOMEM;
- goto Cleanup;
- }
-
- INIT_LIST_HEAD(&blkdev->pending_list);
+ memcpy(vm_srb->cdb, blkvsc_req->cmnd, vm_srb->cdb_length);
- /* Initialize what we can here */
- spin_lock_init(&blkdev->lock);
+ storvsc_req->sense_buffer = blkvsc_req->sense_buffer;
- /* ASSERT(sizeof(struct blkvsc_request_group) <= */
- /* sizeof(struct blkvsc_request)); */
+ ret = storvsc_do_io(blkdev->device_ctx,
+ &blkvsc_req->request);
+ if (ret == 0)
+ blkdev->num_outstanding_reqs++;
- blkdev->request_pool = kmem_cache_create(dev_name(&device_obj->device),
- sizeof(struct blkvsc_request) +
- storvsc_drv_obj->request_ext_size, 0,
- SLAB_HWCACHE_ALIGN, NULL);
- if (!blkdev->request_pool) {
- ret = -ENOMEM;
- goto Cleanup;
- }
+ return ret;
+}
- /* Call to the vsc driver to add the device */
- ret = storvsc_drv_obj->base.dev_add(device_obj, &device_info);
- if (ret != 0) {
- DPRINT_ERR(BLKVSC_DRV, "unable to add blkvsc device");
- goto Cleanup;
- }
+static int blkvsc_open(struct block_device *bdev, fmode_t mode)
+{
+ struct block_device_context *blkdev = bdev->bd_disk->private_data;
+ unsigned long flags;
- blkdev->device_ctx = device_obj;
- /* this identified the device 0 or 1 */
- blkdev->target = device_info.target_id;
- /* this identified the ide ctrl 0 or 1 */
- blkdev->path = device_info.path_id;
+ spin_lock_irqsave(&blkdev->lock, flags);
- dev_set_drvdata(device, blkdev);
+ blkdev->users++;
- /* Calculate the major and device num */
- if (blkdev->path == 0) {
- major = IDE0_MAJOR;
- devnum = blkdev->path + blkdev->target; /* 0 or 1 */
+ spin_unlock_irqrestore(&blkdev->lock, flags);
- if (!ide0_registered) {
- ret = register_blkdev(major, "ide");
- if (ret != 0) {
- DPRINT_ERR(BLKVSC_DRV,
- "register_blkdev() failed! ret %d",
- ret);
- goto Remove;
- }
+ return 0;
+}
- ide0_registered = 1;
- }
- } else if (blkdev->path == 1) {
- major = IDE1_MAJOR;
- devnum = blkdev->path + blkdev->target + 1; /* 2 or 3 */
-
- if (!ide1_registered) {
- ret = register_blkdev(major, "ide");
- if (ret != 0) {
- DPRINT_ERR(BLKVSC_DRV,
- "register_blkdev() failed! ret %d",
- ret);
- goto Remove;
- }
- ide1_registered = 1;
- }
- } else {
- DPRINT_ERR(BLKVSC_DRV, "invalid pathid");
- ret = -1;
- goto Cleanup;
- }
+static int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg)
+{
+ sector_t nsect = get_capacity(bd->bd_disk);
+ sector_t cylinders = nsect;
- DPRINT_INFO(BLKVSC_DRV, "blkvsc registered for major %d!!", major);
+ /*
+ * We are making up these values; let us keep it simple.
+ */
+ hg->heads = 0xff;
+ hg->sectors = 0x3f;
+ sector_div(cylinders, hg->heads * hg->sectors);
+ hg->cylinders = cylinders;
+ if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect)
+ hg->cylinders = 0xffff;
+ return 0;
- blkdev->gd = alloc_disk(BLKVSC_MINORS);
- if (!blkdev->gd) {
- DPRINT_ERR(BLKVSC_DRV, "register_blkdev() failed! ret %d", ret);
- ret = -1;
- goto Cleanup;
- }
+}
- blkdev->gd->queue = blk_init_queue(blkvsc_request, &blkdev->lock);
- blk_queue_max_segment_size(blkdev->gd->queue, PAGE_SIZE);
- blk_queue_max_segments(blkdev->gd->queue, MAX_MULTIPAGE_BUFFER_COUNT);
- blk_queue_segment_boundary(blkdev->gd->queue, PAGE_SIZE-1);
- blk_queue_bounce_limit(blkdev->gd->queue, BLK_BOUNCE_ANY);
- blk_queue_dma_alignment(blkdev->gd->queue, 511);
+static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req)
+{
- blkdev->gd->major = major;
- if (devnum == 1 || devnum == 3)
- blkdev->gd->first_minor = BLKVSC_MINORS;
- else
- blkdev->gd->first_minor = 0;
- blkdev->gd->fops = &block_ops;
- blkdev->gd->events = DISK_EVENT_MEDIA_CHANGE;
- blkdev->gd->private_data = blkdev;
- blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device);
- sprintf(blkdev->gd->disk_name, "hd%c", 'a' + devnum);
+ blkvsc_req->cmd_len = 16;
- blkvsc_do_inquiry(blkdev);
- if (blkdev->device_type == DVD_TYPE) {
- set_disk_ro(blkdev->gd, 1);
- blkdev->gd->flags |= GENHD_FL_REMOVABLE;
- blkvsc_do_read_capacity(blkdev);
+ if (rq_data_dir(blkvsc_req->req)) {
+ blkvsc_req->write = 1;
+ blkvsc_req->cmnd[0] = WRITE_16;
} else {
- blkvsc_do_read_capacity16(blkdev);
+ blkvsc_req->write = 0;
+ blkvsc_req->cmnd[0] = READ_16;
}
- set_capacity(blkdev->gd, blkdev->capacity * (blkdev->sector_size/512));
- blk_queue_logical_block_size(blkdev->gd->queue, blkdev->sector_size);
- /* go! */
- add_disk(blkdev->gd);
+ blkvsc_req->cmnd[1] |=
+ (blkvsc_req->req->cmd_flags & REQ_FUA) ? 0x8 : 0;
- DPRINT_INFO(BLKVSC_DRV, "%s added!! capacity %lu sector_size %d",
- blkdev->gd->disk_name, (unsigned long)blkdev->capacity,
- blkdev->sector_size);
+ *(unsigned long long *)&blkvsc_req->cmnd[2] =
+ cpu_to_be64(blkvsc_req->sector_start);
+ *(unsigned int *)&blkvsc_req->cmnd[10] =
+ cpu_to_be32(blkvsc_req->sector_count);
+}
- return ret;
-Remove:
- storvsc_drv_obj->base.dev_rm(device_obj);
+static int blkvsc_ioctl(struct block_device *bd, fmode_t mode,
+ unsigned cmd, unsigned long arg)
+{
+ struct block_device_context *blkdev = bd->bd_disk->private_data;
+ int ret = 0;
-Cleanup:
- if (blkdev) {
- if (blkdev->request_pool) {
- kmem_cache_destroy(blkdev->request_pool);
- blkdev->request_pool = NULL;
- }
- kfree(blkdev);
- blkdev = NULL;
+ switch (cmd) {
+ case HDIO_GET_IDENTITY:
+ if (copy_to_user((void __user *)arg, blkdev->device_id,
+ blkdev->device_id_len))
+ ret = -EFAULT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
return ret;
}
-static void blkvsc_shutdown(struct device *device)
+static void blkvsc_cmd_completion(struct hv_storvsc_request *request)
{
- struct block_device_context *blkdev = dev_get_drvdata(device);
+ struct blkvsc_request *blkvsc_req =
+ (struct blkvsc_request *)request->context;
+ struct block_device_context *blkdev =
+ (struct block_device_context *)blkvsc_req->dev;
+ struct scsi_sense_hdr sense_hdr;
+ struct vmscsi_request *vm_srb;
unsigned long flags;
- if (!blkdev)
- return;
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_shutdown - users %d disk %s\n",
- blkdev->users, blkdev->gd->disk_name);
+ vm_srb = &blkvsc_req->request.vstor_packet.vm_srb;
spin_lock_irqsave(&blkdev->lock, flags);
-
- blkdev->shutting_down = 1;
-
- blk_stop_queue(blkdev->gd->queue);
-
+ blkdev->num_outstanding_reqs--;
spin_unlock_irqrestore(&blkdev->lock, flags);
- while (blkdev->num_outstanding_reqs) {
- DPRINT_INFO(STORVSC, "waiting for %d requests to complete...",
- blkdev->num_outstanding_reqs);
- udelay(100);
- }
-
- blkvsc_do_flush(blkdev);
-
- spin_lock_irqsave(&blkdev->lock, flags);
-
- blkvsc_cancel_pending_reqs(blkdev);
+ if (vm_srb->scsi_status)
+ if (scsi_normalize_sense(blkvsc_req->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+ scsi_print_sense_hdr("blkvsc", &sense_hdr);
- spin_unlock_irqrestore(&blkdev->lock, flags);
+ complete(&blkvsc_req->request.wait_event);
}
-static int blkvsc_do_flush(struct block_device_context *blkdev)
-{
- struct blkvsc_request *blkvsc_req;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_flush()\n");
- if (blkdev->device_type != HARDDISK_TYPE)
- return 0;
-
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL);
- if (!blkvsc_req)
- return -ENOMEM;
-
- memset(blkvsc_req, 0, sizeof(struct blkvsc_request));
- init_waitqueue_head(&blkvsc_req->wevent);
- blkvsc_req->dev = blkdev;
- blkvsc_req->req = NULL;
- blkvsc_req->write = 0;
-
- blkvsc_req->request.data_buffer.pfn_array[0] = 0;
- blkvsc_req->request.data_buffer.offset = 0;
- blkvsc_req->request.data_buffer.len = 0;
-
- blkvsc_req->cmnd[0] = SYNCHRONIZE_CACHE;
- blkvsc_req->cmd_len = 10;
-
- /*
- * Set this here since the completion routine may be invoked and
- * completed before we return
- */
- blkvsc_req->cond = 0;
- blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
-
- wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
-
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
-
- return 0;
-}
-
-/* Do a scsi INQUIRY cmd here to get the device type (ie disk or dvd) */
-static int blkvsc_do_inquiry(struct block_device_context *blkdev)
+static int blkvsc_do_operation(struct block_device_context *blkdev,
+ enum blkvsc_op_type op)
{
struct blkvsc_request *blkvsc_req;
struct page *page_buf;
unsigned char *buf;
unsigned char device_type;
+ struct scsi_sense_hdr sense_hdr;
+ struct vmscsi_request *vm_srb;
+ unsigned long flags;
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_inquiry()\n");
+ int ret = 0;
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL);
+ blkvsc_req = kmem_cache_zalloc(blkdev->request_pool, GFP_KERNEL);
if (!blkvsc_req)
return -ENOMEM;
- memset(blkvsc_req, 0, sizeof(struct blkvsc_request));
page_buf = alloc_page(GFP_KERNEL);
if (!page_buf) {
kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
return -ENOMEM;
}
- init_waitqueue_head(&blkvsc_req->wevent);
+ vm_srb = &blkvsc_req->request.vstor_packet.vm_srb;
+ init_completion(&blkvsc_req->request.wait_event);
blkvsc_req->dev = blkdev;
blkvsc_req->req = NULL;
blkvsc_req->write = 0;
- blkvsc_req->request.data_buffer.pfn_array[0] = page_to_pfn(page_buf);
+ blkvsc_req->request.data_buffer.pfn_array[0] =
+ page_to_pfn(page_buf);
blkvsc_req->request.data_buffer.offset = 0;
- blkvsc_req->request.data_buffer.len = 64;
-
- blkvsc_req->cmnd[0] = INQUIRY;
- blkvsc_req->cmnd[1] = 0x1; /* Get product data */
- blkvsc_req->cmnd[2] = 0x83; /* mode page 83 */
- blkvsc_req->cmnd[4] = 64;
- blkvsc_req->cmd_len = 6;
-
- /*
- * Set this here since the completion routine may be invoked and
- * completed before we return
- */
- blkvsc_req->cond = 0;
- blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
-
- DPRINT_DBG(BLKVSC_DRV, "waiting %p to complete - cond %d\n",
- blkvsc_req, blkvsc_req->cond);
-
- wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
+ switch (op) {
+ case DO_INQUIRY:
+ blkvsc_req->cmnd[0] = INQUIRY;
+ blkvsc_req->cmnd[1] = 0x1; /* Get product data */
+ blkvsc_req->cmnd[2] = 0x83; /* mode page 83 */
+ blkvsc_req->cmnd[4] = 64;
+ blkvsc_req->cmd_len = 6;
+ blkvsc_req->request.data_buffer.len = 64;
+ break;
- buf = kmap(page_buf);
+ case DO_CAPACITY:
+ blkdev->sector_size = 0;
+ blkdev->capacity = 0;
- /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, 64); */
- /* be to le */
- device_type = buf[0] & 0x1F;
+ blkvsc_req->cmnd[0] = READ_CAPACITY;
+ blkvsc_req->cmd_len = 16;
+ blkvsc_req->request.data_buffer.len = 8;
+ break;
- if (device_type == 0x0) {
- blkdev->device_type = HARDDISK_TYPE;
- } else if (device_type == 0x5) {
- blkdev->device_type = DVD_TYPE;
- } else {
- /* TODO: this is currently unsupported device type */
- blkdev->device_type = UNKNOWN_DEV_TYPE;
+ case DO_FLUSH:
+ blkvsc_req->cmnd[0] = SYNCHRONIZE_CACHE;
+ blkvsc_req->cmd_len = 10;
+ blkvsc_req->request.data_buffer.pfn_array[0] = 0;
+ blkvsc_req->request.data_buffer.len = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto cleanup;
}
- DPRINT_DBG(BLKVSC_DRV, "device type %d\n", device_type);
-
- blkdev->device_id_len = buf[7];
- if (blkdev->device_id_len > 64)
- blkdev->device_id_len = 64;
-
- memcpy(blkdev->device_id, &buf[8], blkdev->device_id_len);
- /* printk_hex_dump_bytes("", DUMP_PREFIX_NONE, blkdev->device_id,
- * blkdev->device_id_len); */
-
- kunmap(page_buf);
-
- __free_page(page_buf);
-
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
-
- return 0;
-}
-
-/* Do a scsi READ_CAPACITY cmd here to get the size of the disk */
-static int blkvsc_do_read_capacity(struct block_device_context *blkdev)
-{
- struct blkvsc_request *blkvsc_req;
- struct page *page_buf;
- unsigned char *buf;
- struct scsi_sense_hdr sense_hdr;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_read_capacity()\n");
+ spin_lock_irqsave(&blkdev->lock, flags);
+ blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
+ spin_unlock_irqrestore(&blkdev->lock, flags);
- blkdev->sector_size = 0;
- blkdev->capacity = 0;
- blkdev->media_not_present = 0; /* assume a disk is present */
+ wait_for_completion_interruptible(&blkvsc_req->request.wait_event);
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL);
- if (!blkvsc_req)
- return -ENOMEM;
+ /* check error */
+ if (vm_srb->scsi_status) {
+ scsi_normalize_sense(blkvsc_req->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr);
- memset(blkvsc_req, 0, sizeof(struct blkvsc_request));
- page_buf = alloc_page(GFP_KERNEL);
- if (!page_buf) {
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
- return -ENOMEM;
+ return 0;
}
- init_waitqueue_head(&blkvsc_req->wevent);
- blkvsc_req->dev = blkdev;
- blkvsc_req->req = NULL;
- blkvsc_req->write = 0;
-
- blkvsc_req->request.data_buffer.pfn_array[0] = page_to_pfn(page_buf);
- blkvsc_req->request.data_buffer.offset = 0;
- blkvsc_req->request.data_buffer.len = 8;
+ buf = kmap(page_buf);
- blkvsc_req->cmnd[0] = READ_CAPACITY;
- blkvsc_req->cmd_len = 16;
+ switch (op) {
+ case DO_INQUIRY:
+ device_type = buf[0] & 0x1F;
- /*
- * Set this here since the completion routine may be invoked
- * and completed before we return
- */
- blkvsc_req->cond = 0;
+ if (device_type == 0x0)
+ blkdev->device_type = HARDDISK_TYPE;
+ else
+ blkdev->device_type = UNKNOWN_DEV_TYPE;
- blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
+ blkdev->device_id_len = buf[7];
+ if (blkdev->device_id_len > 64)
+ blkdev->device_id_len = 64;
- DPRINT_DBG(BLKVSC_DRV, "waiting %p to complete - cond %d\n",
- blkvsc_req, blkvsc_req->cond);
+ memcpy(blkdev->device_id, &buf[8], blkdev->device_id_len);
+ break;
- wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
+ case DO_CAPACITY:
+ /* be to le */
+ blkdev->capacity =
+ ((buf[0] << 24) | (buf[1] << 16) |
+ (buf[2] << 8) | buf[3]) + 1;
- /* check error */
- if (blkvsc_req->request.status) {
- scsi_normalize_sense(blkvsc_req->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr);
+ blkdev->sector_size =
+ (buf[4] << 24) | (buf[5] << 16) |
+ (buf[6] << 8) | buf[7];
+ break;
+ default:
+ break;
- if (sense_hdr.asc == 0x3A) {
- /* Medium not present */
- blkdev->media_not_present = 1;
- }
- return 0;
}
- buf = kmap(page_buf);
- /* be to le */
- blkdev->capacity = ((buf[0] << 24) | (buf[1] << 16) |
- (buf[2] << 8) | buf[3]) + 1;
- blkdev->sector_size = (buf[4] << 24) | (buf[5] << 16) |
- (buf[6] << 8) | buf[7];
+cleanup:
kunmap(page_buf);
@@ -631,119 +424,86 @@ static int blkvsc_do_read_capacity(struct block_device_context *blkdev)
kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
- return 0;
+ return ret;
}
-static int blkvsc_do_read_capacity16(struct block_device_context *blkdev)
-{
- struct blkvsc_request *blkvsc_req;
- struct page *page_buf;
- unsigned char *buf;
- struct scsi_sense_hdr sense_hdr;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_read_capacity16()\n");
- blkdev->sector_size = 0;
- blkdev->capacity = 0;
- blkdev->media_not_present = 0; /* assume a disk is present */
-
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL);
- if (!blkvsc_req)
- return -ENOMEM;
-
- memset(blkvsc_req, 0, sizeof(struct blkvsc_request));
- page_buf = alloc_page(GFP_KERNEL);
- if (!page_buf) {
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
- return -ENOMEM;
- }
+static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev)
+{
+ struct blkvsc_request *pend_req, *tmp;
+ struct blkvsc_request *comp_req, *tmp2;
+ struct vmscsi_request *vm_srb;
- init_waitqueue_head(&blkvsc_req->wevent);
- blkvsc_req->dev = blkdev;
- blkvsc_req->req = NULL;
- blkvsc_req->write = 0;
+ int ret = 0;
- blkvsc_req->request.data_buffer.pfn_array[0] = page_to_pfn(page_buf);
- blkvsc_req->request.data_buffer.offset = 0;
- blkvsc_req->request.data_buffer.len = 12;
- blkvsc_req->cmnd[0] = 0x9E; /* READ_CAPACITY16; */
- blkvsc_req->cmd_len = 16;
+ /* Flush the pending list first */
+ list_for_each_entry_safe(pend_req, tmp, &blkdev->pending_list,
+ pend_entry) {
+ /*
+ * The pend_req could be part of a partially completed
+ * request. If so, complete those req first until we
+ * hit the pend_req
+ */
+ list_for_each_entry_safe(comp_req, tmp2,
+ &pend_req->group->blkvsc_req_list,
+ req_entry) {
- /*
- * Set this here since the completion routine may be invoked
- * and completed before we return
- */
- blkvsc_req->cond = 0;
+ if (comp_req == pend_req)
+ break;
- blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
+ list_del(&comp_req->req_entry);
- DPRINT_DBG(BLKVSC_DRV, "waiting %p to complete - cond %d\n",
- blkvsc_req, blkvsc_req->cond);
+ if (comp_req->req) {
+ vm_srb =
+ &comp_req->request.vstor_packet.
+ vm_srb;
+ ret = __blk_end_request(comp_req->req,
+ (!vm_srb->scsi_status ? 0 : -EIO),
+ comp_req->sector_count *
+ blkdev->sector_size);
- wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
+ /* FIXME: shouldn't this do more than return? */
+ if (ret)
+ goto out;
+ }
- /* check error */
- if (blkvsc_req->request.status) {
- scsi_normalize_sense(blkvsc_req->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr);
- if (sense_hdr.asc == 0x3A) {
- /* Medium not present */
- blkdev->media_not_present = 1;
+ kmem_cache_free(blkdev->request_pool, comp_req);
}
- return 0;
- }
- buf = kmap(page_buf);
-
- /* be to le */
- blkdev->capacity = be64_to_cpu(*(unsigned long long *) &buf[0]) + 1;
- blkdev->sector_size = be32_to_cpu(*(unsigned int *)&buf[8]);
-#if 0
- blkdev->capacity = ((buf[0] << 24) | (buf[1] << 16) |
- (buf[2] << 8) | buf[3]) + 1;
- blkdev->sector_size = (buf[4] << 24) | (buf[5] << 16) |
- (buf[6] << 8) | buf[7];
-#endif
+ list_del(&pend_req->pend_entry);
- kunmap(page_buf);
+ list_del(&pend_req->req_entry);
- __free_page(page_buf);
+ if (comp_req->req) {
+ if (!__blk_end_request(pend_req->req, -EIO,
+ pend_req->sector_count *
+ blkdev->sector_size)) {
+ /*
+ * All the sectors have been xferred ie the
+ * request is done
+ */
+ kmem_cache_free(blkdev->request_pool,
+ pend_req->group);
+ }
+ }
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
+ kmem_cache_free(blkdev->request_pool, pend_req);
+ }
- return 0;
+out:
+ return ret;
}
+
/*
* blkvsc_remove() - Callback when our device is removed
*/
-static int blkvsc_remove(struct device *device)
+static int blkvsc_remove(struct hv_device *dev)
{
- struct hv_driver *drv =
- drv_to_hv_drv(device->driver);
- struct storvsc_driver_object *storvsc_drv_obj =
- drv->priv;
- struct hv_device *device_obj = device_to_hv_device(device);
- struct block_device_context *blkdev = dev_get_drvdata(device);
+ struct block_device_context *blkdev = dev_get_drvdata(&dev->device);
unsigned long flags;
- int ret;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_remove()\n");
- if (!storvsc_drv_obj->base.dev_rm)
- return -1;
-
- /*
- * Call to the vsc driver to let it know that the device is being
- * removed
- */
- ret = storvsc_drv_obj->base.dev_rm(device_obj);
- if (ret != 0) {
- /* TODO: */
- DPRINT_ERR(BLKVSC_DRV,
- "unable to remove blkvsc device (ret %d)", ret);
- }
/* Get to a known state */
spin_lock_irqsave(&blkdev->lock, flags);
@@ -752,149 +512,77 @@ static int blkvsc_remove(struct device *device)
blk_stop_queue(blkdev->gd->queue);
- spin_unlock_irqrestore(&blkdev->lock, flags);
-
- while (blkdev->num_outstanding_reqs) {
- DPRINT_INFO(STORVSC, "waiting for %d requests to complete...",
- blkdev->num_outstanding_reqs);
- udelay(100);
- }
-
- blkvsc_do_flush(blkdev);
-
- spin_lock_irqsave(&blkdev->lock, flags);
-
blkvsc_cancel_pending_reqs(blkdev);
spin_unlock_irqrestore(&blkdev->lock, flags);
+ blkvsc_do_operation(blkdev, DO_FLUSH);
+
blk_cleanup_queue(blkdev->gd->queue);
+ /*
+ * Call to the vsc driver to let it know that the device is being
+ * removed
+ */
+ storvsc_dev_remove(dev);
+
del_gendisk(blkdev->gd);
kmem_cache_destroy(blkdev->request_pool);
kfree(blkdev);
- return ret;
+ return 0;
+
}
-static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req)
+static void blkvsc_shutdown(struct hv_device *dev)
{
- /* ASSERT(blkvsc_req->req); */
- /* ASSERT(blkvsc_req->sector_count <= (MAX_MULTIPAGE_BUFFER_COUNT*8)); */
-
- blkvsc_req->cmd_len = 16;
-
- if (blkvsc_req->sector_start > 0xffffffff) {
- if (rq_data_dir(blkvsc_req->req)) {
- blkvsc_req->write = 1;
- blkvsc_req->cmnd[0] = WRITE_16;
- } else {
- blkvsc_req->write = 0;
- blkvsc_req->cmnd[0] = READ_16;
- }
-
- blkvsc_req->cmnd[1] |=
- (blkvsc_req->req->cmd_flags & REQ_FUA) ? 0x8 : 0;
-
- *(unsigned long long *)&blkvsc_req->cmnd[2] =
- cpu_to_be64(blkvsc_req->sector_start);
- *(unsigned int *)&blkvsc_req->cmnd[10] =
- cpu_to_be32(blkvsc_req->sector_count);
- } else if ((blkvsc_req->sector_count > 0xff) ||
- (blkvsc_req->sector_start > 0x1fffff)) {
- if (rq_data_dir(blkvsc_req->req)) {
- blkvsc_req->write = 1;
- blkvsc_req->cmnd[0] = WRITE_10;
- } else {
- blkvsc_req->write = 0;
- blkvsc_req->cmnd[0] = READ_10;
- }
+ struct block_device_context *blkdev = dev_get_drvdata(&dev->device);
+ unsigned long flags;
- blkvsc_req->cmnd[1] |=
- (blkvsc_req->req->cmd_flags & REQ_FUA) ? 0x8 : 0;
+ if (!blkdev)
+ return;
- *(unsigned int *)&blkvsc_req->cmnd[2] =
- cpu_to_be32(blkvsc_req->sector_start);
- *(unsigned short *)&blkvsc_req->cmnd[7] =
- cpu_to_be16(blkvsc_req->sector_count);
- } else {
- if (rq_data_dir(blkvsc_req->req)) {
- blkvsc_req->write = 1;
- blkvsc_req->cmnd[0] = WRITE_6;
- } else {
- blkvsc_req->write = 0;
- blkvsc_req->cmnd[0] = READ_6;
- }
+ spin_lock_irqsave(&blkdev->lock, flags);
- *(unsigned int *)&blkvsc_req->cmnd[1] =
- cpu_to_be32(blkvsc_req->sector_start) >> 8;
- blkvsc_req->cmnd[1] &= 0x1f;
- blkvsc_req->cmnd[4] = (unsigned char)blkvsc_req->sector_count;
- }
-}
+ blkdev->shutting_down = 1;
-static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req,
- void (*request_completion)(struct hv_storvsc_request *))
-{
- struct block_device_context *blkdev = blkvsc_req->dev;
- struct hv_device *device_ctx = blkdev->device_ctx;
- struct hv_driver *drv =
- drv_to_hv_drv(device_ctx->device.driver);
- struct storvsc_driver_object *storvsc_drv_obj =
- drv->priv;
- struct hv_storvsc_request *storvsc_req;
- int ret;
+ blk_stop_queue(blkdev->gd->queue);
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_submit_request() - "
- "req %p type %s start_sector %lu count %ld offset %d "
- "len %d\n", blkvsc_req,
- (blkvsc_req->write) ? "WRITE" : "READ",
- (unsigned long) blkvsc_req->sector_start,
- blkvsc_req->sector_count,
- blkvsc_req->request.data_buffer.offset,
- blkvsc_req->request.data_buffer.len);
-#if 0
- for (i = 0; i < (blkvsc_req->request.data_buffer.len >> 12); i++) {
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_submit_request() - "
- "req %p pfn[%d] %llx\n",
- blkvsc_req, i,
- blkvsc_req->request.data_buffer.pfn_array[i]);
- }
-#endif
+ blkvsc_cancel_pending_reqs(blkdev);
- storvsc_req = &blkvsc_req->request;
- storvsc_req->extension = (void *)((unsigned long)blkvsc_req +
- sizeof(struct blkvsc_request));
+ spin_unlock_irqrestore(&blkdev->lock, flags);
- storvsc_req->type = blkvsc_req->write ? WRITE_TYPE : READ_TYPE;
+ blkvsc_do_operation(blkdev, DO_FLUSH);
- storvsc_req->on_io_completion = request_completion;
- storvsc_req->context = blkvsc_req;
+ /*
+ * Now wait for all outgoing I/O to be drained.
+ */
+ storvsc_wait_to_drain((struct storvsc_device *)dev->ext);
- storvsc_req->host = blkdev->port;
- storvsc_req->bus = blkdev->path;
- storvsc_req->target_id = blkdev->target;
- storvsc_req->lun_id = 0; /* this is not really used at all */
+}
- storvsc_req->cdb_len = blkvsc_req->cmd_len;
- storvsc_req->cdb = blkvsc_req->cmnd;
+static int blkvsc_release(struct gendisk *disk, fmode_t mode)
+{
+ struct block_device_context *blkdev = disk->private_data;
+ unsigned long flags;
- storvsc_req->sense_buffer = blkvsc_req->sense_buffer;
- storvsc_req->sense_buffer_size = SCSI_SENSE_BUFFERSIZE;
+ if (blkdev->users == 1) {
+ blkvsc_do_operation(blkdev, DO_FLUSH);
+ }
- ret = storvsc_drv_obj->on_io_request(blkdev->device_ctx,
- &blkvsc_req->request);
- if (ret == 0)
- blkdev->num_outstanding_reqs++;
+ spin_lock_irqsave(&blkdev->lock, flags);
+ blkdev->users--;
+ spin_unlock_irqrestore(&blkdev->lock, flags);
- return ret;
+ return 0;
}
+
/*
* We break the request into 1 or more blkvsc_requests and submit
- * them. If we can't submit them all, we put them on the
+ * them. If we cant submit them all, we put them on the
* pending_list. The blkvsc_request() will work on the pending_list.
*/
static int blkvsc_do_request(struct block_device_context *blkdev,
@@ -913,11 +601,8 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
int pending = 0;
struct blkvsc_request_group *group = NULL;
- DPRINT_DBG(BLKVSC_DRV, "blkdev %p req %p sect %lu\n", blkdev, req,
- (unsigned long)blk_rq_pos(req));
-
/* Create a group to tie req to list of blkvsc_reqs */
- group = kmem_cache_alloc(blkdev->request_pool, GFP_ATOMIC);
+ group = kmem_cache_zalloc(blkdev->request_pool, GFP_ATOMIC);
if (!group)
return -ENOMEM;
@@ -933,11 +618,6 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
* Map this bio into an existing or new storvsc request
*/
bio_for_each_segment(bvec, bio, seg_idx) {
- DPRINT_DBG(BLKVSC_DRV, "bio_for_each_segment() "
- "- req %p bio %p bvec %p seg_idx %d "
- "databuf_idx %d\n", req, bio, bvec,
- seg_idx, databuf_idx);
-
/* Get a new storvsc request */
/* 1st-time */
if ((!blkvsc_req) ||
@@ -949,10 +629,15 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
(prev_bvec->bv_len != PAGE_SIZE))) {
/* submit the prev one */
if (blkvsc_req) {
- blkvsc_req->sector_start = start_sector;
- sector_div(blkvsc_req->sector_start, (blkdev->sector_size >> 9));
-
- blkvsc_req->sector_count = num_sectors / (blkdev->sector_size >> 9);
+ blkvsc_req->sector_start =
+ start_sector;
+ sector_div(
+ blkvsc_req->sector_start,
+ (blkdev->sector_size >> 9));
+
+ blkvsc_req->sector_count =
+ num_sectors /
+ (blkdev->sector_size >> 9);
blkvsc_init_rw(blkvsc_req);
}
@@ -960,18 +645,24 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
* Create new blkvsc_req to represent
* the current bvec
*/
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_ATOMIC);
+ blkvsc_req =
+ kmem_cache_zalloc(
+ blkdev->request_pool, GFP_ATOMIC);
if (!blkvsc_req) {
/* free up everything */
list_for_each_entry_safe(
blkvsc_req, tmp,
&group->blkvsc_req_list,
req_entry) {
- list_del(&blkvsc_req->req_entry);
- kmem_cache_free(blkdev->request_pool, blkvsc_req);
+ list_del(
+ &blkvsc_req->req_entry);
+ kmem_cache_free(
+ blkdev->request_pool,
+ blkvsc_req);
}
- kmem_cache_free(blkdev->request_pool, group);
+ kmem_cache_free(
+ blkdev->request_pool, group);
return -ENOMEM;
}
@@ -980,23 +671,27 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
blkvsc_req->dev = blkdev;
blkvsc_req->req = req;
- blkvsc_req->request.data_buffer.offset
- = bvec->bv_offset;
- blkvsc_req->request.data_buffer.len
- = 0;
+ blkvsc_req->request.
+ data_buffer.offset
+ = bvec->bv_offset;
+ blkvsc_req->request.
+ data_buffer.len = 0;
/* Add to the group */
blkvsc_req->group = group;
blkvsc_req->group->outstanding++;
list_add_tail(&blkvsc_req->req_entry,
- &blkvsc_req->group->blkvsc_req_list);
+ &blkvsc_req->group->blkvsc_req_list);
start_sector += num_sectors;
num_sectors = 0;
databuf_idx = 0;
}
- /* Add the curr bvec/segment to the curr blkvsc_req */
+ /*
+ * Add the curr bvec/segment to the curr
+ * blkvsc_req
+ */
blkvsc_req->request.data_buffer.
pfn_array[databuf_idx]
= page_to_pfn(bvec->bv_page);
@@ -1015,10 +710,6 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
/* Handle the last one */
if (blkvsc_req) {
- DPRINT_DBG(BLKVSC_DRV, "blkdev %p req %p group %p count %d\n",
- blkdev, req, blkvsc_req->group,
- blkvsc_req->group->outstanding);
-
blkvsc_req->sector_start = start_sector;
sector_div(blkvsc_req->sector_start,
(blkdev->sector_size >> 9));
@@ -1031,13 +722,6 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
list_for_each_entry(blkvsc_req, &group->blkvsc_req_list, req_entry) {
if (pending) {
- DPRINT_DBG(BLKVSC_DRV, "adding blkvsc_req to "
- "pending_list - blkvsc_req %p start_sect %lu"
- " sect_count %ld (%lu %ld)\n", blkvsc_req,
- (unsigned long)blkvsc_req->sector_start,
- blkvsc_req->sector_count,
- (unsigned long)start_sector,
- (unsigned long)num_sectors);
list_add_tail(&blkvsc_req->pend_entry,
&blkdev->pending_list);
@@ -1050,186 +734,12 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
&blkdev->pending_list);
}
- DPRINT_DBG(BLKVSC_DRV, "submitted blkvsc_req %p "
- "start_sect %lu sect_count %ld (%lu %ld) "
- "ret %d\n", blkvsc_req,
- (unsigned long)blkvsc_req->sector_start,
- blkvsc_req->sector_count,
- (unsigned long)start_sector,
- num_sectors, ret);
}
}
return pending;
}
-static void blkvsc_cmd_completion(struct hv_storvsc_request *request)
-{
- struct blkvsc_request *blkvsc_req =
- (struct blkvsc_request *)request->context;
- struct block_device_context *blkdev =
- (struct block_device_context *)blkvsc_req->dev;
- struct scsi_sense_hdr sense_hdr;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_cmd_completion() - req %p\n",
- blkvsc_req);
-
- blkdev->num_outstanding_reqs--;
-
- if (blkvsc_req->request.status)
- if (scsi_normalize_sense(blkvsc_req->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr))
- scsi_print_sense_hdr("blkvsc", &sense_hdr);
-
- blkvsc_req->cond = 1;
- wake_up_interruptible(&blkvsc_req->wevent);
-}
-
-static void blkvsc_request_completion(struct hv_storvsc_request *request)
-{
- struct blkvsc_request *blkvsc_req =
- (struct blkvsc_request *)request->context;
- struct block_device_context *blkdev =
- (struct block_device_context *)blkvsc_req->dev;
- unsigned long flags;
- struct blkvsc_request *comp_req, *tmp;
-
- /* ASSERT(blkvsc_req->group); */
-
- DPRINT_DBG(BLKVSC_DRV, "blkdev %p blkvsc_req %p group %p type %s "
- "sect_start %lu sect_count %ld len %d group outstd %d "
- "total outstd %d\n",
- blkdev, blkvsc_req, blkvsc_req->group,
- (blkvsc_req->write) ? "WRITE" : "READ",
- (unsigned long)blkvsc_req->sector_start,
- blkvsc_req->sector_count,
- blkvsc_req->request.data_buffer.len,
- blkvsc_req->group->outstanding,
- blkdev->num_outstanding_reqs);
-
- spin_lock_irqsave(&blkdev->lock, flags);
-
- blkdev->num_outstanding_reqs--;
- blkvsc_req->group->outstanding--;
-
- /*
- * Only start processing when all the blkvsc_reqs are
- * completed. This guarantees no out-of-order blkvsc_req
- * completion when calling end_that_request_first()
- */
- if (blkvsc_req->group->outstanding == 0) {
- list_for_each_entry_safe(comp_req, tmp,
- &blkvsc_req->group->blkvsc_req_list,
- req_entry) {
- DPRINT_DBG(BLKVSC_DRV, "completing blkvsc_req %p "
- "sect_start %lu sect_count %ld\n",
- comp_req,
- (unsigned long)comp_req->sector_start,
- comp_req->sector_count);
-
- list_del(&comp_req->req_entry);
-
- if (!__blk_end_request(comp_req->req,
- (!comp_req->request.status ? 0 : -EIO),
- comp_req->sector_count * blkdev->sector_size)) {
- /*
- * All the sectors have been xferred ie the
- * request is done
- */
- DPRINT_DBG(BLKVSC_DRV, "req %p COMPLETED\n",
- comp_req->req);
- kmem_cache_free(blkdev->request_pool,
- comp_req->group);
- }
-
- kmem_cache_free(blkdev->request_pool, comp_req);
- }
-
- if (!blkdev->shutting_down) {
- blkvsc_do_pending_reqs(blkdev);
- blk_start_queue(blkdev->gd->queue);
- blkvsc_request(blkdev->gd->queue);
- }
- }
-
- spin_unlock_irqrestore(&blkdev->lock, flags);
-}
-
-static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev)
-{
- struct blkvsc_request *pend_req, *tmp;
- struct blkvsc_request *comp_req, *tmp2;
-
- int ret = 0;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_cancel_pending_reqs()");
-
- /* Flush the pending list first */
- list_for_each_entry_safe(pend_req, tmp, &blkdev->pending_list,
- pend_entry) {
- /*
- * The pend_req could be part of a partially completed
- * request. If so, complete those req first until we
- * hit the pend_req
- */
- list_for_each_entry_safe(comp_req, tmp2,
- &pend_req->group->blkvsc_req_list,
- req_entry) {
- DPRINT_DBG(BLKVSC_DRV, "completing blkvsc_req %p "
- "sect_start %lu sect_count %ld\n",
- comp_req,
- (unsigned long) comp_req->sector_start,
- comp_req->sector_count);
-
- if (comp_req == pend_req)
- break;
-
- list_del(&comp_req->req_entry);
-
- if (comp_req->req) {
- ret = __blk_end_request(comp_req->req,
- (!comp_req->request.status ? 0 : -EIO),
- comp_req->sector_count *
- blkdev->sector_size);
-
- /* FIXME: shouldn't this do more than return? */
- if (ret)
- goto out;
- }
-
- kmem_cache_free(blkdev->request_pool, comp_req);
- }
-
- DPRINT_DBG(BLKVSC_DRV, "cancelling pending request - %p\n",
- pend_req);
-
- list_del(&pend_req->pend_entry);
-
- list_del(&pend_req->req_entry);
-
- if (comp_req->req) {
- if (!__blk_end_request(pend_req->req, -EIO,
- pend_req->sector_count *
- blkdev->sector_size)) {
- /*
- * All the sectors have been xferred ie the
- * request is done
- */
- DPRINT_DBG(BLKVSC_DRV,
- "blkvsc_cancel_pending_reqs() - "
- "req %p COMPLETED\n", pend_req->req);
- kmem_cache_free(blkdev->request_pool,
- pend_req->group);
- }
- }
-
- kmem_cache_free(blkdev->request_pool, pend_req);
- }
-
-out:
- return ret;
-}
-
static int blkvsc_do_pending_reqs(struct block_device_context *blkdev)
{
struct blkvsc_request *pend_req, *tmp;
@@ -1238,8 +748,6 @@ static int blkvsc_do_pending_reqs(struct block_device_context *blkdev)
/* Flush the pending list first */
list_for_each_entry_safe(pend_req, tmp, &blkdev->pending_list,
pend_entry) {
- DPRINT_DBG(BLKVSC_DRV, "working off pending_list - %p\n",
- pend_req);
ret = blkvsc_submit_request(pend_req,
blkvsc_request_completion);
@@ -1252,19 +760,17 @@ static int blkvsc_do_pending_reqs(struct block_device_context *blkdev)
return ret;
}
+
static void blkvsc_request(struct request_queue *queue)
{
struct block_device_context *blkdev = NULL;
struct request *req;
int ret = 0;
- DPRINT_DBG(BLKVSC_DRV, "- enter\n");
while ((req = blk_peek_request(queue)) != NULL) {
- DPRINT_DBG(BLKVSC_DRV, "- req %p\n", req);
blkdev = req->rq_disk->private_data;
- if (blkdev->shutting_down || req->cmd_type != REQ_TYPE_FS ||
- blkdev->media_not_present) {
+ if (blkdev->shutting_down || req->cmd_type != REQ_TYPE_FS) {
__blk_end_request_cur(req, 0);
continue;
}
@@ -1272,8 +778,6 @@ static void blkvsc_request(struct request_queue *queue)
ret = blkvsc_do_pending_reqs(blkdev);
if (ret != 0) {
- DPRINT_DBG(BLKVSC_DRV,
- "- stop queue - pending_list not empty\n");
blk_stop_queue(queue);
break;
}
@@ -1282,11 +786,9 @@ static void blkvsc_request(struct request_queue *queue)
ret = blkvsc_do_request(blkdev, req);
if (ret > 0) {
- DPRINT_DBG(BLKVSC_DRV, "- stop queue - no room\n");
blk_stop_queue(queue);
break;
} else if (ret < 0) {
- DPRINT_DBG(BLKVSC_DRV, "- stop queue - no mem\n");
blk_requeue_request(queue, req);
blk_stop_queue(queue);
break;
@@ -1294,191 +796,218 @@ static void blkvsc_request(struct request_queue *queue)
}
}
-static int blkvsc_open(struct block_device *bdev, fmode_t mode)
-{
- struct block_device_context *blkdev = bdev->bd_disk->private_data;
-
- DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users,
- blkdev->gd->disk_name);
- mutex_lock(&blkvsc_mutex);
- spin_lock(&blkdev->lock);
- if (!blkdev->users && blkdev->device_type == DVD_TYPE) {
- spin_unlock(&blkdev->lock);
- check_disk_change(bdev);
- spin_lock(&blkdev->lock);
- }
-
- blkdev->users++;
+/* The one and only one */
+static struct hv_driver blkvsc_drv = {
+ .probe = blkvsc_probe,
+ .remove = blkvsc_remove,
+ .shutdown = blkvsc_shutdown,
+};
- spin_unlock(&blkdev->lock);
- mutex_unlock(&blkvsc_mutex);
- return 0;
-}
+static const struct block_device_operations block_ops = {
+ .owner = THIS_MODULE,
+ .open = blkvsc_open,
+ .release = blkvsc_release,
+ .getgeo = blkvsc_getgeo,
+ .ioctl = blkvsc_ioctl,
+};
-static int blkvsc_release(struct gendisk *disk, fmode_t mode)
+/*
+ * blkvsc_drv_init - BlkVsc driver initialization.
+ */
+static int blkvsc_drv_init(void)
{
- struct block_device_context *blkdev = disk->private_data;
+ struct hv_driver *drv = &blkvsc_drv;
+ int ret;
- DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users,
- blkdev->gd->disk_name);
+ BUILD_BUG_ON(sizeof(sector_t) != 8);
- mutex_lock(&blkvsc_mutex);
- spin_lock(&blkdev->lock);
- if (blkdev->users == 1) {
- spin_unlock(&blkdev->lock);
- blkvsc_do_flush(blkdev);
- spin_lock(&blkdev->lock);
- }
+ memcpy(&drv->dev_type, &dev_type, sizeof(struct hv_guid));
+ drv->name = drv_name;
+ drv->driver.name = drv_name;
- blkdev->users--;
+ /* The driver belongs to vmbus */
+ ret = vmbus_child_driver_register(&drv->driver);
- spin_unlock(&blkdev->lock);
- mutex_unlock(&blkvsc_mutex);
- return 0;
+ return ret;
}
-static unsigned int blkvsc_check_events(struct gendisk *gd,
- unsigned int clearing)
+
+static void blkvsc_drv_exit(void)
{
- DPRINT_DBG(BLKVSC_DRV, "- enter\n");
- return DISK_EVENT_MEDIA_CHANGE;
+
+ vmbus_child_driver_unregister(&blkvsc_drv.driver);
}
-static int blkvsc_revalidate_disk(struct gendisk *gd)
+/*
+ * blkvsc_probe - Add a new device for this driver
+ */
+static int blkvsc_probe(struct hv_device *dev)
{
- struct block_device_context *blkdev = gd->private_data;
-
- DPRINT_DBG(BLKVSC_DRV, "- enter\n");
+ struct block_device_context *blkdev = NULL;
+ struct storvsc_device_info device_info;
+ struct storvsc_major_info major_info;
+ int ret = 0;
- if (blkdev->device_type == DVD_TYPE) {
- blkvsc_do_read_capacity(blkdev);
- set_capacity(blkdev->gd, blkdev->capacity *
- (blkdev->sector_size/512));
- blk_queue_logical_block_size(gd->queue, blkdev->sector_size);
+ blkdev = kzalloc(sizeof(struct block_device_context), GFP_KERNEL);
+ if (!blkdev) {
+ ret = -ENOMEM;
+ goto cleanup;
}
- return 0;
-}
-static int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg)
-{
- sector_t total_sectors = get_capacity(bd->bd_disk);
- sector_t cylinder_times_heads = 0;
- sector_t temp = 0;
+ INIT_LIST_HEAD(&blkdev->pending_list);
- int sectors_per_track = 0;
- int heads = 0;
- int cylinders = 0;
- int rem = 0;
+ /* Initialize what we can here */
+ spin_lock_init(&blkdev->lock);
- if (total_sectors > (65535 * 16 * 255))
- total_sectors = (65535 * 16 * 255);
- if (total_sectors >= (65535 * 16 * 63)) {
- sectors_per_track = 255;
- heads = 16;
+ blkdev->request_pool = kmem_cache_create(dev_name(&dev->device),
+ sizeof(struct blkvsc_request), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!blkdev->request_pool) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
- cylinder_times_heads = total_sectors;
- /* sector_div stores the quotient in cylinder_times_heads */
- rem = sector_div(cylinder_times_heads, sectors_per_track);
- } else {
- sectors_per_track = 17;
- cylinder_times_heads = total_sectors;
- /* sector_div stores the quotient in cylinder_times_heads */
- rem = sector_div(cylinder_times_heads, sectors_per_track);
+ ret = blkvsc_device_add(dev, &device_info);
+ if (ret != 0)
+ goto cleanup;
- temp = cylinder_times_heads + 1023;
- /* sector_div stores the quotient in temp */
- rem = sector_div(temp, 1024);
+ blkdev->device_ctx = dev;
+ /* this identified the device 0 or 1 */
+ blkdev->target = device_info.target_id;
+ /* this identified the ide ctrl 0 or 1 */
+ blkdev->path = device_info.path_id;
- heads = temp;
+ dev_set_drvdata(&dev->device, blkdev);
- if (heads < 4)
- heads = 4;
+ ret = storvsc_get_major_info(&device_info, &major_info);
+ if (ret)
+ goto cleanup;
- if (cylinder_times_heads >= (heads * 1024) || (heads > 16)) {
- sectors_per_track = 31;
- heads = 16;
+ if (major_info.do_register) {
+ ret = register_blkdev(major_info.major, major_info.devname);
- cylinder_times_heads = total_sectors;
- /*
- * sector_div stores the quotient in
- * cylinder_times_heads
- */
- rem = sector_div(cylinder_times_heads,
- sectors_per_track);
+ if (ret != 0) {
+ DPRINT_ERR(BLKVSC_DRV,
+ "register_blkdev() failed! ret %d", ret);
+ goto remove;
}
+ }
- if (cylinder_times_heads >= (heads * 1024)) {
- sectors_per_track = 63;
- heads = 16;
+ DPRINT_INFO(BLKVSC_DRV, "blkvsc registered for major %d!!",
+ major_info.major);
- cylinder_times_heads = total_sectors;
- /*
- * sector_div stores the quotient in
- * cylinder_times_heads
- */
- rem = sector_div(cylinder_times_heads,
- sectors_per_track);
- }
+ blkdev->gd = alloc_disk(BLKVSC_MINORS);
+ if (!blkdev->gd) {
+ ret = -1;
+ goto cleanup;
}
- temp = cylinder_times_heads;
- /* sector_div stores the quotient in temp */
- rem = sector_div(temp, heads);
- cylinders = temp;
+ blkdev->gd->queue = blk_init_queue(blkvsc_request, &blkdev->lock);
- hg->heads = heads;
- hg->sectors = sectors_per_track;
- hg->cylinders = cylinders;
+ blk_queue_max_segment_size(blkdev->gd->queue, PAGE_SIZE);
+ blk_queue_max_segments(blkdev->gd->queue, MAX_MULTIPAGE_BUFFER_COUNT);
+ blk_queue_segment_boundary(blkdev->gd->queue, PAGE_SIZE-1);
+ blk_queue_bounce_limit(blkdev->gd->queue, BLK_BOUNCE_ANY);
+ blk_queue_dma_alignment(blkdev->gd->queue, 511);
- DPRINT_INFO(BLKVSC_DRV, "CHS (%d, %d, %d)", cylinders, heads,
- sectors_per_track);
+ blkdev->gd->major = major_info.major;
+ if (major_info.index == 1 || major_info.index == 3)
+ blkdev->gd->first_minor = BLKVSC_MINORS;
+ else
+ blkdev->gd->first_minor = 0;
+ blkdev->gd->fops = &block_ops;
+ blkdev->gd->events = DISK_EVENT_MEDIA_CHANGE;
+ blkdev->gd->private_data = blkdev;
+ blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device);
+ sprintf(blkdev->gd->disk_name, "hd%c", 'a' + major_info.index);
- return 0;
-}
+ blkvsc_do_operation(blkdev, DO_INQUIRY);
+ blkvsc_do_operation(blkdev, DO_CAPACITY);
-static int blkvsc_ioctl(struct block_device *bd, fmode_t mode,
- unsigned cmd, unsigned long argument)
-{
-/* struct block_device_context *blkdev = bd->bd_disk->private_data; */
- int ret;
+ set_capacity(blkdev->gd, blkdev->capacity * (blkdev->sector_size/512));
+ blk_queue_logical_block_size(blkdev->gd->queue, blkdev->sector_size);
+ /* go! */
+ add_disk(blkdev->gd);
- switch (cmd) {
- /*
- * TODO: I think there is certain format for HDIO_GET_IDENTITY rather
- * than just a GUID. Commented it out for now.
- */
-#if 0
- case HDIO_GET_IDENTITY:
- DPRINT_INFO(BLKVSC_DRV, "HDIO_GET_IDENTITY\n");
- if (copy_to_user((void __user *)arg, blkdev->device_id,
- blkdev->device_id_len))
- ret = -EFAULT;
- break;
-#endif
- default:
- ret = -EINVAL;
- break;
+ DPRINT_INFO(BLKVSC_DRV, "%s added!! capacity %lu sector_size %d",
+ blkdev->gd->disk_name, (unsigned long)blkdev->capacity,
+ blkdev->sector_size);
+
+ return ret;
+
+remove:
+ storvsc_dev_remove(dev);
+
+cleanup:
+ if (blkdev) {
+ if (blkdev->request_pool) {
+ kmem_cache_destroy(blkdev->request_pool);
+ blkdev->request_pool = NULL;
+ }
+ kfree(blkdev);
+ blkdev = NULL;
}
return ret;
}
-static int __init blkvsc_init(void)
+static void blkvsc_request_completion(struct hv_storvsc_request *request)
{
- int ret;
+ struct blkvsc_request *blkvsc_req =
+ (struct blkvsc_request *)request->context;
+ struct block_device_context *blkdev =
+ (struct block_device_context *)blkvsc_req->dev;
+ unsigned long flags;
+ struct blkvsc_request *comp_req, *tmp;
+ struct vmscsi_request *vm_srb;
- BUILD_BUG_ON(sizeof(sector_t) != 8);
- DPRINT_INFO(BLKVSC_DRV, "Blkvsc initializing....");
+ spin_lock_irqsave(&blkdev->lock, flags);
- ret = blkvsc_drv_init(blk_vsc_initialize);
+ blkdev->num_outstanding_reqs--;
+ blkvsc_req->group->outstanding--;
- return ret;
+ /*
+ * Only start processing when all the blkvsc_reqs are
+ * completed. This guarantees no out-of-order blkvsc_req
+ * completion when calling end_that_request_first()
+ */
+ if (blkvsc_req->group->outstanding == 0) {
+ list_for_each_entry_safe(comp_req, tmp,
+ &blkvsc_req->group->blkvsc_req_list,
+ req_entry) {
+
+ list_del(&comp_req->req_entry);
+
+ vm_srb =
+ &comp_req->request.vstor_packet.vm_srb;
+ if (!__blk_end_request(comp_req->req,
+ (!vm_srb->scsi_status ? 0 : -EIO),
+ comp_req->sector_count * blkdev->sector_size)) {
+ /*
+ * All the sectors have been xferred ie the
+ * request is done
+ */
+ kmem_cache_free(blkdev->request_pool,
+ comp_req->group);
+ }
+
+ kmem_cache_free(blkdev->request_pool, comp_req);
+ }
+
+ if (!blkdev->shutting_down) {
+ blkvsc_do_pending_reqs(blkdev);
+ blk_start_queue(blkdev->gd->queue);
+ blkvsc_request(blkdev->gd->queue);
+ }
+ }
+
+ spin_unlock_irqrestore(&blkdev->lock, flags);
}
static void __exit blkvsc_exit(void)
@@ -1489,5 +1018,5 @@ static void __exit blkvsc_exit(void)
MODULE_LICENSE("GPL");
MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V virtual block driver");
-module_init(blkvsc_init);
+module_init(blkvsc_drv_init);
module_exit(blkvsc_exit);
diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c
index f7ce7d2494b3..f655e59a9a8f 100644
--- a/drivers/staging/hv/channel.c
+++ b/drivers/staging/hv/channel.c
@@ -18,15 +18,17 @@
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "vmbus_private.h"
+
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
#define NUM_PAGES_SPANNED(addr, len) \
((PAGE_ALIGN(addr + len) >> PAGE_SHIFT) - (addr >> PAGE_SHIFT))
@@ -40,37 +42,6 @@ static int create_gpadl_header(
static void dump_vmbus_channel(struct vmbus_channel *channel);
static void vmbus_setevent(struct vmbus_channel *channel);
-
-#if 0
-static void DumpMonitorPage(struct hv_monitor_page *MonitorPage)
-{
- int i = 0;
- int j = 0;
-
- DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d",
- MonitorPage, MonitorPage->trigger_state);
-
- for (i = 0; i < 4; i++)
- DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i,
- MonitorPage->trigger_group[i].as_uint64);
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 32; j++) {
- DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j,
- MonitorPage->latency[i][j]);
- }
- }
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 32; j++) {
- DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j,
- MonitorPage->parameter[i][j].connectionid.asu32);
- DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j,
- MonitorPage->parameter[i][j].flag_number);
- }
- }
-}
-#endif
-
/*
* vmbus_setevent- Trigger an event notification on the specified
* channel.
@@ -97,28 +68,6 @@ static void vmbus_setevent(struct vmbus_channel *channel)
}
}
-#if 0
-static void VmbusChannelClearEvent(struct vmbus_channel *channel)
-{
- struct hv_monitor_page *monitorPage;
-
- if (Channel->offermsg.monitor_allocated) {
- /* Each u32 represents 32 channels */
- sync_clear_bit(Channel->offermsg.child_relid & 31,
- (unsigned long *)vmbus_connection.send_int_page +
- (Channel->offermsg.child_relid >> 5));
-
- monitorPage = (struct hv_monitor_page *)
- vmbus_connection.monitor_pages;
- monitorPage++; /* Get the child to parent monitor page */
-
- sync_clear_bit(Channel->monitor_bit,
- (unsigned long *)&monitorPage->trigger_group
- [Channel->monitor_grp].Pending);
- }
-}
-
-#endif
/*
* vmbus_get_debug_info -Retrieve various channel debug info
*/
@@ -160,8 +109,8 @@ void vmbus_get_debug_info(struct vmbus_channel *channel,
monitorpage->parameter[monitor_group]
[monitor_offset].connectionid.u.id;
- ringbuffer_get_debuginfo(&channel->inbound, &debuginfo->inbound);
- ringbuffer_get_debuginfo(&channel->outbound, &debuginfo->outbound);
+ hv_ringbuffer_get_debuginfo(&channel->inbound, &debuginfo->inbound);
+ hv_ringbuffer_get_debuginfo(&channel->outbound, &debuginfo->outbound);
}
/*
@@ -175,11 +124,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
struct vmbus_channel_msginfo *openInfo = NULL;
void *in, *out;
unsigned long flags;
- int ret, err = 0;
-
- /* Aligned to page size */
- /* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */
- /* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */
+ int ret, t, err = 0;
newchannel->onchannel_callback = onchannelcallback;
newchannel->channel_callback_context = context;
@@ -191,7 +136,6 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
if (!out)
return -ENOMEM;
- /* ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0); */
in = (void *)((unsigned long)out + send_ringbuffer_size);
@@ -199,13 +143,16 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
newchannel->ringbuffer_pagecount = (send_ringbuffer_size +
recv_ringbuffer_size) >> PAGE_SHIFT;
- ret = ringbuffer_init(&newchannel->outbound, out, send_ringbuffer_size);
+ ret = hv_ringbuffer_init(
+ &newchannel->outbound, out, send_ringbuffer_size);
+
if (ret != 0) {
err = ret;
goto errorout;
}
- ret = ringbuffer_init(&newchannel->inbound, in, recv_ringbuffer_size);
+ ret = hv_ringbuffer_init(
+ &newchannel->inbound, in, recv_ringbuffer_size);
if (ret != 0) {
err = ret;
goto errorout;
@@ -213,9 +160,6 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
/* Establish the gpadl for the ring buffer */
- DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...",
- newchannel);
-
newchannel->ringbuffer_gpadlhandle = 0;
ret = vmbus_establish_gpadl(newchannel,
@@ -229,16 +173,6 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
goto errorout;
}
- DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p "
- "size %d recv ring %p size %d, downstreamoffset %d>",
- newchannel, newchannel->offermsg.child_relid,
- newchannel->ringbuffer_gpadlhandle,
- newchannel->outbound.ring_buffer,
- newchannel->outbound.ring_size,
- newchannel->inbound.ring_buffer,
- newchannel->inbound.ring_size,
- send_ringbuffer_size);
-
/* Create and init the channel open message */
openInfo = kmalloc(sizeof(*openInfo) +
sizeof(struct vmbus_channel_open_channel),
@@ -248,7 +182,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
goto errorout;
}
- init_waitqueue_head(&openInfo->waitevent);
+ init_completion(&openInfo->waitevent);
openMsg = (struct vmbus_channel_open_channel *)openInfo->msg;
openMsg->header.msgtype = CHANNELMSG_OPENCHANNEL;
@@ -272,30 +206,21 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
&vmbus_connection.chn_msg_list);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
- DPRINT_DBG(VMBUS, "Sending channel open msg...");
-
ret = vmbus_post_msg(openMsg,
sizeof(struct vmbus_channel_open_channel));
- if (ret != 0) {
- DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
+
+ if (ret != 0)
goto Cleanup;
- }
- openInfo->wait_condition = 0;
- wait_event_timeout(openInfo->waitevent,
- openInfo->wait_condition,
- msecs_to_jiffies(1000));
- if (openInfo->wait_condition == 0) {
+ t = wait_for_completion_timeout(&openInfo->waitevent, HZ);
+ if (t == 0) {
err = -ETIMEDOUT;
goto errorout;
}
- if (openInfo->response.open_result.status == 0)
- DPRINT_INFO(VMBUS, "channel <%p> open success!!", newchannel);
- else
- DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!",
- newchannel, openInfo->response.open_result.status);
+ if (openInfo->response.open_result.status)
+ err = openInfo->response.open_result.status;
Cleanup:
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
@@ -303,11 +228,11 @@ Cleanup:
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
kfree(openInfo);
- return 0;
+ return err;
errorout:
- ringbuffer_cleanup(&newchannel->outbound);
- ringbuffer_cleanup(&newchannel->inbound);
+ hv_ringbuffer_cleanup(&newchannel->outbound);
+ hv_ringbuffer_cleanup(&newchannel->inbound);
free_pages((unsigned long)out,
get_order(send_ringbuffer_size + recv_ringbuffer_size));
kfree(openInfo);
@@ -326,6 +251,7 @@ static void dump_gpadl_body(struct vmbus_channel_gpadl_body *gpadl, u32 len)
pfncount = (len - sizeof(struct vmbus_channel_gpadl_body)) /
sizeof(u64);
+
DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", len, pfncount);
for (i = 0; i < pfncount; i++)
@@ -377,9 +303,6 @@ static int create_gpadl_header(void *kbuffer, u32 size,
int pfnsum, pfncount, pfnleft, pfncurr, pfnsize;
- /* ASSERT((kbuffer & (PAGE_SIZE-1)) == 0); */
- /* ASSERT((Size & (PAGE_SIZE-1)) == 0); */
-
pagecount = size >> PAGE_SHIFT;
pfn = virt_to_phys(kbuffer) >> PAGE_SHIFT;
@@ -508,6 +431,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
u32 next_gpadl_handle;
unsigned long flags;
int ret = 0;
+ int t;
next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
atomic_inc(&vmbus_connection.next_gpadl_handle);
@@ -516,7 +440,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
if (ret)
return ret;
- init_waitqueue_head(&msginfo->waitevent);
+ init_completion(&msginfo->waitevent);
gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg;
gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER;
@@ -530,19 +454,11 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
&vmbus_connection.chn_msg_list);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
- DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d",
- kbuffer, size, msgcount);
- DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd",
- msginfo->msgsize - sizeof(*msginfo));
-
- msginfo->wait_condition = 0;
ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize -
sizeof(*msginfo));
- if (ret != 0) {
- DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
+ if (ret != 0)
goto Cleanup;
- }
if (msgcount > 1) {
list_for_each(curr, &msginfo->submsglist) {
@@ -556,10 +472,6 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
CHANNELMSG_GPADL_BODY;
gpadl_body->gpadl = next_gpadl_handle;
- DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd",
- submsginfo->msgsize -
- sizeof(*submsginfo));
-
dump_gpadl_body(gpadl_body, submsginfo->msgsize -
sizeof(*submsginfo));
ret = vmbus_post_msg(gpadl_body,
@@ -570,19 +482,11 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
}
}
- wait_event_timeout(msginfo->waitevent,
- msginfo->wait_condition,
- msecs_to_jiffies(1000));
- BUG_ON(msginfo->wait_condition == 0);
+ t = wait_for_completion_timeout(&msginfo->waitevent, HZ);
+ BUG_ON(t == 0);
/* At this point, we received the gpadl created msg */
- DPRINT_DBG(VMBUS, "Received GPADL created "
- "(relid %d, status %d handle %x)",
- channel->offermsg.child_relid,
- msginfo->response.gpadl_created.creation_status,
- gpadlmsg->gpadl);
-
*gpadl_handle = gpadlmsg->gpadl;
Cleanup:
@@ -603,7 +507,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
struct vmbus_channel_gpadl_teardown *msg;
struct vmbus_channel_msginfo *info;
unsigned long flags;
- int ret;
+ int ret, t;
/* ASSERT(gpadl_handle != 0); */
@@ -612,7 +516,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
if (!info)
return -ENOMEM;
- init_waitqueue_head(&info->waitevent);
+ init_completion(&info->waitevent);
msg = (struct vmbus_channel_gpadl_teardown *)info->msg;
@@ -624,14 +528,12 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
list_add_tail(&info->msglistentry,
&vmbus_connection.chn_msg_list);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
- info->wait_condition = 0;
ret = vmbus_post_msg(msg,
sizeof(struct vmbus_channel_gpadl_teardown));
BUG_ON(ret != 0);
- wait_event_timeout(info->waitevent,
- info->wait_condition, msecs_to_jiffies(1000));
- BUG_ON(info->wait_condition == 0);
+ t = wait_for_completion_timeout(&info->waitevent, HZ);
+ BUG_ON(t == 0);
/* Received a torndown response */
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
@@ -681,8 +583,8 @@ void vmbus_close(struct vmbus_channel *channel)
/* TODO: Send a msg to release the childRelId */
/* Cleanup the ring buffers for this channel */
- ringbuffer_cleanup(&channel->outbound);
- ringbuffer_cleanup(&channel->inbound);
+ hv_ringbuffer_cleanup(&channel->outbound);
+ hv_ringbuffer_cleanup(&channel->inbound);
free_pages((unsigned long)channel->ringbuffer_pages,
get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
@@ -730,13 +632,8 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
u64 aligned_data = 0;
int ret;
- DPRINT_DBG(VMBUS, "channel %p buffer %p len %d",
- channel, buffer, bufferlen);
-
dump_vmbus_channel(channel);
- /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
-
/* Setup the descriptor */
desc.type = type; /* VmbusPacketTypeDataInBand; */
desc.flags = flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
@@ -751,10 +648,10 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
sg_set_buf(&bufferlist[2], &aligned_data,
packetlen_aligned - packetlen);
- ret = ringbuffer_write(&channel->outbound, bufferlist, 3);
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
/* TODO: We should determine if this is optional */
- if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound))
+ if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
vmbus_setevent(channel);
return ret;
@@ -794,8 +691,6 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
packetlen = descsize + bufferlen;
packetlen_aligned = ALIGN(packetlen, sizeof(u64));
- /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
-
/* Setup the descriptor */
desc.type = VM_PKT_DATA_USING_GPA_DIRECT;
desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
@@ -816,10 +711,10 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
sg_set_buf(&bufferlist[2], &aligned_data,
packetlen_aligned - packetlen);
- ret = ringbuffer_write(&channel->outbound, bufferlist, 3);
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
/* TODO: We should determine if this is optional */
- if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound))
+ if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
vmbus_setevent(channel);
return ret;
@@ -846,10 +741,6 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
dump_vmbus_channel(channel);
- DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u",
- multi_pagebuffer->offset,
- multi_pagebuffer->len, pfncount);
-
if ((pfncount < 0) || (pfncount > MAX_MULTIPAGE_BUFFER_COUNT))
return -EINVAL;
@@ -863,7 +754,6 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
packetlen = descsize + bufferlen;
packetlen_aligned = ALIGN(packetlen, sizeof(u64));
- /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
/* Setup the descriptor */
desc.type = VM_PKT_DATA_USING_GPA_DIRECT;
@@ -885,10 +775,10 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
sg_set_buf(&bufferlist[2], &aligned_data,
packetlen_aligned - packetlen);
- ret = ringbuffer_write(&channel->outbound, bufferlist, 3);
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
/* TODO: We should determine if this is optional */
- if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound))
+ if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
vmbus_setevent(channel);
return ret;
@@ -922,32 +812,22 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
spin_lock_irqsave(&channel->inbound_lock, flags);
- ret = ringbuffer_peek(&channel->inbound, &desc,
+ ret = hv_ringbuffer_peek(&channel->inbound, &desc,
sizeof(struct vmpacket_descriptor));
if (ret != 0) {
spin_unlock_irqrestore(&channel->inbound_lock, flags);
-
- /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
return 0;
}
- /* VmbusChannelClearEvent(Channel); */
-
packetlen = desc.len8 << 3;
userlen = packetlen - (desc.offset8 << 3);
- /* ASSERT(userLen > 0); */
-
- DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
- "flag %d tid %llx pktlen %d datalen %d> ",
- channel, channel->offermsg.child_relid, desc.type,
- desc.flags, desc.trans_id, packetlen, userlen);
*buffer_actual_len = userlen;
if (userlen > bufferlen) {
spin_unlock_irqrestore(&channel->inbound_lock, flags);
- DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d",
+ pr_err("Buffer too small - got %d needs %d\n",
bufferlen, userlen);
return -1;
}
@@ -955,7 +835,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
*requestid = desc.trans_id;
/* Copy over the packet to the user buffer */
- ret = ringbuffer_read(&channel->inbound, buffer, userlen,
+ ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen,
(desc.offset8 << 3));
spin_unlock_irqrestore(&channel->inbound_lock, flags);
@@ -982,39 +862,32 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
spin_lock_irqsave(&channel->inbound_lock, flags);
- ret = ringbuffer_peek(&channel->inbound, &desc,
+ ret = hv_ringbuffer_peek(&channel->inbound, &desc,
sizeof(struct vmpacket_descriptor));
if (ret != 0) {
spin_unlock_irqrestore(&channel->inbound_lock, flags);
-
- /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
return 0;
}
- /* VmbusChannelClearEvent(Channel); */
packetlen = desc.len8 << 3;
userlen = packetlen - (desc.offset8 << 3);
- DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
- "flag %d tid %llx pktlen %d datalen %d> ",
- channel, channel->offermsg.child_relid, desc.type,
- desc.flags, desc.trans_id, packetlen, userlen);
-
*buffer_actual_len = packetlen;
if (packetlen > bufferlen) {
spin_unlock_irqrestore(&channel->inbound_lock, flags);
- DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but "
- "got space for only %d bytes", packetlen, bufferlen);
+ pr_err("Buffer too small - needed %d bytes but "
+ "got space for only %d bytes\n",
+ packetlen, bufferlen);
return -2;
}
*requestid = desc.trans_id;
/* Copy over the entire packet to the user buffer */
- ret = ringbuffer_read(&channel->inbound, buffer, packetlen, 0);
+ ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0);
spin_unlock_irqrestore(&channel->inbound_lock, flags);
return 0;
@@ -1027,7 +900,6 @@ EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
void vmbus_onchannel_event(struct vmbus_channel *channel)
{
dump_vmbus_channel(channel);
- /* ASSERT(Channel->OnChannelCallback); */
channel->onchannel_callback(channel->channel_callback_context);
@@ -1051,6 +923,6 @@ void vmbus_ontimer(unsigned long data)
static void dump_vmbus_channel(struct vmbus_channel *channel)
{
DPRINT_DBG(VMBUS, "Channel (%d)", channel->offermsg.child_relid);
- dump_ring_info(&channel->outbound, "Outbound ");
- dump_ring_info(&channel->inbound, "Inbound ");
+ hv_dump_ring_info(&channel->outbound, "Outbound ");
+ hv_dump_ring_info(&channel->inbound, "Inbound ");
}
diff --git a/drivers/staging/hv/channel.h b/drivers/staging/hv/channel.h
deleted file mode 100644
index de4f867de171..000000000000
--- a/drivers/staging/hv/channel.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _CHANNEL_H_
-#define _CHANNEL_H_
-
-#include "channel_mgmt.h"
-
-/* The format must be the same as struct vmdata_gpa_direct */
-struct vmbus_channel_packet_page_buffer {
- u16 type;
- u16 dataoffset8;
- u16 length8;
- u16 flags;
- u64 transactionid;
- u32 reserved;
- u32 rangecount;
- struct hv_page_buffer range[MAX_PAGE_BUFFER_COUNT];
-} __packed;
-
-/* The format must be the same as struct vmdata_gpa_direct */
-struct vmbus_channel_packet_multipage_buffer {
- u16 type;
- u16 dataoffset8;
- u16 length8;
- u16 flags;
- u64 transactionid;
- u32 reserved;
- u32 rangecount; /* Always 1 in this case */
- struct hv_multipage_buffer range;
-} __packed;
-
-
-extern int vmbus_open(struct vmbus_channel *channel,
- u32 send_ringbuffersize,
- u32 recv_ringbuffersize,
- void *userdata,
- u32 userdatalen,
- void(*onchannel_callback)(void *context),
- void *context);
-
-extern void vmbus_close(struct vmbus_channel *channel);
-
-extern int vmbus_sendpacket(struct vmbus_channel *channel,
- const void *buffer,
- u32 bufferLen,
- u64 requestid,
- enum vmbus_packet_type type,
- u32 flags);
-
-extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
- struct hv_page_buffer pagebuffers[],
- u32 pagecount,
- void *buffer,
- u32 bufferlen,
- u64 requestid);
-
-extern int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
- struct hv_multipage_buffer *mpb,
- void *buffer,
- u32 bufferlen,
- u64 requestid);
-
-extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
- void *kbuffer,
- u32 size,
- u32 *gpadl_handle);
-
-extern int vmbus_teardown_gpadl(struct vmbus_channel *channel,
- u32 gpadl_handle);
-
-extern int vmbus_recvpacket(struct vmbus_channel *channel,
- void *buffer,
- u32 bufferlen,
- u32 *buffer_actual_len,
- u64 *requestid);
-
-extern int vmbus_recvpacket_raw(struct vmbus_channel *channel,
- void *buffer,
- u32 bufferlen,
- u32 *buffer_actual_len,
- u64 *requestid);
-
-extern void vmbus_onchannel_event(struct vmbus_channel *channel);
-
-extern void vmbus_get_debug_info(struct vmbus_channel *channel,
- struct vmbus_channel_debug_info *debug);
-
-extern void vmbus_ontimer(unsigned long data);
-
-#endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
index 06b573227e8d..957d61ee4ceb 100644
--- a/drivers/staging/hv/channel_mgmt.c
+++ b/drivers/staging/hv/channel_mgmt.c
@@ -18,6 +18,8 @@
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/wait.h>
@@ -26,21 +28,20 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/completion.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "vmbus_private.h"
-#include "utils.h"
+
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
struct vmbus_channel_message_table_entry {
- enum vmbus_channel_message_type messageType;
- void (*messageHandler)(struct vmbus_channel_message_header *msg);
+ enum vmbus_channel_message_type message_type;
+ void (*message_handler)(struct vmbus_channel_message_header *msg);
};
#define MAX_MSG_TYPES 4
#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 8
static const struct hv_guid
- gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
+ supported_device_classes[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
/* Storage - SCSI */
{
@@ -180,6 +181,24 @@ void chn_cb_negotiate(void *context)
struct icmsg_hdr *icmsghdrp;
struct icmsg_negotiate *negop = NULL;
+ if (channel->util_index >= 0) {
+ /*
+ * This is a properly initialized util channel.
+ * Route this callback appropriately and setup state
+ * so that we don't need to reroute again.
+ */
+ if (hv_cb_utils[channel->util_index].callback != NULL) {
+ /*
+ * The util driver has established a handler for
+ * this service; do the magic.
+ */
+ channel->onchannel_callback =
+ hv_cb_utils[channel->util_index].callback;
+ (hv_cb_utils[channel->util_index].callback)(channel);
+ return;
+ }
+ }
+
buflen = PAGE_SIZE;
buf = kmalloc(buflen, GFP_ATOMIC);
@@ -216,7 +235,6 @@ struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
},
- .callback = chn_cb_negotiate,
.log_msg = "Shutdown channel functionality initialized"
},
@@ -228,7 +246,6 @@ struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
},
- .callback = chn_cb_negotiate,
.log_msg = "Timesync channel functionality initialized"
},
/* {57164f39-9115-4e78-ab55-382f3bd5422d} */
@@ -239,7 +256,6 @@ struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
},
- .callback = chn_cb_negotiate,
.log_msg = "Heartbeat channel functionality initialized"
},
/* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
@@ -249,7 +265,6 @@ struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6
},
- .callback = chn_cb_negotiate,
.log_msg = "KVP channel functionality initialized"
},
};
@@ -290,9 +305,7 @@ static void release_channel(struct work_struct *work)
struct vmbus_channel,
work);
- DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
destroy_workqueue(channel->controlwq);
- DPRINT_DBG(VMBUS, "channel released (%p)", channel);
kfree(channel);
}
@@ -314,22 +327,6 @@ void free_channel(struct vmbus_channel *channel)
}
-DECLARE_COMPLETION(hv_channel_ready);
-
-/*
- * Count initialized channels, and ensure all channels are ready when hv_vmbus
- * module loading completes.
- */
-static void count_hv_channel(void)
-{
- static int counter;
- unsigned long flags;
-
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
- if (++counter == MAX_MSG_TYPES)
- complete(&hv_channel_ready);
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
-}
/*
* vmbus_process_rescind_offer -
@@ -384,8 +381,6 @@ static void vmbus_process_offer(struct work_struct *work)
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
if (!fnew) {
- DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
- newchannel->offermsg.child_relid);
free_channel(newchannel);
return;
}
@@ -400,9 +395,6 @@ static void vmbus_process_offer(struct work_struct *work)
&newchannel->offermsg.offer.if_instance,
newchannel);
- DPRINT_DBG(VMBUS, "child device object allocated - %p",
- newchannel->device_obj);
-
/*
* Add the new device to the bus. This will kick off device-driver
* binding which eventually invokes the device driver's AddDevice()
@@ -410,8 +402,7 @@ static void vmbus_process_offer(struct work_struct *work)
*/
ret = vmbus_child_device_register(newchannel->device_obj);
if (ret != 0) {
- DPRINT_ERR(VMBUS,
- "unable to add child device object (relid %d)",
+ pr_err("unable to add child device object (relid %d)\n",
newchannel->offermsg.child_relid);
spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
@@ -426,6 +417,7 @@ static void vmbus_process_offer(struct work_struct *work)
* can cleanup properly
*/
newchannel->state = CHANNEL_OPEN_STATE;
+ newchannel->util_index = -1; /* Invalid index */
/* Open IC channels */
for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
@@ -434,12 +426,13 @@ static void vmbus_process_offer(struct work_struct *work)
sizeof(struct hv_guid)) == 0 &&
vmbus_open(newchannel, 2 * PAGE_SIZE,
2 * PAGE_SIZE, NULL, 0,
- hv_cb_utils[cnt].callback,
+ chn_cb_negotiate,
newchannel) == 0) {
hv_cb_utils[cnt].channel = newchannel;
- DPRINT_INFO(VMBUS, "%s",
- hv_cb_utils[cnt].log_msg);
- count_hv_channel();
+ newchannel->util_index = cnt;
+
+ pr_info("%s\n", hv_cb_utils[cnt].log_msg);
+
}
}
}
@@ -464,55 +457,26 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
offer = (struct vmbus_channel_offer_channel *)hdr;
for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
if (memcmp(&offer->offer.if_type,
- &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
+ &supported_device_classes[i],
+ sizeof(struct hv_guid)) == 0) {
fsupported = 1;
break;
}
}
- if (!fsupported) {
- DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
- "child relid %d", offer->child_relid);
+ if (!fsupported)
return;
- }
guidtype = &offer->offer.if_type;
guidinstance = &offer->offer.if_instance;
- DPRINT_INFO(VMBUS, "Channel offer notification - "
- "child relid %d monitor id %d allocated %d, "
- "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x} "
- "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x}",
- offer->child_relid, offer->monitorid,
- offer->monitor_allocated,
- guidtype->data[3], guidtype->data[2],
- guidtype->data[1], guidtype->data[0],
- guidtype->data[5], guidtype->data[4],
- guidtype->data[7], guidtype->data[6],
- guidtype->data[8], guidtype->data[9],
- guidtype->data[10], guidtype->data[11],
- guidtype->data[12], guidtype->data[13],
- guidtype->data[14], guidtype->data[15],
- guidinstance->data[3], guidinstance->data[2],
- guidinstance->data[1], guidinstance->data[0],
- guidinstance->data[5], guidinstance->data[4],
- guidinstance->data[7], guidinstance->data[6],
- guidinstance->data[8], guidinstance->data[9],
- guidinstance->data[10], guidinstance->data[11],
- guidinstance->data[12], guidinstance->data[13],
- guidinstance->data[14], guidinstance->data[15]);
-
/* Allocate the channel object and save this offer. */
newchannel = alloc_channel();
if (!newchannel) {
- DPRINT_ERR(VMBUS, "unable to allocate channel object");
+ pr_err("Unable to allocate channel object\n");
return;
}
- DPRINT_DBG(VMBUS, "channel object allocated - %p", newchannel);
-
memcpy(&newchannel->offermsg, offer,
sizeof(struct vmbus_channel_offer_channel));
newchannel->monitor_grp = (u8)offer->monitorid / 32;
@@ -535,11 +499,10 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
rescind = (struct vmbus_channel_rescind_offer *)hdr;
channel = relid2channel(rescind->child_relid);
- if (channel == NULL) {
- DPRINT_DBG(VMBUS, "channel not found for relId %d",
- rescind->child_relid);
+
+ if (channel == NULL)
+ /* Just return here, no channel found */
return;
- }
/* work is initialized for vmbus_process_rescind_offer() from
* vmbus_process_offer() where the channel got created */
@@ -573,7 +536,6 @@ static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
unsigned long flags;
result = (struct vmbus_channel_open_result *)hdr;
- DPRINT_DBG(VMBUS, "vmbus open result - %d", result->status);
/*
* Find the open msg, copy the result and signal/unblock the wait event
@@ -592,9 +554,9 @@ static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
openmsg->openid == result->openid) {
memcpy(&msginfo->response.open_result,
result,
- sizeof(struct vmbus_channel_open_result));
- msginfo->wait_condition = 1;
- wake_up(&msginfo->waitevent);
+ sizeof(
+ struct vmbus_channel_open_result));
+ complete(&msginfo->waitevent);
break;
}
}
@@ -618,8 +580,6 @@ static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
unsigned long flags;
gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
- DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
- gpadlcreated->creation_status);
/*
* Find the establish msg, copy the result and signal/unblock the wait
@@ -641,9 +601,9 @@ static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
(gpadlcreated->gpadl == gpadlheader->gpadl)) {
memcpy(&msginfo->response.gpadl_created,
gpadlcreated,
- sizeof(struct vmbus_channel_gpadl_created));
- msginfo->wait_condition = 1;
- wake_up(&msginfo->waitevent);
+ sizeof(
+ struct vmbus_channel_gpadl_created));
+ complete(&msginfo->waitevent);
break;
}
}
@@ -686,9 +646,9 @@ static void vmbus_ongpadl_torndown(
if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
memcpy(&msginfo->response.gpadl_torndown,
gpadl_torndown,
- sizeof(struct vmbus_channel_gpadl_torndown));
- msginfo->wait_condition = 1;
- wake_up(&msginfo->waitevent);
+ sizeof(
+ struct vmbus_channel_gpadl_torndown));
+ complete(&msginfo->waitevent);
break;
}
}
@@ -727,8 +687,7 @@ static void vmbus_onversion_response(
memcpy(&msginfo->response.version_response,
version_response,
sizeof(struct vmbus_channel_version_response));
- msginfo->wait_condition = 1;
- wake_up(&msginfo->waitevent);
+ complete(&msginfo->waitevent);
}
}
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
@@ -736,7 +695,7 @@ static void vmbus_onversion_response(
/* Channel message dispatch table */
static struct vmbus_channel_message_table_entry
- gChannelMessageTable[CHANNELMSG_COUNT] = {
+ channel_message_table[CHANNELMSG_COUNT] = {
{CHANNELMSG_INVALID, NULL},
{CHANNELMSG_OFFERCHANNEL, vmbus_onoffer},
{CHANNELMSG_RESCIND_CHANNELOFFER, vmbus_onoffer_rescind},
@@ -770,22 +729,18 @@ void vmbus_onmessage(void *context)
hdr = (struct vmbus_channel_message_header *)msg->u.payload;
size = msg->header.payload_size;
- DPRINT_DBG(VMBUS, "message type %d size %d", hdr->msgtype, size);
-
if (hdr->msgtype >= CHANNELMSG_COUNT) {
- DPRINT_ERR(VMBUS,
- "Received invalid channel message type %d size %d",
+ pr_err("Received invalid channel message type %d size %d\n",
hdr->msgtype, size);
print_hex_dump_bytes("", DUMP_PREFIX_NONE,
(unsigned char *)msg->u.payload, size);
return;
}
- if (gChannelMessageTable[hdr->msgtype].messageHandler)
- gChannelMessageTable[hdr->msgtype].messageHandler(hdr);
+ if (channel_message_table[hdr->msgtype].message_handler)
+ channel_message_table[hdr->msgtype].message_handler(hdr);
else
- DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
- hdr->msgtype);
+ pr_err("Unhandled channel message type %d\n", hdr->msgtype);
}
/*
@@ -795,7 +750,7 @@ int vmbus_request_offers(void)
{
struct vmbus_channel_message_header *msg;
struct vmbus_channel_msginfo *msginfo;
- int ret;
+ int ret, t;
msginfo = kmalloc(sizeof(*msginfo) +
sizeof(struct vmbus_channel_message_header),
@@ -803,7 +758,7 @@ int vmbus_request_offers(void)
if (!msginfo)
return -ENOMEM;
- init_waitqueue_head(&msginfo->waitevent);
+ init_completion(&msginfo->waitevent);
msg = (struct vmbus_channel_message_header *)msginfo->msg;
@@ -813,15 +768,13 @@ int vmbus_request_offers(void)
ret = vmbus_post_msg(msg,
sizeof(struct vmbus_channel_message_header));
if (ret != 0) {
- DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
+ pr_err("Unable to request offers - %d\n", ret);
goto cleanup;
}
- msginfo->wait_condition = 0;
- wait_event_timeout(msginfo->waitevent, msginfo->wait_condition,
- msecs_to_jiffies(1000));
- if (msginfo->wait_condition == 0) {
+ t = wait_for_completion_timeout(&msginfo->waitevent, HZ);
+ if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
}
@@ -834,38 +787,4 @@ cleanup:
return ret;
}
-/*
- * vmbus_release_unattached_channels - Release channels that are
- * unattached/unconnected ie (no drivers associated)
- */
-void vmbus_release_unattached_channels(void)
-{
- struct vmbus_channel *channel, *pos;
- struct vmbus_channel *start = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
-
- list_for_each_entry_safe(channel, pos, &vmbus_connection.chn_list,
- listentry) {
- if (channel == start)
- break;
-
- if (!channel->device_obj->drv) {
- list_del(&channel->listentry);
- DPRINT_INFO(VMBUS,
- "Releasing unattached device object %p",
- channel->device_obj);
-
- vmbus_child_device_unregister(channel->device_obj);
- free_channel(channel);
- } else {
- if (!start)
- start = channel;
- }
- }
-
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
-}
-
/* eof */
diff --git a/drivers/staging/hv/channel_mgmt.h b/drivers/staging/hv/channel_mgmt.h
deleted file mode 100644
index 96f74e2a3c7f..000000000000
--- a/drivers/staging/hv/channel_mgmt.h
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _CHANNEL_MGMT_H_
-#define _CHANNEL_MGMT_H_
-
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include "ring_buffer.h"
-#include "vmbus_channel_interface.h"
-#include "vmbus_packet_format.h"
-
-/* Version 1 messages */
-enum vmbus_channel_message_type {
- CHANNELMSG_INVALID = 0,
- CHANNELMSG_OFFERCHANNEL = 1,
- CHANNELMSG_RESCIND_CHANNELOFFER = 2,
- CHANNELMSG_REQUESTOFFERS = 3,
- CHANNELMSG_ALLOFFERS_DELIVERED = 4,
- CHANNELMSG_OPENCHANNEL = 5,
- CHANNELMSG_OPENCHANNEL_RESULT = 6,
- CHANNELMSG_CLOSECHANNEL = 7,
- CHANNELMSG_GPADL_HEADER = 8,
- CHANNELMSG_GPADL_BODY = 9,
- CHANNELMSG_GPADL_CREATED = 10,
- CHANNELMSG_GPADL_TEARDOWN = 11,
- CHANNELMSG_GPADL_TORNDOWN = 12,
- CHANNELMSG_RELID_RELEASED = 13,
- CHANNELMSG_INITIATE_CONTACT = 14,
- CHANNELMSG_VERSION_RESPONSE = 15,
- CHANNELMSG_UNLOAD = 16,
-#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
- CHANNELMSG_VIEWRANGE_ADD = 17,
- CHANNELMSG_VIEWRANGE_REMOVE = 18,
-#endif
- CHANNELMSG_COUNT
-};
-
-struct vmbus_channel_message_header {
- enum vmbus_channel_message_type msgtype;
- u32 padding;
-} __packed;
-
-/* Query VMBus Version parameters */
-struct vmbus_channel_query_vmbus_version {
- struct vmbus_channel_message_header header;
- u32 version;
-} __packed;
-
-/* VMBus Version Supported parameters */
-struct vmbus_channel_version_supported {
- struct vmbus_channel_message_header header;
- bool version_supported;
-} __packed;
-
-/* Offer Channel parameters */
-struct vmbus_channel_offer_channel {
- struct vmbus_channel_message_header header;
- struct vmbus_channel_offer offer;
- u32 child_relid;
- u8 monitorid;
- bool monitor_allocated;
-} __packed;
-
-/* Rescind Offer parameters */
-struct vmbus_channel_rescind_offer {
- struct vmbus_channel_message_header header;
- u32 child_relid;
-} __packed;
-
-/*
- * Request Offer -- no parameters, SynIC message contains the partition ID
- * Set Snoop -- no parameters, SynIC message contains the partition ID
- * Clear Snoop -- no parameters, SynIC message contains the partition ID
- * All Offers Delivered -- no parameters, SynIC message contains the partition
- * ID
- * Flush Client -- no parameters, SynIC message contains the partition ID
- */
-
-/* Open Channel parameters */
-struct vmbus_channel_open_channel {
- struct vmbus_channel_message_header header;
-
- /* Identifies the specific VMBus channel that is being opened. */
- u32 child_relid;
-
- /* ID making a particular open request at a channel offer unique. */
- u32 openid;
-
- /* GPADL for the channel's ring buffer. */
- u32 ringbuffer_gpadlhandle;
-
- /* GPADL for the channel's server context save area. */
- u32 server_contextarea_gpadlhandle;
-
- /*
- * The upstream ring buffer begins at offset zero in the memory
- * described by RingBufferGpadlHandle. The downstream ring buffer
- * follows it at this offset (in pages).
- */
- u32 downstream_ringbuffer_pageoffset;
-
- /* User-specific data to be passed along to the server endpoint. */
- unsigned char userdata[MAX_USER_DEFINED_BYTES];
-} __packed;
-
-/* Open Channel Result parameters */
-struct vmbus_channel_open_result {
- struct vmbus_channel_message_header header;
- u32 child_relid;
- u32 openid;
- u32 status;
-} __packed;
-
-/* Close channel parameters; */
-struct vmbus_channel_close_channel {
- struct vmbus_channel_message_header header;
- u32 child_relid;
-} __packed;
-
-/* Channel Message GPADL */
-#define GPADL_TYPE_RING_BUFFER 1
-#define GPADL_TYPE_SERVER_SAVE_AREA 2
-#define GPADL_TYPE_TRANSACTION 8
-
-/*
- * The number of PFNs in a GPADL message is defined by the number of
- * pages that would be spanned by ByteCount and ByteOffset. If the
- * implied number of PFNs won't fit in this packet, there will be a
- * follow-up packet that contains more.
- */
-struct vmbus_channel_gpadl_header {
- struct vmbus_channel_message_header header;
- u32 child_relid;
- u32 gpadl;
- u16 range_buflen;
- u16 rangecount;
- struct gpa_range range[0];
-} __packed;
-
-/* This is the followup packet that contains more PFNs. */
-struct vmbus_channel_gpadl_body {
- struct vmbus_channel_message_header header;
- u32 msgnumber;
- u32 gpadl;
- u64 pfn[0];
-} __packed;
-
-struct vmbus_channel_gpadl_created {
- struct vmbus_channel_message_header header;
- u32 child_relid;
- u32 gpadl;
- u32 creation_status;
-} __packed;
-
-struct vmbus_channel_gpadl_teardown {
- struct vmbus_channel_message_header header;
- u32 child_relid;
- u32 gpadl;
-} __packed;
-
-struct vmbus_channel_gpadl_torndown {
- struct vmbus_channel_message_header header;
- u32 gpadl;
-} __packed;
-
-#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
-struct vmbus_channel_view_range_add {
- struct vmbus_channel_message_header header;
- PHYSICAL_ADDRESS viewrange_base;
- u64 viewrange_length;
- u32 child_relid;
-} __packed;
-
-struct vmbus_channel_view_range_remove {
- struct vmbus_channel_message_header header;
- PHYSICAL_ADDRESS viewrange_base;
- u32 child_relid;
-} __packed;
-#endif
-
-struct vmbus_channel_relid_released {
- struct vmbus_channel_message_header header;
- u32 child_relid;
-} __packed;
-
-struct vmbus_channel_initiate_contact {
- struct vmbus_channel_message_header header;
- u32 vmbus_version_requested;
- u32 padding2;
- u64 interrupt_page;
- u64 monitor_page1;
- u64 monitor_page2;
-} __packed;
-
-struct vmbus_channel_version_response {
- struct vmbus_channel_message_header header;
- bool version_supported;
-} __packed;
-
-enum vmbus_channel_state {
- CHANNEL_OFFER_STATE,
- CHANNEL_OPENING_STATE,
- CHANNEL_OPEN_STATE,
-};
-
-struct vmbus_channel {
- struct list_head listentry;
-
- struct hv_device *device_obj;
-
- struct timer_list poll_timer; /* SA-111 workaround */
- struct work_struct work;
-
- enum vmbus_channel_state state;
-
- struct vmbus_channel_offer_channel offermsg;
- /*
- * These are based on the OfferMsg.MonitorId.
- * Save it here for easy access.
- */
- u8 monitor_grp;
- u8 monitor_bit;
-
- u32 ringbuffer_gpadlhandle;
-
- /* Allocated memory for ring buffer */
- void *ringbuffer_pages;
- u32 ringbuffer_pagecount;
- struct hv_ring_buffer_info outbound; /* send to parent */
- struct hv_ring_buffer_info inbound; /* receive from parent */
- spinlock_t inbound_lock;
- struct workqueue_struct *controlwq;
-
- /* Channel callback are invoked in this workqueue context */
- /* HANDLE dataWorkQueue; */
-
- void (*onchannel_callback)(void *context);
- void *channel_callback_context;
-};
-
-struct vmbus_channel_debug_info {
- u32 relid;
- enum vmbus_channel_state state;
- struct hv_guid interfacetype;
- struct hv_guid interface_instance;
- u32 monitorid;
- u32 servermonitor_pending;
- u32 servermonitor_latency;
- u32 servermonitor_connectionid;
- u32 clientmonitor_pending;
- u32 clientmonitor_latency;
- u32 clientmonitor_connectionid;
-
- struct hv_ring_buffer_debug_info inbound;
- struct hv_ring_buffer_debug_info outbound;
-};
-
-/*
- * Represents each channel msg on the vmbus connection This is a
- * variable-size data structure depending on the msg type itself
- */
-struct vmbus_channel_msginfo {
- /* Bookkeeping stuff */
- struct list_head msglistentry;
-
- /* So far, this is only used to handle gpadl body message */
- struct list_head submsglist;
-
- /* Synchronize the request/response if needed */
- int wait_condition;
- wait_queue_head_t waitevent;
- union {
- struct vmbus_channel_version_supported version_supported;
- struct vmbus_channel_open_result open_result;
- struct vmbus_channel_gpadl_torndown gpadl_torndown;
- struct vmbus_channel_gpadl_created gpadl_created;
- struct vmbus_channel_version_response version_response;
- } response;
-
- u32 msgsize;
- /*
- * The channel message that goes out on the "wire".
- * It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
- */
- unsigned char msg[0];
-};
-
-
-void free_channel(struct vmbus_channel *channel);
-
-void vmbus_onmessage(void *context);
-
-int vmbus_request_offers(void);
-
-void vmbus_release_unattached_channels(void);
-
-#endif /* _CHANNEL_MGMT_H_ */
diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c
index afc8116e7aa4..37bbf770ef11 100644
--- a/drivers/staging/hv/connection.c
+++ b/drivers/staging/hv/connection.c
@@ -20,15 +20,17 @@
* Hank Janssen <hjanssen@microsoft.com>
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "vmbus_private.h"
+
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
struct vmbus_connection vmbus_connection = {
@@ -42,6 +44,7 @@ struct vmbus_connection vmbus_connection = {
int vmbus_connect(void)
{
int ret = 0;
+ int t;
struct vmbus_channel_msginfo *msginfo = NULL;
struct vmbus_channel_initiate_contact *msg;
unsigned long flags;
@@ -55,7 +58,7 @@ int vmbus_connect(void)
vmbus_connection.work_queue = create_workqueue("hv_vmbus_con");
if (!vmbus_connection.work_queue) {
ret = -1;
- goto Cleanup;
+ goto cleanup;
}
INIT_LIST_HEAD(&vmbus_connection.chn_msg_list);
@@ -72,7 +75,7 @@ int vmbus_connect(void)
(void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, 0);
if (vmbus_connection.int_page == NULL) {
ret = -1;
- goto Cleanup;
+ goto cleanup;
}
vmbus_connection.recv_int_page = vmbus_connection.int_page;
@@ -88,7 +91,7 @@ int vmbus_connect(void)
(void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 1);
if (vmbus_connection.monitor_pages == NULL) {
ret = -1;
- goto Cleanup;
+ goto cleanup;
}
msginfo = kzalloc(sizeof(*msginfo) +
@@ -96,10 +99,10 @@ int vmbus_connect(void)
GFP_KERNEL);
if (msginfo == NULL) {
ret = -ENOMEM;
- goto Cleanup;
+ goto cleanup;
}
- init_waitqueue_head(&msginfo->waitevent);
+ init_completion(&msginfo->waitevent);
msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;
@@ -121,11 +124,6 @@ int vmbus_connect(void)
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
- DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, "
- "monitor1 pfn %llx,, monitor2 pfn %llx",
- msg->interrupt_page, msg->monitor_page1, msg->monitor_page2);
-
- DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
ret = vmbus_post_msg(msg,
sizeof(struct vmbus_channel_initiate_contact));
if (ret != 0) {
@@ -133,21 +131,19 @@ int vmbus_connect(void)
list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
flags);
- goto Cleanup;
+ goto cleanup;
}
/* Wait for the connection response */
- msginfo->wait_condition = 0;
- wait_event_timeout(msginfo->waitevent, msginfo->wait_condition,
- msecs_to_jiffies(1000));
- if (msginfo->wait_condition == 0) {
+ t = wait_for_completion_timeout(&msginfo->waitevent, HZ);
+ if (t == 0) {
spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
flags);
list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
flags);
ret = -ETIMEDOUT;
- goto Cleanup;
+ goto cleanup;
}
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
@@ -156,21 +152,19 @@ int vmbus_connect(void)
/* Check if successful */
if (msginfo->response.version_response.version_supported) {
- DPRINT_INFO(VMBUS, "Vmbus connected!!");
vmbus_connection.conn_state = CONNECTED;
-
} else {
- DPRINT_ERR(VMBUS, "Vmbus connection failed!!..."
- "current version (%d) not supported",
- VMBUS_REVISION_NUMBER);
+ pr_err("Unable to connect, "
+ "Version %d not supported by Hyper-V\n",
+ VMBUS_REVISION_NUMBER);
ret = -1;
- goto Cleanup;
+ goto cleanup;
}
kfree(msginfo);
return 0;
-Cleanup:
+cleanup:
vmbus_connection.conn_state = DISCONNECTED;
if (vmbus_connection.work_queue)
@@ -213,7 +207,7 @@ int vmbus_disconnect(void)
ret = vmbus_post_msg(msg,
sizeof(struct vmbus_channel_message_header));
if (ret != 0)
- goto Cleanup;
+ goto cleanup;
free_pages((unsigned long)vmbus_connection.int_page, 0);
free_pages((unsigned long)vmbus_connection.monitor_pages, 1);
@@ -223,9 +217,9 @@ int vmbus_disconnect(void)
vmbus_connection.conn_state = DISCONNECTED;
- DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
+ pr_info("hv_vmbus disconnected\n");
-Cleanup:
+cleanup:
kfree(msg);
return ret;
}
@@ -255,10 +249,9 @@ struct vmbus_channel *relid2channel(u32 relid)
/*
* process_chn_event - Process a channel event notification
*/
-static void process_chn_event(void *context)
+static void process_chn_event(u32 relid)
{
struct vmbus_channel *channel;
- u32 relid = (u32)(unsigned long)context;
/* ASSERT(relId > 0); */
@@ -270,13 +263,8 @@ static void process_chn_event(void *context)
if (channel) {
vmbus_onchannel_event(channel);
- /*
- * WorkQueueQueueWorkItem(channel->dataWorkQueue,
- * vmbus_onchannel_event,
- * (void*)channel);
- */
} else {
- DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relid);
+ pr_err("channel not found for relid - %u\n", relid);
}
}
@@ -285,39 +273,33 @@ static void process_chn_event(void *context)
*/
void vmbus_on_event(unsigned long data)
{
- int dword;
- int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
+ u32 dword;
+ u32 maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
int bit;
- int relid;
+ u32 relid;
u32 *recv_int_page = vmbus_connection.recv_int_page;
/* Check events */
- if (recv_int_page) {
- for (dword = 0; dword < maxdword; dword++) {
- if (recv_int_page[dword]) {
- for (bit = 0; bit < 32; bit++) {
- if (sync_test_and_clear_bit(bit,
- (unsigned long *)
- &recv_int_page[dword])) {
- relid = (dword << 5) + bit;
- DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
-
- if (relid == 0) {
- /* special case - vmbus channel protocol msg */
- DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
- continue;
- } else {
- /* QueueWorkItem(VmbusProcessEvent, (void*)relid); */
- /* ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid); */
- process_chn_event((void *)
- (unsigned long)relid);
- }
- }
+ if (!recv_int_page)
+ return;
+ for (dword = 0; dword < maxdword; dword++) {
+ if (!recv_int_page[dword])
+ continue;
+ for (bit = 0; bit < 32; bit++) {
+ if (sync_test_and_clear_bit(bit, (unsigned long *)&recv_int_page[dword])) {
+ relid = (dword << 5) + bit;
+
+ if (relid == 0) {
+ /*
+ * Special case - vmbus
+ * channel protocol msg
+ */
+ continue;
}
+ process_chn_event(relid);
}
- }
+ }
}
- return;
}
/*
diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c
index 0b06f4fe5838..a2cc0911de58 100644
--- a/drivers/staging/hv/hv.c
+++ b/drivers/staging/hv/hv.c
@@ -19,13 +19,15 @@
* Hank Janssen <hjanssen@microsoft.com>
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "vmbus_private.h"
+
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
/* The one and only */
struct hv_context hv_context = {
@@ -80,33 +82,7 @@ static int query_hypervisor_info(void)
op = HVCPUID_VENDOR_MAXFUNCTION;
cpuid(op, &eax, &ebx, &ecx, &edx);
- DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
- (ebx & 0xFF),
- ((ebx >> 8) & 0xFF),
- ((ebx >> 16) & 0xFF),
- ((ebx >> 24) & 0xFF),
- (ecx & 0xFF),
- ((ecx >> 8) & 0xFF),
- ((ecx >> 16) & 0xFF),
- ((ecx >> 24) & 0xFF),
- (edx & 0xFF),
- ((edx >> 8) & 0xFF),
- ((edx >> 16) & 0xFF),
- ((edx >> 24) & 0xFF));
-
max_leaf = eax;
- eax = 0;
- ebx = 0;
- ecx = 0;
- edx = 0;
- op = HVCPUID_INTERFACE;
- cpuid(op, &eax, &ebx, &ecx, &edx);
-
- DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
- (eax & 0xFF),
- ((eax >> 8) & 0xFF),
- ((eax >> 16) & 0xFF),
- ((eax >> 24) & 0xFF));
if (max_leaf >= HVCPUID_VERSION) {
eax = 0;
@@ -115,7 +91,7 @@ static int query_hypervisor_info(void)
edx = 0;
op = HVCPUID_VERSION;
cpuid(op, &eax, &ebx, &ecx, &edx);
- DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",\
+ pr_info("Hyper-V Host OS Build:%d-%d.%d-%d-%d.%d\n",
eax,
ebx >> 16,
ebx & 0xFFFF,
@@ -137,18 +113,11 @@ static u64 do_hypercall(u64 control, void *input, void *output)
u64 output_address = (output) ? virt_to_phys(output) : 0;
volatile void *hypercall_page = hv_context.hypercall_page;
- DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p "
- "output phys %llx virt %p hypercall %p>",
- control, input_address, input,
- output_address, output, hypercall_page);
-
__asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
__asm__ __volatile__("call *%3" : "=a" (hv_status) :
"c" (control), "d" (input_address),
"m" (hypercall_page));
- DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hv_status);
-
return hv_status;
#else
@@ -165,18 +134,12 @@ static u64 do_hypercall(u64 control, void *input, void *output)
u32 output_address_lo = output_address & 0xFFFFFFFF;
volatile void *hypercall_page = hv_context.hypercall_page;
- DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
- control, input, output);
-
__asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
"=a"(hv_status_lo) : "d" (control_hi),
"a" (control_lo), "b" (input_address_hi),
"c" (input_address_lo), "D"(output_address_hi),
"S"(output_address_lo), "m" (hypercall_page));
- DPRINT_DBG(VMBUS, "Hypercall <return %llx>",
- hv_status_lo | ((u64)hv_status_hi << 32));
-
return hv_status_lo | ((u64)hv_status_hi << 32);
#endif /* !x86_64 */
}
@@ -197,13 +160,8 @@ int hv_init(void)
memset(hv_context.synic_message_page, 0,
sizeof(void *) * MAX_NUM_CPUS);
- if (!query_hypervisor_presence()) {
- DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
- goto Cleanup;
- }
-
- DPRINT_INFO(VMBUS,
- "Windows hypervisor detected! Retrieving more info...");
+ if (!query_hypervisor_presence())
+ goto cleanup;
max_leaf = query_hypervisor_info();
/* HvQueryHypervisorFeatures(maxLeaf); */
@@ -213,11 +171,8 @@ int hv_init(void)
*/
rdmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
- if (hv_context.guestid != 0) {
- DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!",
- hv_context.guestid);
- goto Cleanup;
- }
+ if (hv_context.guestid != 0)
+ goto cleanup;
/* Write our OS info */
wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
@@ -232,11 +187,8 @@ int hv_init(void)
*/
virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
- if (!virtaddr) {
- DPRINT_ERR(VMBUS,
- "unable to allocate hypercall page!!");
- goto Cleanup;
- }
+ if (!virtaddr)
+ goto cleanup;
hypercall_msr.enable = 1;
@@ -247,23 +199,17 @@ int hv_init(void)
hypercall_msr.as_uint64 = 0;
rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
- if (!hypercall_msr.enable) {
- DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
- goto Cleanup;
- }
+ if (!hypercall_msr.enable)
+ goto cleanup;
hv_context.hypercall_page = virtaddr;
- DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx",
- hv_context.hypercall_page,
- (u64)hypercall_msr.guest_physical_address << PAGE_SHIFT);
-
/* Setup the global signal event param for the signal event hypercall */
hv_context.signal_event_buffer =
kmalloc(sizeof(struct hv_input_signal_event_buffer),
GFP_KERNEL);
if (!hv_context.signal_event_buffer)
- goto Cleanup;
+ goto cleanup;
hv_context.signal_event_param =
(struct hv_input_signal_event *)
@@ -278,7 +224,7 @@ int hv_init(void)
return ret;
-Cleanup:
+cleanup:
if (virtaddr) {
if (hypercall_msr.enable) {
hypercall_msr.as_uint64 = 0;
@@ -394,24 +340,20 @@ void hv_synic_init(void *irqarg)
/* Check the version */
rdmsrl(HV_X64_MSR_SVERSION, version);
- DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
-
hv_context.synic_message_page[cpu] =
(void *)get_zeroed_page(GFP_ATOMIC);
if (hv_context.synic_message_page[cpu] == NULL) {
- DPRINT_ERR(VMBUS,
- "unable to allocate SYNIC message page!!");
- goto Cleanup;
+ pr_err("Unable to allocate SYNIC message page\n");
+ goto cleanup;
}
hv_context.synic_event_page[cpu] =
(void *)get_zeroed_page(GFP_ATOMIC);
if (hv_context.synic_event_page[cpu] == NULL) {
- DPRINT_ERR(VMBUS,
- "unable to allocate SYNIC event page!!");
- goto Cleanup;
+ pr_err("Unable to allocate SYNIC event page\n");
+ goto cleanup;
}
/* Setup the Synic's message page */
@@ -420,8 +362,6 @@ void hv_synic_init(void *irqarg)
simp.base_simp_gpa = virt_to_phys(hv_context.synic_message_page[cpu])
>> PAGE_SHIFT;
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.as_uint64);
-
wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
/* Setup the Synic's event page */
@@ -430,14 +370,8 @@ void hv_synic_init(void *irqarg)
siefp.base_siefp_gpa = virt_to_phys(hv_context.synic_event_page[cpu])
>> PAGE_SHIFT;
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.as_uint64);
-
wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
- /* Setup the interception SINT. */
- /* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */
- /* interceptionSint.as_uint64); */
-
/* Setup the shared SINT. */
rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
@@ -446,9 +380,6 @@ void hv_synic_init(void *irqarg)
shared_sint.masked = false;
shared_sint.auto_eoi = true;
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx",
- shared_sint.as_uint64);
-
wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
/* Enable the global synic bit */
@@ -460,7 +391,7 @@ void hv_synic_init(void *irqarg)
hv_context.synic_initialized = true;
return;
-Cleanup:
+cleanup:
if (hv_context.synic_event_page[cpu])
free_page((unsigned long)hv_context.synic_event_page[cpu]);
diff --git a/drivers/staging/hv/hv.h b/drivers/staging/hv/hv.h
deleted file mode 100644
index 829aff81bb30..000000000000
--- a/drivers/staging/hv/hv.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef __HV_H__
-#define __HV_H__
-
-#include "hv_api.h"
-
-enum {
- VMBUS_MESSAGE_CONNECTION_ID = 1,
- VMBUS_MESSAGE_PORT_ID = 1,
- VMBUS_EVENT_CONNECTION_ID = 2,
- VMBUS_EVENT_PORT_ID = 2,
- VMBUS_MONITOR_CONNECTION_ID = 3,
- VMBUS_MONITOR_PORT_ID = 3,
- VMBUS_MESSAGE_SINT = 2,
-};
-
-/* #defines */
-
-#define HV_PRESENT_BIT 0x80000000
-
-#define HV_LINUX_GUEST_ID_LO 0x00000000
-#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
-#define HV_LINUX_GUEST_ID (((u64)HV_LINUX_GUEST_ID_HI << 32) | \
- HV_LINUX_GUEST_ID_LO)
-
-#define HV_CPU_POWER_MANAGEMENT (1 << 0)
-#define HV_RECOMMENDATIONS_MAX 4
-
-#define HV_X64_MAX 5
-#define HV_CAPS_MAX 8
-
-
-#define HV_HYPERCALL_PARAM_ALIGN sizeof(u64)
-
-
-/* Service definitions */
-
-#define HV_SERVICE_PARENT_PORT (0)
-#define HV_SERVICE_PARENT_CONNECTION (0)
-
-#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0)
-#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1)
-#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2)
-#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3)
-
-#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1)
-#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2)
-#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3)
-#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4)
-#define HV_SERVICE_MAX_MESSAGE_ID (4)
-
-#define HV_SERVICE_PROTOCOL_VERSION (0x0010)
-#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64
-
-/* #define VMBUS_REVISION_NUMBER 6 */
-
-/* Our local vmbus's port and connection id. Anything >0 is fine */
-/* #define VMBUS_PORT_ID 11 */
-
-/* 628180B8-308D-4c5e-B7DB-1BEB62E62EF4 */
-static const struct hv_guid VMBUS_SERVICE_ID = {
- .data = {
- 0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c,
- 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4
- },
-};
-
-#define MAX_NUM_CPUS 32
-
-
-struct hv_input_signal_event_buffer {
- u64 align8;
- struct hv_input_signal_event event;
-};
-
-struct hv_context {
- /* We only support running on top of Hyper-V
- * So at this point this really can only contain the Hyper-V ID
- */
- u64 guestid;
-
- void *hypercall_page;
-
- bool synic_initialized;
-
- /*
- * This is used as an input param to HvCallSignalEvent hypercall. The
- * input param is immutable in our usage and must be dynamic mem (vs
- * stack or global). */
- struct hv_input_signal_event_buffer *signal_event_buffer;
- /* 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];
-};
-
-extern struct hv_context hv_context;
-
-
-/* Hv Interface */
-
-extern int hv_init(void);
-
-extern void hv_cleanup(void);
-
-extern u16 hv_post_message(union hv_connection_id connection_id,
- enum hv_message_type message_type,
- void *payload, size_t payload_size);
-
-extern u16 hv_signal_event(void);
-
-extern void hv_synic_init(void *irqarg);
-
-extern void hv_synic_cleanup(void *arg);
-
-#endif /* __HV_H__ */
diff --git a/drivers/staging/hv/hv_api.h b/drivers/staging/hv/hv_api.h
deleted file mode 100644
index 43a722888dc4..000000000000
--- a/drivers/staging/hv/hv_api.h
+++ /dev/null
@@ -1,910 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#ifndef __HV_API_H
-#define __HV_API_H
-
-struct hv_guid {
- unsigned char data[16];
-};
-
-
-
-/* Status codes for hypervisor operations. */
-
-/*
- * HV_STATUS_SUCCESS
- * The specified hypercall succeeded
- */
-#define HV_STATUS_SUCCESS ((u16)0x0000)
-
-/*
- * HV_STATUS_INVALID_HYPERCALL_CODE
- * The hypervisor does not support the operation because the specified
- * hypercall code is not supported.
- */
-#define HV_STATUS_INVALID_HYPERCALL_CODE ((u16)0x0002)
-
-/*
- * HV_STATUS_INVALID_HYPERCALL_INPUT
- * The hypervisor does not support the operation because the encoding for the
- * hypercall input register is not supported.
- */
-#define HV_STATUS_INVALID_HYPERCALL_INPUT ((u16)0x0003)
-
-/*
- * HV_STATUS_INVALID_ALIGNMENT
- * The hypervisor could not perform the operation because a parameter has an
- * invalid alignment.
- */
-#define HV_STATUS_INVALID_ALIGNMENT ((u16)0x0004)
-
-/*
- * HV_STATUS_INVALID_PARAMETER
- * The hypervisor could not perform the operation because an invalid parameter
- * was specified.
- */
-#define HV_STATUS_INVALID_PARAMETER ((u16)0x0005)
-
-/*
- * HV_STATUS_ACCESS_DENIED
- * Access to the specified object was denied.
- */
-#define HV_STATUS_ACCESS_DENIED ((u16)0x0006)
-
-/*
- * HV_STATUS_INVALID_PARTITION_STATE
- * The hypervisor could not perform the operation because the partition is
- * entering or in an invalid state.
- */
-#define HV_STATUS_INVALID_PARTITION_STATE ((u16)0x0007)
-
-/*
- * HV_STATUS_OPERATION_DENIED
- * The operation is not allowed in the current state.
- */
-#define HV_STATUS_OPERATION_DENIED ((u16)0x0008)
-
-/*
- * HV_STATUS_UNKNOWN_PROPERTY
- * The hypervisor does not recognize the specified partition property.
- */
-#define HV_STATUS_UNKNOWN_PROPERTY ((u16)0x0009)
-
-/*
- * HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE
- * The specified value of a partition property is out of range or violates an
- * invariant.
- */
-#define HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE ((u16)0x000A)
-
-/*
- * HV_STATUS_INSUFFICIENT_MEMORY
- * There is not enough memory in the hypervisor pool to complete the operation.
- */
-#define HV_STATUS_INSUFFICIENT_MEMORY ((u16)0x000B)
-
-/*
- * HV_STATUS_PARTITION_TOO_DEEP
- * The maximum partition depth has been exceeded for the partition hierarchy.
- */
-#define HV_STATUS_PARTITION_TOO_DEEP ((u16)0x000C)
-
-/*
- * HV_STATUS_INVALID_PARTITION_ID
- * A partition with the specified partition Id does not exist.
- */
-#define HV_STATUS_INVALID_PARTITION_ID ((u16)0x000D)
-
-/*
- * HV_STATUS_INVALID_VP_INDEX
- * The hypervisor could not perform the operation because the specified VP
- * index is invalid.
- */
-#define HV_STATUS_INVALID_VP_INDEX ((u16)0x000E)
-
-/*
- * HV_STATUS_NOT_FOUND
- * The iteration is complete; no addition items in the iteration could be
- * found.
- */
-#define HV_STATUS_NOT_FOUND ((u16)0x0010)
-
-/*
- * HV_STATUS_INVALID_PORT_ID
- * The hypervisor could not perform the operation because the specified port
- * identifier is invalid.
- */
-#define HV_STATUS_INVALID_PORT_ID ((u16)0x0011)
-
-/*
- * HV_STATUS_INVALID_CONNECTION_ID
- * The hypervisor could not perform the operation because the specified
- * connection identifier is invalid.
- */
-#define HV_STATUS_INVALID_CONNECTION_ID ((u16)0x0012)
-
-/*
- * HV_STATUS_INSUFFICIENT_BUFFERS
- * You did not supply enough message buffers to send a message.
- */
-#define HV_STATUS_INSUFFICIENT_BUFFERS ((u16)0x0013)
-
-/*
- * HV_STATUS_NOT_ACKNOWLEDGED
- * The previous virtual interrupt has not been acknowledged.
- */
-#define HV_STATUS_NOT_ACKNOWLEDGED ((u16)0x0014)
-
-/*
- * HV_STATUS_INVALID_VP_STATE
- * A virtual processor is not in the correct state for the performance of the
- * indicated operation.
- */
-#define HV_STATUS_INVALID_VP_STATE ((u16)0x0015)
-
-/*
- * HV_STATUS_ACKNOWLEDGED
- * The previous virtual interrupt has already been acknowledged.
- */
-#define HV_STATUS_ACKNOWLEDGED ((u16)0x0016)
-
-/*
- * HV_STATUS_INVALID_SAVE_RESTORE_STATE
- * The indicated partition is not in a valid state for saving or restoring.
- */
-#define HV_STATUS_INVALID_SAVE_RESTORE_STATE ((u16)0x0017)
-
-/*
- * HV_STATUS_INVALID_SYNIC_STATE
- * The hypervisor could not complete the operation because a required feature
- * of the synthetic interrupt controller (SynIC) was disabled.
- */
-#define HV_STATUS_INVALID_SYNIC_STATE ((u16)0x0018)
-
-/*
- * HV_STATUS_OBJECT_IN_USE
- * The hypervisor could not perform the operation because the object or value
- * was either already in use or being used for a purpose that would not permit
- * completing the operation.
- */
-#define HV_STATUS_OBJECT_IN_USE ((u16)0x0019)
-
-/*
- * HV_STATUS_INVALID_PROXIMITY_DOMAIN_INFO
- * The proximity domain information is invalid.
- */
-#define HV_STATUS_INVALID_PROXIMITY_DOMAIN_INFO ((u16)0x001A)
-
-/*
- * HV_STATUS_NO_DATA
- * An attempt to retrieve debugging data failed because none was available.
- */
-#define HV_STATUS_NO_DATA ((u16)0x001B)
-
-/*
- * HV_STATUS_INACTIVE
- * The physical connection being used for debuggging has not recorded any
- * receive activity since the last operation.
- */
-#define HV_STATUS_INACTIVE ((u16)0x001C)
-
-/*
- * HV_STATUS_NO_RESOURCES
- * There are not enough resources to complete the operation.
- */
-#define HV_STATUS_NO_RESOURCES ((u16)0x001D)
-
-/*
- * HV_STATUS_FEATURE_UNAVAILABLE
- * A hypervisor feature is not available to the user.
- */
-#define HV_STATUS_FEATURE_UNAVAILABLE ((u16)0x001E)
-
-/*
- * HV_STATUS_UNSUCCESSFUL
- * {Operation Failed} The requested operation was unsuccessful.
- */
-#define HV_STATUS_UNSUCCESSFUL ((u16)0x1001)
-
-/*
- * HV_STATUS_INSUFFICIENT_BUFFER
- * The specified buffer was too small to contain all of the requested data.
- */
-#define HV_STATUS_INSUFFICIENT_BUFFER ((u16)0x1002)
-
-/*
- * HV_STATUS_GPA_NOT_PRESENT
- * The guest physical address is not currently associated with a system
- * physical address.
- */
-#define HV_STATUS_GPA_NOT_PRESENT ((u16)0x1003)
-
-/*
- * HV_STATUS_GUEST_PAGE_FAULT
- * The operation would have resulted in a page fault in the guest.
- */
-#define HV_STATUS_GUEST_PAGE_FAULT ((u16)0x1004)
-
-/*
- * HV_STATUS_RUNDOWN_DISABLED
- * The operation cannot proceed as the rundown object was marked disabled.
- */
-#define HV_STATUS_RUNDOWN_DISABLED ((u16)0x1005)
-
-/*
- * HV_STATUS_KEY_ALREADY_EXISTS
- * The entry cannot be added as another entry with the same key already exists.
- */
-#define HV_STATUS_KEY_ALREADY_EXISTS ((u16)0x1006)
-
-/*
- * HV_STATUS_GPA_INTERCEPT
- * The operation resulted an intercept on a region of guest physical memory.
- */
-#define HV_STATUS_GPA_INTERCEPT ((u16)0x1007)
-
-/*
- * HV_STATUS_GUEST_GENERAL_PROTECTION_FAULT
- * The operation would have resulted in a general protection fault in the
- * guest.
- */
-#define HV_STATUS_GUEST_GENERAL_PROTECTION_FAULT ((u16)0x1008)
-
-/*
- * HV_STATUS_GUEST_STACK_FAULT
- * The operation would have resulted in a stack fault in the guest.
- */
-#define HV_STATUS_GUEST_STACK_FAULT ((u16)0x1009)
-
-/*
- * HV_STATUS_GUEST_INVALID_OPCODE_FAULT
- * The operation would have resulted in an invalid opcode fault in the guest.
- */
-#define HV_STATUS_GUEST_INVALID_OPCODE_FAULT ((u16)0x100A)
-
-/*
- * HV_STATUS_FINALIZE_INCOMPLETE
- * The partition is not completely finalized.
- */
-#define HV_STATUS_FINALIZE_INCOMPLETE ((u16)0x100B)
-
-/*
- * HV_STATUS_GUEST_MACHINE_CHECK_ABORT
- * The operation would have resulted in an machine check abort in the guest.
- */
-#define HV_STATUS_GUEST_MACHINE_CHECK_ABORT ((u16)0x100C)
-
-/*
- * HV_STATUS_ILLEGAL_OVERLAY_ACCESS
- * An illegal access was attempted to an overlay page.
- */
-#define HV_STATUS_ILLEGAL_OVERLAY_ACCESS ((u16)0x100D)
-
-/*
- * HV_STATUS_INSUFFICIENT_SYSTEM_VA
- * There is not enough system VA space available to satisfy the request,
- */
-#define HV_STATUS_INSUFFICIENT_SYSTEM_VA ((u16)0x100E)
-
-/*
- * HV_STATUS_VIRTUAL_ADDRESS_NOT_MAPPED
- * The passed virtual address was not mapped in the hypervisor address space.
- */
-#define HV_STATUS_VIRTUAL_ADDRESS_NOT_MAPPED ((u16)0x100F)
-
-/*
- * HV_STATUS_NOT_IMPLEMENTED
- * The requested operation is not implemented in this version of the
- * hypervisor.
- */
-#define HV_STATUS_NOT_IMPLEMENTED ((u16)0x1010)
-
-/*
- * HV_STATUS_VMX_INSTRUCTION_FAILED
- * The requested VMX instruction failed to complete successfully.
- */
-#define HV_STATUS_VMX_INSTRUCTION_FAILED ((u16)0x1011)
-
-/*
- * HV_STATUS_VMX_INSTRUCTION_FAILED_WITH_STATUS
- * The requested VMX instruction failed to complete successfully indicating
- * status.
- */
-#define HV_STATUS_VMX_INSTRUCTION_FAILED_WITH_STATUS ((u16)0x1012)
-
-/*
- * HV_STATUS_MSR_ACCESS_FAILED
- * The requested access to the model specific register failed.
- */
-#define HV_STATUS_MSR_ACCESS_FAILED ((u16)0x1013)
-
-/*
- * HV_STATUS_CR_ACCESS_FAILED
- * The requested access to the control register failed.
- */
-#define HV_STATUS_CR_ACCESS_FAILED ((u16)0x1014)
-
-/*
- * HV_STATUS_TIMEOUT
- * The specified timeout expired before the operation completed.
- */
-#define HV_STATUS_TIMEOUT ((u16)0x1016)
-
-/*
- * HV_STATUS_MSR_INTERCEPT
- * The requested access to the model specific register generated an intercept.
- */
-#define HV_STATUS_MSR_INTERCEPT ((u16)0x1017)
-
-/*
- * HV_STATUS_CPUID_INTERCEPT
- * The CPUID instruction generated an intercept.
- */
-#define HV_STATUS_CPUID_INTERCEPT ((u16)0x1018)
-
-/*
- * HV_STATUS_REPEAT_INSTRUCTION
- * The current instruction should be repeated and the instruction pointer not
- * advanced.
- */
-#define HV_STATUS_REPEAT_INSTRUCTION ((u16)0x1019)
-
-/*
- * HV_STATUS_PAGE_PROTECTION_VIOLATION
- * The current instruction should be repeated and the instruction pointer not
- * advanced.
- */
-#define HV_STATUS_PAGE_PROTECTION_VIOLATION ((u16)0x101A)
-
-/*
- * HV_STATUS_PAGE_TABLE_INVALID
- * The current instruction should be repeated and the instruction pointer not
- * advanced.
- */
-#define HV_STATUS_PAGE_TABLE_INVALID ((u16)0x101B)
-
-/*
- * HV_STATUS_PAGE_NOT_PRESENT
- * The current instruction should be repeated and the instruction pointer not
- * advanced.
- */
-#define HV_STATUS_PAGE_NOT_PRESENT ((u16)0x101C)
-
-/*
- * HV_STATUS_IO_INTERCEPT
- * The requested access to the I/O port generated an intercept.
- */
-#define HV_STATUS_IO_INTERCEPT ((u16)0x101D)
-
-/*
- * HV_STATUS_NOTHING_TO_DO
- * There is nothing to do.
- */
-#define HV_STATUS_NOTHING_TO_DO ((u16)0x101E)
-
-/*
- * HV_STATUS_THREAD_TERMINATING
- * The requested thread is terminating.
- */
-#define HV_STATUS_THREAD_TERMINATING ((u16)0x101F)
-
-/*
- * HV_STATUS_SECTION_ALREADY_CONSTRUCTED
- * The specified section was already constructed.
- */
-#define HV_STATUS_SECTION_ALREADY_CONSTRUCTED ((u16)0x1020)
-
-/* HV_STATUS_SECTION_NOT_ALREADY_CONSTRUCTED
- * The specified section was not already constructed.
- */
-#define HV_STATUS_SECTION_NOT_ALREADY_CONSTRUCTED ((u16)0x1021)
-
-/*
- * HV_STATUS_PAGE_ALREADY_COMMITTED
- * The specified virtual address was already backed by physical memory.
- */
-#define HV_STATUS_PAGE_ALREADY_COMMITTED ((u16)0x1022)
-
-/*
- * HV_STATUS_PAGE_NOT_ALREADY_COMMITTED
- * The specified virtual address was not already backed by physical memory.
- */
-#define HV_STATUS_PAGE_NOT_ALREADY_COMMITTED ((u16)0x1023)
-
-/*
- * HV_STATUS_COMMITTED_PAGES_REMAIN
- * Committed pages remain in the section.
- */
-#define HV_STATUS_COMMITTED_PAGES_REMAIN ((u16)0x1024)
-
-/*
- * HV_STATUS_NO_REMAINING_COMMITTED_PAGES
- * No additional committed pages beyond the specified page exist in the
- * section.
- */
-#define HV_STATUS_NO_REMAINING_COMMITTED_PAGES ((u16)0x1025)
-
-/*
- * HV_STATUS_INSUFFICIENT_COMPARTMENT_VA
- * The VA space of the compartment is exhausted.
- */
-#define HV_STATUS_INSUFFICIENT_COMPARTMENT_VA ((u16)0x1026)
-
-/*
- * HV_STATUS_DEREF_SPA_LIST_FULL
- * The SPA dereference list is full, and there are additional entries to be
- * added to it.
- */
-#define HV_STATUS_DEREF_SPA_LIST_FULL ((u16)0x1027)
-
-/*
- * HV_STATUS_GPA_OUT_OF_RANGE
- * The supplied GPA is out of range.
- */
-#define HV_STATUS_GPA_OUT_OF_RANGE ((u16)0x1027)
-
-/*
- * HV_STATUS_NONVOLATILE_XMM_STALE
- * The XMM register that was being accessed is stale.
- */
-#define HV_STATUS_NONVOLATILE_XMM_STALE ((u16)0x1028)
-
-/* HV_STATUS_UNSUPPORTED_PROCESSOR
- * The hypervisor does not support the processors in this system.
- */
-#define HV_STATUS_UNSUPPORTED_PROCESSOR ((u16)0x1029)
-
-/*
- * HV_STATUS_INSUFFICIENT_CROM_SPACE
- * Insufficient space existed for copying over the CROM contents.
- */
-#define HV_STATUS_INSUFFICIENT_CROM_SPACE ((u16)0x2000)
-
-/*
- * HV_STATUS_BAD_CROM_FORMAT
- * The contents of the CROM failed validation attempts.
- */
-#define HV_STATUS_BAD_CROM_FORMAT ((u16)0x2001)
-
-/*
- * HV_STATUS_UNSUPPORTED_CROM_FORMAT
- * The contents of the CROM contain contents the parser doesn't support.
- */
-#define HV_STATUS_UNSUPPORTED_CROM_FORMAT ((u16)0x2002)
-
-/*
- * HV_STATUS_UNSUPPORTED_CONTROLLER
- * The register format of the OHCI controller specified for debugging is not
- * supported.
- */
-#define HV_STATUS_UNSUPPORTED_CONTROLLER ((u16)0x2003)
-
-/*
- * HV_STATUS_CROM_TOO_LARGE
- * The CROM contents were to large to copy over.
- */
-#define HV_STATUS_CROM_TOO_LARGE ((u16)0x2004)
-
-/*
- * HV_STATUS_CONTROLLER_IN_USE
- * The OHCI controller specified for debugging cannot be used as it is already
- * in use.
- */
-#define HV_STATUS_CONTROLLER_IN_USE ((u16)0x2005)
-
-
-/*
- * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
- * is set by CPUID(HVCPUID_VERSION_FEATURES).
- */
-enum hv_cpuid_function {
- HVCPUID_VERSION_FEATURES = 0x00000001,
- HVCPUID_VENDOR_MAXFUNCTION = 0x40000000,
- HVCPUID_INTERFACE = 0x40000001,
-
- /*
- * The remaining functions depend on the value of
- * HVCPUID_INTERFACE
- */
- HVCPUID_VERSION = 0x40000002,
- HVCPUID_FEATURES = 0x40000003,
- HVCPUID_ENLIGHTENMENT_INFO = 0x40000004,
- HVCPUID_IMPLEMENTATION_LIMITS = 0x40000005,
-};
-
-/* Define the virtual APIC registers */
-#define HV_X64_MSR_EOI (0x40000070)
-#define HV_X64_MSR_ICR (0x40000071)
-#define HV_X64_MSR_TPR (0x40000072)
-#define HV_X64_MSR_APIC_ASSIST_PAGE (0x40000073)
-
-/* Define version of the synthetic interrupt controller. */
-#define HV_SYNIC_VERSION (1)
-
-/* Define synthetic interrupt controller model specific registers. */
-#define HV_X64_MSR_SCONTROL (0x40000080)
-#define HV_X64_MSR_SVERSION (0x40000081)
-#define HV_X64_MSR_SIEFP (0x40000082)
-#define HV_X64_MSR_SIMP (0x40000083)
-#define HV_X64_MSR_EOM (0x40000084)
-#define HV_X64_MSR_SINT0 (0x40000090)
-#define HV_X64_MSR_SINT1 (0x40000091)
-#define HV_X64_MSR_SINT2 (0x40000092)
-#define HV_X64_MSR_SINT3 (0x40000093)
-#define HV_X64_MSR_SINT4 (0x40000094)
-#define HV_X64_MSR_SINT5 (0x40000095)
-#define HV_X64_MSR_SINT6 (0x40000096)
-#define HV_X64_MSR_SINT7 (0x40000097)
-#define HV_X64_MSR_SINT8 (0x40000098)
-#define HV_X64_MSR_SINT9 (0x40000099)
-#define HV_X64_MSR_SINT10 (0x4000009A)
-#define HV_X64_MSR_SINT11 (0x4000009B)
-#define HV_X64_MSR_SINT12 (0x4000009C)
-#define HV_X64_MSR_SINT13 (0x4000009D)
-#define HV_X64_MSR_SINT14 (0x4000009E)
-#define HV_X64_MSR_SINT15 (0x4000009F)
-
-/* Define the expected SynIC version. */
-#define HV_SYNIC_VERSION_1 (0x1)
-
-/* Define synthetic interrupt controller message constants. */
-#define HV_MESSAGE_SIZE (256)
-#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240)
-#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
-#define HV_ANY_VP (0xFFFFFFFF)
-
-/* Define synthetic interrupt controller flag constants. */
-#define HV_EVENT_FLAGS_COUNT (256 * 8)
-#define HV_EVENT_FLAGS_BYTE_COUNT (256)
-#define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32))
-
-/* Define hypervisor message types. */
-enum hv_message_type {
- HVMSG_NONE = 0x00000000,
-
- /* Memory access messages. */
- HVMSG_UNMAPPED_GPA = 0x80000000,
- HVMSG_GPA_INTERCEPT = 0x80000001,
-
- /* Timer notification messages. */
- HVMSG_TIMER_EXPIRED = 0x80000010,
-
- /* Error messages. */
- HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
- HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021,
- HVMSG_UNSUPPORTED_FEATURE = 0x80000022,
-
- /* Trace buffer complete messages. */
- HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040,
-
- /* Platform-specific processor intercept messages. */
- HVMSG_X64_IOPORT_INTERCEPT = 0x80010000,
- HVMSG_X64_MSR_INTERCEPT = 0x80010001,
- HVMSG_X64_CPUID_INTERCEPT = 0x80010002,
- HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003,
- HVMSG_X64_APIC_EOI = 0x80010004,
- HVMSG_X64_LEGACY_FP_ERROR = 0x80010005
-};
-
-/* Define the number of synthetic interrupt sources. */
-#define HV_SYNIC_SINT_COUNT (16)
-#define HV_SYNIC_STIMER_COUNT (4)
-
-/* Define invalid partition identifier. */
-#define HV_PARTITION_ID_INVALID ((u64)0x0)
-
-/* Define connection identifier type. */
-union hv_connection_id {
- u32 asu32;
- struct {
- u32 id:24;
- u32 reserved:8;
- } u;
-};
-
-/* Define port identifier type. */
-union hv_port_id {
- u32 asu32;
- struct {
- u32 id:24;
- u32 reserved:8;
- } u ;
-};
-
-/* Define port type. */
-enum hv_port_type {
- HVPORT_MSG = 1,
- HVPORT_EVENT = 2,
- HVPORT_MONITOR = 3
-};
-
-/* Define port information structure. */
-struct hv_port_info {
- enum hv_port_type port_type;
- u32 padding;
- union {
- struct {
- u32 target_sint;
- u32 target_vp;
- u64 rsvdz;
- } message_port_info;
- struct {
- u32 target_sint;
- u32 target_vp;
- u16 base_flag_bumber;
- u16 flag_count;
- u32 rsvdz;
- } event_port_info;
- struct {
- u64 monitor_address;
- u64 rsvdz;
- } monitor_port_info;
- };
-};
-
-struct hv_connection_info {
- enum hv_port_type port_type;
- u32 padding;
- union {
- struct {
- u64 rsvdz;
- } message_connection_info;
- struct {
- u64 rsvdz;
- } event_connection_info;
- struct {
- u64 monitor_address;
- } monitor_connection_info;
- };
-};
-
-/* Define synthetic interrupt controller message flags. */
-union hv_message_flags {
- u8 asu8;
- struct {
- u8 msg_pending:1;
- u8 reserved:7;
- };
-};
-
-/* Define synthetic interrupt controller message header. */
-struct hv_message_header {
- enum hv_message_type message_type;
- u8 payload_size;
- union hv_message_flags message_flags;
- u8 reserved[2];
- union {
- u64 sender;
- union hv_port_id port;
- };
-};
-
-/* Define timer message payload structure. */
-struct hv_timer_message_payload {
- u32 timer_index;
- u32 reserved;
- u64 expiration_time; /* When the timer expired */
- u64 delivery_time; /* When the message was delivered */
-};
-
-/* Define synthetic interrupt controller message format. */
-struct hv_message {
- struct hv_message_header header;
- union {
- u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
- } u ;
-};
-
-/* Define the number of message buffers associated with each port. */
-#define HV_PORT_MESSAGE_BUFFER_COUNT (16)
-
-/* Define the synthetic interrupt message page layout. */
-struct hv_message_page {
- struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
-};
-
-/* Define the synthetic interrupt controller event flags format. */
-union hv_synic_event_flags {
- u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT];
- u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT];
-};
-
-/* Define the synthetic interrupt flags page layout. */
-struct hv_synic_event_flags_page {
- union hv_synic_event_flags sintevent_flags[HV_SYNIC_SINT_COUNT];
-};
-
-/* Define SynIC control register. */
-union hv_synic_scontrol {
- u64 as_uint64;
- struct {
- u64 enable:1;
- u64 reserved:63;
- };
-};
-
-/* Define synthetic interrupt source. */
-union hv_synic_sint {
- u64 as_uint64;
- struct {
- u64 vector:8;
- u64 reserved1:8;
- u64 masked:1;
- u64 auto_eoi:1;
- u64 reserved2:46;
- };
-};
-
-/* Define the format of the SIMP register */
-union hv_synic_simp {
- u64 as_uint64;
- struct {
- u64 simp_enabled:1;
- u64 preserved:11;
- u64 base_simp_gpa:52;
- };
-};
-
-/* Define the format of the SIEFP register */
-union hv_synic_siefp {
- u64 as_uint64;
- struct {
- u64 siefp_enabled:1;
- u64 preserved:11;
- u64 base_siefp_gpa:52;
- };
-};
-
-/* Definitions for the monitored notification facility */
-union hv_monitor_trigger_group {
- u64 as_uint64;
- struct {
- u32 pending;
- u32 armed;
- };
-};
-
-struct hv_monitor_parameter {
- union hv_connection_id connectionid;
- u16 flagnumber;
- u16 rsvdz;
-};
-
-union hv_monitor_trigger_state {
- u32 asu32;
-
- struct {
- u32 group_enable:4;
- u32 rsvdz:28;
- };
-};
-
-/* struct hv_monitor_page Layout */
-/* ------------------------------------------------------ */
-/* | 0 | TriggerState (4 bytes) | Rsvd1 (4 bytes) | */
-/* | 8 | TriggerGroup[0] | */
-/* | 10 | TriggerGroup[1] | */
-/* | 18 | TriggerGroup[2] | */
-/* | 20 | TriggerGroup[3] | */
-/* | 28 | Rsvd2[0] | */
-/* | 30 | Rsvd2[1] | */
-/* | 38 | Rsvd2[2] | */
-/* | 40 | NextCheckTime[0][0] | NextCheckTime[0][1] | */
-/* | ... | */
-/* | 240 | Latency[0][0..3] | */
-/* | 340 | Rsvz3[0] | */
-/* | 440 | Parameter[0][0] | */
-/* | 448 | Parameter[0][1] | */
-/* | ... | */
-/* | 840 | Rsvd4[0] | */
-/* ------------------------------------------------------ */
-struct hv_monitor_page {
- union hv_monitor_trigger_state trigger_state;
- u32 rsvdz1;
-
- union hv_monitor_trigger_group trigger_group[4];
- u64 rsvdz2[3];
-
- s32 next_checktime[4][32];
-
- u16 latency[4][32];
- u64 rsvdz3[32];
-
- struct hv_monitor_parameter parameter[4][32];
-
- u8 rsvdz4[1984];
-};
-
-/* Declare the various hypercall operations. */
-enum hv_call_code {
- HVCALL_POST_MESSAGE = 0x005c,
- HVCALL_SIGNAL_EVENT = 0x005d,
-};
-
-/* Definition of the hv_post_message hypercall input structure. */
-struct hv_input_post_message {
- union hv_connection_id connectionid;
- u32 reserved;
- enum hv_message_type message_type;
- u32 payload_size;
- u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
-};
-
-/* Definition of the hv_signal_event hypercall input structure. */
-struct hv_input_signal_event {
- union hv_connection_id connectionid;
- u16 flag_number;
- u16 rsvdz;
-};
-
-/*
- * Versioning definitions used for guests reporting themselves to the
- * hypervisor, and visa versa.
- */
-
-/* Version info reported by guest OS's */
-enum hv_guest_os_vendor {
- HVGUESTOS_VENDOR_MICROSOFT = 0x0001
-};
-
-enum hv_guest_os_microsoft_ids {
- HVGUESTOS_MICROSOFT_UNDEFINED = 0x00,
- HVGUESTOS_MICROSOFT_MSDOS = 0x01,
- HVGUESTOS_MICROSOFT_WINDOWS3X = 0x02,
- HVGUESTOS_MICROSOFT_WINDOWS9X = 0x03,
- HVGUESTOS_MICROSOFT_WINDOWSNT = 0x04,
- HVGUESTOS_MICROSOFT_WINDOWSCE = 0x05
-};
-
-/*
- * Declare the MSR used to identify the guest OS.
- */
-#define HV_X64_MSR_GUEST_OS_ID 0x40000000
-
-union hv_x64_msr_guest_os_id_contents {
- u64 as_uint64;
- struct {
- u64 build_number:16;
- u64 service_version:8; /* Service Pack, etc. */
- u64 minor_version:8;
- u64 major_version:8;
- u64 os_id:8; /* enum hv_guest_os_microsoft_ids (if Vendor=MS) */
- u64 vendor_id:16; /* enum hv_guest_os_vendor */
- };
-};
-
-/*
- * Declare the MSR used to setup pages used to communicate with the hypervisor.
- */
-#define HV_X64_MSR_HYPERCALL 0x40000001
-
-union hv_x64_msr_hypercall_contents {
- u64 as_uint64;
- struct {
- u64 enable:1;
- u64 reserved:11;
- u64 guest_physical_address:52;
- };
-};
-
-#endif
diff --git a/drivers/staging/hv/hv_kvp.c b/drivers/staging/hv/hv_kvp.c
index faf692e4126e..13b0ecf7d5d6 100644
--- a/drivers/staging/hv/hv_kvp.c
+++ b/drivers/staging/hv/hv_kvp.c
@@ -20,23 +20,14 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/net.h>
#include <linux/nls.h>
#include <linux/connector.h>
#include <linux/workqueue.h>
-#include "logging.h"
-#include "hv_api.h"
-#include "vmbus.h"
-#include "vmbus_packet_format.h"
-#include "vmbus_channel_interface.h"
-#include "version_info.h"
-#include "channel.h"
-#include "vmbus_private.h"
-#include "vmbus_api.h"
-#include "utils.h"
+#include "hyperv.h"
#include "hv_kvp.h"
@@ -114,7 +105,7 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
message = (struct hv_ku_msg *)msg->data;
if (msg->seq == KVP_REGISTER) {
- printk(KERN_INFO "KVP: user-mode registering done.\n");
+ pr_info("KVP: user-mode registering done.\n");
kvp_register();
}
@@ -174,7 +165,7 @@ kvp_respond_to_host(char *key, char *value, int error)
/*
* This is a spurious call!
*/
- printk(KERN_WARNING "KVP: Transaction not active\n");
+ pr_warn("KVP: Transaction not active\n");
return;
}
/*
@@ -259,9 +250,6 @@ void hv_kvp_onchannelcallback(void *context)
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
- DPRINT_DBG(VMBUS, "KVP packet: len=%d, requestid=%lld",
- recvlen, requestid);
-
icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
sizeof(struct vmbuspipe_hdr)];
diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c
index 118c7be22562..359e73741c48 100644
--- a/drivers/staging/hv/hv_mouse.c
+++ b/drivers/staging/hv/hv_mouse.c
@@ -26,13 +26,7 @@
#include <linux/dmi.h>
#include <linux/delay.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "version_info.h"
-#include "vmbus.h"
-#include "vmbus_api.h"
-#include "channel.h"
-#include "vmbus_packet_format.h"
+#include "hyperv.h"
/*
@@ -45,13 +39,6 @@ struct hv_input_dev_info {
char name[128];
};
-/* Represents the input vsc driver */
-/* FIXME - can be removed entirely */
-struct mousevsc_drv_obj {
- struct hv_driver Base;
-};
-
-
/* The maximum size of a synthetic input message. */
#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
@@ -169,23 +156,23 @@ struct mousevsc_prt_msg {
* Represents an mousevsc device
*/
struct mousevsc_dev {
- struct hv_device *Device;
+ struct hv_device *device;
/* 0 indicates the device is being destroyed */
- atomic_t RefCount;
- int NumOutstandingRequests;
- unsigned char bInitializeComplete;
- struct mousevsc_prt_msg ProtocolReq;
- struct mousevsc_prt_msg ProtocolResp;
+ atomic_t ref_count;
+ int num_outstanding_req;
+ unsigned char init_complete;
+ struct mousevsc_prt_msg protocol_req;
+ struct mousevsc_prt_msg protocol_resp;
/* Synchronize the request/response if needed */
- wait_queue_head_t ProtocolWaitEvent;
- wait_queue_head_t DeviceInfoWaitEvent;
+ wait_queue_head_t protocol_wait_event;
+ wait_queue_head_t dev_info_wait_event;
int protocol_wait_condition;
int device_wait_condition;
- int DeviceInfoStatus;
+ int dev_info_status;
- struct hid_descriptor *HidDesc;
- unsigned char *ReportDesc;
- u32 ReportDescSize;
+ struct hid_descriptor *hid_desc;
+ unsigned char *report_desc;
+ u32 report_desc_size;
struct hv_input_dev_info hid_dev_info;
};
@@ -202,41 +189,41 @@ static void deviceinfo_callback(struct hv_device *dev, struct hv_input_dev_info
static void inputreport_callback(struct hv_device *dev, void *packet, u32 len);
static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len);
-static struct mousevsc_dev *AllocInputDevice(struct hv_device *Device)
+static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
{
- struct mousevsc_dev *inputDevice;
+ struct mousevsc_dev *input_dev;
- inputDevice = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
+ input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
- if (!inputDevice)
+ if (!input_dev)
return NULL;
/*
* Set to 2 to allow both inbound and outbound traffics
- * (ie GetInputDevice() and MustGetInputDevice()) to proceed.
+ * (ie get_input_device() and must_get_input_device()) to proceed.
*/
- atomic_cmpxchg(&inputDevice->RefCount, 0, 2);
+ atomic_cmpxchg(&input_dev->ref_count, 0, 2);
- inputDevice->Device = Device;
- Device->ext = inputDevice;
+ input_dev->device = device;
+ device->ext = input_dev;
- return inputDevice;
+ return input_dev;
}
-static void FreeInputDevice(struct mousevsc_dev *Device)
+static void free_input_device(struct mousevsc_dev *device)
{
- WARN_ON(atomic_read(&Device->RefCount) == 0);
- kfree(Device);
+ WARN_ON(atomic_read(&device->ref_count) == 0);
+ kfree(device);
}
/*
* Get the inputdevice object if exists and its refcount > 1
*/
-static struct mousevsc_dev *GetInputDevice(struct hv_device *Device)
+static struct mousevsc_dev *get_input_device(struct hv_device *device)
{
- struct mousevsc_dev *inputDevice;
+ struct mousevsc_dev *input_dev;
- inputDevice = (struct mousevsc_dev *)Device->ext;
+ input_dev = (struct mousevsc_dev *)device->ext;
/*
* FIXME
@@ -244,134 +231,137 @@ static struct mousevsc_dev *GetInputDevice(struct hv_device *Device)
* what the intention is...
*
* printk(KERN_ERR "-------------------------> REFCOUNT = %d",
- * inputDevice->RefCount);
+ * input_dev->ref_count);
*/
- if (inputDevice && atomic_read(&inputDevice->RefCount) > 1)
- atomic_inc(&inputDevice->RefCount);
+ if (input_dev && atomic_read(&input_dev->ref_count) > 1)
+ atomic_inc(&input_dev->ref_count);
else
- inputDevice = NULL;
+ input_dev = NULL;
- return inputDevice;
+ return input_dev;
}
/*
* Get the inputdevice object iff exists and its refcount > 0
*/
-static struct mousevsc_dev *MustGetInputDevice(struct hv_device *Device)
+static struct mousevsc_dev *must_get_input_device(struct hv_device *device)
{
- struct mousevsc_dev *inputDevice;
+ struct mousevsc_dev *input_dev;
- inputDevice = (struct mousevsc_dev *)Device->ext;
+ input_dev = (struct mousevsc_dev *)device->ext;
- if (inputDevice && atomic_read(&inputDevice->RefCount))
- atomic_inc(&inputDevice->RefCount);
+ if (input_dev && atomic_read(&input_dev->ref_count))
+ atomic_inc(&input_dev->ref_count);
else
- inputDevice = NULL;
+ input_dev = NULL;
- return inputDevice;
+ return input_dev;
}
-static void PutInputDevice(struct hv_device *Device)
+static void put_input_device(struct hv_device *device)
{
- struct mousevsc_dev *inputDevice;
+ struct mousevsc_dev *input_dev;
- inputDevice = (struct mousevsc_dev *)Device->ext;
+ input_dev = (struct mousevsc_dev *)device->ext;
- atomic_dec(&inputDevice->RefCount);
+ atomic_dec(&input_dev->ref_count);
}
/*
- * Drop ref count to 1 to effectively disable GetInputDevice()
+ * Drop ref count to 1 to effectively disable get_input_device()
*/
-static struct mousevsc_dev *ReleaseInputDevice(struct hv_device *Device)
+static struct mousevsc_dev *release_input_device(struct hv_device *device)
{
- struct mousevsc_dev *inputDevice;
+ struct mousevsc_dev *input_dev;
- inputDevice = (struct mousevsc_dev *)Device->ext;
+ input_dev = (struct mousevsc_dev *)device->ext;
/* Busy wait until the ref drop to 2, then set it to 1 */
- while (atomic_cmpxchg(&inputDevice->RefCount, 2, 1) != 2)
+ while (atomic_cmpxchg(&input_dev->ref_count, 2, 1) != 2)
udelay(100);
- return inputDevice;
+ return input_dev;
}
/*
- * Drop ref count to 0. No one can use InputDevice object.
+ * Drop ref count to 0. No one can use input_device object.
*/
-static struct mousevsc_dev *FinalReleaseInputDevice(struct hv_device *Device)
+static struct mousevsc_dev *final_release_input_device(struct hv_device *device)
{
- struct mousevsc_dev *inputDevice;
+ struct mousevsc_dev *input_dev;
- inputDevice = (struct mousevsc_dev *)Device->ext;
+ input_dev = (struct mousevsc_dev *)device->ext;
/* Busy wait until the ref drop to 1, then set it to 0 */
- while (atomic_cmpxchg(&inputDevice->RefCount, 1, 0) != 1)
+ while (atomic_cmpxchg(&input_dev->ref_count, 1, 0) != 1)
udelay(100);
- Device->ext = NULL;
- return inputDevice;
+ device->ext = NULL;
+ return input_dev;
}
-static void MousevscOnSendCompletion(struct hv_device *Device, struct vmpacket_descriptor *Packet)
+static void mousevsc_on_send_completion(struct hv_device *device,
+ struct vmpacket_descriptor *packet)
{
- struct mousevsc_dev *inputDevice;
+ struct mousevsc_dev *input_dev;
void *request;
- inputDevice = MustGetInputDevice(Device);
- if (!inputDevice) {
+ input_dev = must_get_input_device(device);
+ if (!input_dev) {
pr_err("unable to get input device...device being destroyed?");
return;
}
- request = (void *)(unsigned long)Packet->trans_id;
+ request = (void *)(unsigned long)packet->trans_id;
- if (request == &inputDevice->ProtocolReq) {
+ if (request == &input_dev->protocol_req) {
/* FIXME */
/* Shouldn't we be doing something here? */
}
- PutInputDevice(Device);
+ put_input_device(device);
}
-static void MousevscOnReceiveDeviceInfo(struct mousevsc_dev *InputDevice, struct synthhid_device_info *DeviceInfo)
+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 */
- InputDevice->DeviceInfoStatus = 0;
+ input_device->dev_info_status = 0;
/* Save the device attr */
- memcpy(&InputDevice->hid_dev_info, &DeviceInfo->hid_dev_info, sizeof(struct hv_input_dev_info));
+ memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
+ sizeof(struct hv_input_dev_info));
/* Save the hid desc */
- desc = &DeviceInfo->hid_descriptor;
+ desc = &device_info->hid_descriptor;
WARN_ON(desc->bLength > 0);
- InputDevice->HidDesc = kzalloc(desc->bLength, GFP_KERNEL);
+ input_device->hid_desc = kzalloc(desc->bLength, GFP_KERNEL);
- if (!InputDevice->HidDesc) {
+ if (!input_device->hid_desc) {
pr_err("unable to allocate hid descriptor - size %d", desc->bLength);
goto Cleanup;
}
- memcpy(InputDevice->HidDesc, desc, desc->bLength);
+ memcpy(input_device->hid_desc, desc, desc->bLength);
/* Save the report desc */
- InputDevice->ReportDescSize = desc->desc[0].wDescriptorLength;
- InputDevice->ReportDesc = kzalloc(InputDevice->ReportDescSize,
+ input_device->report_desc_size = desc->desc[0].wDescriptorLength;
+ input_device->report_desc = kzalloc(input_device->report_desc_size,
GFP_KERNEL);
- if (!InputDevice->ReportDesc) {
+ if (!input_device->report_desc) {
pr_err("unable to allocate report descriptor - size %d",
- InputDevice->ReportDescSize);
+ input_device->report_desc_size);
goto Cleanup;
}
- memcpy(InputDevice->ReportDesc,
+ memcpy(input_device->report_desc,
((unsigned char *)desc) + desc->bLength,
desc->desc[0].wDescriptorLength);
@@ -385,7 +375,7 @@ static void MousevscOnReceiveDeviceInfo(struct mousevsc_dev *InputDevice, struct
ack.ack.header.size = 1;
ack.ack.reserved = 0;
- ret = vmbus_sendpacket(InputDevice->Device->channel,
+ ret = vmbus_sendpacket(input_device->device->channel,
&ack,
sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
sizeof(struct synthhid_device_info_ack),
@@ -398,138 +388,143 @@ static void MousevscOnReceiveDeviceInfo(struct mousevsc_dev *InputDevice, struct
goto Cleanup;
}
- InputDevice->device_wait_condition = 1;
- wake_up(&InputDevice->DeviceInfoWaitEvent);
+ input_device->device_wait_condition = 1;
+ wake_up(&input_device->dev_info_wait_event);
return;
Cleanup:
- kfree(InputDevice->HidDesc);
- InputDevice->HidDesc = NULL;
+ kfree(input_device->hid_desc);
+ input_device->hid_desc = NULL;
- kfree(InputDevice->ReportDesc);
- InputDevice->ReportDesc = NULL;
+ kfree(input_device->report_desc);
+ input_device->report_desc = NULL;
- InputDevice->DeviceInfoStatus = -1;
- InputDevice->device_wait_condition = 1;
- wake_up(&InputDevice->DeviceInfoWaitEvent);
+ input_device->dev_info_status = -1;
+ input_device->device_wait_condition = 1;
+ wake_up(&input_device->dev_info_wait_event);
}
-static void MousevscOnReceiveInputReport(struct mousevsc_dev *InputDevice, struct synthhid_input_report *InputReport)
+static void mousevsc_on_receive_input_report(struct mousevsc_dev *input_device,
+ struct synthhid_input_report *input_report)
{
- struct mousevsc_drv_obj *inputDriver;
+ struct hv_driver *input_drv;
- if (!InputDevice->bInitializeComplete) {
- pr_info("Initialization incomplete...ignoring InputReport msg");
+ if (!input_device->init_complete) {
+ pr_info("Initialization incomplete...ignoring input_report msg");
return;
}
- inputDriver = (struct mousevsc_drv_obj *)InputDevice->Device->drv;
+ input_drv = drv_to_hv_drv(input_device->device->device.driver);
- inputreport_callback(InputDevice->Device,
- InputReport->buffer,
- InputReport->header.size);
+ inputreport_callback(input_device->device,
+ input_report->buffer,
+ input_report->header.size);
}
-static void MousevscOnReceive(struct hv_device *Device, struct vmpacket_descriptor *Packet)
+static void mousevsc_on_receive(struct hv_device *device,
+ struct vmpacket_descriptor *packet)
{
- struct pipe_prt_msg *pipeMsg;
- struct synthhid_msg *hidMsg;
- struct mousevsc_dev *inputDevice;
+ struct pipe_prt_msg *pipe_msg;
+ struct synthhid_msg *hid_msg;
+ struct mousevsc_dev *input_dev;
- inputDevice = MustGetInputDevice(Device);
- if (!inputDevice) {
+ input_dev = must_get_input_device(device);
+ if (!input_dev) {
pr_err("unable to get input device...device being destroyed?");
return;
}
- pipeMsg = (struct pipe_prt_msg *)((unsigned long)Packet + (Packet->offset8 << 3));
+ pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
+ (packet->offset8 << 3));
- if (pipeMsg->type != PipeMessageData) {
+ if (pipe_msg->type != PipeMessageData) {
pr_err("unknown pipe msg type - type %d len %d",
- pipeMsg->type, pipeMsg->size);
- PutInputDevice(Device);
+ pipe_msg->type, pipe_msg->size);
+ put_input_device(device);
return ;
}
- hidMsg = (struct synthhid_msg *)&pipeMsg->data[0];
+ hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
- switch (hidMsg->header.type) {
+ switch (hid_msg->header.type) {
case SynthHidProtocolResponse:
- memcpy(&inputDevice->ProtocolResp, pipeMsg,
- pipeMsg->size + sizeof(struct pipe_prt_msg) -
+ memcpy(&input_dev->protocol_resp, pipe_msg,
+ pipe_msg->size + sizeof(struct pipe_prt_msg) -
sizeof(unsigned char));
- inputDevice->protocol_wait_condition = 1;
- wake_up(&inputDevice->ProtocolWaitEvent);
+ input_dev->protocol_wait_condition = 1;
+ wake_up(&input_dev->protocol_wait_event);
break;
case SynthHidInitialDeviceInfo:
- WARN_ON(pipeMsg->size >= sizeof(struct hv_input_dev_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
*/
- MousevscOnReceiveDeviceInfo(inputDevice,
- (struct synthhid_device_info *)&pipeMsg->data[0]);
+ mousevsc_on_receive_device_info(input_dev,
+ (struct synthhid_device_info *)&pipe_msg->data[0]);
break;
case SynthHidInputReport:
- MousevscOnReceiveInputReport(inputDevice,
- (struct synthhid_input_report *)&pipeMsg->data[0]);
+ mousevsc_on_receive_input_report(input_dev,
+ (struct synthhid_input_report *)&pipe_msg->data[0]);
break;
default:
pr_err("unsupported hid msg type - type %d len %d",
- hidMsg->header.type, hidMsg->header.size);
+ hid_msg->header.type, hid_msg->header.size);
break;
}
- PutInputDevice(Device);
+ put_input_device(device);
}
-static void MousevscOnChannelCallback(void *Context)
+static void mousevsc_on_channel_callback(void *context)
{
const int packetSize = 0x100;
int ret = 0;
- struct hv_device *device = (struct hv_device *)Context;
- struct mousevsc_dev *inputDevice;
+ struct hv_device *device = (struct hv_device *)context;
+ struct mousevsc_dev *input_dev;
- u32 bytesRecvd;
- u64 requestId;
- unsigned char packet[packetSize];
+ u32 bytes_recvd;
+ u64 req_id;
+ unsigned char packet[0x100];
struct vmpacket_descriptor *desc;
unsigned char *buffer = packet;
int bufferlen = packetSize;
- inputDevice = MustGetInputDevice(device);
+ input_dev = must_get_input_device(device);
- if (!inputDevice) {
+ if (!input_dev) {
pr_err("unable to get input device...device being destroyed?");
return;
}
do {
- ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, &bytesRecvd, &requestId);
+ ret = vmbus_recvpacket_raw(device->channel, buffer,
+ bufferlen, &bytes_recvd, &req_id);
if (ret == 0) {
- if (bytesRecvd > 0) {
+ if (bytes_recvd > 0) {
desc = (struct vmpacket_descriptor *)buffer;
switch (desc->type) {
case VM_PKT_COMP:
- MousevscOnSendCompletion(device,
- desc);
+ mousevsc_on_send_completion(
+ device, desc);
break;
case VM_PKT_DATA_INBAND:
- MousevscOnReceive(device, desc);
+ mousevsc_on_receive(
+ device, desc);
break;
default:
pr_err("unhandled packet type %d, tid %llx len %d\n",
desc->type,
- requestId,
- bytesRecvd);
+ req_id,
+ bytes_recvd);
break;
}
@@ -555,8 +550,8 @@ static void MousevscOnChannelCallback(void *Context)
}
} else if (ret == -2) {
/* Handle large packet */
- bufferlen = bytesRecvd;
- buffer = kzalloc(bytesRecvd, GFP_KERNEL);
+ bufferlen = bytes_recvd;
+ buffer = kzalloc(bytes_recvd, GFP_KERNEL);
if (buffer == NULL) {
buffer = packet;
@@ -564,35 +559,35 @@ static void MousevscOnChannelCallback(void *Context)
/* Try again next time around */
pr_err("unable to allocate buffer of size %d!",
- bytesRecvd);
+ bytes_recvd);
break;
}
}
} while (1);
- PutInputDevice(device);
+ put_input_device(device);
return;
}
-static int MousevscConnectToVsp(struct hv_device *Device)
+static int mousevsc_connect_to_vsp(struct hv_device *device)
{
int ret = 0;
- struct mousevsc_dev *inputDevice;
+ struct mousevsc_dev *input_dev;
struct mousevsc_prt_msg *request;
struct mousevsc_prt_msg *response;
- inputDevice = GetInputDevice(Device);
+ input_dev = get_input_device(device);
- if (!inputDevice) {
+ if (!input_dev) {
pr_err("unable to get input device...device being destroyed?");
return -1;
}
- init_waitqueue_head(&inputDevice->ProtocolWaitEvent);
- init_waitqueue_head(&inputDevice->DeviceInfoWaitEvent);
+ init_waitqueue_head(&input_dev->protocol_wait_event);
+ init_waitqueue_head(&input_dev->dev_info_wait_event);
- request = &inputDevice->ProtocolReq;
+ request = &input_dev->protocol_req;
/*
* Now, initiate the vsc/vsp initialization protocol on the open channel
@@ -608,7 +603,7 @@ static int MousevscConnectToVsp(struct hv_device *Device)
pr_info("synthhid protocol request...");
- ret = vmbus_sendpacket(Device->channel, request,
+ ret = vmbus_sendpacket(device->channel, request,
sizeof(struct pipe_prt_msg) -
sizeof(unsigned char) +
sizeof(struct synthhid_protocol_request),
@@ -620,14 +615,15 @@ static int MousevscConnectToVsp(struct hv_device *Device)
goto Cleanup;
}
- inputDevice->protocol_wait_condition = 0;
- wait_event_timeout(inputDevice->ProtocolWaitEvent, inputDevice->protocol_wait_condition, msecs_to_jiffies(1000));
- if (inputDevice->protocol_wait_condition == 0) {
+ input_dev->protocol_wait_condition = 0;
+ wait_event_timeout(input_dev->protocol_wait_event,
+ input_dev->protocol_wait_condition, msecs_to_jiffies(1000));
+ if (input_dev->protocol_wait_condition == 0) {
ret = -ETIMEDOUT;
goto Cleanup;
}
- response = &inputDevice->ProtocolResp;
+ response = &input_dev->protocol_resp;
if (!response->response.approved) {
pr_err("synthhid protocol request failed (version %d)",
@@ -636,9 +632,10 @@ static int MousevscConnectToVsp(struct hv_device *Device)
goto Cleanup;
}
- inputDevice->device_wait_condition = 0;
- wait_event_timeout(inputDevice->DeviceInfoWaitEvent, inputDevice->device_wait_condition, msecs_to_jiffies(1000));
- if (inputDevice->device_wait_condition == 0) {
+ input_dev->device_wait_condition = 0;
+ wait_event_timeout(input_dev->dev_info_wait_event,
+ input_dev->device_wait_condition, msecs_to_jiffies(1000));
+ if (input_dev->device_wait_condition == 0) {
ret = -ETIMEDOUT;
goto Cleanup;
}
@@ -647,94 +644,95 @@ static int MousevscConnectToVsp(struct hv_device *Device)
* We should have gotten the device attr, hid desc and report
* desc at this point
*/
- if (!inputDevice->DeviceInfoStatus)
+ if (!input_dev->dev_info_status)
pr_info("**** input channel up and running!! ****");
else
ret = -1;
Cleanup:
- PutInputDevice(Device);
+ put_input_device(device);
return ret;
}
-static int MousevscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
+static int mousevsc_on_device_add(struct hv_device *device,
+ void *additional_info)
{
int ret = 0;
- struct mousevsc_dev *inputDevice;
- struct mousevsc_drv_obj *inputDriver;
+ struct mousevsc_dev *input_dev;
+ struct hv_driver *input_drv;
struct hv_input_dev_info dev_info;
- inputDevice = AllocInputDevice(Device);
+ input_dev = alloc_input_device(device);
- if (!inputDevice) {
+ if (!input_dev) {
ret = -1;
goto Cleanup;
}
- inputDevice->bInitializeComplete = false;
+ input_dev->init_complete = false;
/* Open the channel */
- ret = vmbus_open(Device->channel,
+ ret = vmbus_open(device->channel,
INPUTVSC_SEND_RING_BUFFER_SIZE,
INPUTVSC_RECV_RING_BUFFER_SIZE,
NULL,
0,
- MousevscOnChannelCallback,
- Device
+ mousevsc_on_channel_callback,
+ device
);
if (ret != 0) {
pr_err("unable to open channel: %d", ret);
- FreeInputDevice(inputDevice);
+ free_input_device(input_dev);
return -1;
}
pr_info("InputVsc channel open: %d", ret);
- ret = MousevscConnectToVsp(Device);
+ ret = mousevsc_connect_to_vsp(device);
if (ret != 0) {
pr_err("unable to connect channel: %d", ret);
- vmbus_close(Device->channel);
- FreeInputDevice(inputDevice);
+ vmbus_close(device->channel);
+ free_input_device(input_dev);
return ret;
}
- inputDriver = (struct mousevsc_drv_obj *)inputDevice->Device->drv;
+ input_drv = drv_to_hv_drv(input_dev->device->device.driver);
- dev_info.vendor = inputDevice->hid_dev_info.vendor;
- dev_info.product = inputDevice->hid_dev_info.product;
- dev_info.version = inputDevice->hid_dev_info.version;
+ dev_info.vendor = input_dev->hid_dev_info.vendor;
+ dev_info.product = input_dev->hid_dev_info.product;
+ dev_info.version = input_dev->hid_dev_info.version;
strcpy(dev_info.name, "Microsoft Vmbus HID-compliant Mouse");
/* Send the device info back up */
- deviceinfo_callback(Device, &dev_info);
+ deviceinfo_callback(device, &dev_info);
/* Send the report desc back up */
/* workaround SA-167 */
- if (inputDevice->ReportDesc[14] == 0x25)
- inputDevice->ReportDesc[14] = 0x29;
+ if (input_dev->report_desc[14] == 0x25)
+ input_dev->report_desc[14] = 0x29;
- reportdesc_callback(Device, inputDevice->ReportDesc,
- inputDevice->ReportDescSize);
+ reportdesc_callback(device, input_dev->report_desc,
+ input_dev->report_desc_size);
- inputDevice->bInitializeComplete = true;
+ input_dev->init_complete = true;
Cleanup:
return ret;
}
-static int MousevscOnDeviceRemove(struct hv_device *Device)
+static int mousevsc_on_device_remove(struct hv_device *device)
{
- struct mousevsc_dev *inputDevice;
+ struct mousevsc_dev *input_dev;
int ret = 0;
pr_info("disabling input device (%p)...",
- Device->ext);
+ device->ext);
- inputDevice = ReleaseInputDevice(Device);
+ input_dev = release_input_device(device);
/*
@@ -743,29 +741,27 @@ static int MousevscOnDeviceRemove(struct hv_device *Device)
*
* so that outstanding requests can be completed.
*/
- while (inputDevice->NumOutstandingRequests) {
- pr_info("waiting for %d requests to complete...", inputDevice->NumOutstandingRequests);
+ while (input_dev->num_outstanding_req) {
+ pr_info("waiting for %d requests to complete...",
+ input_dev->num_outstanding_req);
udelay(100);
}
- pr_info("removing input device (%p)...", Device->ext);
+ pr_info("removing input device (%p)...", device->ext);
- inputDevice = FinalReleaseInputDevice(Device);
+ input_dev = final_release_input_device(device);
- pr_info("input device (%p) safe to remove", inputDevice);
+ pr_info("input device (%p) safe to remove", input_dev);
/* Close the channel */
- vmbus_close(Device->channel);
+ vmbus_close(device->channel);
- FreeInputDevice(inputDevice);
+ free_input_device(input_dev);
return ret;
}
-static void MousevscOnCleanup(struct hv_driver *drv)
-{
-}
/*
* Data types
@@ -778,8 +774,6 @@ struct input_device_context {
};
-static struct mousevsc_drv_obj g_mousevsc_drv;
-
static void deviceinfo_callback(struct hv_device *dev, struct hv_input_dev_info *info)
{
struct input_device_context *input_device_ctx =
@@ -813,24 +807,19 @@ static void mousevsc_hid_close(struct hid_device *hid)
{
}
-static int mousevsc_probe(struct device *device)
+static int mousevsc_probe(struct hv_device *dev)
{
int ret = 0;
- struct hv_driver *drv =
- drv_to_hv_drv(device->driver);
- struct mousevsc_drv_obj *mousevsc_drv_obj = drv->priv;
-
- struct hv_device *device_obj = device_to_hv_device(device);
struct input_device_context *input_dev_ctx;
input_dev_ctx = kmalloc(sizeof(struct input_device_context),
GFP_KERNEL);
- dev_set_drvdata(device, input_dev_ctx);
+ dev_set_drvdata(&dev->device, input_dev_ctx);
/* Call to the vsc driver to add the device */
- ret = mousevsc_drv_obj->Base.dev_add(device_obj, NULL);
+ ret = mousevsc_on_device_add(dev, NULL);
if (ret != 0) {
DPRINT_ERR(INPUTVSC_DRV, "unable to add input vsc device");
@@ -841,35 +830,27 @@ static int mousevsc_probe(struct device *device)
return 0;
}
-static int mousevsc_remove(struct device *device)
+static int mousevsc_remove(struct hv_device *dev)
{
int ret = 0;
- struct hv_driver *drv =
- drv_to_hv_drv(device->driver);
- struct mousevsc_drv_obj *mousevsc_drv_obj = drv->priv;
-
- struct hv_device *device_obj = device_to_hv_device(device);
struct input_device_context *input_dev_ctx;
input_dev_ctx = kmalloc(sizeof(struct input_device_context),
GFP_KERNEL);
- dev_set_drvdata(device, input_dev_ctx);
+ dev_set_drvdata(&dev->device, input_dev_ctx);
if (input_dev_ctx->connected) {
hidinput_disconnect(input_dev_ctx->hid_device);
input_dev_ctx->connected = 0;
}
- if (!mousevsc_drv_obj->Base.dev_rm)
- return -1;
-
/*
* Call to the vsc driver to let it know that the device
* is being removed
*/
- ret = mousevsc_drv_obj->Base.dev_rm(device_obj);
+ ret = mousevsc_on_device_remove(dev);
if (ret != 0) {
DPRINT_ERR(INPUTVSC_DRV,
@@ -934,81 +915,28 @@ static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
kfree(hid_dev);
}
-static int mousevsc_drv_exit_cb(struct device *dev, void *data)
-{
- struct device **curr = (struct device **)data;
- *curr = dev;
- return 1;
-}
+static struct hv_driver mousevsc_drv = {
+ .probe = mousevsc_probe,
+ .remove = mousevsc_remove,
+};
static void mousevsc_drv_exit(void)
{
- struct mousevsc_drv_obj *mousevsc_drv_obj = &g_mousevsc_drv;
- struct hv_driver *drv = &g_mousevsc_drv.Base;
- int ret;
-
- struct device *current_dev = NULL;
-
- while (1) {
- current_dev = NULL;
-
- /* Get the device */
- ret = driver_for_each_device(&drv->driver, NULL,
- (void *)&current_dev,
- mousevsc_drv_exit_cb);
- if (ret)
- printk(KERN_ERR "Can't find mouse device!\n");
-
- if (current_dev == NULL)
- break;
-
- /* Initiate removal from the top-down */
- device_unregister(current_dev);
- }
-
- if (mousevsc_drv_obj->Base.cleanup)
- mousevsc_drv_obj->Base.cleanup(&mousevsc_drv_obj->Base);
-
- vmbus_child_driver_unregister(&drv->driver);
-
- return;
+ vmbus_child_driver_unregister(&mousevsc_drv.driver);
}
-static int mouse_vsc_initialize(struct hv_driver *Driver)
-{
- struct mousevsc_drv_obj *inputDriver =
- (struct mousevsc_drv_obj *)Driver;
- int ret = 0;
-
- Driver->name = driver_name;
- memcpy(&Driver->dev_type, &mouse_guid,
- sizeof(struct hv_guid));
-
- /* Setup the dispatch table */
- inputDriver->Base.dev_add = MousevscOnDeviceAdd;
- inputDriver->Base.dev_rm = MousevscOnDeviceRemove;
- inputDriver->Base.cleanup = MousevscOnCleanup;
-
- return ret;
-}
-
-
static int __init mousevsc_init(void)
{
- struct mousevsc_drv_obj *input_drv_obj = &g_mousevsc_drv;
- struct hv_driver *drv = &g_mousevsc_drv.Base;
+ struct hv_driver *drv = &mousevsc_drv;
DPRINT_INFO(INPUTVSC_DRV, "Hyper-V Mouse driver initializing.");
- /* Callback to client driver to complete the initialization */
- mouse_vsc_initialize(&input_drv_obj->Base);
-
- drv->driver.name = input_drv_obj->Base.name;
- drv->priv = input_drv_obj;
+ memcpy(&drv->dev_type, &mouse_guid,
+ sizeof(struct hv_guid));
- drv->driver.probe = mousevsc_probe;
- drv->driver.remove = mousevsc_remove;
+ drv->driver.name = driver_name;
+ drv->name = driver_name;
/* The driver belongs to vmbus */
vmbus_child_driver_register(&drv->driver);
diff --git a/drivers/staging/hv/hv_timesource.c b/drivers/staging/hv/hv_timesource.c
index a7ee533303b4..0efb04915255 100644
--- a/drivers/staging/hv/hv_timesource.c
+++ b/drivers/staging/hv/hv_timesource.c
@@ -20,6 +20,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/version.h>
#include <linux/clocksource.h>
@@ -91,7 +92,7 @@ static int __init init_hv_clocksource(void)
if (!dmi_check_system(hv_timesource_dmi_table))
return -ENODEV;
- printk(KERN_INFO "Registering HyperV clock source\n");
+ pr_info("Registering HyperV clock source\n");
return clocksource_register(&hyperv_cs);
}
diff --git a/drivers/staging/hv/hv_util.c b/drivers/staging/hv/hv_util.c
index 2df15683f8fa..c164b54b4cd7 100644
--- a/drivers/staging/hv/hv_util.c
+++ b/drivers/staging/hv/hv_util.c
@@ -18,6 +18,8 @@
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -27,16 +29,7 @@
#include <linux/dmi.h>
#include <linux/pci.h>
-#include "logging.h"
-#include "hv_api.h"
-#include "vmbus.h"
-#include "vmbus_packet_format.h"
-#include "vmbus_channel_interface.h"
-#include "version_info.h"
-#include "channel.h"
-#include "vmbus_private.h"
-#include "vmbus_api.h"
-#include "utils.h"
+#include "hyperv.h"
#include "hv_kvp.h"
static u8 *shut_txf_buf;
@@ -59,9 +52,6 @@ static void shutdown_onchannelcallback(void *context)
PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
- DPRINT_DBG(VMBUS, "shutdown packet: len=%d, requestid=%lld",
- recvlen, requestid);
-
icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
sizeof(struct vmbuspipe_hdr)];
@@ -79,17 +69,17 @@ static void shutdown_onchannelcallback(void *context)
icmsghdrp->status = HV_S_OK;
execute_shutdown = true;
- DPRINT_INFO(VMBUS, "Shutdown request received -"
- " graceful shutdown initiated");
+ pr_info("Shutdown request received -"
+ " graceful shutdown initiated\n");
break;
default:
icmsghdrp->status = HV_E_FAIL;
execute_shutdown = false;
- DPRINT_INFO(VMBUS, "Shutdown request received -"
- " Invalid request");
+ pr_info("Shutdown request received -"
+ " Invalid request\n");
break;
- };
+ }
}
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
@@ -159,9 +149,6 @@ static void timesync_onchannelcallback(void *context)
PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
- DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld",
- recvlen, requestid);
-
icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr)];
@@ -200,9 +187,6 @@ static void heartbeat_onchannelcallback(void *context)
PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
- DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld",
- recvlen, requestid);
-
icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
sizeof(struct vmbuspipe_hdr)];
@@ -214,9 +198,6 @@ static void heartbeat_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
- DPRINT_DBG(VMBUS, "heartbeat seq = %lld",
- heartbeat_msg->seq_num);
-
heartbeat_msg->seq_num += 1;
}
@@ -254,7 +235,7 @@ MODULE_DEVICE_TABLE(dmi, hv_utils_dmi_table);
static int __init init_hyperv_utils(void)
{
- printk(KERN_INFO "Registering HyperV Utility Driver\n");
+ pr_info("Registering HyperV Utility Driver\n");
if (hv_kvp_init())
return -ENODEV;
@@ -268,52 +249,48 @@ static int __init init_hyperv_utils(void)
hbeat_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!shut_txf_buf || !time_txf_buf || !hbeat_txf_buf) {
- printk(KERN_INFO
- "Unable to allocate memory for receive buffer\n");
+ pr_info("Unable to allocate memory for receive buffer\n");
kfree(shut_txf_buf);
kfree(time_txf_buf);
kfree(hbeat_txf_buf);
return -ENOMEM;
}
- hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
- &shutdown_onchannelcallback;
hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback;
- hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback =
- &timesync_onchannelcallback;
hv_cb_utils[HV_TIMESYNC_MSG].callback = &timesync_onchannelcallback;
- hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
- &heartbeat_onchannelcallback;
hv_cb_utils[HV_HEARTBEAT_MSG].callback = &heartbeat_onchannelcallback;
- hv_cb_utils[HV_KVP_MSG].channel->onchannel_callback =
- &hv_kvp_onchannelcallback;
-
-
+ hv_cb_utils[HV_KVP_MSG].callback = &hv_kvp_onchannelcallback;
return 0;
}
static void exit_hyperv_utils(void)
{
- printk(KERN_INFO "De-Registered HyperV Utility Driver\n");
+ pr_info("De-Registered HyperV Utility Driver\n");
+
+ if (hv_cb_utils[HV_SHUTDOWN_MSG].channel != NULL)
+ hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_SHUTDOWN_MSG].callback = NULL;
- hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_SHUTDOWN_MSG].callback = &chn_cb_negotiate;
+ if (hv_cb_utils[HV_TIMESYNC_MSG].channel != NULL)
+ hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_TIMESYNC_MSG].callback = NULL;
- hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_TIMESYNC_MSG].callback = &chn_cb_negotiate;
+ if (hv_cb_utils[HV_HEARTBEAT_MSG].channel != NULL)
+ hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_HEARTBEAT_MSG].callback = NULL;
- hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate;
+ if (hv_cb_utils[HV_KVP_MSG].channel != NULL)
+ hv_cb_utils[HV_KVP_MSG].channel->onchannel_callback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_KVP_MSG].callback = NULL;
- hv_cb_utils[HV_KVP_MSG].channel->onchannel_callback =
- &chn_cb_negotiate;
hv_kvp_deinit();
kfree(shut_txf_buf);
diff --git a/drivers/staging/hv/hyperv.h b/drivers/staging/hv/hyperv.h
new file mode 100644
index 000000000000..3310e9bdf562
--- /dev/null
+++ b/drivers/staging/hv/hyperv.h
@@ -0,0 +1,944 @@
+/*
+ *
+ * Copyright (c) 2011, Microsoft Corporation.
+ *
+ * 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.
+ *
+ * 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
+ *
+ */
+
+#ifndef _HYPERV_H
+#define _HYPERV_H
+
+#include <linux/scatterlist.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+
+
+#include <asm/hyperv.h>
+
+struct hv_guid {
+ unsigned char data[16];
+};
+
+#define MAX_PAGE_BUFFER_COUNT 16
+#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
+
+#pragma pack(push, 1)
+
+/* Single-page buffer */
+struct hv_page_buffer {
+ u32 len;
+ u32 offset;
+ u64 pfn;
+};
+
+/* Multiple-page buffer */
+struct hv_multipage_buffer {
+ /* Length and Offset determines the # of pfns in the array */
+ u32 len;
+ u32 offset;
+ u64 pfn_array[MAX_MULTIPAGE_BUFFER_COUNT];
+};
+
+/* 0x18 includes the proprietary packet header */
+#define MAX_PAGE_BUFFER_PACKET (0x18 + \
+ (sizeof(struct hv_page_buffer) * \
+ MAX_PAGE_BUFFER_COUNT))
+#define MAX_MULTIPAGE_BUFFER_PACKET (0x18 + \
+ sizeof(struct hv_multipage_buffer))
+
+
+#pragma pack(pop)
+
+struct hv_ring_buffer {
+ /* Offset in bytes from the start of ring data below */
+ u32 write_index;
+
+ /* Offset in bytes from the start of ring data below */
+ u32 read_index;
+
+ u32 interrupt_mask;
+
+ /* Pad it to PAGE_SIZE so that data starts on page boundary */
+ u8 reserved[4084];
+
+ /* NOTE:
+ * The interrupt_mask field is used only for channels but since our
+ * vmbus connection also uses this data structure and its data starts
+ * here, we commented out this field.
+ */
+
+ /*
+ * Ring data starts here + RingDataStartOffset
+ * !!! DO NOT place any fields below this !!!
+ */
+ u8 buffer[0];
+} __packed;
+
+struct hv_ring_buffer_info {
+ struct hv_ring_buffer *ring_buffer;
+ u32 ring_size; /* Include the shared header */
+ spinlock_t ring_lock;
+
+ u32 ring_datasize; /* < ring_size */
+ u32 ring_data_startoffset;
+};
+
+struct hv_ring_buffer_debug_info {
+ u32 current_interrupt_mask;
+ u32 current_read_index;
+ u32 current_write_index;
+ u32 bytes_avail_toread;
+ u32 bytes_avail_towrite;
+};
+
+/*
+ * We use the same version numbering for all Hyper-V modules.
+ *
+ * Definition of versioning is as follows;
+ *
+ * Major Number Changes for these scenarios;
+ * 1. When a new version of Windows Hyper-V
+ * is released.
+ * 2. A Major change has occurred in the
+ * Linux IC's.
+ * (For example the merge for the first time
+ * into the kernel) Every time the Major Number
+ * changes, the Revision number is reset to 0.
+ * Minor Number Changes when new functionality is added
+ * to the Linux IC's that is not a bug fix.
+ *
+ * 3.1 - Added completed hv_utils driver. Shutdown/Heartbeat/Timesync
+ */
+#define HV_DRV_VERSION "3.1"
+
+
+/*
+ * A revision number of vmbus that is used for ensuring both ends on a
+ * partition are using compatible versions.
+ */
+#define VMBUS_REVISION_NUMBER 13
+
+/* Make maximum size of pipe payload of 16K */
+#define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)
+
+/* Define PipeMode values. */
+#define VMBUS_PIPE_TYPE_BYTE 0x00000000
+#define VMBUS_PIPE_TYPE_MESSAGE 0x00000004
+
+/* The size of the user defined data buffer for non-pipe offers. */
+#define MAX_USER_DEFINED_BYTES 120
+
+/* The size of the user defined data buffer for pipe offers. */
+#define MAX_PIPE_USER_DEFINED_BYTES 116
+
+/*
+ * At the center of the Channel Management library is the Channel Offer. This
+ * struct contains the fundamental information about an offer.
+ */
+struct vmbus_channel_offer {
+ struct hv_guid if_type;
+ struct hv_guid if_instance;
+ u64 int_latency; /* in 100ns units */
+ u32 if_revision;
+ u32 server_ctx_size; /* in bytes */
+ u16 chn_flags;
+ u16 mmio_megabytes; /* in bytes * 1024 * 1024 */
+
+ union {
+ /* Non-pipes: The user has MAX_USER_DEFINED_BYTES bytes. */
+ struct {
+ unsigned char user_def[MAX_USER_DEFINED_BYTES];
+ } std;
+
+ /*
+ * Pipes:
+ * The following sructure is an integrated pipe protocol, which
+ * is implemented on top of standard user-defined data. Pipe
+ * clients have MAX_PIPE_USER_DEFINED_BYTES left for their own
+ * use.
+ */
+ struct {
+ u32 pipe_mode;
+ unsigned char user_def[MAX_PIPE_USER_DEFINED_BYTES];
+ } pipe;
+ } u;
+ u32 padding;
+} __packed;
+
+/* Server Flags */
+#define VMBUS_CHANNEL_ENUMERATE_DEVICE_INTERFACE 1
+#define VMBUS_CHANNEL_SERVER_SUPPORTS_TRANSFER_PAGES 2
+#define VMBUS_CHANNEL_SERVER_SUPPORTS_GPADLS 4
+#define VMBUS_CHANNEL_NAMED_PIPE_MODE 0x10
+#define VMBUS_CHANNEL_LOOPBACK_OFFER 0x100
+#define VMBUS_CHANNEL_PARENT_OFFER 0x200
+#define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION 0x400
+
+struct vmpacket_descriptor {
+ u16 type;
+ u16 offset8;
+ u16 len8;
+ u16 flags;
+ u64 trans_id;
+} __packed;
+
+struct vmpacket_header {
+ u32 prev_pkt_start_offset;
+ struct vmpacket_descriptor descriptor;
+} __packed;
+
+struct vmtransfer_page_range {
+ u32 byte_count;
+ u32 byte_offset;
+} __packed;
+
+struct vmtransfer_page_packet_header {
+ struct vmpacket_descriptor d;
+ u16 xfer_pageset_id;
+ bool sender_owns_set;
+ u8 reserved;
+ u32 range_cnt;
+ struct vmtransfer_page_range ranges[1];
+} __packed;
+
+struct vmgpadl_packet_header {
+ struct vmpacket_descriptor d;
+ u32 gpadl;
+ u32 reserved;
+} __packed;
+
+struct vmadd_remove_transfer_page_set {
+ struct vmpacket_descriptor d;
+ u32 gpadl;
+ u16 xfer_pageset_id;
+ u16 reserved;
+} __packed;
+
+/*
+ * This structure defines a range in guest physical space that can be made to
+ * look virtually contiguous.
+ */
+struct gpa_range {
+ u32 byte_count;
+ u32 byte_offset;
+ u64 pfn_array[0];
+};
+
+/*
+ * This is the format for an Establish Gpadl packet, which contains a handle by
+ * which this GPADL will be known and a set of GPA ranges associated with it.
+ * This can be converted to a MDL by the guest OS. If there are multiple GPA
+ * ranges, then the resulting MDL will be "chained," representing multiple VA
+ * ranges.
+ */
+struct vmestablish_gpadl {
+ struct vmpacket_descriptor d;
+ u32 gpadl;
+ u32 range_cnt;
+ struct gpa_range range[1];
+} __packed;
+
+/*
+ * This is the format for a Teardown Gpadl packet, which indicates that the
+ * GPADL handle in the Establish Gpadl packet will never be referenced again.
+ */
+struct vmteardown_gpadl {
+ struct vmpacket_descriptor d;
+ u32 gpadl;
+ u32 reserved; /* for alignment to a 8-byte boundary */
+} __packed;
+
+/*
+ * This is the format for a GPA-Direct packet, which contains a set of GPA
+ * ranges, in addition to commands and/or data.
+ */
+struct vmdata_gpa_direct {
+ struct vmpacket_descriptor d;
+ u32 reserved;
+ u32 range_cnt;
+ struct gpa_range range[1];
+} __packed;
+
+/* This is the format for a Additional Data Packet. */
+struct vmadditional_data {
+ struct vmpacket_descriptor d;
+ u64 total_bytes;
+ u32 offset;
+ u32 byte_cnt;
+ unsigned char data[1];
+} __packed;
+
+union vmpacket_largest_possible_header {
+ struct vmpacket_descriptor simple_hdr;
+ struct vmtransfer_page_packet_header xfer_page_hdr;
+ struct vmgpadl_packet_header gpadl_hdr;
+ struct vmadd_remove_transfer_page_set add_rm_xfer_page_hdr;
+ struct vmestablish_gpadl establish_gpadl_hdr;
+ struct vmteardown_gpadl teardown_gpadl_hdr;
+ struct vmdata_gpa_direct data_gpa_direct_hdr;
+};
+
+#define VMPACKET_DATA_START_ADDRESS(__packet) \
+ (void *)(((unsigned char *)__packet) + \
+ ((struct vmpacket_descriptor)__packet)->offset8 * 8)
+
+#define VMPACKET_DATA_LENGTH(__packet) \
+ ((((struct vmpacket_descriptor)__packet)->len8 - \
+ ((struct vmpacket_descriptor)__packet)->offset8) * 8)
+
+#define VMPACKET_TRANSFER_MODE(__packet) \
+ (((struct IMPACT)__packet)->type)
+
+enum vmbus_packet_type {
+ VM_PKT_INVALID = 0x0,
+ VM_PKT_SYNCH = 0x1,
+ VM_PKT_ADD_XFER_PAGESET = 0x2,
+ VM_PKT_RM_XFER_PAGESET = 0x3,
+ VM_PKT_ESTABLISH_GPADL = 0x4,
+ VM_PKT_TEARDOWN_GPADL = 0x5,
+ VM_PKT_DATA_INBAND = 0x6,
+ VM_PKT_DATA_USING_XFER_PAGES = 0x7,
+ VM_PKT_DATA_USING_GPADL = 0x8,
+ VM_PKT_DATA_USING_GPA_DIRECT = 0x9,
+ VM_PKT_CANCEL_REQUEST = 0xa,
+ VM_PKT_COMP = 0xb,
+ VM_PKT_DATA_USING_ADDITIONAL_PKT = 0xc,
+ VM_PKT_ADDITIONAL_DATA = 0xd
+};
+
+#define VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED 1
+
+
+/* Version 1 messages */
+enum vmbus_channel_message_type {
+ CHANNELMSG_INVALID = 0,
+ CHANNELMSG_OFFERCHANNEL = 1,
+ CHANNELMSG_RESCIND_CHANNELOFFER = 2,
+ CHANNELMSG_REQUESTOFFERS = 3,
+ CHANNELMSG_ALLOFFERS_DELIVERED = 4,
+ CHANNELMSG_OPENCHANNEL = 5,
+ CHANNELMSG_OPENCHANNEL_RESULT = 6,
+ CHANNELMSG_CLOSECHANNEL = 7,
+ CHANNELMSG_GPADL_HEADER = 8,
+ CHANNELMSG_GPADL_BODY = 9,
+ CHANNELMSG_GPADL_CREATED = 10,
+ CHANNELMSG_GPADL_TEARDOWN = 11,
+ CHANNELMSG_GPADL_TORNDOWN = 12,
+ CHANNELMSG_RELID_RELEASED = 13,
+ CHANNELMSG_INITIATE_CONTACT = 14,
+ CHANNELMSG_VERSION_RESPONSE = 15,
+ CHANNELMSG_UNLOAD = 16,
+#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
+ CHANNELMSG_VIEWRANGE_ADD = 17,
+ CHANNELMSG_VIEWRANGE_REMOVE = 18,
+#endif
+ CHANNELMSG_COUNT
+};
+
+struct vmbus_channel_message_header {
+ enum vmbus_channel_message_type msgtype;
+ u32 padding;
+} __packed;
+
+/* Query VMBus Version parameters */
+struct vmbus_channel_query_vmbus_version {
+ struct vmbus_channel_message_header header;
+ u32 version;
+} __packed;
+
+/* VMBus Version Supported parameters */
+struct vmbus_channel_version_supported {
+ struct vmbus_channel_message_header header;
+ bool version_supported;
+} __packed;
+
+/* Offer Channel parameters */
+struct vmbus_channel_offer_channel {
+ struct vmbus_channel_message_header header;
+ struct vmbus_channel_offer offer;
+ u32 child_relid;
+ u8 monitorid;
+ bool monitor_allocated;
+} __packed;
+
+/* Rescind Offer parameters */
+struct vmbus_channel_rescind_offer {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+} __packed;
+
+/*
+ * Request Offer -- no parameters, SynIC message contains the partition ID
+ * Set Snoop -- no parameters, SynIC message contains the partition ID
+ * Clear Snoop -- no parameters, SynIC message contains the partition ID
+ * All Offers Delivered -- no parameters, SynIC message contains the partition
+ * ID
+ * Flush Client -- no parameters, SynIC message contains the partition ID
+ */
+
+/* Open Channel parameters */
+struct vmbus_channel_open_channel {
+ struct vmbus_channel_message_header header;
+
+ /* Identifies the specific VMBus channel that is being opened. */
+ u32 child_relid;
+
+ /* ID making a particular open request at a channel offer unique. */
+ u32 openid;
+
+ /* GPADL for the channel's ring buffer. */
+ u32 ringbuffer_gpadlhandle;
+
+ /* GPADL for the channel's server context save area. */
+ u32 server_contextarea_gpadlhandle;
+
+ /*
+ * The upstream ring buffer begins at offset zero in the memory
+ * described by RingBufferGpadlHandle. The downstream ring buffer
+ * follows it at this offset (in pages).
+ */
+ u32 downstream_ringbuffer_pageoffset;
+
+ /* User-specific data to be passed along to the server endpoint. */
+ unsigned char userdata[MAX_USER_DEFINED_BYTES];
+} __packed;
+
+/* Open Channel Result parameters */
+struct vmbus_channel_open_result {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 openid;
+ u32 status;
+} __packed;
+
+/* Close channel parameters; */
+struct vmbus_channel_close_channel {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+} __packed;
+
+/* Channel Message GPADL */
+#define GPADL_TYPE_RING_BUFFER 1
+#define GPADL_TYPE_SERVER_SAVE_AREA 2
+#define GPADL_TYPE_TRANSACTION 8
+
+/*
+ * The number of PFNs in a GPADL message is defined by the number of
+ * pages that would be spanned by ByteCount and ByteOffset. If the
+ * implied number of PFNs won't fit in this packet, there will be a
+ * follow-up packet that contains more.
+ */
+struct vmbus_channel_gpadl_header {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 gpadl;
+ u16 range_buflen;
+ u16 rangecount;
+ struct gpa_range range[0];
+} __packed;
+
+/* This is the followup packet that contains more PFNs. */
+struct vmbus_channel_gpadl_body {
+ struct vmbus_channel_message_header header;
+ u32 msgnumber;
+ u32 gpadl;
+ u64 pfn[0];
+} __packed;
+
+struct vmbus_channel_gpadl_created {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 gpadl;
+ u32 creation_status;
+} __packed;
+
+struct vmbus_channel_gpadl_teardown {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 gpadl;
+} __packed;
+
+struct vmbus_channel_gpadl_torndown {
+ struct vmbus_channel_message_header header;
+ u32 gpadl;
+} __packed;
+
+#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
+struct vmbus_channel_view_range_add {
+ struct vmbus_channel_message_header header;
+ PHYSICAL_ADDRESS viewrange_base;
+ u64 viewrange_length;
+ u32 child_relid;
+} __packed;
+
+struct vmbus_channel_view_range_remove {
+ struct vmbus_channel_message_header header;
+ PHYSICAL_ADDRESS viewrange_base;
+ u32 child_relid;
+} __packed;
+#endif
+
+struct vmbus_channel_relid_released {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+} __packed;
+
+struct vmbus_channel_initiate_contact {
+ struct vmbus_channel_message_header header;
+ u32 vmbus_version_requested;
+ u32 padding2;
+ u64 interrupt_page;
+ u64 monitor_page1;
+ u64 monitor_page2;
+} __packed;
+
+struct vmbus_channel_version_response {
+ struct vmbus_channel_message_header header;
+ bool version_supported;
+} __packed;
+
+enum vmbus_channel_state {
+ CHANNEL_OFFER_STATE,
+ CHANNEL_OPENING_STATE,
+ CHANNEL_OPEN_STATE,
+};
+
+struct vmbus_channel {
+ struct list_head listentry;
+
+ struct hv_device *device_obj;
+
+ struct timer_list poll_timer; /* SA-111 workaround */
+ struct work_struct work;
+
+ enum vmbus_channel_state state;
+ /*
+ * For util channels, stash the
+ * the service index for easy access.
+ */
+ s8 util_index;
+
+ struct vmbus_channel_offer_channel offermsg;
+ /*
+ * These are based on the OfferMsg.MonitorId.
+ * Save it here for easy access.
+ */
+ u8 monitor_grp;
+ u8 monitor_bit;
+
+ u32 ringbuffer_gpadlhandle;
+
+ /* Allocated memory for ring buffer */
+ void *ringbuffer_pages;
+ u32 ringbuffer_pagecount;
+ struct hv_ring_buffer_info outbound; /* send to parent */
+ struct hv_ring_buffer_info inbound; /* receive from parent */
+ spinlock_t inbound_lock;
+ struct workqueue_struct *controlwq;
+
+ /* Channel callback are invoked in this workqueue context */
+ /* HANDLE dataWorkQueue; */
+
+ void (*onchannel_callback)(void *context);
+ void *channel_callback_context;
+};
+
+struct vmbus_channel_debug_info {
+ u32 relid;
+ enum vmbus_channel_state state;
+ struct hv_guid interfacetype;
+ struct hv_guid interface_instance;
+ u32 monitorid;
+ u32 servermonitor_pending;
+ u32 servermonitor_latency;
+ u32 servermonitor_connectionid;
+ u32 clientmonitor_pending;
+ u32 clientmonitor_latency;
+ u32 clientmonitor_connectionid;
+
+ struct hv_ring_buffer_debug_info inbound;
+ struct hv_ring_buffer_debug_info outbound;
+};
+
+/*
+ * Represents each channel msg on the vmbus connection This is a
+ * variable-size data structure depending on the msg type itself
+ */
+struct vmbus_channel_msginfo {
+ /* Bookkeeping stuff */
+ struct list_head msglistentry;
+
+ /* So far, this is only used to handle gpadl body message */
+ struct list_head submsglist;
+
+ /* Synchronize the request/response if needed */
+ struct completion waitevent;
+ union {
+ struct vmbus_channel_version_supported version_supported;
+ struct vmbus_channel_open_result open_result;
+ struct vmbus_channel_gpadl_torndown gpadl_torndown;
+ struct vmbus_channel_gpadl_created gpadl_created;
+ struct vmbus_channel_version_response version_response;
+ } response;
+
+ u32 msgsize;
+ /*
+ * The channel message that goes out on the "wire".
+ * It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
+ */
+ unsigned char msg[0];
+};
+
+
+void free_channel(struct vmbus_channel *channel);
+
+void vmbus_onmessage(void *context);
+
+int vmbus_request_offers(void);
+
+/* The format must be the same as struct vmdata_gpa_direct */
+struct vmbus_channel_packet_page_buffer {
+ u16 type;
+ u16 dataoffset8;
+ u16 length8;
+ u16 flags;
+ u64 transactionid;
+ u32 reserved;
+ u32 rangecount;
+ struct hv_page_buffer range[MAX_PAGE_BUFFER_COUNT];
+} __packed;
+
+/* The format must be the same as struct vmdata_gpa_direct */
+struct vmbus_channel_packet_multipage_buffer {
+ u16 type;
+ u16 dataoffset8;
+ u16 length8;
+ u16 flags;
+ u64 transactionid;
+ u32 reserved;
+ u32 rangecount; /* Always 1 in this case */
+ struct hv_multipage_buffer range;
+} __packed;
+
+
+extern int vmbus_open(struct vmbus_channel *channel,
+ u32 send_ringbuffersize,
+ u32 recv_ringbuffersize,
+ void *userdata,
+ u32 userdatalen,
+ void(*onchannel_callback)(void *context),
+ void *context);
+
+extern void vmbus_close(struct vmbus_channel *channel);
+
+extern int vmbus_sendpacket(struct vmbus_channel *channel,
+ const void *buffer,
+ u32 bufferLen,
+ u64 requestid,
+ enum vmbus_packet_type type,
+ u32 flags);
+
+extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
+ struct hv_page_buffer pagebuffers[],
+ u32 pagecount,
+ void *buffer,
+ u32 bufferlen,
+ u64 requestid);
+
+extern int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
+ struct hv_multipage_buffer *mpb,
+ void *buffer,
+ u32 bufferlen,
+ u64 requestid);
+
+extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
+ void *kbuffer,
+ u32 size,
+ u32 *gpadl_handle);
+
+extern int vmbus_teardown_gpadl(struct vmbus_channel *channel,
+ u32 gpadl_handle);
+
+extern int vmbus_recvpacket(struct vmbus_channel *channel,
+ void *buffer,
+ u32 bufferlen,
+ u32 *buffer_actual_len,
+ u64 *requestid);
+
+extern int vmbus_recvpacket_raw(struct vmbus_channel *channel,
+ void *buffer,
+ u32 bufferlen,
+ u32 *buffer_actual_len,
+ u64 *requestid);
+
+extern void vmbus_onchannel_event(struct vmbus_channel *channel);
+
+extern void vmbus_get_debug_info(struct vmbus_channel *channel,
+ struct vmbus_channel_debug_info *debug);
+
+extern void vmbus_ontimer(unsigned long data);
+
+
+#define LOWORD(dw) ((unsigned short)(dw))
+#define HIWORD(dw) ((unsigned short)(((unsigned int) (dw) >> 16) & 0xFFFF))
+
+
+#define VMBUS 0x0001
+#define STORVSC 0x0002
+#define NETVSC 0x0004
+#define INPUTVSC 0x0008
+#define BLKVSC 0x0010
+#define VMBUS_DRV 0x0100
+#define STORVSC_DRV 0x0200
+#define NETVSC_DRV 0x0400
+#define INPUTVSC_DRV 0x0800
+#define BLKVSC_DRV 0x1000
+
+#define ALL_MODULES (VMBUS |\
+ STORVSC |\
+ NETVSC |\
+ INPUTVSC |\
+ BLKVSC |\
+ VMBUS_DRV |\
+ STORVSC_DRV |\
+ NETVSC_DRV |\
+ INPUTVSC_DRV|\
+ BLKVSC_DRV)
+
+/* Logging Level */
+#define ERROR_LVL 3
+#define WARNING_LVL 4
+#define INFO_LVL 6
+#define DEBUG_LVL 7
+#define DEBUG_LVL_ENTEREXIT 8
+#define DEBUG_RING_LVL 9
+
+extern unsigned int vmbus_loglevel;
+
+#define DPRINT(mod, lvl, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (lvl <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_DEBUG #mod": %s() " fmt "\n", __func__, ## args);\
+ } while (0)
+
+#define DPRINT_DBG(mod, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (DEBUG_LVL <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_DEBUG #mod": %s() " fmt "\n", __func__, ## args);\
+ } while (0)
+
+#define DPRINT_INFO(mod, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (INFO_LVL <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_INFO #mod": " fmt "\n", ## args);\
+ } while (0)
+
+#define DPRINT_WARN(mod, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (WARNING_LVL <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_WARNING #mod": WARNING! " fmt "\n", ## args);\
+ } while (0)
+
+#define DPRINT_ERR(mod, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (ERROR_LVL <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_ERR #mod": %s() ERROR!! " fmt "\n", \
+ __func__, ## args);\
+ } while (0)
+
+
+
+struct hv_driver;
+struct hv_device;
+
+struct hv_dev_port_info {
+ u32 int_mask;
+ u32 read_idx;
+ u32 write_idx;
+ u32 bytes_avail_toread;
+ u32 bytes_avail_towrite;
+};
+
+struct hv_device_info {
+ u32 chn_id;
+ u32 chn_state;
+ struct hv_guid chn_type;
+ struct hv_guid chn_instance;
+
+ u32 monitor_id;
+ u32 server_monitor_pending;
+ u32 server_monitor_latency;
+ u32 server_monitor_conn_id;
+ u32 client_monitor_pending;
+ u32 client_monitor_latency;
+ u32 client_monitor_conn_id;
+
+ struct hv_dev_port_info inbound;
+ struct hv_dev_port_info outbound;
+};
+
+/* Base driver object */
+struct hv_driver {
+ const char *name;
+
+ /* the device type supported by this driver */
+ struct hv_guid dev_type;
+
+ struct device_driver driver;
+
+ int (*probe)(struct hv_device *);
+ int (*remove)(struct hv_device *);
+ void (*shutdown)(struct hv_device *);
+
+};
+
+/* Base device object */
+struct hv_device {
+ /* the device type id of this device */
+ struct hv_guid dev_type;
+
+ /* the device instance id of this device */
+ struct hv_guid dev_instance;
+
+ struct device device;
+
+ struct vmbus_channel *channel;
+
+ /* Device extension; */
+ void *ext;
+};
+
+
+static inline struct hv_device *device_to_hv_device(struct device *d)
+{
+ return container_of(d, struct hv_device, device);
+}
+
+static inline struct hv_driver *drv_to_hv_drv(struct device_driver *d)
+{
+ return container_of(d, struct hv_driver, driver);
+}
+
+
+/* Vmbus interface */
+int vmbus_child_driver_register(struct device_driver *drv);
+void vmbus_child_driver_unregister(struct device_driver *drv);
+
+/*
+ * Common header for Hyper-V ICs
+ */
+
+#define ICMSGTYPE_NEGOTIATE 0
+#define ICMSGTYPE_HEARTBEAT 1
+#define ICMSGTYPE_KVPEXCHANGE 2
+#define ICMSGTYPE_SHUTDOWN 3
+#define ICMSGTYPE_TIMESYNC 4
+#define ICMSGTYPE_VSS 5
+
+#define ICMSGHDRFLAG_TRANSACTION 1
+#define ICMSGHDRFLAG_REQUEST 2
+#define ICMSGHDRFLAG_RESPONSE 4
+
+#define HV_S_OK 0x00000000
+#define HV_E_FAIL 0x80004005
+#define HV_ERROR_NOT_SUPPORTED 0x80070032
+#define HV_ERROR_MACHINE_LOCKED 0x800704F7
+
+struct vmbuspipe_hdr {
+ u32 flags;
+ u32 msgsize;
+} __packed;
+
+struct ic_version {
+ u16 major;
+ u16 minor;
+} __packed;
+
+struct icmsg_hdr {
+ struct ic_version icverframe;
+ u16 icmsgtype;
+ struct ic_version icvermsg;
+ u16 icmsgsize;
+ u32 status;
+ u8 ictransaction_id;
+ u8 icflags;
+ u8 reserved[2];
+} __packed;
+
+struct icmsg_negotiate {
+ u16 icframe_vercnt;
+ u16 icmsg_vercnt;
+ u32 reserved;
+ struct ic_version icversion_data[1]; /* any size array */
+} __packed;
+
+struct shutdown_msg_data {
+ u32 reason_code;
+ u32 timeout_seconds;
+ u32 flags;
+ u8 display_message[2048];
+} __packed;
+
+struct heartbeat_msg_data {
+ u64 seq_num;
+ u32 reserved[8];
+} __packed;
+
+/* Time Sync IC defs */
+#define ICTIMESYNCFLAG_PROBE 0
+#define ICTIMESYNCFLAG_SYNC 1
+#define ICTIMESYNCFLAG_SAMPLE 2
+
+#ifdef __x86_64__
+#define WLTIMEDELTA 116444736000000000L /* in 100ns unit */
+#else
+#define WLTIMEDELTA 116444736000000000LL
+#endif
+
+struct ictimesync_data {
+ u64 parenttime;
+ u64 childtime;
+ u64 roundtriptime;
+ u8 flags;
+} __packed;
+
+/* Index for each IC struct in array hv_cb_utils[] */
+#define HV_SHUTDOWN_MSG 0
+#define HV_TIMESYNC_MSG 1
+#define HV_HEARTBEAT_MSG 2
+#define HV_KVP_MSG 3
+
+struct hyperv_service_callback {
+ u8 msg_type;
+ char *log_msg;
+ unsigned char data[16];
+ struct vmbus_channel *channel;
+ void (*callback) (void *context);
+};
+
+extern void prep_negotiate_resp(struct icmsg_hdr *,
+ struct icmsg_negotiate *, u8 *);
+extern void chn_cb_negotiate(void *);
+extern struct hyperv_service_callback hv_cb_utils[];
+
+#endif /* _HYPERV_H */
diff --git a/drivers/staging/hv/rndis.h b/drivers/staging/hv/hyperv_net.h
index 014de047b86d..315097df799a 100644
--- a/drivers/staging/hv/rndis.h
+++ b/drivers/staging/hv/hyperv_net.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2009, Microsoft Corporation.
+ * Copyright (c) 2011, Microsoft Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -18,11 +18,395 @@
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
*
*/
-#ifndef _RNDIS_H_
-#define _RNDIS_H_
+#ifndef _HYPERV_NET_H
+#define _HYPERV_NET_H
+
+#include <linux/list.h>
+#include "hyperv.h"
+
+/* Fwd declaration */
+struct hv_netvsc_packet;
+
+/* Represent the xfer page packet which contains 1 or more netvsc packet */
+struct xferpage_packet {
+ struct list_head list_ent;
+
+ /* # of netvsc packets this xfer packet contains */
+ 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
+ */
+struct hv_netvsc_packet {
+ /* Bookkeeping stuff */
+ struct list_head list_ent;
+
+ struct hv_device *device;
+ bool is_data_pkt;
+
+ /*
+ * Valid only for receives when we break a xfer page packet
+ * into multiple netvsc packets
+ */
+ struct xferpage_packet *xfer_page_pkt;
+
+ union {
+ struct {
+ u64 recv_completion_tid;
+ void *recv_completion_ctx;
+ void (*recv_completion)(void *context);
+ } recv;
+ struct {
+ u64 send_completion_tid;
+ void *send_completion_ctx;
+ void (*send_completion)(void *context);
+ } send;
+ } completion;
+
+ /* This points to the memory after page_buf */
+ void *extension;
+
+ u32 total_data_buflen;
+ /* Points to the send/receive buffer where the ethernet frame is */
+ u32 page_buf_cnt;
+ struct hv_page_buffer page_buf[NETVSC_PACKET_MAXPAGE];
+};
+
+struct netvsc_device_info {
+ unsigned char mac_adr[6];
+ bool link_state; /* 0 - link up, 1 - link down */
+ int ring_size;
+};
+
+/* Interface */
+int netvsc_device_add(struct hv_device *device, void *additional_info);
+int netvsc_device_remove(struct hv_device *device);
+int netvsc_send(struct hv_device *device,
+ struct hv_netvsc_packet *packet);
+void netvsc_linkstatus_callback(struct hv_device *device_obj,
+ unsigned int status);
+int netvsc_recv_callback(struct hv_device *device_obj,
+ struct hv_netvsc_packet *packet);
+int netvsc_initialize(struct hv_driver *drv);
+int rndis_filter_open(struct hv_device *dev);
+int rndis_filter_close(struct hv_device *dev);
+int rndis_filte_device_add(struct hv_device *dev,
+ void *additional_info);
+int rndis_filter_device_remove(struct hv_device *dev);
+int rndis_filter_receive(struct hv_device *dev,
+ struct hv_netvsc_packet *pkt);
+
+
+
+int rndis_filter_send(struct hv_device *dev,
+ struct hv_netvsc_packet *pkt);
+
+#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
+
+enum {
+ NVSP_MSG_TYPE_NONE = 0,
+
+ /* Init Messages */
+ NVSP_MSG_TYPE_INIT = 1,
+ NVSP_MSG_TYPE_INIT_COMPLETE = 2,
+
+ NVSP_VERSION_MSG_START = 100,
+
+ /* Version 1 Messages */
+ NVSP_MSG1_TYPE_SEND_NDIS_VER = NVSP_VERSION_MSG_START,
+
+ NVSP_MSG1_TYPE_SEND_RECV_BUF,
+ NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE,
+ NVSP_MSG1_TYPE_REVOKE_RECV_BUF,
+
+ NVSP_MSG1_TYPE_SEND_SEND_BUF,
+ NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE,
+ NVSP_MSG1_TYPE_REVOKE_SEND_BUF,
+
+ 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,
+};
+
+enum {
+ NVSP_STAT_NONE = 0,
+ NVSP_STAT_SUCCESS,
+ NVSP_STAT_FAIL,
+ NVSP_STAT_PROTOCOL_TOO_NEW,
+ NVSP_STAT_PROTOCOL_TOO_OLD,
+ NVSP_STAT_INVALID_RNDIS_PKT,
+ NVSP_STAT_BUSY,
+ NVSP_STAT_MAX,
+};
+
+struct nvsp_message_header {
+ u32 msg_type;
+};
+
+/* Init Messages */
+
+/*
+ * This message is used by the VSC to initialize the channel after the channels
+ * has been opened. This message should never include anything other then
+ * versioning (i.e. this message will be the same for ever).
+ */
+struct nvsp_message_init {
+ u32 min_protocol_ver;
+ u32 max_protocol_ver;
+} __packed;
+
+/*
+ * This message is used by the VSP to complete the initialization of the
+ * channel. This message should never include anything other then versioning
+ * (i.e. this message will be the same for ever).
+ */
+struct nvsp_message_init_complete {
+ u32 negotiated_protocol_ver;
+ u32 max_mdl_chain_len;
+ u32 status;
+} __packed;
+
+union nvsp_message_init_uber {
+ struct nvsp_message_init init;
+ struct nvsp_message_init_complete init_complete;
+} __packed;
+
+/* Version 1 Messages */
+
+/*
+ * This message is used by the VSC to send the NDIS version to the VSP. The VSP
+ * can use this information when handling OIDs sent by the VSC.
+ */
+struct nvsp_1_message_send_ndis_version {
+ u32 ndis_major_ver;
+ u32 ndis_minor_ver;
+} __packed;
+
+/*
+ * This message is used by the VSC to send a receive buffer to the VSP. The VSP
+ * can then use the receive buffer to send data to the VSC.
+ */
+struct nvsp_1_message_send_receive_buffer {
+ u32 gpadl_handle;
+ u16 id;
+} __packed;
+
+struct nvsp_1_receive_buffer_section {
+ u32 offset;
+ u32 sub_alloc_size;
+ u32 num_sub_allocs;
+ u32 end_offset;
+} __packed;
+
+/*
+ * This message is used by the VSP to acknowledge a receive buffer send by the
+ * VSC. This message must be sent by the VSP before the VSP uses the receive
+ * buffer.
+ */
+struct nvsp_1_message_send_receive_buffer_complete {
+ u32 status;
+ u32 num_sections;
+
+ /*
+ * The receive buffer is split into two parts, a large suballocation
+ * section and a small suballocation section. These sections are then
+ * suballocated by a certain size.
+ */
+
+ /*
+ * For example, the following break up of the receive buffer has 6
+ * large suballocations and 10 small suballocations.
+ */
+
+ /*
+ * | Large Section | | Small Section |
+ * ------------------------------------------------------------
+ * | | | | | | | | | | | | | | | | | |
+ * | |
+ * LargeOffset SmallOffset
+ */
+
+ struct nvsp_1_receive_buffer_section sections[1];
+} __packed;
+
+/*
+ * This message is sent by the VSC to revoke the receive buffer. After the VSP
+ * completes this transaction, the vsp should never use the receive buffer
+ * again.
+ */
+struct nvsp_1_message_revoke_receive_buffer {
+ u16 id;
+};
+
+/*
+ * This message is used by the VSC to send a send buffer to the VSP. The VSC
+ * can then use the send buffer to send data to the VSP.
+ */
+struct nvsp_1_message_send_send_buffer {
+ u32 gpadl_handle;
+ u16 id;
+} __packed;
+
+/*
+ * This message is used by the VSP to acknowledge a send buffer sent by the
+ * VSC. This message must be sent by the VSP before the VSP uses the sent
+ * buffer.
+ */
+struct nvsp_1_message_send_send_buffer_complete {
+ u32 status;
+
+ /*
+ * The VSC gets to choose the size of the send buffer and the VSP gets
+ * to choose the sections size of the buffer. This was done to enable
+ * dynamic reconfigurations when the cost of GPA-direct buffers
+ * decreases.
+ */
+ u32 section_size;
+} __packed;
+
+/*
+ * This message is sent by the VSC to revoke the send buffer. After the VSP
+ * completes this transaction, the vsp should never use the send buffer again.
+ */
+struct nvsp_1_message_revoke_send_buffer {
+ u16 id;
+};
+
+/*
+ * This message is used by both the VSP and the VSC to send a RNDIS message to
+ * the opposite channel endpoint.
+ */
+struct nvsp_1_message_send_rndis_packet {
+ /*
+ * This field is specified by RNIDS. They assume there's two different
+ * channels of communication. However, the Network VSP only has one.
+ * Therefore, the channel travels with the RNDIS packet.
+ */
+ u32 channel_type;
+
+ /*
+ * This field is used to send part or all of the data through a send
+ * buffer. This values specifies an index into the send buffer. If the
+ * index is 0xFFFFFFFF, then the send buffer is not being used and all
+ * of the data was sent through other VMBus mechanisms.
+ */
+ u32 send_buf_section_index;
+ u32 send_buf_section_size;
+} __packed;
+
+/*
+ * This message is used by both the VSP and the VSC to complete a RNDIS message
+ * to the opposite channel endpoint. At this point, the initiator of this
+ * message cannot use any resources associated with the original RNDIS packet.
+ */
+struct nvsp_1_message_send_rndis_packet_complete {
+ u32 status;
+};
+
+union nvsp_1_message_uber {
+ struct nvsp_1_message_send_ndis_version send_ndis_ver;
+
+ struct nvsp_1_message_send_receive_buffer send_recv_buf;
+ struct nvsp_1_message_send_receive_buffer_complete
+ send_recv_buf_complete;
+ struct nvsp_1_message_revoke_receive_buffer revoke_recv_buf;
+
+ struct nvsp_1_message_send_send_buffer send_send_buf;
+ struct nvsp_1_message_send_send_buffer_complete send_send_buf_complete;
+ struct nvsp_1_message_revoke_send_buffer revoke_send_buf;
+
+ struct nvsp_1_message_send_rndis_packet send_rndis_pkt;
+ struct nvsp_1_message_send_rndis_packet_complete
+ send_rndis_pkt_complete;
+} __packed;
+
+union nvsp_all_messages {
+ union nvsp_message_init_uber init_msg;
+ union nvsp_1_message_uber v1_msg;
+} __packed;
+
+/* ALL Messages */
+struct nvsp_message {
+ struct nvsp_message_header hdr;
+ union nvsp_all_messages msg;
+} __packed;
+
+
+
+
+/* #define NVSC_MIN_PROTOCOL_VERSION 1 */
+/* #define NVSC_MAX_PROTOCOL_VERSION 1 */
+
+#define NETVSC_SEND_BUFFER_SIZE (64*1024) /* 64K */
+#define NETVSC_SEND_BUFFER_ID 0xface
+
+
+#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024) /* 1MB */
+
+#define NETVSC_RECEIVE_BUFFER_ID 0xcafe
+
+#define NETVSC_RECEIVE_SG_COUNT 1
+
+/* Preallocated receive packets */
+#define NETVSC_RECEIVE_PACKETLIST_COUNT 256
+
+#define NETVSC_PACKET_SIZE 2048
+
+/* Per netvsc channel-specific */
+struct netvsc_device {
+ struct hv_device *dev;
+
+ atomic_t refcnt;
+ atomic_t num_outstanding_sends;
+ /*
+ * List of free preallocated hv_netvsc_packet to represent receive
+ * packet
+ */
+ struct list_head recv_pkt_list;
+ spinlock_t recv_pkt_list_lock;
+
+ /* Send buffer allocated by us but manages by NetVSP */
+ void *send_buf;
+ u32 send_buf_size;
+ u32 send_buf_gpadl_handle;
+ u32 send_section_size;
+
+ /* Receive buffer allocated by us but manages by NetVSP */
+ void *recv_buf;
+ u32 recv_buf_size;
+ u32 recv_buf_gpadl_handle;
+ u32 recv_section_cnt;
+ struct nvsp_1_receive_buffer_section *recv_section;
+
+ /* Used for NetVSP initialization protocol */
+ struct completion channel_init_wait;
+ struct nvsp_message channel_init_pkt;
+
+ struct nvsp_message revoke_packet;
+ /* unsigned char HwMacAddr[HW_MACADDR_LEN]; */
+
+ /* Holds rndis device info */
+ void *extension;
+};
+
/* Status codes */
@@ -618,6 +1002,13 @@ struct rndis_message {
union rndis_message_container msg;
};
+
+struct rndis_filter_packet {
+ void *completion_ctx;
+ void (*completion)(void *context);
+ struct rndis_message msg;
+};
+
/* Handy macros */
/* get the size of an RNDIS message. Pass in the message type, */
@@ -650,4 +1041,27 @@ struct rndis_message {
#define RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(rndis_msg) \
((void *) rndis_msg)
-#endif /* _RNDIS_H_ */
+
+#define __struct_bcount(x)
+
+
+
+#define RNDIS_HEADER_SIZE (sizeof(struct rndis_message) - \
+ sizeof(union rndis_message_container))
+
+#define NDIS_PACKET_TYPE_DIRECTED 0x00000001
+#define NDIS_PACKET_TYPE_MULTICAST 0x00000002
+#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004
+#define NDIS_PACKET_TYPE_BROADCAST 0x00000008
+#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010
+#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020
+#define NDIS_PACKET_TYPE_SMT 0x00000040
+#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080
+#define NDIS_PACKET_TYPE_GROUP 0x00000100
+#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200
+#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400
+#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800
+
+
+
+#endif /* _HYPERV_NET_H */
diff --git a/drivers/staging/hv/vstorage.h b/drivers/staging/hv/hyperv_storage.h
index ebb4d671c424..a01f9a07c988 100644
--- a/drivers/staging/hv/vstorage.h
+++ b/drivers/staging/hv/hyperv_storage.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2009, Microsoft Corporation.
+ * Copyright (c) 2011, Microsoft Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -18,13 +18,19 @@
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
*
*/
+#ifndef _HYPERV_STORAGE_H
+#define _HYPERV_STORAGE_H
+
+
/* vstorage.w revision number. This is used in the case of a version match, */
/* 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 { \
@@ -190,3 +196,139 @@ struct vstor_packet {
/* This is the set of flags that the vsc can set in any packets it sends */
#define VSC_LEGAL_FLAGS (REQUEST_COMPLETION_FLAG)
+
+
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include "hyperv_storage.h"
+#include "hyperv.h"
+
+/* Defines */
+#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
+#define BLKVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
+
+#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 hv_storvsc_request;
+
+/* Matches Windows-end */
+enum storvsc_request_type {
+ WRITE_TYPE,
+ READ_TYPE,
+ UNKNOWN_TYPE,
+};
+
+
+struct hv_storvsc_request {
+ struct hv_storvsc_request *request;
+ struct hv_device *device;
+
+ /* Synchronize the request/response if needed */
+ struct completion wait_event;
+
+ 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;
+};
+
+
+struct storvsc_device_info {
+ u32 ring_buffer_size;
+ unsigned int port_number;
+ unsigned char path_id;
+ unsigned char target_id;
+};
+
+struct storvsc_major_info {
+ int major;
+ int index;
+ bool do_register;
+ char *devname;
+ char *diskname;
+};
+
+/* A storvsc device is a device object that contains a vmbus channel */
+struct storvsc_device {
+ struct hv_device *device;
+
+ /* 0 indicates the device is being destroyed */
+ atomic_t ref_count;
+
+ bool drain_notify;
+ atomic_t num_outstanding_req;
+
+ wait_queue_head_t waiting_to_drain;
+
+ /*
+ * Each unique Port/Path/Target represents 1 channel ie scsi
+ * controller. In reality, the pathid, targetid is always 0
+ * and the port is set by us
+ */
+ unsigned int port_number;
+ unsigned char path_id;
+ unsigned char target_id;
+
+ /* Used for vsc/vsp channel reset process */
+ struct hv_storvsc_request init_request;
+ struct hv_storvsc_request reset_request;
+};
+
+
+/* Get the stordevice object iff exists and its refcount > 1 */
+static inline struct storvsc_device *get_stor_device(struct hv_device *device)
+{
+ struct storvsc_device *stor_device;
+
+ stor_device = (struct storvsc_device *)device->ext;
+ if (stor_device && atomic_read(&stor_device->ref_count) > 1)
+ atomic_inc(&stor_device->ref_count);
+ else
+ stor_device = NULL;
+
+ return stor_device;
+}
+
+
+static inline void put_stor_device(struct hv_device *device)
+{
+ struct storvsc_device *stor_device;
+
+ stor_device = (struct storvsc_device *)device->ext;
+
+ atomic_dec(&stor_device->ref_count);
+}
+
+static inline void storvsc_wait_to_drain(struct storvsc_device *dev)
+{
+ dev->drain_notify = true;
+ wait_event(dev->waiting_to_drain,
+ atomic_read(&dev->num_outstanding_req) == 0);
+ dev->drain_notify = false;
+}
+
+/* Interface */
+
+int storvsc_dev_add(struct hv_device *device,
+ void *additional_info);
+int storvsc_dev_remove(struct hv_device *device);
+
+int storvsc_do_io(struct hv_device *device,
+ struct hv_storvsc_request *request);
+
+int storvsc_get_major_info(struct storvsc_device_info *device_info,
+ struct storvsc_major_info *major_info);
+
+#endif /* _HYPERV_STORAGE_H */
diff --git a/drivers/staging/hv/hyperv_vmbus.h b/drivers/staging/hv/hyperv_vmbus.h
new file mode 100644
index 000000000000..bf30a425b643
--- /dev/null
+++ b/drivers/staging/hv/hyperv_vmbus.h
@@ -0,0 +1,631 @@
+/*
+ *
+ * Copyright (c) 2011, Microsoft Corporation.
+ *
+ * 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.
+ *
+ * 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
+ *
+ */
+
+#ifndef _HYPERV_VMBUS_H
+#define _HYPERV_VMBUS_H
+
+#include <linux/list.h>
+#include <asm/sync_bitops.h>
+#include <linux/atomic.h>
+
+#include "hyperv.h"
+
+/*
+ * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
+ * is set by CPUID(HVCPUID_VERSION_FEATURES).
+ */
+enum hv_cpuid_function {
+ HVCPUID_VERSION_FEATURES = 0x00000001,
+ HVCPUID_VENDOR_MAXFUNCTION = 0x40000000,
+ HVCPUID_INTERFACE = 0x40000001,
+
+ /*
+ * The remaining functions depend on the value of
+ * HVCPUID_INTERFACE
+ */
+ HVCPUID_VERSION = 0x40000002,
+ HVCPUID_FEATURES = 0x40000003,
+ HVCPUID_ENLIGHTENMENT_INFO = 0x40000004,
+ HVCPUID_IMPLEMENTATION_LIMITS = 0x40000005,
+};
+
+/* Define version of the synthetic interrupt controller. */
+#define HV_SYNIC_VERSION (1)
+
+/* Define the expected SynIC version. */
+#define HV_SYNIC_VERSION_1 (0x1)
+
+/* Define synthetic interrupt controller message constants. */
+#define HV_MESSAGE_SIZE (256)
+#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240)
+#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
+#define HV_ANY_VP (0xFFFFFFFF)
+
+/* Define synthetic interrupt controller flag constants. */
+#define HV_EVENT_FLAGS_COUNT (256 * 8)
+#define HV_EVENT_FLAGS_BYTE_COUNT (256)
+#define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32))
+
+/* Define hypervisor message types. */
+enum hv_message_type {
+ HVMSG_NONE = 0x00000000,
+
+ /* Memory access messages. */
+ HVMSG_UNMAPPED_GPA = 0x80000000,
+ HVMSG_GPA_INTERCEPT = 0x80000001,
+
+ /* Timer notification messages. */
+ HVMSG_TIMER_EXPIRED = 0x80000010,
+
+ /* Error messages. */
+ HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
+ HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021,
+ HVMSG_UNSUPPORTED_FEATURE = 0x80000022,
+
+ /* Trace buffer complete messages. */
+ HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040,
+
+ /* Platform-specific processor intercept messages. */
+ HVMSG_X64_IOPORT_INTERCEPT = 0x80010000,
+ HVMSG_X64_MSR_INTERCEPT = 0x80010001,
+ HVMSG_X64_CPUID_INTERCEPT = 0x80010002,
+ HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003,
+ HVMSG_X64_APIC_EOI = 0x80010004,
+ HVMSG_X64_LEGACY_FP_ERROR = 0x80010005
+};
+
+/* Define the number of synthetic interrupt sources. */
+#define HV_SYNIC_SINT_COUNT (16)
+#define HV_SYNIC_STIMER_COUNT (4)
+
+/* Define invalid partition identifier. */
+#define HV_PARTITION_ID_INVALID ((u64)0x0)
+
+/* Define connection identifier type. */
+union hv_connection_id {
+ u32 asu32;
+ struct {
+ u32 id:24;
+ u32 reserved:8;
+ } u;
+};
+
+/* Define port identifier type. */
+union hv_port_id {
+ u32 asu32;
+ struct {
+ u32 id:24;
+ u32 reserved:8;
+ } u ;
+};
+
+/* Define port type. */
+enum hv_port_type {
+ HVPORT_MSG = 1,
+ HVPORT_EVENT = 2,
+ HVPORT_MONITOR = 3
+};
+
+/* Define port information structure. */
+struct hv_port_info {
+ enum hv_port_type port_type;
+ u32 padding;
+ union {
+ struct {
+ u32 target_sint;
+ u32 target_vp;
+ u64 rsvdz;
+ } message_port_info;
+ struct {
+ u32 target_sint;
+ u32 target_vp;
+ u16 base_flag_bumber;
+ u16 flag_count;
+ u32 rsvdz;
+ } event_port_info;
+ struct {
+ u64 monitor_address;
+ u64 rsvdz;
+ } monitor_port_info;
+ };
+};
+
+struct hv_connection_info {
+ enum hv_port_type port_type;
+ u32 padding;
+ union {
+ struct {
+ u64 rsvdz;
+ } message_connection_info;
+ struct {
+ u64 rsvdz;
+ } event_connection_info;
+ struct {
+ u64 monitor_address;
+ } monitor_connection_info;
+ };
+};
+
+/* Define synthetic interrupt controller message flags. */
+union hv_message_flags {
+ u8 asu8;
+ struct {
+ u8 msg_pending:1;
+ u8 reserved:7;
+ };
+};
+
+/* Define synthetic interrupt controller message header. */
+struct hv_message_header {
+ enum hv_message_type message_type;
+ u8 payload_size;
+ union hv_message_flags message_flags;
+ u8 reserved[2];
+ union {
+ u64 sender;
+ union hv_port_id port;
+ };
+};
+
+/* Define timer message payload structure. */
+struct hv_timer_message_payload {
+ u32 timer_index;
+ u32 reserved;
+ u64 expiration_time; /* When the timer expired */
+ u64 delivery_time; /* When the message was delivered */
+};
+
+/* Define synthetic interrupt controller message format. */
+struct hv_message {
+ struct hv_message_header header;
+ union {
+ u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+ } u ;
+};
+
+/* Define the number of message buffers associated with each port. */
+#define HV_PORT_MESSAGE_BUFFER_COUNT (16)
+
+/* Define the synthetic interrupt message page layout. */
+struct hv_message_page {
+ struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
+};
+
+/* Define the synthetic interrupt controller event flags format. */
+union hv_synic_event_flags {
+ u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT];
+ u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT];
+};
+
+/* Define the synthetic interrupt flags page layout. */
+struct hv_synic_event_flags_page {
+ union hv_synic_event_flags sintevent_flags[HV_SYNIC_SINT_COUNT];
+};
+
+/* Define SynIC control register. */
+union hv_synic_scontrol {
+ u64 as_uint64;
+ struct {
+ u64 enable:1;
+ u64 reserved:63;
+ };
+};
+
+/* Define synthetic interrupt source. */
+union hv_synic_sint {
+ u64 as_uint64;
+ struct {
+ u64 vector:8;
+ u64 reserved1:8;
+ u64 masked:1;
+ u64 auto_eoi:1;
+ u64 reserved2:46;
+ };
+};
+
+/* Define the format of the SIMP register */
+union hv_synic_simp {
+ u64 as_uint64;
+ struct {
+ u64 simp_enabled:1;
+ u64 preserved:11;
+ u64 base_simp_gpa:52;
+ };
+};
+
+/* Define the format of the SIEFP register */
+union hv_synic_siefp {
+ u64 as_uint64;
+ struct {
+ u64 siefp_enabled:1;
+ u64 preserved:11;
+ u64 base_siefp_gpa:52;
+ };
+};
+
+/* Definitions for the monitored notification facility */
+union hv_monitor_trigger_group {
+ u64 as_uint64;
+ struct {
+ u32 pending;
+ u32 armed;
+ };
+};
+
+struct hv_monitor_parameter {
+ union hv_connection_id connectionid;
+ u16 flagnumber;
+ u16 rsvdz;
+};
+
+union hv_monitor_trigger_state {
+ u32 asu32;
+
+ struct {
+ u32 group_enable:4;
+ u32 rsvdz:28;
+ };
+};
+
+/* struct hv_monitor_page Layout */
+/* ------------------------------------------------------ */
+/* | 0 | TriggerState (4 bytes) | Rsvd1 (4 bytes) | */
+/* | 8 | TriggerGroup[0] | */
+/* | 10 | TriggerGroup[1] | */
+/* | 18 | TriggerGroup[2] | */
+/* | 20 | TriggerGroup[3] | */
+/* | 28 | Rsvd2[0] | */
+/* | 30 | Rsvd2[1] | */
+/* | 38 | Rsvd2[2] | */
+/* | 40 | NextCheckTime[0][0] | NextCheckTime[0][1] | */
+/* | ... | */
+/* | 240 | Latency[0][0..3] | */
+/* | 340 | Rsvz3[0] | */
+/* | 440 | Parameter[0][0] | */
+/* | 448 | Parameter[0][1] | */
+/* | ... | */
+/* | 840 | Rsvd4[0] | */
+/* ------------------------------------------------------ */
+struct hv_monitor_page {
+ union hv_monitor_trigger_state trigger_state;
+ u32 rsvdz1;
+
+ union hv_monitor_trigger_group trigger_group[4];
+ u64 rsvdz2[3];
+
+ s32 next_checktime[4][32];
+
+ u16 latency[4][32];
+ u64 rsvdz3[32];
+
+ struct hv_monitor_parameter parameter[4][32];
+
+ u8 rsvdz4[1984];
+};
+
+/* Declare the various hypercall operations. */
+enum hv_call_code {
+ HVCALL_POST_MESSAGE = 0x005c,
+ HVCALL_SIGNAL_EVENT = 0x005d,
+};
+
+/* Definition of the hv_post_message hypercall input structure. */
+struct hv_input_post_message {
+ union hv_connection_id connectionid;
+ u32 reserved;
+ enum hv_message_type message_type;
+ u32 payload_size;
+ u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+};
+
+/* Definition of the hv_signal_event hypercall input structure. */
+struct hv_input_signal_event {
+ union hv_connection_id connectionid;
+ u16 flag_number;
+ u16 rsvdz;
+};
+
+/*
+ * Versioning definitions used for guests reporting themselves to the
+ * hypervisor, and visa versa.
+ */
+
+/* Version info reported by guest OS's */
+enum hv_guest_os_vendor {
+ HVGUESTOS_VENDOR_MICROSOFT = 0x0001
+};
+
+enum hv_guest_os_microsoft_ids {
+ HVGUESTOS_MICROSOFT_UNDEFINED = 0x00,
+ HVGUESTOS_MICROSOFT_MSDOS = 0x01,
+ HVGUESTOS_MICROSOFT_WINDOWS3X = 0x02,
+ HVGUESTOS_MICROSOFT_WINDOWS9X = 0x03,
+ HVGUESTOS_MICROSOFT_WINDOWSNT = 0x04,
+ HVGUESTOS_MICROSOFT_WINDOWSCE = 0x05
+};
+
+/*
+ * Declare the MSR used to identify the guest OS.
+ */
+#define HV_X64_MSR_GUEST_OS_ID 0x40000000
+
+union hv_x64_msr_guest_os_id_contents {
+ u64 as_uint64;
+ struct {
+ u64 build_number:16;
+ u64 service_version:8; /* Service Pack, etc. */
+ u64 minor_version:8;
+ u64 major_version:8;
+ u64 os_id:8; /* enum hv_guest_os_microsoft_ids (if Vendor=MS) */
+ u64 vendor_id:16; /* enum hv_guest_os_vendor */
+ };
+};
+
+/*
+ * Declare the MSR used to setup pages used to communicate with the hypervisor.
+ */
+#define HV_X64_MSR_HYPERCALL 0x40000001
+
+union hv_x64_msr_hypercall_contents {
+ u64 as_uint64;
+ struct {
+ u64 enable:1;
+ u64 reserved:11;
+ u64 guest_physical_address:52;
+ };
+};
+
+
+enum {
+ VMBUS_MESSAGE_CONNECTION_ID = 1,
+ VMBUS_MESSAGE_PORT_ID = 1,
+ VMBUS_EVENT_CONNECTION_ID = 2,
+ VMBUS_EVENT_PORT_ID = 2,
+ VMBUS_MONITOR_CONNECTION_ID = 3,
+ VMBUS_MONITOR_PORT_ID = 3,
+ VMBUS_MESSAGE_SINT = 2,
+};
+
+/* #defines */
+
+#define HV_PRESENT_BIT 0x80000000
+
+#define HV_LINUX_GUEST_ID_LO 0x00000000
+#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
+#define HV_LINUX_GUEST_ID (((u64)HV_LINUX_GUEST_ID_HI << 32) | \
+ HV_LINUX_GUEST_ID_LO)
+
+#define HV_CPU_POWER_MANAGEMENT (1 << 0)
+#define HV_RECOMMENDATIONS_MAX 4
+
+#define HV_X64_MAX 5
+#define HV_CAPS_MAX 8
+
+
+#define HV_HYPERCALL_PARAM_ALIGN sizeof(u64)
+
+
+/* Service definitions */
+
+#define HV_SERVICE_PARENT_PORT (0)
+#define HV_SERVICE_PARENT_CONNECTION (0)
+
+#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0)
+#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1)
+#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2)
+#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3)
+
+#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1)
+#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2)
+#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3)
+#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4)
+#define HV_SERVICE_MAX_MESSAGE_ID (4)
+
+#define HV_SERVICE_PROTOCOL_VERSION (0x0010)
+#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64
+
+/* #define VMBUS_REVISION_NUMBER 6 */
+
+/* Our local vmbus's port and connection id. Anything >0 is fine */
+/* #define VMBUS_PORT_ID 11 */
+
+/* 628180B8-308D-4c5e-B7DB-1BEB62E62EF4 */
+static const struct hv_guid VMBUS_SERVICE_ID = {
+ .data = {
+ 0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c,
+ 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4
+ },
+};
+
+#define MAX_NUM_CPUS 32
+
+
+struct hv_input_signal_event_buffer {
+ u64 align8;
+ struct hv_input_signal_event event;
+};
+
+struct hv_context {
+ /* We only support running on top of Hyper-V
+ * So at this point this really can only contain the Hyper-V ID
+ */
+ u64 guestid;
+
+ void *hypercall_page;
+
+ bool synic_initialized;
+
+ /*
+ * This is used as an input param to HvCallSignalEvent hypercall. The
+ * input param is immutable in our usage and must be dynamic mem (vs
+ * stack or global). */
+ struct hv_input_signal_event_buffer *signal_event_buffer;
+ /* 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];
+};
+
+extern struct hv_context hv_context;
+
+
+/* Hv Interface */
+
+extern int hv_init(void);
+
+extern void hv_cleanup(void);
+
+extern u16 hv_post_message(union hv_connection_id connection_id,
+ enum hv_message_type message_type,
+ void *payload, size_t payload_size);
+
+extern u16 hv_signal_event(void);
+
+extern void hv_synic_init(void *irqarg);
+
+extern void hv_synic_cleanup(void *arg);
+
+
+/* Interface */
+
+
+int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
+ u32 buflen);
+
+void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
+
+int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
+ struct scatterlist *sglist,
+ u32 sgcount);
+
+int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
+ u32 buflen);
+
+int hv_ringbuffer_read(struct hv_ring_buffer_info *ring_info,
+ void *buffer,
+ u32 buflen,
+ u32 offset);
+
+u32 hv_get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *ring_info);
+
+void hv_dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix);
+
+void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
+ struct hv_ring_buffer_debug_info *debug_info);
+
+/*
+ * Maximum channels is determined by the size of the interrupt page
+ * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt
+ * and the other is receive endpoint interrupt
+ */
+#define MAX_NUM_CHANNELS ((PAGE_SIZE >> 1) << 3) /* 16348 channels */
+
+/* The value here must be in multiple of 32 */
+/* TODO: Need to make this configurable */
+#define MAX_NUM_CHANNELS_SUPPORTED 256
+
+
+enum vmbus_connect_state {
+ DISCONNECTED,
+ CONNECTING,
+ CONNECTED,
+ DISCONNECTING
+};
+
+#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT
+
+struct vmbus_connection {
+ enum vmbus_connect_state conn_state;
+
+ atomic_t next_gpadl_handle;
+
+ /*
+ * Represents channel interrupts. Each bit position represents a
+ * channel. When a channel sends an interrupt via VMBUS, it finds its
+ * bit in the sendInterruptPage, set it and calls Hv to generate a port
+ * event. The other end receives the port event and parse the
+ * recvInterruptPage to see which bit is set
+ */
+ void *int_page;
+ void *send_int_page;
+ void *recv_int_page;
+
+ /*
+ * 2 pages - 1st page for parent->child notification and 2nd
+ * is child->parent notification
+ */
+ void *monitor_pages;
+ struct list_head chn_msg_list;
+ spinlock_t channelmsg_lock;
+
+ /* List of channels */
+ struct list_head chn_list;
+ spinlock_t channel_lock;
+
+ struct workqueue_struct *work_queue;
+};
+
+
+struct vmbus_msginfo {
+ /* Bookkeeping stuff */
+ struct list_head msglist_entry;
+
+ /* The message itself */
+ unsigned char msg[0];
+};
+
+
+extern struct vmbus_connection vmbus_connection;
+
+/* General vmbus interface */
+
+struct hv_device *vmbus_child_device_create(struct hv_guid *type,
+ struct hv_guid *instance,
+ struct vmbus_channel *channel);
+
+int vmbus_child_device_register(struct hv_device *child_device_obj);
+void vmbus_child_device_unregister(struct hv_device *device_obj);
+
+/* static void */
+/* VmbusChildDeviceDestroy( */
+/* struct hv_device *); */
+
+struct vmbus_channel *relid2channel(u32 relid);
+
+
+/* Connection interface */
+
+int vmbus_connect(void);
+
+int vmbus_disconnect(void);
+
+int vmbus_post_msg(void *buffer, size_t buflen);
+
+int vmbus_set_event(u32 child_relid);
+
+void vmbus_on_event(unsigned long data);
+
+
+#endif /* _HYPERV_VMBUS_H */
diff --git a/drivers/staging/hv/logging.h b/drivers/staging/hv/logging.h
deleted file mode 100644
index 17999515ce08..000000000000
--- a/drivers/staging/hv/logging.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _LOGGING_H_
-#define _LOGGING_H_
-
-#define LOWORD(dw) ((unsigned short)(dw))
-#define HIWORD(dw) ((unsigned short)(((unsigned int) (dw) >> 16) & 0xFFFF))
-
-/* #include <linux/init.h> */
-/* #include <linux/module.h> */
-
-
-#define VMBUS 0x0001
-#define STORVSC 0x0002
-#define NETVSC 0x0004
-#define INPUTVSC 0x0008
-#define BLKVSC 0x0010
-#define VMBUS_DRV 0x0100
-#define STORVSC_DRV 0x0200
-#define NETVSC_DRV 0x0400
-#define INPUTVSC_DRV 0x0800
-#define BLKVSC_DRV 0x1000
-
-#define ALL_MODULES (VMBUS |\
- STORVSC |\
- NETVSC |\
- INPUTVSC |\
- BLKVSC |\
- VMBUS_DRV |\
- STORVSC_DRV |\
- NETVSC_DRV |\
- INPUTVSC_DRV|\
- BLKVSC_DRV)
-
-/* Logging Level */
-#define ERROR_LVL 3
-#define WARNING_LVL 4
-#define INFO_LVL 6
-#define DEBUG_LVL 7
-#define DEBUG_LVL_ENTEREXIT 8
-#define DEBUG_RING_LVL 9
-
-extern unsigned int vmbus_loglevel;
-
-#define DPRINT(mod, lvl, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (lvl <= LOWORD(vmbus_loglevel))) \
- printk(KERN_DEBUG #mod": %s() " fmt "\n", __func__, ## args);\
- } while (0)
-
-#define DPRINT_DBG(mod, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (DEBUG_LVL <= LOWORD(vmbus_loglevel))) \
- printk(KERN_DEBUG #mod": %s() " fmt "\n", __func__, ## args);\
- } while (0)
-
-#define DPRINT_INFO(mod, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (INFO_LVL <= LOWORD(vmbus_loglevel))) \
- printk(KERN_INFO #mod": " fmt "\n", ## args);\
- } while (0)
-
-#define DPRINT_WARN(mod, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (WARNING_LVL <= LOWORD(vmbus_loglevel))) \
- printk(KERN_WARNING #mod": WARNING! " fmt "\n", ## args);\
- } while (0)
-
-#define DPRINT_ERR(mod, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (ERROR_LVL <= LOWORD(vmbus_loglevel))) \
- printk(KERN_ERR #mod": %s() ERROR!! " fmt "\n", \
- __func__, ## args);\
- } while (0)
-
-#endif /* _LOGGING_H_ */
diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 20b159775e88..41cbb26eccbf 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -18,6 +18,8 @@
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/wait.h>
@@ -25,11 +27,9 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/slab.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "netvsc.h"
-#include "rndis_filter.h"
-#include "channel.h"
+
+#include "hyperv.h"
+#include "hyperv_net.h"
/* Globals */
@@ -43,38 +43,6 @@ static const struct hv_guid netvsc_device_type = {
}
};
-static int netvsc_device_add(struct hv_device *device, void *additional_info);
-
-static int netvsc_device_remove(struct hv_device *device);
-
-static void netvsc_cleanup(struct hv_driver *driver);
-
-static void netvsc_channel_cb(void *context);
-
-static int netvsc_init_send_buf(struct hv_device *device);
-
-static int netvsc_init_recv_buf(struct hv_device *device);
-
-static int netvsc_destroy_send_buf(struct netvsc_device *net_device);
-
-static int netvsc_destroy_recv_buf(struct netvsc_device *net_device);
-
-static int netvsc_connect_vsp(struct hv_device *device);
-
-static void netvsc_send_completion(struct hv_device *device,
- struct vmpacket_descriptor *packet);
-
-static int netvsc_send(struct hv_device *device,
- struct hv_netvsc_packet *packet);
-
-static void netvsc_receive(struct hv_device *device,
- struct vmpacket_descriptor *packet);
-
-static void netvsc_receive_completion(void *context);
-
-static void netvsc_send_recv_completion(struct hv_device *device,
- u64 transaction_id);
-
static struct netvsc_device *alloc_net_device(struct hv_device *device)
{
@@ -171,43 +139,85 @@ static struct netvsc_device *release_inbound_net_device(
return net_device;
}
-/*
- * netvsc_initialize - Main entry point
- */
-int netvsc_initialize(struct hv_driver *drv)
+static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
{
- struct netvsc_driver *driver = (struct netvsc_driver *)drv;
+ struct nvsp_message *revoke_packet;
+ int ret = 0;
- DPRINT_DBG(NETVSC, "sizeof(struct hv_netvsc_packet)=%zd, "
- "sizeof(struct nvsp_message)=%zd, "
- "sizeof(struct vmtransfer_page_packet_header)=%zd",
- sizeof(struct hv_netvsc_packet),
- sizeof(struct nvsp_message),
- sizeof(struct vmtransfer_page_packet_header));
+ /*
+ * If we got a section count, it means we received a
+ * SendReceiveBufferComplete msg (ie sent
+ * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
+ * to send a revoke msg here
+ */
+ if (net_device->recv_section_cnt) {
+ /* Send the revoke receive buffer */
+ revoke_packet = &net_device->revoke_packet;
+ memset(revoke_packet, 0, sizeof(struct nvsp_message));
- drv->name = driver_name;
- memcpy(&drv->dev_type, &netvsc_device_type, sizeof(struct hv_guid));
+ revoke_packet->hdr.msg_type =
+ NVSP_MSG1_TYPE_REVOKE_RECV_BUF;
+ revoke_packet->msg.v1_msg.
+ revoke_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
- /* Setup the dispatch table */
- driver->base.dev_add = netvsc_device_add;
- driver->base.dev_rm = netvsc_device_remove;
- driver->base.cleanup = netvsc_cleanup;
+ ret = vmbus_sendpacket(net_device->dev->channel,
+ revoke_packet,
+ sizeof(struct nvsp_message),
+ (unsigned long)revoke_packet,
+ VM_PKT_DATA_INBAND, 0);
+ /*
+ * If we failed here, we might as well return and
+ * have a leak rather than continue and a bugchk
+ */
+ if (ret != 0) {
+ dev_err(&net_device->dev->device, "unable to send "
+ "revoke receive buffer to netvsp");
+ return -1;
+ }
+ }
- driver->send = netvsc_send;
+ /* Teardown the gpadl on the vsp end */
+ if (net_device->recv_buf_gpadl_handle) {
+ ret = vmbus_teardown_gpadl(net_device->dev->channel,
+ net_device->recv_buf_gpadl_handle);
- rndis_filter_init(driver);
- return 0;
+ /* If we failed here, we might as well return and have a leak
+ * rather than continue and a bugchk
+ */
+ if (ret != 0) {
+ dev_err(&net_device->dev->device,
+ "unable to teardown receive buffer's gpadl");
+ return -1;
+ }
+ net_device->recv_buf_gpadl_handle = 0;
+ }
+
+ if (net_device->recv_buf) {
+ /* Free up the receive buffer */
+ free_pages((unsigned long)net_device->recv_buf,
+ get_order(net_device->recv_buf_size));
+ net_device->recv_buf = NULL;
+ }
+
+ if (net_device->recv_section) {
+ net_device->recv_section_cnt = 0;
+ kfree(net_device->recv_section);
+ net_device->recv_section = NULL;
+ }
+
+ return ret;
}
static int netvsc_init_recv_buf(struct hv_device *device)
{
int ret = 0;
+ int t;
struct netvsc_device *net_device;
struct nvsp_message *init_packet;
net_device = get_outbound_net_device(device);
if (!net_device) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
+ dev_err(&device->device, "unable to get net device..."
"device being destroyed?");
return -1;
}
@@ -216,15 +226,12 @@ static int netvsc_init_recv_buf(struct hv_device *device)
(void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
get_order(net_device->recv_buf_size));
if (!net_device->recv_buf) {
- DPRINT_ERR(NETVSC,
- "unable to allocate receive buffer of size %d",
- net_device->recv_buf_size);
+ dev_err(&device->device, "unable to allocate receive "
+ "buffer of size %d", net_device->recv_buf_size);
ret = -1;
goto cleanup;
}
- DPRINT_INFO(NETVSC, "Establishing receive buffer's GPADL...");
-
/*
* Establish the gpadl handle for this buffer on this
* channel. Note: This call uses the vmbus connection rather
@@ -234,15 +241,13 @@ static int netvsc_init_recv_buf(struct hv_device *device)
net_device->recv_buf_size,
&net_device->recv_buf_gpadl_handle);
if (ret != 0) {
- DPRINT_ERR(NETVSC,
- "unable to establish receive buffer's gpadl");
+ dev_err(&device->device,
+ "unable to establish receive buffer's gpadl");
goto cleanup;
}
/* Notify the NetVsp of the gpadl handle */
- DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer...");
-
init_packet = &net_device->channel_init_pkt;
memset(init_packet, 0, sizeof(struct nvsp_message));
@@ -254,28 +259,25 @@ static int netvsc_init_recv_buf(struct hv_device *device)
send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
/* Send the gpadl notification request */
- net_device->wait_condition = 0;
ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
(unsigned long)init_packet,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
- DPRINT_ERR(NETVSC,
- "unable to send receive buffer's gpadl to netvsp");
+ dev_err(&device->device,
+ "unable to send receive buffer's gpadl to netvsp");
goto cleanup;
}
- wait_event_timeout(net_device->channel_init_wait,
- net_device->wait_condition,
- msecs_to_jiffies(1000));
- BUG_ON(net_device->wait_condition == 0);
+ t = wait_for_completion_timeout(&net_device->channel_init_wait, HZ);
+ BUG_ON(t == 0);
/* Check the response */
if (init_packet->msg.v1_msg.
send_recv_buf_complete.status != NVSP_STAT_SUCCESS) {
- DPRINT_ERR(NETVSC, "Unable to complete receive buffer "
+ dev_err(&device->device, "Unable to complete receive buffer "
"initialzation with NetVsp - status %d",
init_packet->msg.v1_msg.
send_recv_buf_complete.status);
@@ -301,14 +303,6 @@ static int netvsc_init_recv_buf(struct hv_device *device)
net_device->recv_section_cnt *
sizeof(struct nvsp_1_receive_buffer_section));
- DPRINT_INFO(NETVSC, "Receive sections info (count %d, offset %d, "
- "endoffset %d, suballoc size %d, num suballocs %d)",
- net_device->recv_section_cnt,
- net_device->recv_section[0].offset,
- net_device->recv_section[0].end_offset,
- net_device->recv_section[0].sub_alloc_size,
- net_device->recv_section[0].num_sub_allocs);
-
/*
* For 1st release, there should only be 1 section that represents the
* entire receive buffer
@@ -329,15 +323,80 @@ exit:
return ret;
}
+static int netvsc_destroy_send_buf(struct netvsc_device *net_device)
+{
+ struct nvsp_message *revoke_packet;
+ int ret = 0;
+
+ /*
+ * If we got a section count, it means we received a
+ * SendReceiveBufferComplete msg (ie sent
+ * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
+ * to send a revoke msg here
+ */
+ if (net_device->send_section_size) {
+ /* Send the revoke send buffer */
+ revoke_packet = &net_device->revoke_packet;
+ memset(revoke_packet, 0, sizeof(struct nvsp_message));
+
+ revoke_packet->hdr.msg_type =
+ NVSP_MSG1_TYPE_REVOKE_SEND_BUF;
+ revoke_packet->msg.v1_msg.
+ revoke_send_buf.id = NETVSC_SEND_BUFFER_ID;
+
+ ret = vmbus_sendpacket(net_device->dev->channel,
+ revoke_packet,
+ sizeof(struct nvsp_message),
+ (unsigned long)revoke_packet,
+ VM_PKT_DATA_INBAND, 0);
+ /*
+ * If we failed here, we might as well return and have a leak
+ * rather than continue and a bugchk
+ */
+ if (ret != 0) {
+ dev_err(&net_device->dev->device, "unable to send "
+ "revoke send buffer to netvsp");
+ return -1;
+ }
+ }
+
+ /* Teardown the gpadl on the vsp end */
+ if (net_device->send_buf_gpadl_handle) {
+ ret = vmbus_teardown_gpadl(net_device->dev->channel,
+ net_device->send_buf_gpadl_handle);
+
+ /*
+ * If we failed here, we might as well return and have a leak
+ * rather than continue and a bugchk
+ */
+ if (ret != 0) {
+ dev_err(&net_device->dev->device,
+ "unable to teardown send buffer's gpadl");
+ return -1;
+ }
+ net_device->send_buf_gpadl_handle = 0;
+ }
+
+ if (net_device->send_buf) {
+ /* Free up the receive buffer */
+ free_pages((unsigned long)net_device->send_buf,
+ get_order(net_device->send_buf_size));
+ net_device->send_buf = NULL;
+ }
+
+ return ret;
+}
+
static int netvsc_init_send_buf(struct hv_device *device)
{
int ret = 0;
+ int t;
struct netvsc_device *net_device;
struct nvsp_message *init_packet;
net_device = get_outbound_net_device(device);
if (!net_device) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
+ dev_err(&device->device, "unable to get net device..."
"device being destroyed?");
return -1;
}
@@ -350,14 +409,12 @@ static int netvsc_init_send_buf(struct hv_device *device)
(void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
get_order(net_device->send_buf_size));
if (!net_device->send_buf) {
- DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d",
- net_device->send_buf_size);
+ dev_err(&device->device, "unable to allocate send "
+ "buffer of size %d", net_device->send_buf_size);
ret = -1;
goto cleanup;
}
- DPRINT_INFO(NETVSC, "Establishing send buffer's GPADL...");
-
/*
* Establish the gpadl handle for this buffer on this
* channel. Note: This call uses the vmbus connection rather
@@ -367,13 +424,11 @@ static int netvsc_init_send_buf(struct hv_device *device)
net_device->send_buf_size,
&net_device->send_buf_gpadl_handle);
if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl");
+ dev_err(&device->device, "unable to establish send buffer's gpadl");
goto cleanup;
}
/* Notify the NetVsp of the gpadl handle */
- DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer...");
-
init_packet = &net_device->channel_init_pkt;
memset(init_packet, 0, sizeof(struct nvsp_message));
@@ -385,27 +440,25 @@ static int netvsc_init_send_buf(struct hv_device *device)
NETVSC_SEND_BUFFER_ID;
/* Send the gpadl notification request */
- net_device->wait_condition = 0;
ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
(unsigned long)init_packet,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
- DPRINT_ERR(NETVSC,
+ dev_err(&device->device,
"unable to send receive buffer's gpadl to netvsp");
goto cleanup;
}
- wait_event_timeout(net_device->channel_init_wait,
- net_device->wait_condition,
- msecs_to_jiffies(1000));
- BUG_ON(net_device->wait_condition == 0);
+ t = wait_for_completion_timeout(&net_device->channel_init_wait, HZ);
+
+ BUG_ON(t == 0);
/* Check the response */
if (init_packet->msg.v1_msg.
send_send_buf_complete.status != NVSP_STAT_SUCCESS) {
- DPRINT_ERR(NETVSC, "Unable to complete send buffer "
+ dev_err(&device->device, "Unable to complete send buffer "
"initialzation with NetVsp - status %d",
init_packet->msg.v1_msg.
send_send_buf_complete.status);
@@ -426,161 +479,17 @@ exit:
return ret;
}
-static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
-{
- struct nvsp_message *revoke_packet;
- int ret = 0;
-
- /*
- * If we got a section count, it means we received a
- * SendReceiveBufferComplete msg (ie sent
- * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
- * to send a revoke msg here
- */
- if (net_device->recv_section_cnt) {
- DPRINT_INFO(NETVSC,
- "Sending NvspMessage1TypeRevokeReceiveBuffer...");
-
- /* Send the revoke receive buffer */
- revoke_packet = &net_device->revoke_packet;
- memset(revoke_packet, 0, sizeof(struct nvsp_message));
-
- revoke_packet->hdr.msg_type =
- NVSP_MSG1_TYPE_REVOKE_RECV_BUF;
- revoke_packet->msg.v1_msg.
- revoke_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
-
- ret = vmbus_sendpacket(net_device->dev->channel,
- revoke_packet,
- sizeof(struct nvsp_message),
- (unsigned long)revoke_packet,
- VM_PKT_DATA_INBAND, 0);
- /*
- * If we failed here, we might as well return and
- * have a leak rather than continue and a bugchk
- */
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to send revoke receive "
- "buffer to netvsp");
- return -1;
- }
- }
-
- /* Teardown the gpadl on the vsp end */
- if (net_device->recv_buf_gpadl_handle) {
- DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL...");
-
- ret = vmbus_teardown_gpadl(net_device->dev->channel,
- net_device->recv_buf_gpadl_handle);
-
- /* If we failed here, we might as well return and have a leak rather than continue and a bugchk */
- if (ret != 0) {
- DPRINT_ERR(NETVSC,
- "unable to teardown receive buffer's gpadl");
- return -1;
- }
- net_device->recv_buf_gpadl_handle = 0;
- }
-
- if (net_device->recv_buf) {
- DPRINT_INFO(NETVSC, "Freeing up receive buffer...");
-
- /* Free up the receive buffer */
- free_pages((unsigned long)net_device->recv_buf,
- get_order(net_device->recv_buf_size));
- net_device->recv_buf = NULL;
- }
-
- if (net_device->recv_section) {
- net_device->recv_section_cnt = 0;
- kfree(net_device->recv_section);
- net_device->recv_section = NULL;
- }
-
- return ret;
-}
-
-static int netvsc_destroy_send_buf(struct netvsc_device *net_device)
-{
- struct nvsp_message *revoke_packet;
- int ret = 0;
-
- /*
- * If we got a section count, it means we received a
- * SendReceiveBufferComplete msg (ie sent
- * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
- * to send a revoke msg here
- */
- if (net_device->send_section_size) {
- DPRINT_INFO(NETVSC,
- "Sending NvspMessage1TypeRevokeSendBuffer...");
-
- /* Send the revoke send buffer */
- revoke_packet = &net_device->revoke_packet;
- memset(revoke_packet, 0, sizeof(struct nvsp_message));
-
- revoke_packet->hdr.msg_type =
- NVSP_MSG1_TYPE_REVOKE_SEND_BUF;
- revoke_packet->msg.v1_msg.
- revoke_send_buf.id = NETVSC_SEND_BUFFER_ID;
-
- ret = vmbus_sendpacket(net_device->dev->channel,
- revoke_packet,
- sizeof(struct nvsp_message),
- (unsigned long)revoke_packet,
- VM_PKT_DATA_INBAND, 0);
- /*
- * If we failed here, we might as well return and have a leak
- * rather than continue and a bugchk
- */
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to send revoke send buffer "
- "to netvsp");
- return -1;
- }
- }
-
- /* Teardown the gpadl on the vsp end */
- if (net_device->send_buf_gpadl_handle) {
- DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL...");
- ret = vmbus_teardown_gpadl(net_device->dev->channel,
- net_device->send_buf_gpadl_handle);
-
- /*
- * If we failed here, we might as well return and have a leak
- * rather than continue and a bugchk
- */
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to teardown send buffer's "
- "gpadl");
- return -1;
- }
- net_device->send_buf_gpadl_handle = 0;
- }
-
- if (net_device->send_buf) {
- DPRINT_INFO(NETVSC, "Freeing up send buffer...");
-
- /* Free up the receive buffer */
- free_pages((unsigned long)net_device->send_buf,
- get_order(net_device->send_buf_size));
- net_device->send_buf = NULL;
- }
-
- return ret;
-}
-
static int netvsc_connect_vsp(struct hv_device *device)
{
- int ret;
+ int ret, t;
struct netvsc_device *net_device;
struct nvsp_message *init_packet;
int ndis_version;
net_device = get_outbound_net_device(device);
if (!net_device) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
+ dev_err(&device->device, "unable to get net device..."
"device being destroyed?");
return -1;
}
@@ -594,54 +503,34 @@ static int netvsc_connect_vsp(struct hv_device *device)
init_packet->msg.init_msg.init.max_protocol_ver =
NVSP_MAX_PROTOCOL_VERSION;
- DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit...");
-
/* Send the init request */
- net_device->wait_condition = 0;
ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
(unsigned long)init_packet,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to send NvspMessageTypeInit");
+ if (ret != 0)
goto cleanup;
- }
- wait_event_timeout(net_device->channel_init_wait,
- net_device->wait_condition,
- msecs_to_jiffies(1000));
- if (net_device->wait_condition == 0) {
+ t = wait_for_completion_timeout(&net_device->channel_init_wait, HZ);
+
+ if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
}
- DPRINT_INFO(NETVSC, "NvspMessageTypeInit status(%d) max mdl chain (%d)",
- init_packet->msg.init_msg.init_complete.status,
- init_packet->msg.init_msg.
- init_complete.max_mdl_chain_len);
-
if (init_packet->msg.init_msg.init_complete.status !=
NVSP_STAT_SUCCESS) {
- DPRINT_ERR(NETVSC,
- "unable to initialize with netvsp (status 0x%x)",
- init_packet->msg.init_msg.init_complete.status);
ret = -1;
goto cleanup;
}
if (init_packet->msg.init_msg.init_complete.
negotiated_protocol_ver != NVSP_PROTOCOL_VERSION_1) {
- DPRINT_ERR(NETVSC, "unable to initialize with netvsp "
- "(version expected 1 got %d)",
- init_packet->msg.init_msg.
- init_complete.negotiated_protocol_ver);
ret = -1;
goto cleanup;
}
- DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendNdisVersion...");
-
/* Send the ndis version */
memset(init_packet, 0, sizeof(struct nvsp_message));
@@ -661,8 +550,6 @@ static int netvsc_connect_vsp(struct hv_device *device)
(unsigned long)init_packet,
VM_PKT_DATA_INBAND, 0);
if (ret != 0) {
- DPRINT_ERR(NETVSC,
- "unable to send NvspMessage1TypeSendNdisVersion");
ret = -1;
goto cleanup;
}
@@ -677,143 +564,42 @@ cleanup:
return ret;
}
-static void NetVscDisconnectFromVsp(struct netvsc_device *net_device)
+static void netvsc_disconnect_vsp(struct netvsc_device *net_device)
{
netvsc_destroy_recv_buf(net_device);
netvsc_destroy_send_buf(net_device);
}
/*
- * netvsc_device_add - Callback when the device belonging to this
- * driver is added
- */
-static int netvsc_device_add(struct hv_device *device, void *additional_info)
-{
- int ret = 0;
- int i;
- struct netvsc_device *net_device;
- struct hv_netvsc_packet *packet, *pos;
- struct netvsc_driver *net_driver =
- (struct netvsc_driver *)device->drv;
-
- net_device = alloc_net_device(device);
- if (!net_device) {
- ret = -1;
- goto cleanup;
- }
-
- DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", net_device);
-
- /* Initialize the NetVSC channel extension */
- net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
- spin_lock_init(&net_device->recv_pkt_list_lock);
-
- net_device->send_buf_size = NETVSC_SEND_BUFFER_SIZE;
-
- INIT_LIST_HEAD(&net_device->recv_pkt_list);
-
- for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
- packet = kzalloc(sizeof(struct hv_netvsc_packet) +
- (NETVSC_RECEIVE_SG_COUNT *
- sizeof(struct hv_page_buffer)), GFP_KERNEL);
- if (!packet) {
- DPRINT_DBG(NETVSC, "unable to allocate netvsc pkts "
- "for receive pool (wanted %d got %d)",
- NETVSC_RECEIVE_PACKETLIST_COUNT, i);
- break;
- }
- list_add_tail(&packet->list_ent,
- &net_device->recv_pkt_list);
- }
- init_waitqueue_head(&net_device->channel_init_wait);
-
- /* Open the channel */
- ret = vmbus_open(device->channel, net_driver->ring_buf_size,
- net_driver->ring_buf_size, NULL, 0,
- netvsc_channel_cb, device);
-
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to open channel: %d", ret);
- ret = -1;
- goto cleanup;
- }
-
- /* Channel is opened */
- DPRINT_INFO(NETVSC, "*** NetVSC channel opened successfully! ***");
-
- /* Connect with the NetVsp */
- ret = netvsc_connect_vsp(device);
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret);
- ret = -1;
- goto close;
- }
-
- DPRINT_INFO(NETVSC, "*** NetVSC channel handshake result - %d ***",
- ret);
-
- return ret;
-
-close:
- /* Now, we can close the channel safely */
- vmbus_close(device->channel);
-
-cleanup:
-
- if (net_device) {
- list_for_each_entry_safe(packet, pos,
- &net_device->recv_pkt_list,
- list_ent) {
- list_del(&packet->list_ent);
- kfree(packet);
- }
-
- release_outbound_net_device(device);
- release_inbound_net_device(device);
-
- free_net_device(net_device);
- }
-
- return ret;
-}
-
-/*
* netvsc_device_remove - Callback when the root bus device is removed
*/
-static int netvsc_device_remove(struct hv_device *device)
+int netvsc_device_remove(struct hv_device *device)
{
struct netvsc_device *net_device;
struct hv_netvsc_packet *netvsc_packet, *pos;
- DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...",
- device->ext);
-
/* Stop outbound traffic ie sends and receives completions */
net_device = release_outbound_net_device(device);
if (!net_device) {
- DPRINT_ERR(NETVSC, "No net device present!!");
+ dev_err(&device->device, "No net device present!!");
return -1;
}
/* Wait for all send completions */
while (atomic_read(&net_device->num_outstanding_sends)) {
- DPRINT_INFO(NETVSC, "waiting for %d requests to complete...",
- atomic_read(&net_device->num_outstanding_sends));
+ dev_err(&device->device,
+ "waiting for %d requests to complete...",
+ atomic_read(&net_device->num_outstanding_sends));
udelay(100);
}
- DPRINT_INFO(NETVSC, "Disconnecting from netvsp...");
-
- NetVscDisconnectFromVsp(net_device);
-
- DPRINT_INFO(NETVSC, "Disabling inbound traffic on net device (%p)...",
- device->ext);
+ netvsc_disconnect_vsp(net_device);
/* Stop inbound traffic ie receives and sends completions */
net_device = release_inbound_net_device(device);
/* At this point, no one should be accessing netDevice except in here */
- DPRINT_INFO(NETVSC, "net device (%p) safe to remove", net_device);
+ dev_notice(&device->device, "net device safe to remove");
/* Now, we can close the channel safely */
vmbus_close(device->channel);
@@ -829,13 +615,6 @@ static int netvsc_device_remove(struct hv_device *device)
return 0;
}
-/*
- * netvsc_cleanup - Perform any cleanup when the driver is removed
- */
-static void netvsc_cleanup(struct hv_driver *drv)
-{
-}
-
static void netvsc_send_completion(struct hv_device *device,
struct vmpacket_descriptor *packet)
{
@@ -845,7 +624,7 @@ static void netvsc_send_completion(struct hv_device *device,
net_device = get_inbound_net_device(device);
if (!net_device) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
+ dev_err(&device->device, "unable to get net device..."
"device being destroyed?");
return;
}
@@ -853,9 +632,6 @@ static void netvsc_send_completion(struct hv_device *device,
nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
(packet->offset8 << 3));
- DPRINT_DBG(NETVSC, "send completion packet - type %d",
- nvsp_packet->hdr.msg_type);
-
if ((nvsp_packet->hdr.msg_type == NVSP_MSG_TYPE_INIT_COMPLETE) ||
(nvsp_packet->hdr.msg_type ==
NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) ||
@@ -864,8 +640,7 @@ static void netvsc_send_completion(struct hv_device *device,
/* Copy the response back */
memcpy(&net_device->channel_init_pkt, nvsp_packet,
sizeof(struct nvsp_message));
- net_device->wait_condition = 1;
- wake_up(&net_device->channel_init_wait);
+ complete(&net_device->channel_init_wait);
} else if (nvsp_packet->hdr.msg_type ==
NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) {
/* Get the send context */
@@ -878,14 +653,14 @@ static void netvsc_send_completion(struct hv_device *device,
atomic_dec(&net_device->num_outstanding_sends);
} else {
- DPRINT_ERR(NETVSC, "Unknown send completion packet type - "
+ dev_err(&device->device, "Unknown send completion packet type- "
"%d received!!", nvsp_packet->hdr.msg_type);
}
put_net_device(device);
}
-static int netvsc_send(struct hv_device *device,
+int netvsc_send(struct hv_device *device,
struct hv_netvsc_packet *packet)
{
struct netvsc_device *net_device;
@@ -895,7 +670,7 @@ static int netvsc_send(struct hv_device *device,
net_device = get_outbound_net_device(device);
if (!net_device) {
- DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
+ dev_err(&device->device, "net device (%p) shutting down..."
"ignoring outbound packets", net_device);
return -2;
}
@@ -931,7 +706,7 @@ static int netvsc_send(struct hv_device *device,
}
if (ret != 0)
- DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d",
+ dev_err(&device->device, "Unable to send packet %p ret %d",
packet, ret);
atomic_inc(&net_device->num_outstanding_sends);
@@ -939,6 +714,98 @@ static int netvsc_send(struct hv_device *device,
return ret;
}
+static void netvsc_send_recv_completion(struct hv_device *device,
+ u64 transaction_id)
+{
+ struct nvsp_message recvcompMessage;
+ int retries = 0;
+ int ret;
+
+ recvcompMessage.hdr.msg_type =
+ NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE;
+
+ /* FIXME: Pass in the status */
+ recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status =
+ NVSP_STAT_SUCCESS;
+
+retry_send_cmplt:
+ /* Send the completion */
+ ret = vmbus_sendpacket(device->channel, &recvcompMessage,
+ sizeof(struct nvsp_message), transaction_id,
+ VM_PKT_COMP, 0);
+ if (ret == 0) {
+ /* success */
+ /* no-op */
+ } else if (ret == -1) {
+ /* no more room...wait a bit and attempt to retry 3 times */
+ retries++;
+ dev_err(&device->device, "unable to send receive completion pkt"
+ " (tid %llx)...retrying %d", transaction_id, retries);
+
+ if (retries < 4) {
+ udelay(100);
+ goto retry_send_cmplt;
+ } else {
+ dev_err(&device->device, "unable to send receive "
+ "completion pkt (tid %llx)...give up retrying",
+ transaction_id);
+ }
+ } else {
+ dev_err(&device->device, "unable to send receive "
+ "completion pkt - %llx", transaction_id);
+ }
+}
+
+/* Send a receive completion packet to RNDIS device (ie NetVsp) */
+static void netvsc_receive_completion(void *context)
+{
+ struct hv_netvsc_packet *packet = context;
+ struct hv_device *device = (struct hv_device *)packet->device;
+ struct netvsc_device *net_device;
+ u64 transaction_id = 0;
+ bool fsend_receive_comp = false;
+ unsigned long flags;
+
+ /*
+ * Even though it seems logical to do a GetOutboundNetDevice() here to
+ * send out receive completion, we are using GetInboundNetDevice()
+ * since we may have disable outbound traffic already.
+ */
+ net_device = get_inbound_net_device(device);
+ if (!net_device) {
+ dev_err(&device->device, "unable to get net device..."
+ "device being destroyed?");
+ return;
+ }
+
+ /* Overloading use of the lock. */
+ spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
+
+ packet->xfer_page_pkt->count--;
+
+ /*
+ * Last one in the line that represent 1 xfer page packet.
+ * Return the xfer page packet itself to the freelist
+ */
+ if (packet->xfer_page_pkt->count == 0) {
+ fsend_receive_comp = true;
+ transaction_id = packet->completion.recv.recv_completion_tid;
+ list_add_tail(&packet->xfer_page_pkt->list_ent,
+ &net_device->recv_pkt_list);
+
+ }
+
+ /* Put the packet back */
+ list_add_tail(&packet->list_ent, &net_device->recv_pkt_list);
+ spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
+
+ /* Send a receive completion for the xfer page packet */
+ if (fsend_receive_comp)
+ netvsc_send_recv_completion(device, transaction_id);
+
+ put_net_device(device);
+}
+
static void netvsc_receive(struct hv_device *device,
struct vmpacket_descriptor *packet)
{
@@ -953,11 +820,12 @@ static void netvsc_receive(struct hv_device *device,
int i, j;
int count = 0, bytes_remain = 0;
unsigned long flags;
+
LIST_HEAD(listHead);
net_device = get_inbound_net_device(device);
if (!net_device) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
+ dev_err(&device->device, "unable to get net device..."
"device being destroyed?");
return;
}
@@ -967,7 +835,7 @@ static void netvsc_receive(struct hv_device *device,
* packet
*/
if (packet->type != VM_PKT_DATA_USING_XFER_PAGES) {
- DPRINT_ERR(NETVSC, "Unknown packet type received - %d",
+ dev_err(&device->device, "Unknown packet type received - %d",
packet->type);
put_net_device(device);
return;
@@ -979,28 +847,22 @@ static void netvsc_receive(struct hv_device *device,
/* Make sure this is a valid nvsp packet */
if (nvsp_packet->hdr.msg_type !=
NVSP_MSG1_TYPE_SEND_RNDIS_PKT) {
- DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d",
- nvsp_packet->hdr.msg_type);
+ dev_err(&device->device, "Unknown nvsp packet type received-"
+ " %d", nvsp_packet->hdr.msg_type);
put_net_device(device);
return;
}
- DPRINT_DBG(NETVSC, "NVSP packet received - type %d",
- nvsp_packet->hdr.msg_type);
-
vmxferpage_packet = (struct vmtransfer_page_packet_header *)packet;
if (vmxferpage_packet->xfer_pageset_id != NETVSC_RECEIVE_BUFFER_ID) {
- DPRINT_ERR(NETVSC, "Invalid xfer page set id - "
+ dev_err(&device->device, "Invalid xfer page set id - "
"expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID,
vmxferpage_packet->xfer_pageset_id);
put_net_device(device);
return;
}
- DPRINT_DBG(NETVSC, "xfer page - range count %d",
- vmxferpage_packet->range_cnt);
-
/*
* Grab free packets (range count + 1) to represent this xfer
* page packet. +1 to represent the xfer page packet itself.
@@ -1021,9 +883,9 @@ static void netvsc_receive(struct hv_device *device,
* some of the xfer page packet ranges...
*/
if (count < 2) {
- DPRINT_ERR(NETVSC, "Got only %d netvsc pkt...needed %d pkts. "
- "Dropping this xfer page packet completely!",
- count, vmxferpage_packet->range_cnt + 1);
+ dev_err(&device->device, "Got only %d netvsc pkt...needed "
+ "%d pkts. Dropping this xfer page packet completely!",
+ count, vmxferpage_packet->range_cnt + 1);
/* Return it to the freelist */
spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
@@ -1049,9 +911,9 @@ static void netvsc_receive(struct hv_device *device,
xferpage_packet->count = count - 1;
if (xferpage_packet->count != vmxferpage_packet->range_cnt) {
- DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer "
- "page...got %d", vmxferpage_packet->range_cnt,
- xferpage_packet->count);
+ dev_err(&device->device, "Needed %d netvsc pkts to satisy "
+ "this xfer page...got %d",
+ vmxferpage_packet->range_cnt, xferpage_packet->count);
}
/* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
@@ -1117,17 +979,9 @@ static void netvsc_receive(struct hv_device *device,
break;
}
}
- DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => "
- "(pfn %llx, offset %u, len %u)", i,
- vmxferpage_packet->ranges[i].byte_offset,
- vmxferpage_packet->ranges[i].byte_count,
- netvsc_packet->page_buf[0].pfn,
- netvsc_packet->page_buf[0].offset,
- netvsc_packet->page_buf[0].len);
/* Pass it to the upper layer */
- ((struct netvsc_driver *)device->drv)->
- recv_cb(device, netvsc_packet);
+ rndis_filter_receive(device, netvsc_packet);
netvsc_receive_completion(netvsc_packet->
completion.recv.recv_completion_ctx);
@@ -1136,101 +990,6 @@ static void netvsc_receive(struct hv_device *device,
put_net_device(device);
}
-static void netvsc_send_recv_completion(struct hv_device *device,
- u64 transaction_id)
-{
- struct nvsp_message recvcompMessage;
- int retries = 0;
- int ret;
-
- DPRINT_DBG(NETVSC, "Sending receive completion pkt - %llx",
- transaction_id);
-
- recvcompMessage.hdr.msg_type =
- NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE;
-
- /* FIXME: Pass in the status */
- recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status =
- NVSP_STAT_SUCCESS;
-
-retry_send_cmplt:
- /* Send the completion */
- ret = vmbus_sendpacket(device->channel, &recvcompMessage,
- sizeof(struct nvsp_message), transaction_id,
- VM_PKT_COMP, 0);
- if (ret == 0) {
- /* success */
- /* no-op */
- } else if (ret == -1) {
- /* no more room...wait a bit and attempt to retry 3 times */
- retries++;
- DPRINT_ERR(NETVSC, "unable to send receive completion pkt "
- "(tid %llx)...retrying %d", transaction_id, retries);
-
- if (retries < 4) {
- udelay(100);
- goto retry_send_cmplt;
- } else {
- DPRINT_ERR(NETVSC, "unable to send receive completion "
- "pkt (tid %llx)...give up retrying",
- transaction_id);
- }
- } else {
- DPRINT_ERR(NETVSC, "unable to send receive completion pkt - "
- "%llx", transaction_id);
- }
-}
-
-/* Send a receive completion packet to RNDIS device (ie NetVsp) */
-static void netvsc_receive_completion(void *context)
-{
- struct hv_netvsc_packet *packet = context;
- struct hv_device *device = (struct hv_device *)packet->device;
- struct netvsc_device *net_device;
- u64 transaction_id = 0;
- bool fsend_receive_comp = false;
- unsigned long flags;
-
- /*
- * Even though it seems logical to do a GetOutboundNetDevice() here to
- * send out receive completion, we are using GetInboundNetDevice()
- * since we may have disable outbound traffic already.
- */
- net_device = get_inbound_net_device(device);
- if (!net_device) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
- "device being destroyed?");
- return;
- }
-
- /* Overloading use of the lock. */
- spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
-
- packet->xfer_page_pkt->count--;
-
- /*
- * Last one in the line that represent 1 xfer page packet.
- * Return the xfer page packet itself to the freelist
- */
- if (packet->xfer_page_pkt->count == 0) {
- fsend_receive_comp = true;
- transaction_id = packet->completion.recv.recv_completion_tid;
- list_add_tail(&packet->xfer_page_pkt->list_ent,
- &net_device->recv_pkt_list);
-
- }
-
- /* Put the packet back */
- list_add_tail(&packet->list_ent, &net_device->recv_pkt_list);
- spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
-
- /* Send a receive completion for the xfer page packet */
- if (fsend_receive_comp)
- netvsc_send_recv_completion(device, transaction_id);
-
- put_net_device(device);
-}
-
static void netvsc_channel_cb(void *context)
{
int ret;
@@ -1251,7 +1010,7 @@ static void netvsc_channel_cb(void *context)
net_device = get_inbound_net_device(device);
if (!net_device) {
- DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
+ dev_err(&device->device, "net device (%p) shutting down..."
"ignoring inbound packets", net_device);
goto out;
}
@@ -1261,9 +1020,6 @@ static void netvsc_channel_cb(void *context)
&bytes_recvd, &request_id);
if (ret == 0) {
if (bytes_recvd > 0) {
- DPRINT_DBG(NETVSC, "receive %d bytes, tid %llx",
- bytes_recvd, request_id);
-
desc = (struct vmpacket_descriptor *)buffer;
switch (desc->type) {
case VM_PKT_COMP:
@@ -1275,7 +1031,7 @@ static void netvsc_channel_cb(void *context)
break;
default:
- DPRINT_ERR(NETVSC,
+ dev_err(&device->device,
"unhandled packet type %d, "
"tid %llx len %d\n",
desc->type, request_id,
@@ -1304,7 +1060,7 @@ static void netvsc_channel_cb(void *context)
buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
if (buffer == NULL) {
/* Try again next time around */
- DPRINT_ERR(NETVSC,
+ dev_err(&device->device,
"unable to allocate buffer of size "
"(%d)!!", bytes_recvd);
break;
@@ -1319,3 +1075,102 @@ out:
kfree(buffer);
return;
}
+
+/*
+ * netvsc_device_add - Callback when the device belonging to this
+ * driver is added
+ */
+int netvsc_device_add(struct hv_device *device, void *additional_info)
+{
+ int ret = 0;
+ int i;
+ int ring_size =
+ ((struct netvsc_device_info *)additional_info)->ring_size;
+ struct netvsc_device *net_device;
+ struct hv_netvsc_packet *packet, *pos;
+
+ net_device = alloc_net_device(device);
+ if (!net_device) {
+ ret = -1;
+ goto cleanup;
+ }
+
+ /* Initialize the NetVSC channel extension */
+ net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
+ spin_lock_init(&net_device->recv_pkt_list_lock);
+
+ net_device->send_buf_size = NETVSC_SEND_BUFFER_SIZE;
+
+ INIT_LIST_HEAD(&net_device->recv_pkt_list);
+
+ for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
+ packet = kzalloc(sizeof(struct hv_netvsc_packet) +
+ (NETVSC_RECEIVE_SG_COUNT *
+ sizeof(struct hv_page_buffer)), GFP_KERNEL);
+ if (!packet)
+ break;
+
+ list_add_tail(&packet->list_ent,
+ &net_device->recv_pkt_list);
+ }
+ init_completion(&net_device->channel_init_wait);
+
+ /* Open the channel */
+ ret = vmbus_open(device->channel, ring_size * PAGE_SIZE,
+ ring_size * PAGE_SIZE, NULL, 0,
+ netvsc_channel_cb, device);
+
+ if (ret != 0) {
+ dev_err(&device->device, "unable to open channel: %d", ret);
+ ret = -1;
+ goto cleanup;
+ }
+
+ /* Channel is opened */
+ pr_info("hv_netvsc channel opened successfully");
+
+ /* Connect with the NetVsp */
+ ret = netvsc_connect_vsp(device);
+ if (ret != 0) {
+ dev_err(&device->device,
+ "unable to connect to NetVSP - %d", ret);
+ ret = -1;
+ goto close;
+ }
+
+ return ret;
+
+close:
+ /* Now, we can close the channel safely */
+ vmbus_close(device->channel);
+
+cleanup:
+
+ if (net_device) {
+ list_for_each_entry_safe(packet, pos,
+ &net_device->recv_pkt_list,
+ list_ent) {
+ list_del(&packet->list_ent);
+ kfree(packet);
+ }
+
+ release_outbound_net_device(device);
+ release_inbound_net_device(device);
+
+ free_net_device(net_device);
+ }
+
+ return ret;
+}
+
+/*
+ * netvsc_initialize - Main entry point
+ */
+int netvsc_initialize(struct hv_driver *drv)
+{
+
+ drv->name = driver_name;
+ memcpy(&drv->dev_type, &netvsc_device_type, sizeof(struct hv_guid));
+
+ return 0;
+}
diff --git a/drivers/staging/hv/netvsc.h b/drivers/staging/hv/netvsc.h
deleted file mode 100644
index 45d24b9d91a1..000000000000
--- a/drivers/staging/hv/netvsc.h
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _NETVSC_H_
-#define _NETVSC_H_
-
-#include <linux/list.h>
-#include "vmbus_packet_format.h"
-#include "vmbus_channel_interface.h"
-#include "netvsc_api.h"
-
-
-#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
-
-enum {
- NVSP_MSG_TYPE_NONE = 0,
-
- /* Init Messages */
- NVSP_MSG_TYPE_INIT = 1,
- NVSP_MSG_TYPE_INIT_COMPLETE = 2,
-
- NVSP_VERSION_MSG_START = 100,
-
- /* Version 1 Messages */
- NVSP_MSG1_TYPE_SEND_NDIS_VER = NVSP_VERSION_MSG_START,
-
- NVSP_MSG1_TYPE_SEND_RECV_BUF,
- NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE,
- NVSP_MSG1_TYPE_REVOKE_RECV_BUF,
-
- NVSP_MSG1_TYPE_SEND_SEND_BUF,
- NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE,
- NVSP_MSG1_TYPE_REVOKE_SEND_BUF,
-
- 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,
-};
-
-enum {
- NVSP_STAT_NONE = 0,
- NVSP_STAT_SUCCESS,
- NVSP_STAT_FAIL,
- NVSP_STAT_PROTOCOL_TOO_NEW,
- NVSP_STAT_PROTOCOL_TOO_OLD,
- NVSP_STAT_INVALID_RNDIS_PKT,
- NVSP_STAT_BUSY,
- NVSP_STAT_MAX,
-};
-
-struct nvsp_message_header {
- u32 msg_type;
-};
-
-/* Init Messages */
-
-/*
- * This message is used by the VSC to initialize the channel after the channels
- * has been opened. This message should never include anything other then
- * versioning (i.e. this message will be the same for ever).
- */
-struct nvsp_message_init {
- u32 min_protocol_ver;
- u32 max_protocol_ver;
-} __packed;
-
-/*
- * This message is used by the VSP to complete the initialization of the
- * channel. This message should never include anything other then versioning
- * (i.e. this message will be the same for ever).
- */
-struct nvsp_message_init_complete {
- u32 negotiated_protocol_ver;
- u32 max_mdl_chain_len;
- u32 status;
-} __packed;
-
-union nvsp_message_init_uber {
- struct nvsp_message_init init;
- struct nvsp_message_init_complete init_complete;
-} __packed;
-
-/* Version 1 Messages */
-
-/*
- * This message is used by the VSC to send the NDIS version to the VSP. The VSP
- * can use this information when handling OIDs sent by the VSC.
- */
-struct nvsp_1_message_send_ndis_version {
- u32 ndis_major_ver;
- u32 ndis_minor_ver;
-} __packed;
-
-/*
- * This message is used by the VSC to send a receive buffer to the VSP. The VSP
- * can then use the receive buffer to send data to the VSC.
- */
-struct nvsp_1_message_send_receive_buffer {
- u32 gpadl_handle;
- u16 id;
-} __packed;
-
-struct nvsp_1_receive_buffer_section {
- u32 offset;
- u32 sub_alloc_size;
- u32 num_sub_allocs;
- u32 end_offset;
-} __packed;
-
-/*
- * This message is used by the VSP to acknowledge a receive buffer send by the
- * VSC. This message must be sent by the VSP before the VSP uses the receive
- * buffer.
- */
-struct nvsp_1_message_send_receive_buffer_complete {
- u32 status;
- u32 num_sections;
-
- /*
- * The receive buffer is split into two parts, a large suballocation
- * section and a small suballocation section. These sections are then
- * suballocated by a certain size.
- */
-
- /*
- * For example, the following break up of the receive buffer has 6
- * large suballocations and 10 small suballocations.
- */
-
- /*
- * | Large Section | | Small Section |
- * ------------------------------------------------------------
- * | | | | | | | | | | | | | | | | | |
- * | |
- * LargeOffset SmallOffset
- */
-
- struct nvsp_1_receive_buffer_section sections[1];
-} __packed;
-
-/*
- * This message is sent by the VSC to revoke the receive buffer. After the VSP
- * completes this transaction, the vsp should never use the receive buffer
- * again.
- */
-struct nvsp_1_message_revoke_receive_buffer {
- u16 id;
-};
-
-/*
- * This message is used by the VSC to send a send buffer to the VSP. The VSC
- * can then use the send buffer to send data to the VSP.
- */
-struct nvsp_1_message_send_send_buffer {
- u32 gpadl_handle;
- u16 id;
-} __packed;
-
-/*
- * This message is used by the VSP to acknowledge a send buffer sent by the
- * VSC. This message must be sent by the VSP before the VSP uses the sent
- * buffer.
- */
-struct nvsp_1_message_send_send_buffer_complete {
- u32 status;
-
- /*
- * The VSC gets to choose the size of the send buffer and the VSP gets
- * to choose the sections size of the buffer. This was done to enable
- * dynamic reconfigurations when the cost of GPA-direct buffers
- * decreases.
- */
- u32 section_size;
-} __packed;
-
-/*
- * This message is sent by the VSC to revoke the send buffer. After the VSP
- * completes this transaction, the vsp should never use the send buffer again.
- */
-struct nvsp_1_message_revoke_send_buffer {
- u16 id;
-};
-
-/*
- * This message is used by both the VSP and the VSC to send a RNDIS message to
- * the opposite channel endpoint.
- */
-struct nvsp_1_message_send_rndis_packet {
- /*
- * This field is specified by RNIDS. They assume there's two different
- * channels of communication. However, the Network VSP only has one.
- * Therefore, the channel travels with the RNDIS packet.
- */
- u32 channel_type;
-
- /*
- * This field is used to send part or all of the data through a send
- * buffer. This values specifies an index into the send buffer. If the
- * index is 0xFFFFFFFF, then the send buffer is not being used and all
- * of the data was sent through other VMBus mechanisms.
- */
- u32 send_buf_section_index;
- u32 send_buf_section_size;
-} __packed;
-
-/*
- * This message is used by both the VSP and the VSC to complete a RNDIS message
- * to the opposite channel endpoint. At this point, the initiator of this
- * message cannot use any resources associated with the original RNDIS packet.
- */
-struct nvsp_1_message_send_rndis_packet_complete {
- u32 status;
-};
-
-union nvsp_1_message_uber {
- struct nvsp_1_message_send_ndis_version send_ndis_ver;
-
- struct nvsp_1_message_send_receive_buffer send_recv_buf;
- struct nvsp_1_message_send_receive_buffer_complete
- send_recv_buf_complete;
- struct nvsp_1_message_revoke_receive_buffer revoke_recv_buf;
-
- struct nvsp_1_message_send_send_buffer send_send_buf;
- struct nvsp_1_message_send_send_buffer_complete send_send_buf_complete;
- struct nvsp_1_message_revoke_send_buffer revoke_send_buf;
-
- struct nvsp_1_message_send_rndis_packet send_rndis_pkt;
- struct nvsp_1_message_send_rndis_packet_complete
- send_rndis_pkt_complete;
-} __packed;
-
-union nvsp_all_messages {
- union nvsp_message_init_uber init_msg;
- union nvsp_1_message_uber v1_msg;
-} __packed;
-
-/* ALL Messages */
-struct nvsp_message {
- struct nvsp_message_header hdr;
- union nvsp_all_messages msg;
-} __packed;
-
-
-
-
-/* #define NVSC_MIN_PROTOCOL_VERSION 1 */
-/* #define NVSC_MAX_PROTOCOL_VERSION 1 */
-
-#define NETVSC_SEND_BUFFER_SIZE (64*1024) /* 64K */
-#define NETVSC_SEND_BUFFER_ID 0xface
-
-
-#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024) /* 1MB */
-
-#define NETVSC_RECEIVE_BUFFER_ID 0xcafe
-
-#define NETVSC_RECEIVE_SG_COUNT 1
-
-/* Preallocated receive packets */
-#define NETVSC_RECEIVE_PACKETLIST_COUNT 256
-
-#define NETVSC_PACKET_SIZE 2048
-
-/* Per netvsc channel-specific */
-struct netvsc_device {
- struct hv_device *dev;
-
- atomic_t refcnt;
- atomic_t num_outstanding_sends;
- /*
- * List of free preallocated hv_netvsc_packet to represent receive
- * packet
- */
- struct list_head recv_pkt_list;
- spinlock_t recv_pkt_list_lock;
-
- /* Send buffer allocated by us but manages by NetVSP */
- void *send_buf;
- u32 send_buf_size;
- u32 send_buf_gpadl_handle;
- u32 send_section_size;
-
- /* Receive buffer allocated by us but manages by NetVSP */
- void *recv_buf;
- u32 recv_buf_size;
- u32 recv_buf_gpadl_handle;
- u32 recv_section_cnt;
- struct nvsp_1_receive_buffer_section *recv_section;
-
- /* Used for NetVSP initialization protocol */
- int wait_condition;
- wait_queue_head_t channel_init_wait;
- struct nvsp_message channel_init_pkt;
-
- struct nvsp_message revoke_packet;
- /* unsigned char HwMacAddr[HW_MACADDR_LEN]; */
-
- /* Holds rndis device info */
- void *extension;
-};
-
-#endif /* _NETVSC_H_ */
diff --git a/drivers/staging/hv/netvsc_api.h b/drivers/staging/hv/netvsc_api.h
deleted file mode 100644
index b4bed3636594..000000000000
--- a/drivers/staging/hv/netvsc_api.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _NETVSC_API_H_
-#define _NETVSC_API_H_
-
-#include "vmbus_api.h"
-
-/* Fwd declaration */
-struct hv_netvsc_packet;
-
-/* Represent the xfer page packet which contains 1 or more netvsc packet */
-struct xferpage_packet {
- struct list_head list_ent;
-
- /* # of netvsc packets this xfer packet contains */
- 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
- */
-struct hv_netvsc_packet {
- /* Bookkeeping stuff */
- struct list_head list_ent;
-
- struct hv_device *device;
- bool is_data_pkt;
-
- /*
- * Valid only for receives when we break a xfer page packet
- * into multiple netvsc packets
- */
- struct xferpage_packet *xfer_page_pkt;
-
- union {
- struct{
- u64 recv_completion_tid;
- void *recv_completion_ctx;
- void (*recv_completion)(void *context);
- } recv;
- struct{
- u64 send_completion_tid;
- void *send_completion_ctx;
- void (*send_completion)(void *context);
- } send;
- } completion;
-
- /* This points to the memory after page_buf */
- void *extension;
-
- u32 total_data_buflen;
- /* Points to the send/receive buffer where the ethernet frame is */
- u32 page_buf_cnt;
- struct hv_page_buffer page_buf[NETVSC_PACKET_MAXPAGE];
-};
-
-/* Represents the net vsc driver */
-struct netvsc_driver {
- /* Must be the first field */
- /* Which is a bug FIXME! */
- struct hv_driver base;
-
- u32 ring_buf_size;
- u32 req_ext_size;
-
- /*
- * This is set by the caller to allow us to callback when we
- * receive a packet from the "wire"
- */
- int (*recv_cb)(struct hv_device *dev,
- struct hv_netvsc_packet *packet);
- void (*link_status_change)(struct hv_device *dev, u32 status);
-
- /* Specific to this driver */
- int (*send)(struct hv_device *dev, struct hv_netvsc_packet *packet);
-
- void *ctx;
-};
-
-struct netvsc_device_info {
- unsigned char mac_adr[6];
- bool link_state; /* 0 - link up, 1 - link down */
-};
-
-/* Interface */
-int netvsc_initialize(struct hv_driver *drv);
-int rndis_filter_open(struct hv_device *dev);
-int rndis_filter_close(struct hv_device *dev);
-
-#endif /* _NETVSC_API_H_ */
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index aaa81883f0ad..7b9c229f7295 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -18,6 +18,8 @@
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/highmem.h>
@@ -36,11 +38,9 @@
#include <net/route.h>
#include <net/sock.h>
#include <net/pkt_sched.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "version_info.h"
-#include "vmbus.h"
-#include "netvsc_api.h"
+
+#include "hyperv.h"
+#include "hyperv_net.h"
struct net_device_context {
/* point back to our device context */
@@ -58,9 +58,6 @@ static int ring_size = 128;
module_param(ring_size, int, S_IRUGO);
MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
-/* The one and only one */
-static struct netvsc_driver g_netvsc_drv;
-
/* 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() */
@@ -78,14 +75,14 @@ static int netvsc_open(struct net_device *net)
/* Open up the device */
ret = rndis_filter_open(device_obj);
if (ret != 0) {
- DPRINT_ERR(NETVSC_DRV,
- "unable to open device (ret %d).", ret);
+ netdev_err(net, "unable to open device (ret %d).\n",
+ ret);
return ret;
}
netif_start_queue(net);
} else {
- DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down.");
+ netdev_err(net, "unable to open device...link is down.\n");
}
return ret;
@@ -101,7 +98,7 @@ static int netvsc_close(struct net_device *net)
ret = rndis_filter_close(device_obj);
if (ret != 0)
- DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret);
+ netdev_err(net, "unable to close device (ret %d).\n", ret);
return ret;
}
@@ -130,16 +127,10 @@ static void netvsc_xmit_completion(void *context)
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_driver *drv =
- drv_to_hv_drv(net_device_ctx->device_ctx->device.driver);
- struct netvsc_driver *net_drv_obj = drv->priv;
struct hv_netvsc_packet *packet;
int ret;
unsigned int i, num_pages;
- DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d",
- skb->len, skb->data_len);
-
/* Add 1 for skb->data and additional one for RNDIS */
num_pages = skb_shinfo(skb)->nr_frags + 1 + 1;
if (num_pages > net_device_ctx->avail)
@@ -148,10 +139,10 @@ 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)) +
- net_drv_obj->req_ext_size, GFP_ATOMIC);
+ sizeof(struct rndis_filter_packet), GFP_ATOMIC);
if (!packet) {
/* out of memory, silently drop packet */
- DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet");
+ netdev_err(net, "unable to allocate hv_netvsc_packet\n");
dev_kfree_skb(skb);
net->stats.tx_dropped++;
@@ -191,16 +182,12 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
packet->completion.send.send_completion_ctx = packet;
packet->completion.send.send_completion_tid = (unsigned long)skb;
- ret = net_drv_obj->send(net_device_ctx->device_ctx,
+ ret = rndis_filter_send(net_device_ctx->device_ctx,
packet);
if (ret == 0) {
net->stats.tx_bytes += skb->len;
net->stats.tx_packets++;
- DPRINT_DBG(NETVSC_DRV, "# of xmits %lu total size %lu",
- net->stats.tx_packets,
- net->stats.tx_bytes);
-
net_device_ctx->avail -= num_pages;
if (net_device_ctx->avail < PACKET_PAGES_LOWATER)
netif_stop_queue(net);
@@ -216,15 +203,15 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
/*
* netvsc_linkstatus_callback - Link up/down notification
*/
-static void netvsc_linkstatus_callback(struct hv_device *device_obj,
+void netvsc_linkstatus_callback(struct hv_device *device_obj,
unsigned int status)
{
struct net_device *net = dev_get_drvdata(&device_obj->device);
struct net_device_context *ndev_ctx;
if (!net) {
- DPRINT_ERR(NETVSC_DRV, "got link status but net device "
- "not initialized yet");
+ netdev_err(net, "got link status but net device "
+ "not initialized yet\n");
return;
}
@@ -244,7 +231,7 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj,
* netvsc_recv_callback - Callback when we receive a packet from the
* "wire" on the specified device.
*/
-static int netvsc_recv_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);
@@ -254,8 +241,8 @@ static int netvsc_recv_callback(struct hv_device *device_obj,
unsigned long flags;
if (!net) {
- DPRINT_ERR(NETVSC_DRV, "got receive callback but net device "
- "not initialized yet");
+ netdev_err(net, "got receive callback but net device"
+ " not initialized yet\n");
return 0;
}
@@ -301,9 +288,6 @@ static int netvsc_recv_callback(struct hv_device *device_obj,
*/
netif_rx(skb);
- DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu",
- net->stats.rx_packets, net->stats.rx_bytes);
-
return 0;
}
@@ -349,20 +333,13 @@ static void netvsc_send_garp(struct work_struct *w)
}
-static int netvsc_probe(struct device *device)
+static int netvsc_probe(struct hv_device *dev)
{
- struct hv_driver *drv =
- drv_to_hv_drv(device->driver);
- struct netvsc_driver *net_drv_obj = drv->priv;
- struct hv_device *device_obj = device_to_hv_device(device);
struct net_device *net = NULL;
struct net_device_context *net_device_ctx;
struct netvsc_device_info device_info;
int ret;
- if (!net_drv_obj->base.dev_add)
- return -1;
-
net = alloc_etherdev(sizeof(struct net_device_context));
if (!net)
return -1;
@@ -371,19 +348,19 @@ static int netvsc_probe(struct device *device)
netif_carrier_off(net);
net_device_ctx = netdev_priv(net);
- net_device_ctx->device_ctx = device_obj;
+ net_device_ctx->device_ctx = dev;
net_device_ctx->avail = ring_size;
- dev_set_drvdata(device, net);
+ dev_set_drvdata(&dev->device, net);
INIT_WORK(&net_device_ctx->work, netvsc_send_garp);
/* Notify the netvsc driver of the new device */
- ret = net_drv_obj->base.dev_add(device_obj, &device_info);
+ device_info.ring_size = ring_size;
+ ret = rndis_filte_device_add(dev, &device_info);
if (ret != 0) {
free_netdev(net);
- dev_set_drvdata(device, NULL);
+ dev_set_drvdata(&dev->device, NULL);
- DPRINT_ERR(NETVSC_DRV, "unable to add netvsc device (ret %d)",
- ret);
+ netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
return ret;
}
@@ -408,35 +385,28 @@ static int netvsc_probe(struct device *device)
net->features = NETIF_F_SG;
SET_ETHTOOL_OPS(net, &ethtool_ops);
- SET_NETDEV_DEV(net, device);
+ SET_NETDEV_DEV(net, &dev->device);
ret = register_netdev(net);
if (ret != 0) {
/* Remove the device and release the resource */
- net_drv_obj->base.dev_rm(device_obj);
+ rndis_filter_device_remove(dev);
free_netdev(net);
}
return ret;
}
-static int netvsc_remove(struct device *device)
+static int netvsc_remove(struct hv_device *dev)
{
- struct hv_driver *drv =
- drv_to_hv_drv(device->driver);
- struct netvsc_driver *net_drv_obj = drv->priv;
- struct hv_device *device_obj = device_to_hv_device(device);
- struct net_device *net = dev_get_drvdata(&device_obj->device);
+ struct net_device *net = dev_get_drvdata(&dev->device);
int ret;
if (net == NULL) {
- DPRINT_INFO(NETVSC, "no net device to remove");
+ dev_err(&dev->device, "No net device to remove\n");
return 0;
}
- if (!net_drv_obj->base.dev_rm)
- return -1;
-
/* Stop outbound asap */
netif_stop_queue(net);
/* netif_carrier_off(net); */
@@ -447,84 +417,27 @@ static int netvsc_remove(struct device *device)
* Call to the vsc driver to let it know that the device is being
* removed
*/
- ret = net_drv_obj->base.dev_rm(device_obj);
+ ret = rndis_filter_device_remove(dev);
if (ret != 0) {
/* TODO: */
- DPRINT_ERR(NETVSC, "unable to remove vsc device (ret %d)", ret);
+ netdev_err(net, "unable to remove vsc device (ret %d)\n", ret);
}
free_netdev(net);
return ret;
}
-static int netvsc_drv_exit_cb(struct device *dev, void *data)
-{
- struct device **curr = (struct device **)data;
-
- *curr = dev;
- /* stop iterating */
- return 1;
-}
+/* The one and only one */
+static struct hv_driver netvsc_drv = {
+ .probe = netvsc_probe,
+ .remove = netvsc_remove,
+};
-static void netvsc_drv_exit(void)
+static void __exit netvsc_drv_exit(void)
{
- struct netvsc_driver *netvsc_drv_obj = &g_netvsc_drv;
- struct hv_driver *drv = &g_netvsc_drv.base;
- struct device *current_dev;
- int ret;
-
- while (1) {
- current_dev = NULL;
-
- /* Get the device */
- ret = driver_for_each_device(&drv->driver, NULL,
- &current_dev, netvsc_drv_exit_cb);
- if (ret)
- DPRINT_WARN(NETVSC_DRV,
- "driver_for_each_device returned %d", ret);
-
- if (current_dev == NULL)
- break;
-
- /* Initiate removal from the top-down */
- DPRINT_INFO(NETVSC_DRV, "unregistering device (%p)...",
- current_dev);
-
- device_unregister(current_dev);
- }
-
- if (netvsc_drv_obj->base.cleanup)
- netvsc_drv_obj->base.cleanup(&netvsc_drv_obj->base);
-
- vmbus_child_driver_unregister(&drv->driver);
-
- return;
+ vmbus_child_driver_unregister(&netvsc_drv.driver);
}
-static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
-{
- struct netvsc_driver *net_drv_obj = &g_netvsc_drv;
- struct hv_driver *drv = &g_netvsc_drv.base;
- int ret;
-
- net_drv_obj->ring_buf_size = ring_size * PAGE_SIZE;
- net_drv_obj->recv_cb = netvsc_recv_callback;
- net_drv_obj->link_status_change = netvsc_linkstatus_callback;
- drv->priv = net_drv_obj;
-
- /* Callback to client driver to complete the initialization */
- drv_init(&net_drv_obj->base);
-
- drv->driver.name = net_drv_obj->base.name;
-
- drv->driver.probe = netvsc_probe;
- drv->driver.remove = netvsc_remove;
-
- /* The driver belongs to vmbus */
- ret = vmbus_child_driver_register(&drv->driver);
-
- return ret;
-}
static const struct dmi_system_id __initconst
hv_netvsc_dmi_table[] __maybe_unused = {
@@ -540,19 +453,26 @@ hv_netvsc_dmi_table[] __maybe_unused = {
};
MODULE_DEVICE_TABLE(dmi, hv_netvsc_dmi_table);
-static int __init netvsc_init(void)
+static int __init netvsc_drv_init(void)
{
- DPRINT_INFO(NETVSC_DRV, "Netvsc initializing....");
+ struct hv_driver *drv = &netvsc_drv;
+ int ret;
+
+ pr_info("initializing....");
if (!dmi_check_system(hv_netvsc_dmi_table))
return -ENODEV;
- return netvsc_drv_init(netvsc_initialize);
-}
-static void __exit netvsc_exit(void)
-{
- netvsc_drv_exit();
+ /* Callback to client driver to complete the initialization */
+ netvsc_initialize(drv);
+
+ drv->driver.name = drv->name;
+
+ /* The driver belongs to vmbus */
+ ret = vmbus_child_driver_register(&drv->driver);
+
+ return ret;
}
static const struct pci_device_id __initconst
@@ -566,5 +486,5 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V network driver");
-module_init(netvsc_init);
-module_exit(netvsc_exit);
+module_init(netvsc_drv_init);
+module_exit(netvsc_drv_exit);
diff --git a/drivers/staging/hv/ring_buffer.c b/drivers/staging/hv/ring_buffer.c
index 66688fb69741..3da333018b5a 100644
--- a/drivers/staging/hv/ring_buffer.c
+++ b/drivers/staging/hv/ring_buffer.c
@@ -18,13 +18,16 @@
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/mm.h>
-#include "logging.h"
-#include "ring_buffer.h"
+
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
/* #defines */
@@ -34,18 +37,15 @@
#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w))
-/*++
-
-Name:
- get_ringbuffer_availbytes()
-
-Description:
- Get number of bytes available to read and to write to
- for the specified ring buffer
-
---*/
+/*
+ *
+ * hv_get_ringbuffer_availbytes()
+ *
+ * Get number of bytes available to read and to write to
+ * for the specified ring buffer
+ */
static inline void
-get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
+hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
u32 *read, u32 *write)
{
u32 read_loc, write_loc;
@@ -58,162 +58,131 @@ get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
*read = rbi->ring_datasize - *write;
}
-/*++
-
-Name:
- get_next_write_location()
-
-Description:
- Get the next write location for the specified ring buffer
-
---*/
+/*
+ * hv_get_next_write_location()
+ *
+ * Get the next write location for the specified ring buffer
+ *
+ */
static inline u32
-get_next_write_location(struct hv_ring_buffer_info *ring_info)
+hv_get_next_write_location(struct hv_ring_buffer_info *ring_info)
{
u32 next = ring_info->ring_buffer->write_index;
- /* ASSERT(next < ring_info->RingDataSize); */
-
return next;
}
-/*++
-
-Name:
- set_next_write_location()
-
-Description:
- Set the next write location for the specified ring buffer
-
---*/
+/*
+ * hv_set_next_write_location()
+ *
+ * Set the next write location for the specified ring buffer
+ *
+ */
static inline void
-set_next_write_location(struct hv_ring_buffer_info *ring_info,
+hv_set_next_write_location(struct hv_ring_buffer_info *ring_info,
u32 next_write_location)
{
ring_info->ring_buffer->write_index = next_write_location;
}
-/*++
-
-Name:
- get_next_read_location()
-
-Description:
- Get the next read location for the specified ring buffer
-
---*/
+/*
+ * hv_get_next_read_location()
+ *
+ * Get the next read location for the specified ring buffer
+ */
static inline u32
-get_next_read_location(struct hv_ring_buffer_info *ring_info)
+hv_get_next_read_location(struct hv_ring_buffer_info *ring_info)
{
u32 next = ring_info->ring_buffer->read_index;
- /* ASSERT(next < ring_info->RingDataSize); */
-
return next;
}
-/*++
-
-Name:
- get_next_readlocation_withoffset()
-
-Description:
- Get the next read location + offset for the specified ring buffer.
- This allows the caller to skip
-
---*/
+/*
+ * hv_get_next_readlocation_withoffset()
+ *
+ * Get the next read location + offset for the specified ring buffer.
+ * This allows the caller to skip
+ */
static inline u32
-get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info,
+hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info,
u32 offset)
{
u32 next = ring_info->ring_buffer->read_index;
- /* ASSERT(next < ring_info->RingDataSize); */
next += offset;
next %= ring_info->ring_datasize;
return next;
}
-/*++
-
-Name:
- set_next_read_location()
-
-Description:
- Set the next read location for the specified ring buffer
-
---*/
+/*
+ *
+ * hv_set_next_read_location()
+ *
+ * Set the next read location for the specified ring buffer
+ *
+ */
static inline void
-set_next_read_location(struct hv_ring_buffer_info *ring_info,
+hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
u32 next_read_location)
{
ring_info->ring_buffer->read_index = next_read_location;
}
-/*++
-
-Name:
- get_ring_buffer()
-
-Description:
- Get the start of the ring buffer
-
---*/
+/*
+ *
+ * hv_get_ring_buffer()
+ *
+ * Get the start of the ring buffer
+ */
static inline void *
-get_ring_buffer(struct hv_ring_buffer_info *ring_info)
+hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
{
return (void *)ring_info->ring_buffer->buffer;
}
-/*++
-
-Name:
- get_ring_buffersize()
-
-Description:
- Get the size of the ring buffer
-
---*/
+/*
+ *
+ * hv_get_ring_buffersize()
+ *
+ * Get the size of the ring buffer
+ */
static inline u32
-get_ring_buffersize(struct hv_ring_buffer_info *ring_info)
+hv_get_ring_buffersize(struct hv_ring_buffer_info *ring_info)
{
return ring_info->ring_datasize;
}
-/*++
-
-Name:
- get_ring_bufferindices()
-
-Description:
- Get the read and write indices as u64 of the specified ring buffer
-
---*/
+/*
+ *
+ * hv_get_ring_bufferindices()
+ *
+ * Get the read and write indices as u64 of the specified ring buffer
+ *
+ */
static inline u64
-get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
+hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
{
return (u64)ring_info->ring_buffer->write_index << 32;
}
-/*++
-
-Name:
- dump_ring_info()
-
-Description:
- Dump out to console the ring buffer info
-
---*/
-void dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix)
+/*
+ *
+ * hv_dump_ring_info()
+ *
+ * Dump out to console the ring buffer info
+ *
+ */
+void hv_dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix)
{
u32 bytes_avail_towrite;
u32 bytes_avail_toread;
- get_ringbuffer_availbytes(ring_info,
+ hv_get_ringbuffer_availbytes(ring_info,
&bytes_avail_toread,
&bytes_avail_towrite);
@@ -231,41 +200,90 @@ void dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix)
}
-/* Internal routines */
-
-static u32
-copyto_ringbuffer(
- struct hv_ring_buffer_info *ring_info,
- u32 start_write_offset,
- void *src,
- u32 srclen);
-
-static u32
-copyfrom_ringbuffer(
+/*
+ *
+ * hv_copyfrom_ringbuffer()
+ *
+ * Helper routine to copy to source from ring buffer.
+ * Assume there is enough room. Handles wrap-around in src case only!!
+ *
+ */
+static u32 hv_copyfrom_ringbuffer(
struct hv_ring_buffer_info *ring_info,
void *dest,
u32 destlen,
- u32 start_read_offset);
+ u32 start_read_offset)
+{
+ void *ring_buffer = hv_get_ring_buffer(ring_info);
+ u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
+ u32 frag_len;
+ /* wrap-around detected at the src */
+ if (destlen > ring_buffer_size - start_read_offset) {
+ frag_len = ring_buffer_size - start_read_offset;
-/*++
+ memcpy(dest, ring_buffer + start_read_offset, frag_len);
+ memcpy(dest + frag_len, ring_buffer, destlen - frag_len);
+ } else
+
+ memcpy(dest, ring_buffer + start_read_offset, destlen);
+
+
+ start_read_offset += destlen;
+ start_read_offset %= ring_buffer_size;
+
+ return start_read_offset;
+}
+
+
+/*
+ *
+ * hv_copyto_ringbuffer()
+ *
+ * Helper routine to copy from source to ring buffer.
+ * Assume there is enough room. Handles wrap-around in dest case only!!
+ *
+ */
+static u32 hv_copyto_ringbuffer(
+ struct hv_ring_buffer_info *ring_info,
+ u32 start_write_offset,
+ void *src,
+ u32 srclen)
+{
+ void *ring_buffer = hv_get_ring_buffer(ring_info);
+ u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
+ u32 frag_len;
+
+ /* wrap-around detected! */
+ if (srclen > ring_buffer_size - start_write_offset) {
+ frag_len = ring_buffer_size - start_write_offset;
+ memcpy(ring_buffer + start_write_offset, src, frag_len);
+ memcpy(ring_buffer, src + frag_len, srclen - frag_len);
+ } else
+ memcpy(ring_buffer + start_write_offset, src, srclen);
-Name:
- ringbuffer_get_debuginfo()
+ start_write_offset += srclen;
+ start_write_offset %= ring_buffer_size;
-Description:
- Get various debug metrics for the specified ring buffer
+ return start_write_offset;
+}
---*/
-void ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
+/*
+ *
+ * hv_ringbuffer_get_debuginfo()
+ *
+ * Get various debug metrics for the specified ring buffer
+ *
+ */
+void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info)
{
u32 bytes_avail_towrite;
u32 bytes_avail_toread;
if (ring_info->ring_buffer) {
- get_ringbuffer_availbytes(ring_info,
+ hv_get_ringbuffer_availbytes(ring_info,
&bytes_avail_toread,
&bytes_avail_towrite);
@@ -281,30 +299,26 @@ void ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
}
-/*++
-
-Name:
- get_ringbuffer_interrupt_mask()
-
-Description:
- Get the interrupt mask for the specified ring buffer
-
---*/
-u32 get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *rbi)
+/*
+ *
+ * hv_get_ringbuffer_interrupt_mask()
+ *
+ * Get the interrupt mask for the specified ring buffer
+ *
+ */
+u32 hv_get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *rbi)
{
return rbi->ring_buffer->interrupt_mask;
}
-/*++
-
-Name:
- ringbuffer_init()
-
-Description:
- Initialize the ring buffer
-
---*/
-int ringbuffer_init(struct hv_ring_buffer_info *ring_info,
+/*
+ *
+ * hv_ringbuffer_init()
+ *
+ *Initialize the ring buffer
+ *
+ */
+int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
void *buffer, u32 buflen)
{
if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
@@ -324,29 +338,25 @@ int ringbuffer_init(struct hv_ring_buffer_info *ring_info,
return 0;
}
-/*++
-
-Name:
- ringbuffer_cleanup()
-
-Description:
- Cleanup the ring buffer
-
---*/
-void ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
+/*
+ *
+ * hv_ringbuffer_cleanup()
+ *
+ * Cleanup the ring buffer
+ *
+ */
+void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
{
}
-/*++
-
-Name:
- ringbuffer_write()
-
-Description:
- Write to the ring buffer
-
---*/
-int ringbuffer_write(struct hv_ring_buffer_info *outring_info,
+/*
+ *
+ * hv_ringbuffer_write()
+ *
+ * Write to the ring buffer
+ *
+ */
+int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
struct scatterlist *sglist, u32 sgcount)
{
int i = 0;
@@ -355,7 +365,7 @@ int ringbuffer_write(struct hv_ring_buffer_info *outring_info,
u32 totalbytes_towrite = 0;
struct scatterlist *sg;
- volatile u32 next_write_location;
+ u32 next_write_location;
u64 prev_indices = 0;
unsigned long flags;
@@ -368,43 +378,34 @@ int ringbuffer_write(struct hv_ring_buffer_info *outring_info,
spin_lock_irqsave(&outring_info->ring_lock, flags);
- get_ringbuffer_availbytes(outring_info,
+ hv_get_ringbuffer_availbytes(outring_info,
&bytes_avail_toread,
&bytes_avail_towrite);
- DPRINT_DBG(VMBUS, "Writing %u bytes...", totalbytes_towrite);
-
- /* Dumpring_info(Outring_info, "BEFORE "); */
/* If there is only room for the packet, assume it is full. */
/* Otherwise, the next time around, we think the ring buffer */
/* is empty since the read index == write index */
if (bytes_avail_towrite <= totalbytes_towrite) {
- DPRINT_DBG(VMBUS,
- "No more space left on outbound ring buffer "
- "(needed %u, avail %u)",
- totalbytes_towrite,
- bytes_avail_towrite);
-
spin_unlock_irqrestore(&outring_info->ring_lock, flags);
return -1;
}
/* Write to the ring buffer */
- next_write_location = get_next_write_location(outring_info);
+ next_write_location = hv_get_next_write_location(outring_info);
for_each_sg(sglist, sg, sgcount, i)
{
- next_write_location = copyto_ringbuffer(outring_info,
+ next_write_location = hv_copyto_ringbuffer(outring_info,
next_write_location,
sg_virt(sg),
sg->length);
}
/* Set previous packet start */
- prev_indices = get_ring_bufferindices(outring_info);
+ prev_indices = hv_get_ring_bufferindices(outring_info);
- next_write_location = copyto_ringbuffer(outring_info,
+ next_write_location = hv_copyto_ringbuffer(outring_info,
next_write_location,
&prev_indices,
sizeof(u64));
@@ -413,25 +414,22 @@ int ringbuffer_write(struct hv_ring_buffer_info *outring_info,
mb();
/* Now, update the write location */
- set_next_write_location(outring_info, next_write_location);
+ hv_set_next_write_location(outring_info, next_write_location);
- /* Dumpring_info(Outring_info, "AFTER "); */
spin_unlock_irqrestore(&outring_info->ring_lock, flags);
return 0;
}
-/*++
-
-Name:
- ringbuffer_peek()
-
-Description:
- Read without advancing the read index
-
---*/
-int ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
+/*
+ *
+ * hv_ringbuffer_peek()
+ *
+ * Read without advancing the read index
+ *
+ */
+int hv_ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
void *Buffer, u32 buflen)
{
u32 bytes_avail_towrite;
@@ -441,17 +439,12 @@ int ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
spin_lock_irqsave(&Inring_info->ring_lock, flags);
- get_ringbuffer_availbytes(Inring_info,
+ hv_get_ringbuffer_availbytes(Inring_info,
&bytes_avail_toread,
&bytes_avail_towrite);
/* Make sure there is something to read */
if (bytes_avail_toread < buflen) {
- /* DPRINT_DBG(VMBUS,
- "got callback but not enough to read "
- "<avail to read %d read size %d>!!",
- bytes_avail_toread,
- BufferLen); */
spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
@@ -459,9 +452,9 @@ int ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
}
/* Convert to byte offset */
- next_read_location = get_next_read_location(Inring_info);
+ next_read_location = hv_get_next_read_location(Inring_info);
- next_read_location = copyfrom_ringbuffer(Inring_info,
+ next_read_location = hv_copyfrom_ringbuffer(Inring_info,
Buffer,
buflen,
next_read_location);
@@ -472,16 +465,14 @@ int ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
}
-/*++
-
-Name:
- ringbuffer_read()
-
-Description:
- Read and advance the read index
-
---*/
-int ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
+/*
+ *
+ * hv_ringbuffer_read()
+ *
+ * Read and advance the read index
+ *
+ */
+int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
u32 buflen, u32 offset)
{
u32 bytes_avail_towrite;
@@ -495,36 +486,26 @@ int ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
spin_lock_irqsave(&inring_info->ring_lock, flags);
- get_ringbuffer_availbytes(inring_info,
+ hv_get_ringbuffer_availbytes(inring_info,
&bytes_avail_toread,
&bytes_avail_towrite);
- DPRINT_DBG(VMBUS, "Reading %u bytes...", buflen);
-
- /* Dumpring_info(Inring_info, "BEFORE "); */
-
/* Make sure there is something to read */
if (bytes_avail_toread < buflen) {
- DPRINT_DBG(VMBUS,
- "got callback but not enough to read "
- "<avail to read %d read size %d>!!",
- bytes_avail_toread,
- buflen);
-
spin_unlock_irqrestore(&inring_info->ring_lock, flags);
return -1;
}
next_read_location =
- get_next_readlocation_withoffset(inring_info, offset);
+ hv_get_next_readlocation_withoffset(inring_info, offset);
- next_read_location = copyfrom_ringbuffer(inring_info,
+ next_read_location = hv_copyfrom_ringbuffer(inring_info,
buffer,
buflen,
next_read_location);
- next_read_location = copyfrom_ringbuffer(inring_info,
+ next_read_location = hv_copyfrom_ringbuffer(inring_info,
&prev_indices,
sizeof(u64),
next_read_location);
@@ -535,94 +516,9 @@ int ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
mb();
/* Update the read index */
- set_next_read_location(inring_info, next_read_location);
-
- /* Dumpring_info(Inring_info, "AFTER "); */
+ hv_set_next_read_location(inring_info, next_read_location);
spin_unlock_irqrestore(&inring_info->ring_lock, flags);
return 0;
}
-
-
-/*++
-
-Name:
- copyto_ringbuffer()
-
-Description:
- Helper routine to copy from source to ring buffer.
- Assume there is enough room. Handles wrap-around in dest case only!!
-
---*/
-static u32
-copyto_ringbuffer(
- struct hv_ring_buffer_info *ring_info,
- u32 start_write_offset,
- void *src,
- u32 srclen)
-{
- void *ring_buffer = get_ring_buffer(ring_info);
- u32 ring_buffer_size = get_ring_buffersize(ring_info);
- u32 frag_len;
-
- /* wrap-around detected! */
- if (srclen > ring_buffer_size - start_write_offset) {
- DPRINT_DBG(VMBUS, "wrap-around detected!");
-
- frag_len = ring_buffer_size - start_write_offset;
- memcpy(ring_buffer + start_write_offset, src, frag_len);
- memcpy(ring_buffer, src + frag_len, srclen - frag_len);
- } else
- memcpy(ring_buffer + start_write_offset, src, srclen);
-
- start_write_offset += srclen;
- start_write_offset %= ring_buffer_size;
-
- return start_write_offset;
-}
-
-
-/*++
-
-Name:
- copyfrom_ringbuffer()
-
-Description:
- Helper routine to copy to source from ring buffer.
- Assume there is enough room. Handles wrap-around in src case only!!
-
---*/
-static u32
-copyfrom_ringbuffer(
- struct hv_ring_buffer_info *ring_info,
- void *dest,
- u32 destlen,
- u32 start_read_offset)
-{
- void *ring_buffer = get_ring_buffer(ring_info);
- u32 ring_buffer_size = get_ring_buffersize(ring_info);
-
- u32 frag_len;
-
- /* wrap-around detected at the src */
- if (destlen > ring_buffer_size - start_read_offset) {
- DPRINT_DBG(VMBUS, "src wrap-around detected!");
-
- frag_len = ring_buffer_size - start_read_offset;
-
- memcpy(dest, ring_buffer + start_read_offset, frag_len);
- memcpy(dest + frag_len, ring_buffer, destlen - frag_len);
- } else
-
- memcpy(dest, ring_buffer + start_read_offset, destlen);
-
-
- start_read_offset += destlen;
- start_read_offset %= ring_buffer_size;
-
- return start_read_offset;
-}
-
-
-/* eof */
diff --git a/drivers/staging/hv/ring_buffer.h b/drivers/staging/hv/ring_buffer.h
deleted file mode 100644
index 7bf20d67187b..000000000000
--- a/drivers/staging/hv/ring_buffer.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _RING_BUFFER_H_
-#define _RING_BUFFER_H_
-
-#include <linux/scatterlist.h>
-
-struct hv_ring_buffer {
- /* Offset in bytes from the start of ring data below */
- volatile u32 write_index;
-
- /* Offset in bytes from the start of ring data below */
- volatile u32 read_index;
-
- volatile u32 interrupt_mask;
-
- /* Pad it to PAGE_SIZE so that data starts on page boundary */
- u8 reserved[4084];
-
- /* NOTE:
- * The interrupt_mask field is used only for channels but since our
- * vmbus connection also uses this data structure and its data starts
- * here, we commented out this field.
- */
- /* volatile u32 InterruptMask; */
-
- /*
- * Ring data starts here + RingDataStartOffset
- * !!! DO NOT place any fields below this !!!
- */
- u8 buffer[0];
-} __packed;
-
-struct hv_ring_buffer_info {
- struct hv_ring_buffer *ring_buffer;
- u32 ring_size; /* Include the shared header */
- spinlock_t ring_lock;
-
- u32 ring_datasize; /* < ring_size */
- u32 ring_data_startoffset;
-};
-
-struct hv_ring_buffer_debug_info {
- u32 current_interrupt_mask;
- u32 current_read_index;
- u32 current_write_index;
- u32 bytes_avail_toread;
- u32 bytes_avail_towrite;
-};
-
-
-
-/* Interface */
-
-
-int ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
- u32 buflen);
-
-void ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
-
-int ringbuffer_write(struct hv_ring_buffer_info *ring_info,
- struct scatterlist *sglist,
- u32 sgcount);
-
-int ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
- u32 buflen);
-
-int ringbuffer_read(struct hv_ring_buffer_info *ring_info,
- void *buffer,
- u32 buflen,
- u32 offset);
-
-u32 get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *ring_info);
-
-void dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix);
-
-void ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
- struct hv_ring_buffer_debug_info *debug_info);
-
-#endif /* _RING_BUFFER_H_ */
diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c
index 048376b2b676..60ebdb1b6082 100644
--- a/drivers/staging/hv/rndis_filter.c
+++ b/drivers/staging/hv/rndis_filter.c
@@ -25,17 +25,11 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/if_ether.h>
+#include <linux/netdevice.h>
-#include "logging.h"
-#include "hv_api.h"
-#include "netvsc_api.h"
-#include "rndis_filter.h"
+#include "hyperv.h"
+#include "hyperv_net.h"
-/* Data types */
-struct rndis_filter_driver_object {
- /* The original driver */
- struct netvsc_driver inner_drv;
-};
enum rndis_device_state {
RNDIS_DEV_UNINITIALIZED = 0,
@@ -59,8 +53,7 @@ struct rndis_device {
struct rndis_request {
struct list_head list_ent;
- int wait_condition;
- wait_queue_head_t wait_event;
+ struct completion wait_event;
/*
* FIXME: We assumed a fixed size response here. If we do ever need to
@@ -76,31 +69,11 @@ struct rndis_request {
struct rndis_message request_msg;
};
-
-struct rndis_filter_packet {
- void *completion_ctx;
- void (*completion)(void *context);
- struct rndis_message msg;
-};
-
-
-static int rndis_filte_device_add(struct hv_device *dev,
- void *additional_info);
-
-static int rndis_filter_device_remove(struct hv_device *dev);
-
-static void rndis_filter_cleanup(struct hv_driver *drv);
-
-static int rndis_filter_send(struct hv_device *dev,
- struct hv_netvsc_packet *pkt);
-
static void rndis_filter_send_completion(void *ctx);
static void rndis_filter_send_request_completion(void *ctx);
-/* The one and only */
-static struct rndis_filter_driver_object rndis_filter;
static struct rndis_device *get_rndis_device(void)
{
@@ -132,7 +105,7 @@ static struct rndis_request *get_rndis_request(struct rndis_device *dev,
if (!request)
return NULL;
- init_waitqueue_head(&request->wait_event);
+ init_completion(&request->wait_event);
rndis_msg = &request->request_msg;
rndis_msg->ndis_msg_type = msg_type;
@@ -264,7 +237,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
rndis_filter_send_request_completion;
packet->completion.send.send_completion_tid = (unsigned long)dev;
- ret = rndis_filter.inner_drv.send(dev->net_dev->dev, packet);
+ ret = netvsc_send(dev->net_dev->dev, packet);
return ret;
}
@@ -283,14 +256,6 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
*/
if (request->request_msg.msg.init_req.req_id
== resp->msg.init_complete.req_id) {
- DPRINT_DBG(NETVSC, "found rndis request for "
- "this response (id 0x%x req type 0x%x res "
- "type 0x%x)",
- request->request_msg.msg.
- init_req.req_id,
- request->request_msg.ndis_msg_type,
- resp->ndis_msg_type);
-
found = true;
break;
}
@@ -302,10 +267,11 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
memcpy(&request->response_msg, resp,
resp->msg_len);
} else {
- DPRINT_ERR(NETVSC, "rndis response buffer overflow "
- "detected (size %u max %zu)",
- resp->msg_len,
- sizeof(struct rndis_filter_packet));
+ dev_err(&dev->net_dev->dev->device,
+ "rndis response buffer overflow "
+ "detected (size %u max %zu)\n",
+ resp->msg_len,
+ sizeof(struct rndis_filter_packet));
if (resp->ndis_msg_type ==
REMOTE_NDIS_RESET_CMPLT) {
@@ -319,13 +285,13 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
}
}
- request->wait_condition = 1;
- wake_up(&request->wait_event);
+ complete(&request->wait_event);
} else {
- DPRINT_ERR(NETVSC, "no rndis request found for this response "
- "(id 0x%x res type 0x%x)",
- resp->msg.init_complete.req_id,
- resp->ndis_msg_type);
+ dev_err(&dev->net_dev->dev->device,
+ "no rndis request found for this response "
+ "(id 0x%x res type 0x%x)\n",
+ resp->msg.init_complete.req_id,
+ resp->ndis_msg_type);
}
}
@@ -336,10 +302,10 @@ static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
&resp->msg.indicate_status;
if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) {
- rndis_filter.inner_drv.link_status_change(
+ netvsc_linkstatus_callback(
dev->net_dev->dev, 1);
} else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) {
- rndis_filter.inner_drv.link_status_change(
+ netvsc_linkstatus_callback(
dev->net_dev->dev, 0);
} else {
/*
@@ -371,11 +337,10 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
pkt->is_data_pkt = true;
- rndis_filter.inner_drv.recv_cb(dev->net_dev->dev,
- pkt);
+ netvsc_recv_callback(dev->net_dev->dev, pkt);
}
-static int rndis_filter_receive(struct hv_device *dev,
+int rndis_filter_receive(struct hv_device *dev,
struct hv_netvsc_packet *pkt)
{
struct netvsc_device *net_dev = dev->ext;
@@ -388,15 +353,15 @@ static int rndis_filter_receive(struct hv_device *dev,
/* Make sure the rndis device state is initialized */
if (!net_dev->extension) {
- DPRINT_ERR(NETVSC, "got rndis message but no rndis device..."
- "dropping this message!");
+ dev_err(&dev->device, "got rndis message but no rndis device - "
+ "dropping this message!\n");
return -1;
}
rndis_dev = (struct rndis_device *)net_dev->extension;
if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
- DPRINT_ERR(NETVSC, "got rndis message but rndis device "
- "uninitialized...dropping this message!");
+ dev_err(&dev->device, "got rndis message but rndis device "
+ "uninitialized...dropping this message!\n");
return -1;
}
@@ -417,8 +382,8 @@ static int rndis_filter_receive(struct hv_device *dev,
kunmap_atomic(rndis_hdr - pkt->page_buf[0].offset,
KM_IRQ0);
- DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u "
- "bytes got %u)...dropping this message!",
+ dev_err(&dev->device, "invalid rndis message? (expected %u "
+ "bytes got %u)...dropping this message!\n",
rndis_hdr->msg_len,
pkt->total_data_buflen);
return -1;
@@ -427,8 +392,8 @@ static int rndis_filter_receive(struct hv_device *dev,
if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
(rndis_hdr->msg_len > sizeof(struct rndis_message))) {
- DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow "
- "detected (got %u, max %zu)...marking it an error!",
+ dev_err(&dev->device, "incoming rndis message buffer overflow "
+ "detected (got %u, max %zu)..marking it an error!\n",
rndis_hdr->msg_len,
sizeof(struct rndis_message));
}
@@ -460,7 +425,8 @@ static int rndis_filter_receive(struct hv_device *dev,
rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg);
break;
default:
- DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)",
+ dev_err(&dev->device,
+ "unhandled rndis message (type %u len %u)\n",
rndis_msg.ndis_msg_type,
rndis_msg.msg_len);
break;
@@ -477,6 +443,7 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
struct rndis_query_request *query;
struct rndis_query_complete *query_complete;
int ret = 0;
+ int t;
if (!result)
return -EINVAL;
@@ -496,14 +463,12 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
query->info_buflen = 0;
query->dev_vc_handle = 0;
- request->wait_condition = 0;
ret = rndis_filter_send_request(dev, request);
if (ret != 0)
goto Cleanup;
- wait_event_timeout(request->wait_event, request->wait_condition,
- msecs_to_jiffies(1000));
- if (request->wait_condition == 0) {
+ t = wait_for_completion_timeout(&request->wait_event, HZ);
+ if (t == 0) {
ret = -ETIMEDOUT;
goto Cleanup;
}
@@ -555,7 +520,7 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev,
struct rndis_set_request *set;
struct rndis_set_complete *set_complete;
u32 status;
- int ret;
+ int ret, t;
request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
@@ -574,16 +539,16 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev,
memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
&new_filter, sizeof(u32));
- request->wait_condition = 0;
ret = rndis_filter_send_request(dev, request);
if (ret != 0)
goto Cleanup;
- wait_event_timeout(request->wait_event, request->wait_condition,
- msecs_to_jiffies(2000));
- if (request->wait_condition == 0) {
+ t = wait_for_completion_timeout(&request->wait_event, HZ);
+
+ if (t == 0) {
ret = -1;
- DPRINT_ERR(NETVSC, "timeout before we got a set response...");
+ dev_err(&dev->net_dev->dev->device,
+ "timeout before we got a set response...\n");
/*
* We can't deallocate the request since we may still receive a
* send completion for it.
@@ -603,42 +568,6 @@ Exit:
return ret;
}
-int rndis_filter_init(struct netvsc_driver *drv)
-{
- DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd",
- sizeof(struct rndis_filter_packet));
-
- drv->req_ext_size = sizeof(struct rndis_filter_packet);
-
- /* Driver->Context = rndisDriver; */
-
- memset(&rndis_filter, 0, sizeof(struct rndis_filter_driver_object));
-
- /*rndisDriver->Driver = Driver;
-
- ASSERT(Driver->OnLinkStatusChanged);
- rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/
-
- /* Save the original dispatch handlers before we override it */
- rndis_filter.inner_drv.base.dev_add = drv->base.dev_add;
- rndis_filter.inner_drv.base.dev_rm =
- drv->base.dev_rm;
- rndis_filter.inner_drv.base.cleanup = drv->base.cleanup;
-
- rndis_filter.inner_drv.send = drv->send;
- rndis_filter.inner_drv.recv_cb = drv->recv_cb;
- rndis_filter.inner_drv.link_status_change =
- drv->link_status_change;
-
- /* Override */
- drv->base.dev_add = rndis_filte_device_add;
- drv->base.dev_rm = rndis_filter_device_remove;
- drv->base.cleanup = rndis_filter_cleanup;
- drv->send = rndis_filter_send;
- drv->recv_cb = rndis_filter_receive;
-
- return 0;
-}
static int rndis_filter_init_device(struct rndis_device *dev)
{
@@ -646,7 +575,7 @@ static int rndis_filter_init_device(struct rndis_device *dev)
struct rndis_initialize_request *init;
struct rndis_initialize_complete *init_complete;
u32 status;
- int ret;
+ int ret, t;
request = get_rndis_request(dev, REMOTE_NDIS_INITIALIZE_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
@@ -664,7 +593,6 @@ static int rndis_filter_init_device(struct rndis_device *dev)
dev->state = RNDIS_DEV_INITIALIZING;
- request->wait_condition = 0;
ret = rndis_filter_send_request(dev, request);
if (ret != 0) {
dev->state = RNDIS_DEV_UNINITIALIZED;
@@ -672,9 +600,9 @@ static int rndis_filter_init_device(struct rndis_device *dev)
}
- wait_event_timeout(request->wait_event, request->wait_condition,
- msecs_to_jiffies(1000));
- if (request->wait_condition == 0) {
+ t = wait_for_completion_timeout(&request->wait_event, HZ);
+
+ if (t == 0) {
ret = -ETIMEDOUT;
goto Cleanup;
}
@@ -753,7 +681,7 @@ static int rndis_filter_close_device(struct rndis_device *dev)
return ret;
}
-static int rndis_filte_device_add(struct hv_device *dev,
+int rndis_filte_device_add(struct hv_device *dev,
void *additional_info)
{
int ret;
@@ -765,14 +693,12 @@ static int rndis_filte_device_add(struct hv_device *dev,
if (!rndisDevice)
return -1;
- DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice);
-
/*
* Let the inner driver handle this first to create the netvsc channel
* NOTE! Once the channel is created, we may get a receive callback
* (RndisFilterOnReceive()) before this call is completed
*/
- ret = rndis_filter.inner_drv.base.dev_add(dev, additional_info);
+ ret = netvsc_device_add(dev, additional_info);
if (ret != 0) {
kfree(rndisDevice);
return ret;
@@ -802,21 +728,20 @@ static int rndis_filte_device_add(struct hv_device *dev,
*/
}
- DPRINT_INFO(NETVSC, "Device 0x%p mac addr %pM",
- rndisDevice, rndisDevice->hw_mac_adr);
-
memcpy(deviceInfo->mac_adr, rndisDevice->hw_mac_adr, ETH_ALEN);
rndis_filter_query_device_link_status(rndisDevice);
deviceInfo->link_state = rndisDevice->link_stat;
- DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice,
- ((deviceInfo->link_state) ? ("down") : ("up")));
+
+ dev_info(&dev->device, "Device MAC %pM link state %s",
+ rndisDevice->hw_mac_adr,
+ ((deviceInfo->link_state) ? ("down\n") : ("up\n")));
return ret;
}
-static int rndis_filter_device_remove(struct hv_device *dev)
+int rndis_filter_device_remove(struct hv_device *dev)
{
struct netvsc_device *net_dev = dev->ext;
struct rndis_device *rndis_dev = net_dev->extension;
@@ -827,15 +752,11 @@ static int rndis_filter_device_remove(struct hv_device *dev)
kfree(rndis_dev);
net_dev->extension = NULL;
- /* Pass control to inner driver to remove the device */
- rndis_filter.inner_drv.base.dev_rm(dev);
+ netvsc_device_remove(dev);
return 0;
}
-static void rndis_filter_cleanup(struct hv_driver *drv)
-{
-}
int rndis_filter_open(struct hv_device *dev)
{
@@ -857,7 +778,7 @@ int rndis_filter_close(struct hv_device *dev)
return rndis_filter_close_device(netDevice->extension);
}
-static int rndis_filter_send(struct hv_device *dev,
+int rndis_filter_send(struct hv_device *dev,
struct hv_netvsc_packet *pkt)
{
int ret;
@@ -897,7 +818,7 @@ static int rndis_filter_send(struct hv_device *dev,
pkt->completion.send.send_completion = rndis_filter_send_completion;
pkt->completion.send.send_completion_ctx = filterPacket;
- ret = rndis_filter.inner_drv.send(dev, pkt);
+ ret = netvsc_send(dev, pkt);
if (ret != 0) {
/*
* Reset the completion to originals to allow retries from
diff --git a/drivers/staging/hv/rndis_filter.h b/drivers/staging/hv/rndis_filter.h
deleted file mode 100644
index 4da18f3cbade..000000000000
--- a/drivers/staging/hv/rndis_filter.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _RNDISFILTER_H_
-#define _RNDISFILTER_H_
-
-#define __struct_bcount(x)
-
-#include "netvsc.h"
-
-#include "rndis.h"
-
-#define RNDIS_HEADER_SIZE (sizeof(struct rndis_message) - \
- sizeof(union rndis_message_container))
-
-#define NDIS_PACKET_TYPE_DIRECTED 0x00000001
-#define NDIS_PACKET_TYPE_MULTICAST 0x00000002
-#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004
-#define NDIS_PACKET_TYPE_BROADCAST 0x00000008
-#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010
-#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020
-#define NDIS_PACKET_TYPE_SMT 0x00000040
-#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080
-#define NDIS_PACKET_TYPE_GROUP 0x00000100
-#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200
-#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400
-#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800
-
-
-/* Interface */
-
-extern int rndis_filter_init(struct netvsc_driver *driver);
-
-#endif /* _RNDISFILTER_H_ */
diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index e2ad72924184..06cd3276813c 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -17,71 +17,19 @@
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
+ *
*/
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/wait.h>
+#include <linux/completion.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/delay.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "storvsc_api.h"
-#include "vmbus_packet_format.h"
-#include "vstorage.h"
-#include "channel.h"
-
-
-struct storvsc_request_extension {
- /* LIST_ENTRY ListEntry; */
-
- struct hv_storvsc_request *request;
- struct hv_device *device;
-
- /* Synchronize the request/response if needed */
- int wait_condition;
- wait_queue_head_t wait_event;
-
- struct vstor_packet vstor_packet;
-};
-
-/* A storvsc device is a device object that contains a vmbus channel */
-struct storvsc_device {
- struct hv_device *device;
-
- /* 0 indicates the device is being destroyed */
- atomic_t ref_count;
- atomic_t num_outstanding_req;
-
- /*
- * Each unique Port/Path/Target represents 1 channel ie scsi
- * controller. In reality, the pathid, targetid is always 0
- * and the port is set by us
- */
- unsigned int port_number;
- unsigned char path_id;
- unsigned char target_id;
-
- /* LIST_ENTRY OutstandingRequestList; */
- /* HANDLE OutstandingRequestLock; */
-
- /* Used for vsc/vsp channel reset process */
- struct storvsc_request_extension init_request;
- struct storvsc_request_extension reset_request;
-};
-
-
-static const char *g_driver_name = "storvsc";
-
-/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
-static const struct hv_guid gStorVscDeviceType = {
- .data = {
- 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
- 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
- }
-};
+#include "hyperv.h"
+#include "hyperv_storage.h"
static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
@@ -96,6 +44,7 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
/* (ie get_stor_device() and must_get_stor_device()) to proceed. */
atomic_cmpxchg(&stor_device->ref_count, 0, 2);
+ init_waitqueue_head(&stor_device->waiting_to_drain);
stor_device->device = device;
device->ext = stor_device;
@@ -104,24 +53,9 @@ static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
static inline void free_stor_device(struct storvsc_device *device)
{
- /* ASSERT(atomic_read(&device->ref_count) == 0); */
kfree(device);
}
-/* Get the stordevice object iff exists and its refcount > 1 */
-static inline struct storvsc_device *get_stor_device(struct hv_device *device)
-{
- struct storvsc_device *stor_device;
-
- stor_device = (struct storvsc_device *)device->ext;
- if (stor_device && atomic_read(&stor_device->ref_count) > 1)
- atomic_inc(&stor_device->ref_count);
- else
- stor_device = NULL;
-
- return stor_device;
-}
-
/* Get the stordevice object iff exists and its refcount > 0 */
static inline struct storvsc_device *must_get_stor_device(
struct hv_device *device)
@@ -137,17 +71,6 @@ static inline struct storvsc_device *must_get_stor_device(
return stor_device;
}
-static inline void put_stor_device(struct hv_device *device)
-{
- struct storvsc_device *stor_device;
-
- stor_device = (struct storvsc_device *)device->ext;
- /* ASSERT(stor_device); */
-
- atomic_dec(&stor_device->ref_count);
- /* ASSERT(atomic_read(&stor_device->ref_count)); */
-}
-
/* Drop ref count to 1 to effectively disable get_stor_device() */
static inline struct storvsc_device *release_stor_device(
struct hv_device *device)
@@ -155,7 +78,6 @@ static inline struct storvsc_device *release_stor_device(
struct storvsc_device *stor_device;
stor_device = (struct storvsc_device *)device->ext;
- /* ASSERT(stor_device); */
/* Busy wait until the ref drop to 2, then set it to 1 */
while (atomic_cmpxchg(&stor_device->ref_count, 2, 1) != 2)
@@ -171,7 +93,6 @@ static inline struct storvsc_device *final_release_stor_device(
struct storvsc_device *stor_device;
stor_device = (struct storvsc_device *)device->ext;
- /* ASSERT(stor_device); */
/* Busy wait until the ref drop to 1, then set it to 0 */
while (atomic_cmpxchg(&stor_device->ref_count, 1, 0) != 1)
@@ -181,19 +102,16 @@ static inline struct storvsc_device *final_release_stor_device(
return stor_device;
}
-static int stor_vsc_channel_init(struct hv_device *device)
+static int storvsc_channel_init(struct hv_device *device)
{
struct storvsc_device *stor_device;
- struct storvsc_request_extension *request;
+ struct hv_storvsc_request *request;
struct vstor_packet *vstor_packet;
- int ret;
+ int ret, t;
stor_device = get_stor_device(device);
- if (!stor_device) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
+ if (!stor_device)
return -1;
- }
request = &stor_device->init_request;
vstor_packet = &request->vstor_packet;
@@ -202,40 +120,30 @@ static int stor_vsc_channel_init(struct hv_device *device)
* Now, initiate the vsc/vsp initialization protocol on the open
* channel
*/
- memset(request, 0, sizeof(struct storvsc_request_extension));
- init_waitqueue_head(&request->wait_event);
+ memset(request, 0, sizeof(struct hv_storvsc_request));
+ init_completion(&request->wait_event);
vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
DPRINT_INFO(STORVSC, "BEGIN_INITIALIZATION_OPERATION...");
- request->wait_condition = 0;
ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
(unsigned long)request,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(STORVSC,
- "unable to send BEGIN_INITIALIZATION_OPERATION");
+ if (ret != 0)
goto cleanup;
- }
- wait_event_timeout(request->wait_event, request->wait_condition,
- msecs_to_jiffies(1000));
- if (request->wait_condition == 0) {
+ t = wait_for_completion_timeout(&request->wait_event, HZ);
+ if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
}
-
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- DPRINT_ERR(STORVSC, "BEGIN_INITIALIZATION_OPERATION failed "
- "(op %d status 0x%x)",
- vstor_packet->operation, vstor_packet->status);
+ vstor_packet->status != 0)
goto cleanup;
- }
DPRINT_INFO(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION...");
@@ -247,33 +155,24 @@ static int stor_vsc_channel_init(struct hv_device *device)
vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT;
FILL_VMSTOR_REVISION(vstor_packet->version.revision);
- request->wait_condition = 0;
ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
(unsigned long)request,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(STORVSC,
- "unable to send BEGIN_INITIALIZATION_OPERATION");
+ if (ret != 0)
goto cleanup;
- }
- wait_event_timeout(request->wait_event, request->wait_condition,
- msecs_to_jiffies(1000));
- if (request->wait_condition == 0) {
+ t = wait_for_completion_timeout(&request->wait_event, HZ);
+ if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
}
/* TODO: Check returned version */
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- DPRINT_ERR(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION failed "
- "(op %d status 0x%x)",
- vstor_packet->operation, vstor_packet->status);
+ vstor_packet->status != 0)
goto cleanup;
- }
/* Query channel properties */
DPRINT_INFO(STORVSC, "QUERY_PROPERTIES_OPERATION...");
@@ -284,76 +183,54 @@ static int stor_vsc_channel_init(struct hv_device *device)
vstor_packet->storage_channel_properties.port_number =
stor_device->port_number;
- request->wait_condition = 0;
ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
(unsigned long)request,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(STORVSC,
- "unable to send QUERY_PROPERTIES_OPERATION");
+ if (ret != 0)
goto cleanup;
- }
- wait_event_timeout(request->wait_event, request->wait_condition,
- msecs_to_jiffies(1000));
- if (request->wait_condition == 0) {
+ t = wait_for_completion_timeout(&request->wait_event, HZ);
+ if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
}
/* TODO: Check returned version */
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- DPRINT_ERR(STORVSC, "QUERY_PROPERTIES_OPERATION failed "
- "(op %d status 0x%x)",
- vstor_packet->operation, vstor_packet->status);
+ vstor_packet->status != 0)
goto cleanup;
- }
stor_device->path_id = vstor_packet->storage_channel_properties.path_id;
stor_device->target_id
= vstor_packet->storage_channel_properties.target_id;
- DPRINT_DBG(STORVSC, "channel flag 0x%x, max xfer len 0x%x",
- vstor_packet->storage_channel_properties.flags,
- vstor_packet->storage_channel_properties.max_transfer_bytes);
-
DPRINT_INFO(STORVSC, "END_INITIALIZATION_OPERATION...");
memset(vstor_packet, 0, sizeof(struct vstor_packet));
vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
- request->wait_condition = 0;
ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
(unsigned long)request,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(STORVSC,
- "unable to send END_INITIALIZATION_OPERATION");
+ if (ret != 0)
goto cleanup;
- }
- wait_event_timeout(request->wait_event, request->wait_condition,
- msecs_to_jiffies(1000));
- if (request->wait_condition == 0) {
+ t = wait_for_completion_timeout(&request->wait_event, HZ);
+ if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
}
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- DPRINT_ERR(STORVSC, "END_INITIALIZATION_OPERATION failed "
- "(op %d status 0x%x)",
- vstor_packet->operation, vstor_packet->status);
+ vstor_packet->status != 0)
goto cleanup;
- }
DPRINT_INFO(STORVSC, "**** storage channel up and running!! ****");
@@ -362,78 +239,70 @@ cleanup:
return ret;
}
-static void stor_vsc_on_io_completion(struct hv_device *device,
+static void storvsc_on_io_completion(struct hv_device *device,
struct vstor_packet *vstor_packet,
- struct storvsc_request_extension *request_ext)
+ struct hv_storvsc_request *request)
{
- struct hv_storvsc_request *request;
struct storvsc_device *stor_device;
+ struct vstor_packet *stor_pkt;
stor_device = must_get_stor_device(device);
- if (!stor_device) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
+ if (!stor_device)
return;
- }
-
- DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION - request extension %p "
- "completed bytes xfer %u", request_ext,
- vstor_packet->vm_srb.data_transfer_length);
- /* ASSERT(request_ext != NULL); */
- /* ASSERT(request_ext->request != NULL); */
+ stor_pkt = &request->vstor_packet;
- request = request_ext->request;
-
- /* ASSERT(request->OnIOCompletion != NULL); */
/* Copy over the status...etc */
- request->status = vstor_packet->vm_srb.scsi_status;
+ stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status;
+ stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status;
+ stor_pkt->vm_srb.sense_info_length =
+ vstor_packet->vm_srb.sense_info_length;
- if (request->status != 0 || vstor_packet->vm_srb.srb_status != 1) {
+ if (vstor_packet->vm_srb.scsi_status != 0 ||
+ vstor_packet->vm_srb.srb_status != 1){
DPRINT_WARN(STORVSC,
"cmd 0x%x scsi status 0x%x srb status 0x%x\n",
- request->cdb[0], vstor_packet->vm_srb.scsi_status,
+ stor_pkt->vm_srb.cdb[0],
+ vstor_packet->vm_srb.scsi_status,
vstor_packet->vm_srb.srb_status);
}
- if ((request->status & 0xFF) == 0x02) {
+ if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
/* CHECK_CONDITION */
if (vstor_packet->vm_srb.srb_status & 0x80) {
/* autosense data available */
DPRINT_WARN(STORVSC, "storvsc pkt %p autosense data "
- "valid - len %d\n", request_ext,
+ "valid - len %d\n", request,
vstor_packet->vm_srb.sense_info_length);
- /* ASSERT(vstor_packet->vm_srb.sense_info_length <= */
- /* request->SenseBufferSize); */
memcpy(request->sense_buffer,
vstor_packet->vm_srb.sense_data,
vstor_packet->vm_srb.sense_info_length);
- request->sense_buffer_size =
- vstor_packet->vm_srb.sense_info_length;
}
}
- /* TODO: */
- request->bytes_xfer = vstor_packet->vm_srb.data_transfer_length;
+ stor_pkt->vm_srb.data_transfer_length =
+ vstor_packet->vm_srb.data_transfer_length;
request->on_io_completion(request);
- atomic_dec(&stor_device->num_outstanding_req);
+ if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
+ stor_device->drain_notify)
+ wake_up(&stor_device->waiting_to_drain);
+
put_stor_device(device);
}
-static void stor_vsc_on_receive(struct hv_device *device,
+static void storvsc_on_receive(struct hv_device *device,
struct vstor_packet *vstor_packet,
- struct storvsc_request_extension *request_ext)
+ struct hv_storvsc_request *request)
{
switch (vstor_packet->operation) {
case VSTOR_OPERATION_COMPLETE_IO:
- DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION");
- stor_vsc_on_io_completion(device, vstor_packet, request_ext);
+ storvsc_on_io_completion(device, vstor_packet, request);
break;
case VSTOR_OPERATION_REMOVE_DEVICE:
DPRINT_INFO(STORVSC, "REMOVE_DEVICE_OPERATION");
@@ -447,60 +316,42 @@ static void stor_vsc_on_receive(struct hv_device *device,
}
}
-static void stor_vsc_on_channel_callback(void *context)
+static void storvsc_on_channel_callback(void *context)
{
struct hv_device *device = (struct hv_device *)context;
struct storvsc_device *stor_device;
u32 bytes_recvd;
u64 request_id;
unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)];
- struct storvsc_request_extension *request;
+ struct hv_storvsc_request *request;
int ret;
- /* ASSERT(device); */
stor_device = must_get_stor_device(device);
- if (!stor_device) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
+ if (!stor_device)
return;
- }
do {
ret = vmbus_recvpacket(device->channel, packet,
ALIGN(sizeof(struct vstor_packet), 8),
&bytes_recvd, &request_id);
if (ret == 0 && bytes_recvd > 0) {
- DPRINT_DBG(STORVSC, "receive %d bytes - tid %llx",
- bytes_recvd, request_id);
- /* ASSERT(bytes_recvd ==
- sizeof(struct vstor_packet)); */
-
- request = (struct storvsc_request_extension *)
+ request = (struct hv_storvsc_request *)
(unsigned long)request_id;
- /* ASSERT(request);c */
- /* if (vstor_packet.Flags & SYNTHETIC_FLAG) */
if ((request == &stor_device->init_request) ||
(request == &stor_device->reset_request)) {
- /* DPRINT_INFO(STORVSC,
- * "reset completion - operation "
- * "%u status %u",
- * vstor_packet.Operation,
- * vstor_packet.Status); */
memcpy(&request->vstor_packet, packet,
sizeof(struct vstor_packet));
- request->wait_condition = 1;
- wake_up(&request->wait_event);
+ complete(&request->wait_event);
} else {
- stor_vsc_on_receive(device,
+ storvsc_on_receive(device,
(struct vstor_packet *)packet,
request);
}
} else {
- /* DPRINT_DBG(STORVSC, "nothing else to read..."); */
break;
}
} while (1);
@@ -509,45 +360,33 @@ static void stor_vsc_on_channel_callback(void *context)
return;
}
-static int stor_vsc_connect_to_vsp(struct hv_device *device)
+static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
{
struct vmstorage_channel_properties props;
- struct storvsc_driver_object *stor_driver;
int ret;
- stor_driver = (struct storvsc_driver_object *)device->drv;
memset(&props, 0, sizeof(struct vmstorage_channel_properties));
/* Open the channel */
ret = vmbus_open(device->channel,
- stor_driver->ring_buffer_size,
- stor_driver->ring_buffer_size,
+ ring_size,
+ ring_size,
(void *)&props,
sizeof(struct vmstorage_channel_properties),
- stor_vsc_on_channel_callback, device);
-
- DPRINT_DBG(STORVSC, "storage props: path id %d, tgt id %d, max xfer %d",
- props.path_id, props.target_id, props.max_transfer_bytes);
+ storvsc_on_channel_callback, device);
- if (ret != 0) {
- DPRINT_ERR(STORVSC, "unable to open channel: %d", ret);
+ if (ret != 0)
return -1;
- }
- ret = stor_vsc_channel_init(device);
+ ret = storvsc_channel_init(device);
return ret;
}
-/*
- * stor_vsc_on_device_add - Callback when the device belonging to this driver
- * is added
- */
-static int stor_vsc_on_device_add(struct hv_device *device,
+int storvsc_dev_add(struct hv_device *device,
void *additional_info)
{
struct storvsc_device *stor_device;
- /* struct vmstorage_channel_properties *props; */
struct storvsc_device_info *device_info;
int ret = 0;
@@ -559,8 +398,6 @@ static int stor_vsc_on_device_add(struct hv_device *device,
}
/* Save the channel properties to our storvsc channel */
- /* props = (struct vmstorage_channel_properties *)
- * channel->offerMsg.Offer.u.Standard.UserDefined; */
/* FIXME: */
/*
@@ -569,30 +406,18 @@ static int stor_vsc_on_device_add(struct hv_device *device,
* scsi channel prior to the bus scan
*/
- /* storChannel->PortNumber = 0;
- storChannel->PathId = props->PathId;
- storChannel->TargetId = props->TargetId; */
-
stor_device->port_number = device_info->port_number;
/* Send it back up */
- ret = stor_vsc_connect_to_vsp(device);
+ ret = storvsc_connect_to_vsp(device, device_info->ring_buffer_size);
- /* device_info->PortNumber = stor_device->PortNumber; */
device_info->path_id = stor_device->path_id;
device_info->target_id = stor_device->target_id;
- DPRINT_DBG(STORVSC, "assigned port %u, path %u target %u\n",
- stor_device->port_number, stor_device->path_id,
- stor_device->target_id);
-
cleanup:
return ret;
}
-/*
- * stor_vsc_on_device_remove - Callback when the our device is being removed
- */
-static int stor_vsc_on_device_remove(struct hv_device *device)
+int storvsc_dev_remove(struct hv_device *device)
{
struct storvsc_device *stor_device;
@@ -606,19 +431,11 @@ static int stor_vsc_on_device_remove(struct hv_device *device)
* only allow inbound traffic (responses) to proceed so that
* outstanding requests can be completed.
*/
- while (atomic_read(&stor_device->num_outstanding_req)) {
- DPRINT_INFO(STORVSC, "waiting for %d requests to complete...",
- atomic_read(&stor_device->num_outstanding_req));
- udelay(100);
- }
- DPRINT_INFO(STORVSC, "removing storage device (%p)...",
- device->ext);
+ storvsc_wait_to_drain(stor_device);
stor_device = final_release_stor_device(device);
- DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", stor_device);
-
/* Close the channel */
vmbus_close(device->channel);
@@ -626,148 +443,52 @@ static int stor_vsc_on_device_remove(struct hv_device *device)
return 0;
}
-int stor_vsc_on_host_reset(struct hv_device *device)
-{
- struct storvsc_device *stor_device;
- struct storvsc_request_extension *request;
- struct vstor_packet *vstor_packet;
- int ret;
-
- DPRINT_INFO(STORVSC, "resetting host adapter...");
-
- stor_device = get_stor_device(device);
- if (!stor_device) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
- return -1;
- }
-
- request = &stor_device->reset_request;
- vstor_packet = &request->vstor_packet;
-
- init_waitqueue_head(&request->wait_event);
-
- vstor_packet->operation = VSTOR_OPERATION_RESET_BUS;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
- vstor_packet->vm_srb.path_id = stor_device->path_id;
-
- request->wait_condition = 0;
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- sizeof(struct vstor_packet),
- (unsigned long)&stor_device->reset_request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(STORVSC, "Unable to send reset packet %p ret %d",
- vstor_packet, ret);
- goto cleanup;
- }
-
- wait_event_timeout(request->wait_event, request->wait_condition,
- msecs_to_jiffies(1000));
- if (request->wait_condition == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- DPRINT_INFO(STORVSC, "host adapter reset completed");
-
- /*
- * At this point, all outstanding requests in the adapter
- * should have been flushed out and return to us
- */
-
-cleanup:
- put_stor_device(device);
- return ret;
-}
-
-/*
- * stor_vsc_on_io_request - Callback to initiate an I/O request
- */
-static int stor_vsc_on_io_request(struct hv_device *device,
+int storvsc_do_io(struct hv_device *device,
struct hv_storvsc_request *request)
{
struct storvsc_device *stor_device;
- struct storvsc_request_extension *request_extension;
struct vstor_packet *vstor_packet;
int ret = 0;
- request_extension =
- (struct storvsc_request_extension *)request->extension;
- vstor_packet = &request_extension->vstor_packet;
+ vstor_packet = &request->vstor_packet;
stor_device = get_stor_device(device);
- DPRINT_DBG(STORVSC, "enter - Device %p, DeviceExt %p, Request %p, "
- "Extension %p", device, stor_device, request,
- request_extension);
-
- DPRINT_DBG(STORVSC, "req %p len %d bus %d, target %d, lun %d cdblen %d",
- request, request->data_buffer.len, request->bus,
- request->target_id, request->lun_id, request->cdb_len);
-
- if (!stor_device) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
+ if (!stor_device)
return -2;
- }
- /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, request->Cdb,
- * request->CdbLen); */
- request_extension->request = request;
- request_extension->device = device;
+ request->device = device;
- memset(vstor_packet, 0 , sizeof(struct vstor_packet));
vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
vstor_packet->vm_srb.length = sizeof(struct vmscsi_request);
- vstor_packet->vm_srb.port_number = request->host;
- vstor_packet->vm_srb.path_id = request->bus;
- vstor_packet->vm_srb.target_id = request->target_id;
- vstor_packet->vm_srb.lun = request->lun_id;
vstor_packet->vm_srb.sense_info_length = SENSE_BUFFER_SIZE;
- /* Copy over the scsi command descriptor block */
- vstor_packet->vm_srb.cdb_length = request->cdb_len;
- memcpy(&vstor_packet->vm_srb.cdb, request->cdb, request->cdb_len);
- vstor_packet->vm_srb.data_in = request->type;
- vstor_packet->vm_srb.data_transfer_length = request->data_buffer.len;
+ vstor_packet->vm_srb.data_transfer_length =
+ request->data_buffer.len;
vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
- DPRINT_DBG(STORVSC, "srb - len %d port %d, path %d, target %d, "
- "lun %d senselen %d cdblen %d",
- vstor_packet->vm_srb.length,
- vstor_packet->vm_srb.port_number,
- vstor_packet->vm_srb.path_id,
- vstor_packet->vm_srb.target_id,
- vstor_packet->vm_srb.lun,
- vstor_packet->vm_srb.sense_info_length,
- vstor_packet->vm_srb.cdb_length);
-
- if (request_extension->request->data_buffer.len) {
+ if (request->data_buffer.len) {
ret = vmbus_sendpacket_multipagebuffer(device->channel,
- &request_extension->request->data_buffer,
+ &request->data_buffer,
vstor_packet,
sizeof(struct vstor_packet),
- (unsigned long)request_extension);
+ (unsigned long)request);
} else {
ret = vmbus_sendpacket(device->channel, vstor_packet,
sizeof(struct vstor_packet),
- (unsigned long)request_extension,
+ (unsigned long)request,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
}
- if (ret != 0) {
- DPRINT_DBG(STORVSC, "Unable to send packet %p ret %d",
- vstor_packet, ret);
- }
+ if (ret != 0)
+ return ret;
atomic_inc(&stor_device->num_outstanding_req);
@@ -776,62 +497,68 @@ static int stor_vsc_on_io_request(struct hv_device *device,
}
/*
- * stor_vsc_on_cleanup - Perform any cleanup when the driver is removed
+ * The channel properties uniquely specify how the device is to be
+ * presented to the guest. Map this information for use by the block
+ * driver. For Linux guests on Hyper-V, we emulate a scsi HBA in the guest
+ * (storvsc_drv) and so scsi devices in the guest are handled by
+ * native upper level Linux drivers. Consequently, Hyper-V
+ * block driver, while being a generic block driver, presently does not
+ * deal with anything other than devices that would need to be presented
+ * to the guest as an IDE disk.
+ *
+ * This function maps the channel properties as embedded in the input
+ * parameter device_info onto information necessary to register the
+ * corresponding block device.
+ *
+ * Currently, there is no way to stop the emulation of the block device
+ * on the host side. And so, to prevent the native IDE drivers in Linux
+ * from taking over these devices (to be managedby Hyper-V block
+ * driver), we will take over if need be the major of the IDE controllers.
+ *
*/
-static void stor_vsc_on_cleanup(struct hv_driver *driver)
-{
-}
-/*
- * stor_vsc_initialize - Main entry point
- */
-int stor_vsc_initialize(struct hv_driver *driver)
+int storvsc_get_major_info(struct storvsc_device_info *device_info,
+ struct storvsc_major_info *major_info)
{
- struct storvsc_driver_object *stor_driver;
-
- stor_driver = (struct storvsc_driver_object *)driver;
-
- DPRINT_DBG(STORVSC, "sizeof(STORVSC_REQUEST)=%zd "
- "sizeof(struct storvsc_request_extension)=%zd "
- "sizeof(struct vstor_packet)=%zd, "
- "sizeof(struct vmscsi_request)=%zd",
- sizeof(struct hv_storvsc_request),
- sizeof(struct storvsc_request_extension),
- sizeof(struct vstor_packet),
- sizeof(struct vmscsi_request));
-
- /* Make sure we are at least 2 pages since 1 page is used for control */
- /* ASSERT(stor_driver->RingBufferSize >= (PAGE_SIZE << 1)); */
-
- driver->name = g_driver_name;
- memcpy(&driver->dev_type, &gStorVscDeviceType,
- sizeof(struct hv_guid));
-
- stor_driver->request_ext_size =
- sizeof(struct storvsc_request_extension);
+ static bool ide0_registered;
+ static bool ide1_registered;
/*
- * Divide the ring buffer data size (which is 1 page less
- * than the ring buffer size since that page is reserved for
- * the ring buffer indices) by the max request size (which is
- * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
+ * For now we only support IDE disks.
*/
- stor_driver->max_outstanding_req_per_channel =
- ((stor_driver->ring_buffer_size - PAGE_SIZE) /
- ALIGN(MAX_MULTIPAGE_BUFFER_PACKET +
- sizeof(struct vstor_packet) + sizeof(u64),
- sizeof(u64)));
-
- DPRINT_INFO(STORVSC, "max io %u, currently %u\n",
- stor_driver->max_outstanding_req_per_channel,
- STORVSC_MAX_IO_REQUESTS);
-
- /* Setup the dispatch table */
- stor_driver->base.dev_add = stor_vsc_on_device_add;
- stor_driver->base.dev_rm = stor_vsc_on_device_remove;
- stor_driver->base.cleanup = stor_vsc_on_cleanup;
-
- stor_driver->on_io_request = stor_vsc_on_io_request;
+ major_info->devname = "ide";
+ major_info->diskname = "hd";
+
+ if (device_info->path_id) {
+ major_info->major = 22;
+ if (!ide1_registered) {
+ major_info->do_register = true;
+ ide1_registered = true;
+ } else
+ major_info->do_register = false;
+
+ if (device_info->target_id)
+ major_info->index = 3;
+ else
+ major_info->index = 2;
+
+ return 0;
+ } else {
+ major_info->major = 3;
+ if (!ide0_registered) {
+ major_info->do_register = true;
+ ide0_registered = true;
+ } else
+ major_info->do_register = false;
+
+ if (device_info->target_id)
+ major_info->index = 1;
+ else
+ major_info->index = 0;
+
+ return 0;
+ }
- return 0;
+ return -ENODEV;
}
+
diff --git a/drivers/staging/hv/storvsc_api.h b/drivers/staging/hv/storvsc_api.h
deleted file mode 100644
index fbf57556d890..000000000000
--- a/drivers/staging/hv/storvsc_api.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _STORVSC_API_H_
-#define _STORVSC_API_H_
-
-#include "vmbus_api.h"
-
-/* Defines */
-#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
-#define BLKVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
-
-#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 hv_storvsc_request;
-
-/* Matches Windows-end */
-enum storvsc_request_type{
- WRITE_TYPE,
- READ_TYPE,
- UNKNOWN_TYPE,
-};
-
-struct hv_storvsc_request {
- enum storvsc_request_type type;
- u32 host;
- u32 bus;
- u32 target_id;
- u32 lun_id;
- u8 *cdb;
- u32 cdb_len;
- u32 status;
- u32 bytes_xfer;
-
- unsigned char *sense_buffer;
- u32 sense_buffer_size;
-
- void *context;
-
- void (*on_io_completion)(struct hv_storvsc_request *request);
-
- /* This points to the memory after DataBuffer */
- void *extension;
-
- struct hv_multipage_buffer data_buffer;
-};
-
-/* Represents the block vsc driver */
-struct storvsc_driver_object {
- /* Must be the first field */
- /* Which is a bug FIXME! */
- struct hv_driver base;
-
- /* Set by caller (in bytes) */
- u32 ring_buffer_size;
-
- /* Allocate this much private extension for each I/O request */
- u32 request_ext_size;
-
- /* Maximum # of requests in flight per channel/device */
- u32 max_outstanding_req_per_channel;
-
- /* Specific to this driver */
- int (*on_io_request)(struct hv_device *device,
- struct hv_storvsc_request *request);
-};
-
-struct storvsc_device_info {
- unsigned int port_number;
- unsigned char path_id;
- unsigned char target_id;
-};
-
-/* Interface */
-int stor_vsc_initialize(struct hv_driver *driver);
-int stor_vsc_on_host_reset(struct hv_device *device);
-int blk_vsc_initialize(struct hv_driver *driver);
-
-#endif /* _STORVSC_API_H_ */
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index e6462a2fe9ab..942cc5f98db1 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -17,6 +17,7 @@
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
*/
#include <linux/init.h>
#include <linux/slab.h>
@@ -31,18 +32,27 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_dbg.h>
-#include "hv_api.h"
-#include "logging.h"
-#include "version_info.h"
-#include "vmbus.h"
-#include "storvsc_api.h"
-
-
-struct host_device_context {
- /* must be 1st field
- * FIXME this is a bug */
- /* point back to our device context */
- struct hv_device *device_ctx;
+
+#include "hyperv.h"
+#include "hyperv_storage.h"
+
+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)");
+
+static const char *driver_name = "storvsc";
+
+/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
+static const struct hv_guid gStorVscDeviceType = {
+ .data = {
+ 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
+ 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
+ }
+};
+
+struct hv_host_device {
+ struct hv_device *dev;
struct kmem_cache *request_pool;
unsigned int port;
unsigned char path;
@@ -57,331 +67,57 @@ struct storvsc_cmd_request {
struct scatterlist *bounce_sgl;
struct hv_storvsc_request request;
- /* !!!DO NOT ADD ANYTHING BELOW HERE!!! */
- /* The extension buffer falls right here and is pointed to by
- * request.Extension;
- * Which sounds like a very bad design... */
};
-/* Static decl */
-static int storvsc_probe(struct device *dev);
-static int storvsc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd);
-static int storvsc_device_alloc(struct scsi_device *);
-static int storvsc_device_configure(struct scsi_device *);
-static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd);
-static int storvsc_remove(struct device *dev);
-
-static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count,
- unsigned int len);
-static void destroy_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count);
-static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count);
-static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count);
-static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count);
-
-static int storvsc_get_chs(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int *info);
-
-
-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)");
-
-/* The one and only one */
-static struct storvsc_driver_object g_storvsc_drv;
-
-/* Scsi driver */
-static struct scsi_host_template scsi_driver = {
- .module = THIS_MODULE,
- .name = "storvsc_host_t",
- .bios_param = storvsc_get_chs,
- .queuecommand = storvsc_queuecommand,
- .eh_host_reset_handler = storvsc_host_reset_handler,
- .slave_alloc = storvsc_device_alloc,
- .slave_configure = storvsc_device_configure,
- .cmd_per_lun = 1,
- /* 64 max_queue * 1 target */
- .can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS,
- .this_id = -1,
- /* no use setting to 0 since ll_blk_rw reset it to 1 */
- /* currently 32 */
- .sg_tablesize = MAX_MULTIPAGE_BUFFER_COUNT,
+static int storvsc_device_alloc(struct scsi_device *sdevice)
+{
/*
- * 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
+ * This enables luns to be located sparsely. Otherwise, we may not
+ * discovered them.
*/
- /* physically contig pfns (ie sg[x].length > PAGE_SIZE). */
- .use_clustering = ENABLE_CLUSTERING,
- /* Make sure we dont get a sg segment crosses a page boundary */
- .dma_boundary = PAGE_SIZE-1,
-};
-
-
-/*
- * storvsc_drv_init - StorVsc driver initialization.
- */
-static int storvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
-{
- int ret;
- struct storvsc_driver_object *storvsc_drv_obj = &g_storvsc_drv;
- struct hv_driver *drv = &g_storvsc_drv.base;
-
- storvsc_drv_obj->ring_buffer_size = storvsc_ringbuffer_size;
-
- /* Callback to client driver to complete the initialization */
- drv_init(&storvsc_drv_obj->base);
-
- drv->priv = storvsc_drv_obj;
-
- DPRINT_INFO(STORVSC_DRV,
- "request extension size %u, max outstanding reqs %u",
- storvsc_drv_obj->request_ext_size,
- storvsc_drv_obj->max_outstanding_req_per_channel);
-
- if (storvsc_drv_obj->max_outstanding_req_per_channel <
- STORVSC_MAX_IO_REQUESTS) {
- DPRINT_ERR(STORVSC_DRV,
- "The number of outstanding io requests (%d) "
- "is larger than that supported (%d) internally.",
- STORVSC_MAX_IO_REQUESTS,
- storvsc_drv_obj->max_outstanding_req_per_channel);
- return -1;
- }
-
- drv->driver.name = storvsc_drv_obj->base.name;
-
- drv->driver.probe = storvsc_probe;
- drv->driver.remove = storvsc_remove;
-
- /* The driver belongs to vmbus */
- ret = vmbus_child_driver_register(&drv->driver);
-
- return ret;
-}
-
-static int storvsc_drv_exit_cb(struct device *dev, void *data)
-{
- struct device **curr = (struct device **)data;
- *curr = dev;
- return 1; /* stop iterating */
-}
-
-static void storvsc_drv_exit(void)
-{
- struct storvsc_driver_object *storvsc_drv_obj = &g_storvsc_drv;
- struct hv_driver *drv = &g_storvsc_drv.base;
- struct device *current_dev = NULL;
- int ret;
-
- while (1) {
- current_dev = NULL;
-
- /* Get the device */
- ret = driver_for_each_device(&drv->driver, NULL,
- (void *) &current_dev,
- storvsc_drv_exit_cb);
-
- if (ret)
- DPRINT_WARN(STORVSC_DRV,
- "driver_for_each_device returned %d", ret);
-
- if (current_dev == NULL)
- break;
-
- /* Initiate removal from the top-down */
- device_unregister(current_dev);
- }
-
- if (storvsc_drv_obj->base.cleanup)
- storvsc_drv_obj->base.cleanup(&storvsc_drv_obj->base);
-
- vmbus_child_driver_unregister(&drv->driver);
- return;
+ sdevice->sdev_bflags |= BLIST_SPARSELUN | BLIST_LARGELUN;
+ return 0;
}
-/*
- * storvsc_probe - Add a new device for this driver
- */
-static int storvsc_probe(struct device *device)
+static int storvsc_merge_bvec(struct request_queue *q,
+ struct bvec_merge_data *bmd, struct bio_vec *bvec)
{
- int ret;
- struct hv_driver *drv =
- drv_to_hv_drv(device->driver);
- struct storvsc_driver_object *storvsc_drv_obj = drv->priv;
- struct hv_device *device_obj = device_to_hv_device(device);
- struct Scsi_Host *host;
- struct host_device_context *host_device_ctx;
- struct storvsc_device_info device_info;
-
- if (!storvsc_drv_obj->base.dev_add)
- return -1;
-
- host = scsi_host_alloc(&scsi_driver,
- sizeof(struct host_device_context));
- if (!host) {
- DPRINT_ERR(STORVSC_DRV, "unable to allocate scsi host object");
- return -ENOMEM;
- }
-
- dev_set_drvdata(device, host);
-
- host_device_ctx = (struct host_device_context *)host->hostdata;
- memset(host_device_ctx, 0, sizeof(struct host_device_context));
-
- host_device_ctx->port = host->host_no;
- host_device_ctx->device_ctx = device_obj;
-
- host_device_ctx->request_pool =
- kmem_cache_create(dev_name(&device_obj->device),
- sizeof(struct storvsc_cmd_request) +
- storvsc_drv_obj->request_ext_size, 0,
- SLAB_HWCACHE_ALIGN, NULL);
-
- if (!host_device_ctx->request_pool) {
- scsi_host_put(host);
- return -ENOMEM;
- }
-
- device_info.port_number = host->host_no;
- /* Call to the vsc driver to add the device */
- ret = storvsc_drv_obj->base.dev_add(device_obj,
- (void *)&device_info);
- if (ret != 0) {
- DPRINT_ERR(STORVSC_DRV, "unable to add scsi vsc device");
- kmem_cache_destroy(host_device_ctx->request_pool);
- scsi_host_put(host);
- return -1;
- }
-
- /* host_device_ctx->port = device_info.PortNumber; */
- host_device_ctx->path = device_info.path_id;
- host_device_ctx->target = device_info.target_id;
-
- /* max # of devices per target */
- host->max_lun = STORVSC_MAX_LUNS_PER_TARGET;
- /* max # of targets per channel */
- host->max_id = STORVSC_MAX_TARGETS;
- /* max # of channels */
- host->max_channel = STORVSC_MAX_CHANNELS - 1;
-
- /* Register the HBA and start the scsi bus scan */
- ret = scsi_add_host(host, device);
- if (ret != 0) {
- DPRINT_ERR(STORVSC_DRV, "unable to add scsi host device");
-
- storvsc_drv_obj->base.dev_rm(device_obj);
-
- kmem_cache_destroy(host_device_ctx->request_pool);
- scsi_host_put(host);
- return -1;
- }
-
- scsi_scan_host(host);
- return ret;
+ /* checking done by caller. */
+ return bvec->bv_len;
}
-/*
- * storvsc_remove - Callback when our device is removed
- */
-static int storvsc_remove(struct device *device)
+static int storvsc_device_configure(struct scsi_device *sdevice)
{
- int ret;
- struct hv_driver *drv =
- drv_to_hv_drv(device->driver);
- struct storvsc_driver_object *storvsc_drv_obj = drv->priv;
- struct hv_device *device_obj = device_to_hv_device(device);
- struct Scsi_Host *host = dev_get_drvdata(device);
- struct host_device_context *host_device_ctx =
- (struct host_device_context *)host->hostdata;
-
-
- if (!storvsc_drv_obj->base.dev_rm)
- return -1;
+ scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
+ STORVSC_MAX_IO_REQUESTS);
- /*
- * Call to the vsc driver to let it know that the device is being
- * removed
- */
- ret = storvsc_drv_obj->base.dev_rm(device_obj);
- if (ret != 0) {
- /* TODO: */
- DPRINT_ERR(STORVSC, "unable to remove vsc device (ret %d)",
- ret);
- }
+ DPRINT_INFO(STORVSC_DRV, "sdev (%p) - setting max segment size to %ld",
+ sdevice, PAGE_SIZE);
+ blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
- if (host_device_ctx->request_pool) {
- kmem_cache_destroy(host_device_ctx->request_pool);
- host_device_ctx->request_pool = NULL;
- }
+ DPRINT_INFO(STORVSC_DRV, "sdev (%p) - adding merge bio vec routine",
+ sdevice);
+ blk_queue_merge_bvec(sdevice->request_queue, storvsc_merge_bvec);
- DPRINT_INFO(STORVSC, "removing host adapter (%p)...", host);
- scsi_remove_host(host);
+ blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
- DPRINT_INFO(STORVSC, "releasing host adapter (%p)...", host);
- scsi_host_put(host);
- return ret;
+ return 0;
}
-/*
- * storvsc_commmand_completion - Command completion processing
- */
-static void storvsc_commmand_completion(struct hv_storvsc_request *request)
+static void destroy_bounce_buffer(struct scatterlist *sgl,
+ unsigned int sg_count)
{
- struct storvsc_cmd_request *cmd_request =
- (struct storvsc_cmd_request *)request->context;
- struct scsi_cmnd *scmnd = cmd_request->cmd;
- struct host_device_context *host_device_ctx =
- (struct host_device_context *)scmnd->device->host->hostdata;
- void (*scsi_done_fn)(struct scsi_cmnd *);
- struct scsi_sense_hdr sense_hdr;
-
- /* ASSERT(request == &cmd_request->request); */
- /* ASSERT(scmnd); */
- /* ASSERT((unsigned long)scmnd->host_scribble == */
- /* (unsigned long)cmd_request); */
- /* ASSERT(scmnd->scsi_done); */
-
- if (cmd_request->bounce_sgl_count) {
- /* using bounce buffer */
- /* printk("copy_from_bounce_buffer\n"); */
-
- /* FIXME: We can optimize on writes by just skipping this */
- copy_from_bounce_buffer(scsi_sglist(scmnd),
- cmd_request->bounce_sgl,
- scsi_sg_count(scmnd));
- destroy_bounce_buffer(cmd_request->bounce_sgl,
- cmd_request->bounce_sgl_count);
- }
-
- scmnd->result = request->status;
+ int i;
+ struct page *page_buf;
- if (scmnd->result) {
- if (scsi_normalize_sense(scmnd->sense_buffer,
- request->sense_buffer_size, &sense_hdr))
- scsi_print_sense_hdr("storvsc", &sense_hdr);
+ for (i = 0; i < sg_count; i++) {
+ page_buf = sg_page((&sgl[i]));
+ if (page_buf != NULL)
+ __free_page(page_buf);
}
- /* ASSERT(request->BytesXfer <= request->data_buffer.Length); */
- scsi_set_resid(scmnd,
- request->data_buffer.len - request->bytes_xfer);
-
- scsi_done_fn = scmnd->scsi_done;
-
- scmnd->host_scribble = NULL;
- scmnd->scsi_done = NULL;
-
- /* !!DO NOT MODIFY the scmnd after this call */
- scsi_done_fn(scmnd);
-
- kmem_cache_free(host_device_ctx->request_pool, cmd_request);
+ kfree(sgl);
}
static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
@@ -440,21 +176,72 @@ cleanup:
return NULL;
}
-static void destroy_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count)
+
+/* 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)
{
int i;
- struct page *page_buf;
+ 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;
- for (i = 0; i < sg_count; i++) {
- page_buf = sg_page((&sgl[i]));
- if (page_buf != NULL)
- __free_page(page_buf);
+ 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++;
+
+ /* 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);
}
- kfree(sgl);
+ 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,
@@ -477,10 +264,10 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
src = src_addr;
srclen = orig_sgl[i].length;
- /* ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE); */
-
if (bounce_addr == 0)
- bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0);
+ bounce_addr =
+ (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
+ KM_IRQ0);
while (srclen) {
/* assume bounce offset always == 0 */
@@ -502,7 +289,10 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
/* 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 =
+ (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);
@@ -517,67 +307,185 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
return total_copied;
}
-/* 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)
+
+/*
+ * storvsc_remove - Callback when our device is removed
+ */
+static int storvsc_remove(struct hv_device *dev)
{
- 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;
+ struct Scsi_Host *host = dev_get_drvdata(&dev->device);
+ struct hv_host_device *host_dev =
+ (struct hv_host_device *)host->hostdata;
- local_irq_save(flags);
+ /*
+ * Call to the vsc driver to let it know that the device is being
+ * removed
+ */
+ storvsc_dev_remove(dev);
- 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;
- /* ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE); */
+ if (host_dev->request_pool) {
+ kmem_cache_destroy(host_dev->request_pool);
+ host_dev->request_pool = NULL;
+ }
- if (bounce_addr == 0)
- bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0);
+ DPRINT_INFO(STORVSC, "removing host adapter (%p)...", host);
+ scsi_remove_host(host);
- while (destlen) {
- src = bounce_addr + bounce_sgl[j].offset;
- srclen = bounce_sgl[j].length - bounce_sgl[j].offset;
+ DPRINT_INFO(STORVSC, "releasing host adapter (%p)...", host);
+ scsi_host_put(host);
+ return 0;
+}
- copylen = min(srclen, destlen);
- memcpy((void *)dest, (void *)src, copylen);
- total_copied += copylen;
- bounce_sgl[j].offset += copylen;
- destlen -= copylen;
- dest += copylen;
+static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
+ sector_t capacity, int *info)
+{
+ sector_t nsect = capacity;
+ sector_t cylinders = nsect;
+ int heads, sectors_pt;
- if (bounce_sgl[j].offset == bounce_sgl[j].length) {
- /* full */
- kunmap_atomic((void *)bounce_addr, KM_IRQ0);
- j++;
+ /*
+ * We are making up these values; let us keep it simple.
+ */
+ heads = 0xff;
+ sectors_pt = 0x3f; /* Sectors per track */
+ sector_div(cylinders, heads * sectors_pt);
+ if ((sector_t)(cylinders + 1) * heads * sectors_pt < nsect)
+ cylinders = 0xffff;
- /* 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);
- }
- }
+ info[0] = heads;
+ info[1] = sectors_pt;
+ info[2] = (int)cylinders;
- kunmap_atomic((void *)(dest_addr - orig_sgl[i].offset),
- KM_IRQ0);
+ DPRINT_INFO(STORVSC_DRV, "CHS (%d, %d, %d)", (int)cylinders, heads,
+ sectors_pt);
+
+ return 0;
+}
+
+static int storvsc_host_reset(struct hv_device *device)
+{
+ struct storvsc_device *stor_device;
+ struct hv_storvsc_request *request;
+ struct vstor_packet *vstor_packet;
+ int ret, t;
+
+ DPRINT_INFO(STORVSC, "resetting host adapter...");
+
+ stor_device = get_stor_device(device);
+ if (!stor_device)
+ return -1;
+
+ request = &stor_device->reset_request;
+ vstor_packet = &request->vstor_packet;
+
+ init_completion(&request->wait_event);
+
+ vstor_packet->operation = VSTOR_OPERATION_RESET_BUS;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+ vstor_packet->vm_srb.path_id = stor_device->path_id;
+
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
+ sizeof(struct vstor_packet),
+ (unsigned long)&stor_device->reset_request,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (ret != 0)
+ goto cleanup;
+
+ t = wait_for_completion_timeout(&request->wait_event, HZ);
+ if (t == 0) {
+ ret = -ETIMEDOUT;
+ goto cleanup;
}
- local_irq_restore(flags);
+ DPRINT_INFO(STORVSC, "host adapter reset completed");
- return total_copied;
+ /*
+ * At this point, all outstanding requests in the adapter
+ * should have been flushed out and return to us
+ */
+
+cleanup:
+ put_stor_device(device);
+ return ret;
+}
+
+
+/*
+ * storvsc_host_reset_handler - Reset the scsi HBA
+ */
+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;
+
+ DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host resetting...",
+ scmnd->device, dev);
+
+ /* Invokes the vsc to reset the host/bus */
+ ret = storvsc_host_reset(dev);
+ if (ret != 0)
+ return ret;
+
+ DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host reseted",
+ scmnd->device, dev);
+
+ return ret;
}
+
+/*
+ * storvsc_commmand_completion - Command completion processing
+ */
+static void storvsc_commmand_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;
+ void (*scsi_done_fn)(struct scsi_cmnd *);
+ struct scsi_sense_hdr sense_hdr;
+ struct vmscsi_request *vm_srb;
+
+ if (cmd_request->bounce_sgl_count) {
+
+ /* FIXME: We can optimize on writes by just skipping this */
+ copy_from_bounce_buffer(scsi_sglist(scmnd),
+ cmd_request->bounce_sgl,
+ scsi_sg_count(scmnd));
+ destroy_bounce_buffer(cmd_request->bounce_sgl,
+ cmd_request->bounce_sgl_count);
+ }
+
+ vm_srb = &request->vstor_packet.vm_srb;
+ scmnd->result = vm_srb->scsi_status;
+
+ 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;
+
+ /* !!DO NOT MODIFY the scmnd after this call */
+ scsi_done_fn(scmnd);
+
+ kmem_cache_free(host_dev->request_pool, cmd_request);
+}
+
+
/*
* storvsc_queuecommand - Initiate command processing
*/
@@ -585,28 +493,20 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
void (*done)(struct scsi_cmnd *))
{
int ret;
- struct host_device_context *host_device_ctx =
- (struct host_device_context *)scmnd->device->host->hostdata;
- struct hv_device *device_ctx = host_device_ctx->device_ctx;
- struct hv_driver *drv =
- drv_to_hv_drv(device_ctx->device.driver);
- struct storvsc_driver_object *storvsc_drv_obj = drv->priv;
+ struct hv_host_device *host_dev =
+ (struct hv_host_device *)scmnd->device->host->hostdata;
+ 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;
struct scatterlist *sgl;
unsigned int sg_count = 0;
+ struct vmscsi_request *vm_srb;
- DPRINT_DBG(STORVSC_DRV, "scmnd %p dir %d, use_sg %d buf %p len %d "
- "queue depth %d tagged %d", scmnd, scmnd->sc_data_direction,
- scsi_sg_count(scmnd), scsi_sglist(scmnd),
- scsi_bufflen(scmnd), scmnd->device->queue_depth,
- scmnd->device->tagged_supported);
/* If retrying, no need to prep the cmd */
if (scmnd->host_scribble) {
- /* ASSERT(scmnd->scsi_done != NULL); */
cmd_request =
(struct storvsc_cmd_request *)scmnd->host_scribble;
@@ -616,18 +516,13 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
goto retry_request;
}
- /* ASSERT(scmnd->scsi_done == NULL); */
- /* ASSERT(scmnd->host_scribble == NULL); */
-
scmnd->scsi_done = done;
request_size = sizeof(struct storvsc_cmd_request);
- cmd_request = kmem_cache_alloc(host_device_ctx->request_pool,
+ cmd_request = kmem_cache_zalloc(host_dev->request_pool,
GFP_ATOMIC);
if (!cmd_request) {
- DPRINT_ERR(STORVSC_DRV, "scmnd (%p) - unable to allocate "
- "storvsc_cmd_request...marking queue busy", scmnd);
scmnd->scsi_done = NULL;
return SCSI_MLQUEUE_DEVICE_BUSY;
}
@@ -640,40 +535,35 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
scmnd->host_scribble = (unsigned char *)cmd_request;
request = &cmd_request->request;
+ vm_srb = &request->vstor_packet.vm_srb;
- request->extension =
- (void *)((unsigned long)cmd_request + request_size);
- DPRINT_DBG(STORVSC_DRV, "req %p size %d ext %d", request, request_size,
- storvsc_drv_obj->request_ext_size);
/* Build the SRB */
switch (scmnd->sc_data_direction) {
case DMA_TO_DEVICE:
- request->type = WRITE_TYPE;
+ vm_srb->data_in = WRITE_TYPE;
break;
case DMA_FROM_DEVICE:
- request->type = READ_TYPE;
+ vm_srb->data_in = READ_TYPE;
break;
default:
- request->type = UNKNOWN_TYPE;
+ vm_srb->data_in = UNKNOWN_TYPE;
break;
}
request->on_io_completion = storvsc_commmand_completion;
request->context = cmd_request;/* scmnd; */
- /* request->PortId = scmnd->device->channel; */
- request->host = host_device_ctx->port;
- request->bus = scmnd->device->channel;
- request->target_id = scmnd->device->id;
- request->lun_id = scmnd->device->lun;
+ vm_srb->port_number = host_dev->port;
+ vm_srb->path_id = scmnd->device->channel;
+ vm_srb->target_id = scmnd->device->id;
+ vm_srb->lun = scmnd->device->lun;
+
+ vm_srb->cdb_length = scmnd->cmd_len;
- /* ASSERT(scmnd->cmd_len <= 16); */
- request->cdb_len = scmnd->cmd_len;
- request->cdb = scmnd->cmnd;
+ memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length);
request->sense_buffer = scmnd->sense_buffer;
- request->sense_buffer_size = SCSI_SENSE_BUFFERSIZE;
request->data_buffer.len = scsi_bufflen(scmnd);
@@ -683,20 +573,13 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
/* check if we need to bounce the sgl */
if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
- DPRINT_INFO(STORVSC_DRV,
- "need to bounce buffer for this scmnd %p",
- scmnd);
cmd_request->bounce_sgl =
create_bounce_buffer(sgl, scsi_sg_count(scmnd),
scsi_bufflen(scmnd));
if (!cmd_request->bounce_sgl) {
- DPRINT_ERR(STORVSC_DRV,
- "unable to create bounce buffer for "
- "this scmnd %p", scmnd);
-
scmnd->scsi_done = NULL;
scmnd->host_scribble = NULL;
- kmem_cache_free(host_device_ctx->request_pool,
+ kmem_cache_free(host_dev->request_pool,
cmd_request);
return SCSI_MLQUEUE_HOST_BUSY;
@@ -719,14 +602,11 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
request->data_buffer.offset = sgl[0].offset;
- for (i = 0; i < sg_count; i++) {
- DPRINT_DBG(STORVSC_DRV, "sgl[%d] len %d offset %d\n",
- i, sgl[i].length, sgl[i].offset);
+ for (i = 0; i < sg_count; i++)
request->data_buffer.pfn_array[i] =
page_to_pfn(sg_page((&sgl[i])));
- }
+
} else if (scsi_sglist(scmnd)) {
- /* ASSERT(scsi_bufflen(scmnd) <= PAGE_SIZE); */
request->data_buffer.offset =
virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1);
request->data_buffer.pfn_array[0] =
@@ -735,13 +615,10 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
retry_request:
/* Invokes the vsc to start an IO */
- ret = storvsc_drv_obj->on_io_request(device_ctx,
- &cmd_request->request);
+ ret = storvsc_do_io(dev, &cmd_request->request);
+
if (ret == -1) {
/* no more space */
- DPRINT_ERR(STORVSC_DRV,
- "scmnd (%p) - queue FULL...marking queue busy",
- scmnd);
if (cmd_request->bounce_sgl_count) {
/*
@@ -755,7 +632,7 @@ retry_request:
cmd_request->bounce_sgl_count);
}
- kmem_cache_free(host_device_ctx->request_pool, cmd_request);
+ kmem_cache_free(host_dev->request_pool, cmd_request);
scmnd->scsi_done = NULL;
scmnd->host_scribble = NULL;
@@ -768,154 +645,156 @@ retry_request:
static DEF_SCSI_QCMD(storvsc_queuecommand)
-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;
-}
-/*
- * storvsc_device_configure - Configure the specified scsi device
- */
-static int storvsc_device_alloc(struct scsi_device *sdevice)
-{
- DPRINT_DBG(STORVSC_DRV, "sdev (%p) - setting device flag to %d",
- sdevice, BLIST_SPARSELUN);
+/* Scsi driver */
+static struct scsi_host_template scsi_driver = {
+ .module = THIS_MODULE,
+ .name = "storvsc_host_t",
+ .bios_param = storvsc_get_chs,
+ .queuecommand = storvsc_queuecommand,
+ .eh_host_reset_handler = storvsc_host_reset_handler,
+ .slave_alloc = storvsc_device_alloc,
+ .slave_configure = storvsc_device_configure,
+ .cmd_per_lun = 1,
+ /* 64 max_queue * 1 target */
+ .can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS,
+ .this_id = -1,
+ /* no use setting to 0 since ll_blk_rw reset it to 1 */
+ /* currently 32 */
+ .sg_tablesize = MAX_MULTIPAGE_BUFFER_COUNT,
/*
- * This enables luns to be located sparsely. Otherwise, we may not
- * discovered them.
+ * 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
*/
- sdevice->sdev_bflags |= BLIST_SPARSELUN | BLIST_LARGELUN;
- return 0;
-}
+ /* physically contig pfns (ie sg[x].length > PAGE_SIZE). */
+ .use_clustering = ENABLE_CLUSTERING,
+ /* Make sure we dont get a sg segment crosses a page boundary */
+ .dma_boundary = PAGE_SIZE-1,
+};
-static int storvsc_device_configure(struct scsi_device *sdevice)
+
+/*
+ * storvsc_probe - Add a new device for this driver
+ */
+
+static int storvsc_probe(struct hv_device *device)
{
- DPRINT_INFO(STORVSC_DRV, "sdev (%p) - curr queue depth %d", sdevice,
- sdevice->queue_depth);
+ int ret;
+ struct Scsi_Host *host;
+ struct hv_host_device *host_dev;
+ struct storvsc_device_info device_info;
- DPRINT_INFO(STORVSC_DRV, "sdev (%p) - setting queue depth to %d",
- sdevice, STORVSC_MAX_IO_REQUESTS);
- scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
- STORVSC_MAX_IO_REQUESTS);
+ host = scsi_host_alloc(&scsi_driver,
+ sizeof(struct hv_host_device));
+ if (!host)
+ return -ENOMEM;
- DPRINT_INFO(STORVSC_DRV, "sdev (%p) - setting max segment size to %ld",
- sdevice, PAGE_SIZE);
- blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
+ dev_set_drvdata(&device->device, host);
- DPRINT_INFO(STORVSC_DRV, "sdev (%p) - adding merge bio vec routine",
- sdevice);
- blk_queue_merge_bvec(sdevice->request_queue, storvsc_merge_bvec);
+ host_dev = (struct hv_host_device *)host->hostdata;
+ memset(host_dev, 0, sizeof(struct hv_host_device));
- blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
- /* sdevice->timeout = (2000 * HZ);//(75 * HZ); */
+ host_dev->port = host->host_no;
+ host_dev->dev = device;
- return 0;
-}
+ host_dev->request_pool =
+ kmem_cache_create(dev_name(&device->device),
+ sizeof(struct storvsc_cmd_request), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
-/*
- * storvsc_host_reset_handler - Reset the scsi HBA
- */
-static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
-{
- int ret;
- struct host_device_context *host_device_ctx =
- (struct host_device_context *)scmnd->device->host->hostdata;
- struct hv_device *device_ctx = host_device_ctx->device_ctx;
+ if (!host_dev->request_pool) {
+ scsi_host_put(host);
+ return -ENOMEM;
+ }
- DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host resetting...",
- scmnd->device, device_ctx);
+ device_info.port_number = host->host_no;
+ device_info.ring_buffer_size = storvsc_ringbuffer_size;
+ /* Call to the vsc driver to add the device */
+ ret = storvsc_dev_add(device, (void *)&device_info);
- /* Invokes the vsc to reset the host/bus */
- ret = stor_vsc_on_host_reset(device_ctx);
- if (ret != 0)
- return ret;
+ if (ret != 0) {
+ kmem_cache_destroy(host_dev->request_pool);
+ scsi_host_put(host);
+ return -1;
+ }
- DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host reseted",
- scmnd->device, device_ctx);
+ host_dev->path = device_info.path_id;
+ host_dev->target = device_info.target_id;
- return ret;
-}
+ /* max # of devices per target */
+ host->max_lun = STORVSC_MAX_LUNS_PER_TARGET;
+ /* max # of targets per channel */
+ host->max_id = STORVSC_MAX_TARGETS;
+ /* max # of channels */
+ host->max_channel = STORVSC_MAX_CHANNELS - 1;
-static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
- sector_t capacity, int *info)
-{
- sector_t total_sectors = capacity;
- sector_t cylinder_times_heads = 0;
- sector_t temp = 0;
+ /* Register the HBA and start the scsi bus scan */
+ ret = scsi_add_host(host, &device->device);
+ if (ret != 0) {
- int sectors_per_track = 0;
- int heads = 0;
- int cylinders = 0;
- int rem = 0;
+ storvsc_dev_remove(device);
- if (total_sectors > (65535 * 16 * 255))
- total_sectors = (65535 * 16 * 255);
+ kmem_cache_destroy(host_dev->request_pool);
+ scsi_host_put(host);
+ return -1;
+ }
- if (total_sectors >= (65535 * 16 * 63)) {
- sectors_per_track = 255;
- heads = 16;
+ scsi_scan_host(host);
+ return ret;
+}
- cylinder_times_heads = total_sectors;
- /* sector_div stores the quotient in cylinder_times_heads */
- rem = sector_div(cylinder_times_heads, sectors_per_track);
- } else {
- sectors_per_track = 17;
+/* The one and only one */
- cylinder_times_heads = total_sectors;
- /* sector_div stores the quotient in cylinder_times_heads */
- rem = sector_div(cylinder_times_heads, sectors_per_track);
+static struct hv_driver storvsc_drv = {
+ .probe = storvsc_probe,
+ .remove = storvsc_remove,
+};
- temp = cylinder_times_heads + 1023;
- /* sector_div stores the quotient in temp */
- rem = sector_div(temp, 1024);
- heads = temp;
+/*
+ * storvsc_drv_init - StorVsc driver initialization.
+ */
+static int storvsc_drv_init(void)
+{
+ int ret;
+ struct hv_driver *drv = &storvsc_drv;
+ u32 max_outstanding_req_per_channel;
- if (heads < 4)
- heads = 4;
+ /*
+ * Divide the ring buffer data size (which is 1 page less
+ * than the ring buffer size since that page is reserved for
+ * the ring buffer indices) by the max request size (which is
+ * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
+ */
- if (cylinder_times_heads >= (heads * 1024) || (heads > 16)) {
- sectors_per_track = 31;
- heads = 16;
+ max_outstanding_req_per_channel =
+ ((storvsc_ringbuffer_size - PAGE_SIZE) /
+ ALIGN(MAX_MULTIPAGE_BUFFER_PACKET +
+ sizeof(struct vstor_packet) + sizeof(u64),
+ sizeof(u64)));
- cylinder_times_heads = total_sectors;
- /*
- * sector_div stores the quotient in
- * cylinder_times_heads
- */
- rem = sector_div(cylinder_times_heads,
- sectors_per_track);
- }
+ memcpy(&drv->dev_type, &gStorVscDeviceType,
+ sizeof(struct hv_guid));
- if (cylinder_times_heads >= (heads * 1024)) {
- sectors_per_track = 63;
- heads = 16;
+ if (max_outstanding_req_per_channel <
+ STORVSC_MAX_IO_REQUESTS)
+ return -1;
- cylinder_times_heads = total_sectors;
- /*
- * sector_div stores the quotient in
- * cylinder_times_heads
- */
- rem = sector_div(cylinder_times_heads,
- sectors_per_track);
- }
- }
+ drv->name = driver_name;
+ drv->driver.name = driver_name;
- temp = cylinder_times_heads;
- /* sector_div stores the quotient in temp */
- rem = sector_div(temp, heads);
- cylinders = temp;
- info[0] = heads;
- info[1] = sectors_per_track;
- info[2] = cylinders;
+ /* The driver belongs to vmbus */
+ ret = vmbus_child_driver_register(&drv->driver);
- DPRINT_INFO(STORVSC_DRV, "CHS (%d, %d, %d)", cylinders, heads,
- sectors_per_track);
+ return ret;
+}
- return 0;
+static void storvsc_drv_exit(void)
+{
+ vmbus_child_driver_unregister(&storvsc_drv.driver);
}
static int __init storvsc_init(void)
@@ -923,7 +802,7 @@ static int __init storvsc_init(void)
int ret;
DPRINT_INFO(STORVSC_DRV, "Storvsc initializing....");
- ret = storvsc_drv_init(stor_vsc_initialize);
+ ret = storvsc_drv_init();
return ret;
}
diff --git a/drivers/staging/hv/utils.h b/drivers/staging/hv/utils.h
deleted file mode 100644
index acebbbf888b0..000000000000
--- a/drivers/staging/hv/utils.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#ifndef __HV_UTILS_H_
-#define __HV_UTILS_H_
-
-/*
- * Common header for Hyper-V ICs
- */
-#define ICMSGTYPE_NEGOTIATE 0
-#define ICMSGTYPE_HEARTBEAT 1
-#define ICMSGTYPE_KVPEXCHANGE 2
-#define ICMSGTYPE_SHUTDOWN 3
-#define ICMSGTYPE_TIMESYNC 4
-#define ICMSGTYPE_VSS 5
-
-#define ICMSGHDRFLAG_TRANSACTION 1
-#define ICMSGHDRFLAG_REQUEST 2
-#define ICMSGHDRFLAG_RESPONSE 4
-
-#define HV_S_OK 0x00000000
-#define HV_E_FAIL 0x80004005
-#define HV_ERROR_NOT_SUPPORTED 0x80070032
-#define HV_ERROR_MACHINE_LOCKED 0x800704F7
-
-struct vmbuspipe_hdr {
- u32 flags;
- u32 msgsize;
-} __packed;
-
-struct ic_version {
- u16 major;
- u16 minor;
-} __packed;
-
-struct icmsg_hdr {
- struct ic_version icverframe;
- u16 icmsgtype;
- struct ic_version icvermsg;
- u16 icmsgsize;
- u32 status;
- u8 ictransaction_id;
- u8 icflags;
- u8 reserved[2];
-} __packed;
-
-struct icmsg_negotiate {
- u16 icframe_vercnt;
- u16 icmsg_vercnt;
- u32 reserved;
- struct ic_version icversion_data[1]; /* any size array */
-} __packed;
-
-struct shutdown_msg_data {
- u32 reason_code;
- u32 timeout_seconds;
- u32 flags;
- u8 display_message[2048];
-} __packed;
-
-struct heartbeat_msg_data {
- u64 seq_num;
- u32 reserved[8];
-} __packed;
-
-/* Time Sync IC defs */
-#define ICTIMESYNCFLAG_PROBE 0
-#define ICTIMESYNCFLAG_SYNC 1
-#define ICTIMESYNCFLAG_SAMPLE 2
-
-#ifdef __x86_64__
-#define WLTIMEDELTA 116444736000000000L /* in 100ns unit */
-#else
-#define WLTIMEDELTA 116444736000000000LL
-#endif
-
-struct ictimesync_data{
- u64 parenttime;
- u64 childtime;
- u64 roundtriptime;
- u8 flags;
-} __packed;
-
-/* Index for each IC struct in array hv_cb_utils[] */
-#define HV_SHUTDOWN_MSG 0
-#define HV_TIMESYNC_MSG 1
-#define HV_HEARTBEAT_MSG 2
-#define HV_KVP_MSG 3
-
-struct hyperv_service_callback {
- u8 msg_type;
- char *log_msg;
- unsigned char data[16];
- struct vmbus_channel *channel;
- void (*callback) (void *context);
-};
-
-extern void prep_negotiate_resp(struct icmsg_hdr *,
- struct icmsg_negotiate *, u8 *);
-extern void chn_cb_negotiate(void *);
-extern struct hyperv_service_callback hv_cb_utils[];
-
-#endif /* __HV_UTILS_H_ */
diff --git a/drivers/staging/hv/version_info.h b/drivers/staging/hv/version_info.h
deleted file mode 100644
index 35178f2c7967..000000000000
--- a/drivers/staging/hv/version_info.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-#ifndef __HV_VERSION_INFO
-#define __HV_VERSION_INFO
-
-/*
- * We use the same version numbering for all Hyper-V modules.
- *
- * Definition of versioning is as follows;
- *
- * Major Number Changes for these scenarios;
- * 1. When a new version of Windows Hyper-V
- * is released.
- * 2. A Major change has occurred in the
- * Linux IC's.
- * (For example the merge for the first time
- * into the kernel) Every time the Major Number
- * changes, the Revision number is reset to 0.
- * Minor Number Changes when new functionality is added
- * to the Linux IC's that is not a bug fix.
- *
- * 3.1 - Added completed hv_utils driver. Shutdown/Heartbeat/Timesync
- */
-#define HV_DRV_VERSION "3.1"
-
-
-#endif
diff --git a/drivers/staging/hv/vmbus.h b/drivers/staging/hv/vmbus.h
deleted file mode 100644
index 73087f26bec2..000000000000
--- a/drivers/staging/hv/vmbus.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _VMBUS_H_
-#define _VMBUS_H_
-
-#include <linux/device.h>
-#include "vmbus_api.h"
-
-
-
-
-static inline struct hv_device *device_to_hv_device(struct device *d)
-{
- return container_of(d, struct hv_device, device);
-}
-
-static inline struct hv_driver *drv_to_hv_drv(struct device_driver *d)
-{
- return container_of(d, struct hv_driver, driver);
-}
-
-
-/* Vmbus interface */
-int vmbus_child_driver_register(struct device_driver *drv);
-void vmbus_child_driver_unregister(struct device_driver *drv);
-
-extern struct completion hv_channel_ready;
-
-#endif /* _VMBUS_H_ */
diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h
deleted file mode 100644
index f0d96eba7013..000000000000
--- a/drivers/staging/hv/vmbus_api.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _VMBUS_API_H_
-#define _VMBUS_API_H_
-
-#include <linux/device.h>
-#include <linux/workqueue.h>
-
-#define MAX_PAGE_BUFFER_COUNT 16
-#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
-
-#pragma pack(push, 1)
-
-/* Single-page buffer */
-struct hv_page_buffer {
- u32 len;
- u32 offset;
- u64 pfn;
-};
-
-/* Multiple-page buffer */
-struct hv_multipage_buffer {
- /* Length and Offset determines the # of pfns in the array */
- u32 len;
- u32 offset;
- u64 pfn_array[MAX_MULTIPAGE_BUFFER_COUNT];
-};
-
-/* 0x18 includes the proprietary packet header */
-#define MAX_PAGE_BUFFER_PACKET (0x18 + \
- (sizeof(struct hv_page_buffer) * \
- MAX_PAGE_BUFFER_COUNT))
-#define MAX_MULTIPAGE_BUFFER_PACKET (0x18 + \
- sizeof(struct hv_multipage_buffer))
-
-
-#pragma pack(pop)
-
-struct hv_driver;
-struct hv_device;
-
-struct hv_dev_port_info {
- u32 int_mask;
- u32 read_idx;
- u32 write_idx;
- u32 bytes_avail_toread;
- u32 bytes_avail_towrite;
-};
-
-struct hv_device_info {
- u32 chn_id;
- u32 chn_state;
- struct hv_guid chn_type;
- struct hv_guid chn_instance;
-
- u32 monitor_id;
- u32 server_monitor_pending;
- u32 server_monitor_latency;
- u32 server_monitor_conn_id;
- u32 client_monitor_pending;
- u32 client_monitor_latency;
- u32 client_monitor_conn_id;
-
- struct hv_dev_port_info inbound;
- struct hv_dev_port_info outbound;
-};
-
-/* Base driver object */
-struct hv_driver {
- const char *name;
-
- /* the device type supported by this driver */
- struct hv_guid dev_type;
-
- /*
- * Device type specific drivers (net, blk etc.)
- * need a mechanism to get a pointer to
- * device type specific driver structure given
- * a pointer to the base hyperv driver structure.
- * The current code solves this problem using
- * a hack. Support this need explicitly
- */
- void *priv;
-
- struct device_driver driver;
-
- int (*dev_add)(struct hv_device *device, void *data);
- int (*dev_rm)(struct hv_device *device);
- void (*cleanup)(struct hv_driver *driver);
-};
-
-/* Base device object */
-struct hv_device {
- /* the driver for this device */
- struct hv_driver *drv;
-
- char name[64];
-
- struct work_struct probe_failed_work_item;
-
- int probe_error;
-
- /* the device type id of this device */
- struct hv_guid dev_type;
-
- /* the device instance id of this device */
- struct hv_guid dev_instance;
-
- struct device device;
-
- struct vmbus_channel *channel;
-
- /* Device extension; */
- void *ext;
-};
-
-#endif /* _VMBUS_API_H_ */
diff --git a/drivers/staging/hv/vmbus_channel_interface.h b/drivers/staging/hv/vmbus_channel_interface.h
deleted file mode 100644
index 20ae258e5f9c..000000000000
--- a/drivers/staging/hv/vmbus_channel_interface.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-#ifndef __VMBUSCHANNELINTERFACE_H
-#define __VMBUSCHANNELINTERFACE_H
-
-/*
- * A revision number of vmbus that is used for ensuring both ends on a
- * partition are using compatible versions.
- */
-#define VMBUS_REVISION_NUMBER 13
-
-/* Make maximum size of pipe payload of 16K */
-#define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)
-
-/* Define PipeMode values. */
-#define VMBUS_PIPE_TYPE_BYTE 0x00000000
-#define VMBUS_PIPE_TYPE_MESSAGE 0x00000004
-
-/* The size of the user defined data buffer for non-pipe offers. */
-#define MAX_USER_DEFINED_BYTES 120
-
-/* The size of the user defined data buffer for pipe offers. */
-#define MAX_PIPE_USER_DEFINED_BYTES 116
-
-/*
- * At the center of the Channel Management library is the Channel Offer. This
- * struct contains the fundamental information about an offer.
- */
-struct vmbus_channel_offer {
- struct hv_guid if_type;
- struct hv_guid if_instance;
- u64 int_latency; /* in 100ns units */
- u32 if_revision;
- u32 server_ctx_size; /* in bytes */
- u16 chn_flags;
- u16 mmio_megabytes; /* in bytes * 1024 * 1024 */
-
- union {
- /* Non-pipes: The user has MAX_USER_DEFINED_BYTES bytes. */
- struct {
- unsigned char user_def[MAX_USER_DEFINED_BYTES];
- } std;
-
- /*
- * Pipes:
- * The following sructure is an integrated pipe protocol, which
- * is implemented on top of standard user-defined data. Pipe
- * clients have MAX_PIPE_USER_DEFINED_BYTES left for their own
- * use.
- */
- struct {
- u32 pipe_mode;
- unsigned char user_def[MAX_PIPE_USER_DEFINED_BYTES];
- } pipe;
- } u;
- u32 padding;
-} __packed;
-
-/* Server Flags */
-#define VMBUS_CHANNEL_ENUMERATE_DEVICE_INTERFACE 1
-#define VMBUS_CHANNEL_SERVER_SUPPORTS_TRANSFER_PAGES 2
-#define VMBUS_CHANNEL_SERVER_SUPPORTS_GPADLS 4
-#define VMBUS_CHANNEL_NAMED_PIPE_MODE 0x10
-#define VMBUS_CHANNEL_LOOPBACK_OFFER 0x100
-#define VMBUS_CHANNEL_PARENT_OFFER 0x200
-#define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION 0x400
-
-#endif
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
index 79089f85d903..ec1d38cd481c 100644
--- a/drivers/staging/hv/vmbus_drv.c
+++ b/drivers/staging/hv/vmbus_drv.c
@@ -17,7 +17,11 @@
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
+ *
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -27,52 +31,176 @@
#include <linux/pci.h>
#include <linux/dmi.h>
#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
#include <linux/completion.h>
-#include "version_info.h"
-#include "hv_api.h"
-#include "logging.h"
-#include "vmbus.h"
-#include "channel.h"
-#include "vmbus_private.h"
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
-/* FIXME! We need to do this dynamically for PIC and APIC system */
-#define VMBUS_IRQ 0x5
-#define VMBUS_IRQ_VECTOR IRQ5_VECTOR
-/* Main vmbus driver data structure */
-struct vmbus_driver_context {
+static struct pci_dev *hv_pci_dev;
- struct bus_type bus;
- struct tasklet_struct msg_dpc;
- struct tasklet_struct event_dpc;
+static struct tasklet_struct msg_dpc;
+static struct tasklet_struct event_dpc;
- /* The bus root device */
- struct hv_device device_ctx;
-};
+unsigned int vmbus_loglevel = (ALL_MODULES << 16 | INFO_LVL);
+EXPORT_SYMBOL(vmbus_loglevel);
+ /* (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); */
+ /* (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); */
+
+static int pci_probe_error;
+static struct completion probe_event;
+static int irq;
+
+static void get_channel_info(struct hv_device *device,
+ struct hv_device_info *info)
+{
+ struct vmbus_channel_debug_info debug_info;
-static int vmbus_match(struct device *device, struct device_driver *driver);
-static int vmbus_probe(struct device *device);
-static int vmbus_remove(struct device *device);
-static void vmbus_shutdown(struct device *device);
-static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env);
+ if (!device->channel)
+ return;
-static irqreturn_t vmbus_isr(int irq, void *dev_id);
+ vmbus_get_debug_info(device->channel, &debug_info);
-static void vmbus_device_release(struct device *device);
-static void vmbus_bus_release(struct device *device);
+ info->chn_id = debug_info.relid;
+ info->chn_state = debug_info.state;
+ memcpy(&info->chn_type, &debug_info.interfacetype,
+ sizeof(struct hv_guid));
+ memcpy(&info->chn_instance, &debug_info.interface_instance,
+ sizeof(struct hv_guid));
+
+ info->monitor_id = debug_info.monitorid;
+
+ info->server_monitor_pending = debug_info.servermonitor_pending;
+ info->server_monitor_latency = debug_info.servermonitor_latency;
+ info->server_monitor_conn_id = debug_info.servermonitor_connectionid;
+
+ info->client_monitor_pending = debug_info.clientmonitor_pending;
+ info->client_monitor_latency = debug_info.clientmonitor_latency;
+ info->client_monitor_conn_id = debug_info.clientmonitor_connectionid;
+
+ info->inbound.int_mask = debug_info.inbound.current_interrupt_mask;
+ info->inbound.read_idx = debug_info.inbound.current_read_index;
+ info->inbound.write_idx = debug_info.inbound.current_write_index;
+ info->inbound.bytes_avail_toread =
+ debug_info.inbound.bytes_avail_toread;
+ info->inbound.bytes_avail_towrite =
+ debug_info.inbound.bytes_avail_towrite;
+
+ info->outbound.int_mask =
+ debug_info.outbound.current_interrupt_mask;
+ info->outbound.read_idx = debug_info.outbound.current_read_index;
+ info->outbound.write_idx = debug_info.outbound.current_write_index;
+ info->outbound.bytes_avail_toread =
+ debug_info.outbound.bytes_avail_toread;
+ info->outbound.bytes_avail_towrite =
+ debug_info.outbound.bytes_avail_towrite;
+}
+/*
+ * vmbus_show_device_attr - Show the device attribute in sysfs.
+ *
+ * This is invoked when user does a
+ * "cat /sys/bus/vmbus/devices/<busdevice>/<attr name>"
+ */
static ssize_t vmbus_show_device_attr(struct device *dev,
struct device_attribute *dev_attr,
- char *buf);
+ char *buf)
+{
+ struct hv_device *device_ctx = device_to_hv_device(dev);
+ struct hv_device_info device_info;
+ memset(&device_info, 0, sizeof(struct hv_device_info));
-unsigned int vmbus_loglevel = (ALL_MODULES << 16 | INFO_LVL);
-EXPORT_SYMBOL(vmbus_loglevel);
- /* (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); */
- /* (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); */
+ get_channel_info(device_ctx, &device_info);
-static int vmbus_irq = VMBUS_IRQ;
+ if (!strcmp(dev_attr->attr.name, "class_id")) {
+ return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
+ device_info.chn_type.data[3],
+ device_info.chn_type.data[2],
+ device_info.chn_type.data[1],
+ device_info.chn_type.data[0],
+ device_info.chn_type.data[5],
+ device_info.chn_type.data[4],
+ device_info.chn_type.data[7],
+ device_info.chn_type.data[6],
+ device_info.chn_type.data[8],
+ device_info.chn_type.data[9],
+ device_info.chn_type.data[10],
+ device_info.chn_type.data[11],
+ device_info.chn_type.data[12],
+ device_info.chn_type.data[13],
+ device_info.chn_type.data[14],
+ device_info.chn_type.data[15]);
+ } else if (!strcmp(dev_attr->attr.name, "device_id")) {
+ return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
+ device_info.chn_instance.data[3],
+ device_info.chn_instance.data[2],
+ device_info.chn_instance.data[1],
+ device_info.chn_instance.data[0],
+ device_info.chn_instance.data[5],
+ device_info.chn_instance.data[4],
+ device_info.chn_instance.data[7],
+ device_info.chn_instance.data[6],
+ device_info.chn_instance.data[8],
+ device_info.chn_instance.data[9],
+ device_info.chn_instance.data[10],
+ device_info.chn_instance.data[11],
+ device_info.chn_instance.data[12],
+ device_info.chn_instance.data[13],
+ device_info.chn_instance.data[14],
+ device_info.chn_instance.data[15]);
+ } else if (!strcmp(dev_attr->attr.name, "state")) {
+ return sprintf(buf, "%d\n", device_info.chn_state);
+ } else if (!strcmp(dev_attr->attr.name, "id")) {
+ return sprintf(buf, "%d\n", device_info.chn_id);
+ } else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) {
+ return sprintf(buf, "%d\n", device_info.outbound.int_mask);
+ } else if (!strcmp(dev_attr->attr.name, "out_read_index")) {
+ return sprintf(buf, "%d\n", device_info.outbound.read_idx);
+ } else if (!strcmp(dev_attr->attr.name, "out_write_index")) {
+ return sprintf(buf, "%d\n", device_info.outbound.write_idx);
+ } else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) {
+ return sprintf(buf, "%d\n",
+ device_info.outbound.bytes_avail_toread);
+ } else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) {
+ return sprintf(buf, "%d\n",
+ device_info.outbound.bytes_avail_towrite);
+ } else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) {
+ return sprintf(buf, "%d\n", device_info.inbound.int_mask);
+ } else if (!strcmp(dev_attr->attr.name, "in_read_index")) {
+ return sprintf(buf, "%d\n", device_info.inbound.read_idx);
+ } else if (!strcmp(dev_attr->attr.name, "in_write_index")) {
+ return sprintf(buf, "%d\n", device_info.inbound.write_idx);
+ } else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) {
+ return sprintf(buf, "%d\n",
+ device_info.inbound.bytes_avail_toread);
+ } else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) {
+ return sprintf(buf, "%d\n",
+ device_info.inbound.bytes_avail_towrite);
+ } else if (!strcmp(dev_attr->attr.name, "monitor_id")) {
+ return sprintf(buf, "%d\n", device_info.monitor_id);
+ } else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) {
+ return sprintf(buf, "%d\n", device_info.server_monitor_pending);
+ } else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) {
+ return sprintf(buf, "%d\n", device_info.server_monitor_latency);
+ } else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) {
+ return sprintf(buf, "%d\n",
+ device_info.server_monitor_conn_id);
+ } else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) {
+ return sprintf(buf, "%d\n", device_info.client_monitor_pending);
+ } else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) {
+ return sprintf(buf, "%d\n", device_info.client_monitor_latency);
+ } else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) {
+ return sprintf(buf, "%d\n",
+ device_info.client_monitor_conn_id);
+ } else {
+ return 0;
+ }
+}
/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
static struct device_attribute vmbus_device_attrs[] = {
@@ -104,68 +232,182 @@ static struct device_attribute vmbus_device_attrs[] = {
__ATTR_NULL
};
-/* The one and only one */
-static struct vmbus_driver_context vmbus_drv = {
- .bus.name = "vmbus",
- .bus.match = vmbus_match,
- .bus.shutdown = vmbus_shutdown,
- .bus.remove = vmbus_remove,
- .bus.probe = vmbus_probe,
- .bus.uevent = vmbus_uevent,
- .bus.dev_attrs = vmbus_device_attrs,
-};
-static const char *driver_name = "hyperv";
+/*
+ * vmbus_uevent - add uevent for our device
+ *
+ * This routine is invoked when a device is added or removed on the vmbus to
+ * generate a uevent to udev in the userspace. The udev will then look at its
+ * rule and the uevent generated here to load the appropriate driver
+ */
+static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
+{
+ struct hv_device *dev = device_to_hv_device(device);
+ int ret;
+
+ ret = add_uevent_var(env, "VMBUS_DEVICE_CLASS_GUID={"
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x%02x%02x}",
+ dev->dev_type.data[3],
+ dev->dev_type.data[2],
+ dev->dev_type.data[1],
+ dev->dev_type.data[0],
+ dev->dev_type.data[5],
+ dev->dev_type.data[4],
+ dev->dev_type.data[7],
+ dev->dev_type.data[6],
+ dev->dev_type.data[8],
+ dev->dev_type.data[9],
+ dev->dev_type.data[10],
+ dev->dev_type.data[11],
+ dev->dev_type.data[12],
+ dev->dev_type.data[13],
+ dev->dev_type.data[14],
+ dev->dev_type.data[15]);
+
+ if (ret)
+ return ret;
+
+ ret = add_uevent_var(env, "VMBUS_DEVICE_DEVICE_GUID={"
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x%02x%02x}",
+ dev->dev_instance.data[3],
+ dev->dev_instance.data[2],
+ dev->dev_instance.data[1],
+ dev->dev_instance.data[0],
+ dev->dev_instance.data[5],
+ dev->dev_instance.data[4],
+ dev->dev_instance.data[7],
+ dev->dev_instance.data[6],
+ dev->dev_instance.data[8],
+ dev->dev_instance.data[9],
+ dev->dev_instance.data[10],
+ dev->dev_instance.data[11],
+ dev->dev_instance.data[12],
+ dev->dev_instance.data[13],
+ dev->dev_instance.data[14],
+ dev->dev_instance.data[15]);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
/*
- * Windows vmbus does not defined this.
- * We defined this to be consistent with other devices
+ * vmbus_match - Attempt to match the specified device to the specified driver
+ */
+static int vmbus_match(struct device *device, struct device_driver *driver)
+{
+ int match = 0;
+ struct hv_driver *drv = drv_to_hv_drv(driver);
+ struct hv_device *device_ctx = device_to_hv_device(device);
+
+ /* We found our driver ? */
+ if (memcmp(&device_ctx->dev_type, &drv->dev_type,
+ sizeof(struct hv_guid)) == 0)
+ match = 1;
+
+ return match;
+}
+
+/*
+ * vmbus_probe - Add the new vmbus's child device
*/
-/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */
-static const struct hv_guid device_type = {
- .data = {
- 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d,
- 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85
+static int vmbus_probe(struct device *child_device)
+{
+ int ret = 0;
+ struct hv_driver *drv =
+ drv_to_hv_drv(child_device->driver);
+ struct hv_device *dev = device_to_hv_device(child_device);
+
+ if (drv->probe) {
+ ret = drv->probe(dev);
+ if (ret != 0)
+ pr_err("probe failed for device %s (%d)\n",
+ dev_name(child_device), ret);
+
+ } else {
+ pr_err("probe not set for driver %s\n",
+ dev_name(child_device));
+ ret = -1;
}
-};
+ return ret;
+}
+
+/*
+ * vmbus_remove - Remove a vmbus device
+ */
+static int vmbus_remove(struct device *child_device)
+{
+ int ret;
+ struct hv_driver *drv;
+
+ struct hv_device *dev = device_to_hv_device(child_device);
+
+ if (child_device->driver) {
+ drv = drv_to_hv_drv(child_device->driver);
-/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */
-static const struct hv_guid device_id = {
- .data = {
- 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40,
- 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5
+ if (drv->remove) {
+ ret = drv->remove(dev);
+ } else {
+ pr_err("remove not set for driver %s\n",
+ dev_name(child_device));
+ ret = -1;
+ }
}
-};
-static struct hv_device *vmbus_device; /* vmbus root device */
+ return 0;
+}
/*
- * vmbus_dev_add - Callback when the root bus device is added
+ * vmbus_shutdown - Shutdown a vmbus device
*/
-static int vmbus_dev_add(struct hv_device *dev, void *info)
+static void vmbus_shutdown(struct device *child_device)
{
- u32 *irqvector = info;
- int ret;
+ struct hv_driver *drv;
+ struct hv_device *dev = device_to_hv_device(child_device);
- vmbus_device = dev;
- memcpy(&vmbus_device->dev_type, &device_type, sizeof(struct hv_guid));
- memcpy(&vmbus_device->dev_instance, &device_id,
- sizeof(struct hv_guid));
+ /* The device may not be attached yet */
+ if (!child_device->driver)
+ return;
- /* strcpy(dev->name, "vmbus"); */
- /* SynIC setup... */
- on_each_cpu(hv_synic_init, (void *)irqvector, 1);
+ drv = drv_to_hv_drv(child_device->driver);
- /* Connect to VMBus in the root partition */
- ret = vmbus_connect();
+ if (drv->shutdown)
+ drv->shutdown(dev);
- /* VmbusSendEvent(device->localPortId+1); */
- return ret;
+ return;
}
+/*
+ * vmbus_device_release - Final callback release of the vmbus child device
+ */
+static void vmbus_device_release(struct device *device)
+{
+ struct hv_device *device_ctx = device_to_hv_device(device);
+
+ kfree(device_ctx);
+
+}
+
+/* The one and only one */
+static struct bus_type hv_bus = {
+ .name = "vmbus",
+ .match = vmbus_match,
+ .shutdown = vmbus_shutdown,
+ .remove = vmbus_remove,
+ .probe = vmbus_probe,
+ .uevent = vmbus_uevent,
+ .dev_attrs = vmbus_device_attrs,
+};
+
+static const char *driver_name = "hyperv";
+
+
struct onmessage_work_context {
struct work_struct work;
struct hv_message msg;
@@ -242,172 +484,38 @@ static int vmbus_on_isr(void)
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
/* Check if there are actual msgs to be process */
- if (msg->header.message_type != HVMSG_NONE) {
- DPRINT_DBG(VMBUS, "received msg type %d size %d",
- msg->header.message_type,
- msg->header.payload_size);
+ if (msg->header.message_type != HVMSG_NONE)
ret |= 0x1;
- }
/* TODO: Check if there are events to be process */
page_addr = hv_context.synic_event_page[cpu];
event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
/* Since we are a child, we only need to check bit 0 */
- if (sync_test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) {
- DPRINT_DBG(VMBUS, "received event %d", event->flags32[0]);
+ if (sync_test_and_clear_bit(0, (unsigned long *) &event->flags32[0]))
ret |= 0x2;
- }
return ret;
}
-static void get_channel_info(struct hv_device *device,
- struct hv_device_info *info)
-{
- struct vmbus_channel_debug_info debug_info;
-
- if (!device->channel)
- return;
-
- vmbus_get_debug_info(device->channel, &debug_info);
-
- info->chn_id = debug_info.relid;
- info->chn_state = debug_info.state;
- memcpy(&info->chn_type, &debug_info.interfacetype,
- sizeof(struct hv_guid));
- memcpy(&info->chn_instance, &debug_info.interface_instance,
- sizeof(struct hv_guid));
- info->monitor_id = debug_info.monitorid;
-
- info->server_monitor_pending = debug_info.servermonitor_pending;
- info->server_monitor_latency = debug_info.servermonitor_latency;
- info->server_monitor_conn_id = debug_info.servermonitor_connectionid;
-
- info->client_monitor_pending = debug_info.clientmonitor_pending;
- info->client_monitor_latency = debug_info.clientmonitor_latency;
- info->client_monitor_conn_id = debug_info.clientmonitor_connectionid;
-
- info->inbound.int_mask = debug_info.inbound.current_interrupt_mask;
- info->inbound.read_idx = debug_info.inbound.current_read_index;
- info->inbound.write_idx = debug_info.inbound.current_write_index;
- info->inbound.bytes_avail_toread =
- debug_info.inbound.bytes_avail_toread;
- info->inbound.bytes_avail_towrite =
- debug_info.inbound.bytes_avail_towrite;
-
- info->outbound.int_mask =
- debug_info.outbound.current_interrupt_mask;
- info->outbound.read_idx = debug_info.outbound.current_read_index;
- info->outbound.write_idx = debug_info.outbound.current_write_index;
- info->outbound.bytes_avail_toread =
- debug_info.outbound.bytes_avail_toread;
- info->outbound.bytes_avail_towrite =
- debug_info.outbound.bytes_avail_towrite;
-}
-
-/*
- * vmbus_show_device_attr - Show the device attribute in sysfs.
- *
- * This is invoked when user does a
- * "cat /sys/bus/vmbus/devices/<busdevice>/<attr name>"
- */
-static ssize_t vmbus_show_device_attr(struct device *dev,
- struct device_attribute *dev_attr,
- char *buf)
+static irqreturn_t vmbus_isr(int irq, void *dev_id)
{
- struct hv_device *device_ctx = device_to_hv_device(dev);
- struct hv_device_info device_info;
+ int ret;
- memset(&device_info, 0, sizeof(struct hv_device_info));
+ ret = vmbus_on_isr();
- get_channel_info(device_ctx, &device_info);
+ /* Schedules a dpc if necessary */
+ if (ret > 0) {
+ if (test_bit(0, (unsigned long *)&ret))
+ tasklet_schedule(&msg_dpc);
- if (!strcmp(dev_attr->attr.name, "class_id")) {
- return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
- device_info.chn_type.data[3],
- device_info.chn_type.data[2],
- device_info.chn_type.data[1],
- device_info.chn_type.data[0],
- device_info.chn_type.data[5],
- device_info.chn_type.data[4],
- device_info.chn_type.data[7],
- device_info.chn_type.data[6],
- device_info.chn_type.data[8],
- device_info.chn_type.data[9],
- device_info.chn_type.data[10],
- device_info.chn_type.data[11],
- device_info.chn_type.data[12],
- device_info.chn_type.data[13],
- device_info.chn_type.data[14],
- device_info.chn_type.data[15]);
- } else if (!strcmp(dev_attr->attr.name, "device_id")) {
- return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
- device_info.chn_instance.data[3],
- device_info.chn_instance.data[2],
- device_info.chn_instance.data[1],
- device_info.chn_instance.data[0],
- device_info.chn_instance.data[5],
- device_info.chn_instance.data[4],
- device_info.chn_instance.data[7],
- device_info.chn_instance.data[6],
- device_info.chn_instance.data[8],
- device_info.chn_instance.data[9],
- device_info.chn_instance.data[10],
- device_info.chn_instance.data[11],
- device_info.chn_instance.data[12],
- device_info.chn_instance.data[13],
- device_info.chn_instance.data[14],
- device_info.chn_instance.data[15]);
- } else if (!strcmp(dev_attr->attr.name, "state")) {
- return sprintf(buf, "%d\n", device_info.chn_state);
- } else if (!strcmp(dev_attr->attr.name, "id")) {
- return sprintf(buf, "%d\n", device_info.chn_id);
- } else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) {
- return sprintf(buf, "%d\n", device_info.outbound.int_mask);
- } else if (!strcmp(dev_attr->attr.name, "out_read_index")) {
- return sprintf(buf, "%d\n", device_info.outbound.read_idx);
- } else if (!strcmp(dev_attr->attr.name, "out_write_index")) {
- return sprintf(buf, "%d\n", device_info.outbound.write_idx);
- } else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) {
- return sprintf(buf, "%d\n",
- device_info.outbound.bytes_avail_toread);
- } else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) {
- return sprintf(buf, "%d\n",
- device_info.outbound.bytes_avail_towrite);
- } else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) {
- return sprintf(buf, "%d\n", device_info.inbound.int_mask);
- } else if (!strcmp(dev_attr->attr.name, "in_read_index")) {
- return sprintf(buf, "%d\n", device_info.inbound.read_idx);
- } else if (!strcmp(dev_attr->attr.name, "in_write_index")) {
- return sprintf(buf, "%d\n", device_info.inbound.write_idx);
- } else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) {
- return sprintf(buf, "%d\n",
- device_info.inbound.bytes_avail_toread);
- } else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) {
- return sprintf(buf, "%d\n",
- device_info.inbound.bytes_avail_towrite);
- } else if (!strcmp(dev_attr->attr.name, "monitor_id")) {
- return sprintf(buf, "%d\n", device_info.monitor_id);
- } else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) {
- return sprintf(buf, "%d\n", device_info.server_monitor_pending);
- } else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) {
- return sprintf(buf, "%d\n", device_info.server_monitor_latency);
- } else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) {
- return sprintf(buf, "%d\n",
- device_info.server_monitor_conn_id);
- } else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) {
- return sprintf(buf, "%d\n", device_info.client_monitor_pending);
- } else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) {
- return sprintf(buf, "%d\n", device_info.client_monitor_latency);
- } else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) {
- return sprintf(buf, "%d\n",
- device_info.client_monitor_conn_id);
+ if (test_bit(1, (unsigned long *)&ret))
+ tasklet_schedule(&event_dpc);
+
+ return IRQ_HANDLED;
} else {
- return 0;
+ return IRQ_NONE;
}
}
@@ -416,148 +524,69 @@ static ssize_t vmbus_show_device_attr(struct device *dev,
*
* Here, we
* - initialize the vmbus driver context
- * - setup various driver entry points
* - invoke the vmbus hv main init routine
* - get the irq resource
- * - invoke the vmbus to add the vmbus root device
- * - setup the vmbus root device
* - retrieve the channel offers
*/
-static int vmbus_bus_init(void)
+static int vmbus_bus_init(struct pci_dev *pdev)
{
- struct vmbus_driver_context *vmbus_drv_ctx = &vmbus_drv;
- struct hv_device *dev_ctx = &vmbus_drv.device_ctx;
int ret;
unsigned int vector;
- DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++",
- HV_DRV_VERSION);
- DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++",
- VMBUS_REVISION_NUMBER);
- DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++",
- VMBUS_MESSAGE_SINT);
- DPRINT_DBG(VMBUS, "sizeof(vmbus_channel_packet_page_buffer)=%zd, "
- "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
- sizeof(struct vmbus_channel_packet_page_buffer),
- sizeof(struct vmbus_channel_packet_multipage_buffer));
-
-
/* Hypervisor initialization...setup hypercall page..etc */
ret = hv_init();
if (ret != 0) {
- DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x",
- ret);
+ pr_err("Unable to initialize the hypervisor - 0x%x\n", ret);
goto cleanup;
}
-
- vmbus_drv_ctx->bus.name = driver_name;
-
/* Initialize the bus context */
- tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_on_msg_dpc,
- (unsigned long)NULL);
- tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_on_event,
- (unsigned long)NULL);
+ tasklet_init(&msg_dpc, vmbus_on_msg_dpc, 0);
+ tasklet_init(&event_dpc, vmbus_on_event, 0);
/* Now, register the bus with LDM */
- ret = bus_register(&vmbus_drv_ctx->bus);
+ ret = bus_register(&hv_bus);
if (ret) {
ret = -1;
goto cleanup;
}
/* Get the interrupt resource */
- ret = request_irq(vmbus_irq, vmbus_isr, IRQF_SAMPLE_RANDOM,
- driver_name, NULL);
+ ret = request_irq(pdev->irq, vmbus_isr,
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+ driver_name, pdev);
if (ret != 0) {
- DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d",
- vmbus_irq);
+ pr_err("Unable to request IRQ %d\n",
+ pdev->irq);
- bus_unregister(&vmbus_drv_ctx->bus);
+ bus_unregister(&hv_bus);
ret = -1;
goto cleanup;
}
- vector = VMBUS_IRQ_VECTOR;
- DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector);
+ vector = IRQ0_VECTOR + pdev->irq;
- /* Add the root device */
- memset(dev_ctx, 0, sizeof(struct hv_device));
-
- ret = vmbus_dev_add(dev_ctx, &vector);
- if (ret != 0) {
- DPRINT_ERR(VMBUS_DRV,
- "ERROR - Unable to add vmbus root device");
-
- free_irq(vmbus_irq, NULL);
-
- bus_unregister(&vmbus_drv_ctx->bus);
-
- ret = -1;
- goto cleanup;
- }
- /* strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name); */
- dev_set_name(&dev_ctx->device, "vmbus_0_0");
-
- /* No need to bind a driver to the root device. */
- dev_ctx->device.parent = NULL;
- /* NULL; vmbus_remove() does not get invoked */
- dev_ctx->device.bus = &vmbus_drv_ctx->bus;
-
- /* Setup the device dispatch table */
- dev_ctx->device.release = vmbus_bus_release;
-
- /* register the root device */
- ret = device_register(&dev_ctx->device);
+ /*
+ * Notify the hypervisor of our irq and
+ * connect to the host.
+ */
+ on_each_cpu(hv_synic_init, (void *)&vector, 1);
+ ret = vmbus_connect();
if (ret) {
- DPRINT_ERR(VMBUS_DRV,
- "ERROR - Unable to register vmbus root device");
-
- free_irq(vmbus_irq, NULL);
- bus_unregister(&vmbus_drv_ctx->bus);
-
- ret = -1;
+ free_irq(pdev->irq, pdev);
+ bus_unregister(&hv_bus);
goto cleanup;
}
+
vmbus_request_offers();
- wait_for_completion(&hv_channel_ready);
cleanup:
return ret;
}
-/*
- * vmbus_bus_exit - Terminate the vmbus driver.
- *
- * This routine is opposite of vmbus_bus_init()
- */
-static void vmbus_bus_exit(void)
-{
- struct vmbus_driver_context *vmbus_drv_ctx = &vmbus_drv;
-
- struct hv_device *dev_ctx = &vmbus_drv.device_ctx;
-
- vmbus_release_unattached_channels();
- vmbus_disconnect();
- on_each_cpu(hv_synic_cleanup, NULL, 1);
-
- hv_cleanup();
-
- /* Unregister the root bus device */
- device_unregister(&dev_ctx->device);
-
- bus_unregister(&vmbus_drv_ctx->bus);
-
- free_irq(vmbus_irq, NULL);
-
- tasklet_kill(&vmbus_drv_ctx->msg_dpc);
- tasklet_kill(&vmbus_drv_ctx->event_dpc);
-}
-
-
/**
* vmbus_child_driver_register() - Register a vmbus's child driver
* @drv: Pointer to driver structure you want to register
@@ -573,11 +602,10 @@ int vmbus_child_driver_register(struct device_driver *drv)
{
int ret;
- DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s",
- drv, drv->name);
+ pr_info("child driver registering - name %s\n", drv->name);
/* The child driver on this vmbus */
- drv->bus = &vmbus_drv.bus;
+ drv->bus = &hv_bus;
ret = driver_register(drv);
@@ -599,8 +627,7 @@ EXPORT_SYMBOL(vmbus_child_driver_register);
*/
void vmbus_child_driver_unregister(struct device_driver *drv)
{
- DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s",
- drv, drv->name);
+ pr_info("child driver unregistering - name %s\n", drv->name);
driver_unregister(drv);
@@ -621,30 +648,10 @@ struct hv_device *vmbus_child_device_create(struct hv_guid *type,
/* Allocate the new child device */
child_device_obj = kzalloc(sizeof(struct hv_device), GFP_KERNEL);
if (!child_device_obj) {
- DPRINT_ERR(VMBUS_DRV,
- "unable to allocate device_context for child device");
+ pr_err("Unable to allocate device object for child device\n");
return NULL;
}
- DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - "
- "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x},"
- "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x}",
- &child_device_obj->device,
- type->data[3], type->data[2], type->data[1], type->data[0],
- type->data[5], type->data[4], type->data[7], type->data[6],
- type->data[8], type->data[9], type->data[10], type->data[11],
- type->data[12], type->data[13], type->data[14], type->data[15],
- instance->data[3], instance->data[2],
- instance->data[1], instance->data[0],
- instance->data[5], instance->data[4],
- instance->data[7], instance->data[6],
- instance->data[8], instance->data[9],
- instance->data[10], instance->data[11],
- instance->data[12], instance->data[13],
- instance->data[14], instance->data[15]);
-
child_device_obj->channel = channel;
memcpy(&child_device_obj->dev_type, type, sizeof(struct hv_guid));
memcpy(&child_device_obj->dev_instance, instance,
@@ -663,16 +670,13 @@ int vmbus_child_device_register(struct hv_device *child_device_obj)
static atomic_t device_num = ATOMIC_INIT(0);
- DPRINT_DBG(VMBUS_DRV, "child device (%p) registering",
- child_device_obj);
-
/* Set the device name. Otherwise, device_register() will fail. */
dev_set_name(&child_device_obj->device, "vmbus_0_%d",
atomic_inc_return(&device_num));
/* The new device belongs to this bus */
- child_device_obj->device.bus = &vmbus_drv.bus; /* device->dev.bus; */
- child_device_obj->device.parent = &vmbus_device->device;
+ child_device_obj->device.bus = &hv_bus; /* device->dev.bus; */
+ child_device_obj->device.parent = &hv_pci_dev->dev;
child_device_obj->device.release = vmbus_device_release;
/*
@@ -681,15 +685,11 @@ int vmbus_child_device_register(struct hv_device *child_device_obj)
*/
ret = device_register(&child_device_obj->device);
- /* vmbus_probe() error does not get propergate to device_register(). */
- ret = child_device_obj->probe_error;
-
if (ret)
- DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p)",
- &child_device_obj->device);
+ pr_err("Unable to register child device\n");
else
- DPRINT_INFO(VMBUS_DRV, "child device (%p) registered",
- &child_device_obj->device);
+ pr_info("child device %s registered\n",
+ dev_name(&child_device_obj->device));
return ret;
}
@@ -700,313 +700,110 @@ int vmbus_child_device_register(struct hv_device *child_device_obj)
*/
void vmbus_child_device_unregister(struct hv_device *device_obj)
{
-
- DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)",
- &device_obj->device);
-
/*
* Kick off the process of unregistering the device.
* This will call vmbus_remove() and eventually vmbus_device_release()
*/
device_unregister(&device_obj->device);
- DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered",
- &device_obj->device);
+ pr_info("child device %s unregistered\n",
+ dev_name(&device_obj->device));
}
-/*
- * vmbus_uevent - add uevent for our device
- *
- * This routine is invoked when a device is added or removed on the vmbus to
- * generate a uevent to udev in the userspace. The udev will then look at its
- * rule and the uevent generated here to load the appropriate driver
- */
-static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
-{
- struct hv_device *dev = device_to_hv_device(device);
- int ret;
-
- DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={"
- "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x}",
- dev->dev_type.data[3], dev->dev_type.data[2],
- dev->dev_type.data[1], dev->dev_type.data[0],
- dev->dev_type.data[5], dev->dev_type.data[4],
- dev->dev_type.data[7], dev->dev_type.data[6],
- dev->dev_type.data[8], dev->dev_type.data[9],
- dev->dev_type.data[10],
- dev->dev_type.data[11],
- dev->dev_type.data[12],
- dev->dev_type.data[13],
- dev->dev_type.data[14],
- dev->dev_type.data[15]);
-
- ret = add_uevent_var(env, "VMBUS_DEVICE_CLASS_GUID={"
- "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x}",
- dev->dev_type.data[3],
- dev->dev_type.data[2],
- dev->dev_type.data[1],
- dev->dev_type.data[0],
- dev->dev_type.data[5],
- dev->dev_type.data[4],
- dev->dev_type.data[7],
- dev->dev_type.data[6],
- dev->dev_type.data[8],
- dev->dev_type.data[9],
- dev->dev_type.data[10],
- dev->dev_type.data[11],
- dev->dev_type.data[12],
- dev->dev_type.data[13],
- dev->dev_type.data[14],
- dev->dev_type.data[15]);
-
- if (ret)
- return ret;
-
- ret = add_uevent_var(env, "VMBUS_DEVICE_DEVICE_GUID={"
- "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x}",
- dev->dev_instance.data[3],
- dev->dev_instance.data[2],
- dev->dev_instance.data[1],
- dev->dev_instance.data[0],
- dev->dev_instance.data[5],
- dev->dev_instance.data[4],
- dev->dev_instance.data[7],
- dev->dev_instance.data[6],
- dev->dev_instance.data[8],
- dev->dev_instance.data[9],
- dev->dev_instance.data[10],
- dev->dev_instance.data[11],
- dev->dev_instance.data[12],
- dev->dev_instance.data[13],
- dev->dev_instance.data[14],
- dev->dev_instance.data[15]);
- if (ret)
- return ret;
-
- return 0;
-}
/*
- * vmbus_match - Attempt to match the specified device to the specified driver
+ * VMBUS is an acpi enumerated device. Get the the IRQ information
+ * from DSDT.
*/
-static int vmbus_match(struct device *device, struct device_driver *driver)
-{
- int match = 0;
- struct hv_driver *drv = drv_to_hv_drv(driver);
- struct hv_device *device_ctx = device_to_hv_device(device);
-
- /* We found our driver ? */
- if (memcmp(&device_ctx->dev_type, &drv->dev_type,
- sizeof(struct hv_guid)) == 0) {
-
- device_ctx->drv = drv->priv;
- DPRINT_INFO(VMBUS_DRV,
- "device object (%p) set to driver object (%p)",
- &device_ctx,
- device_ctx->drv);
-
- match = 1;
- }
- return match;
-}
-/*
- * vmbus_probe_failed_cb - Callback when a driver probe failed in vmbus_probe()
- *
- * We need a callback because we cannot invoked device_unregister() inside
- * vmbus_probe() since vmbus_probe() may be invoked inside device_register()
- * i.e. we cannot call device_unregister() inside device_register()
- */
-static void vmbus_probe_failed_cb(struct work_struct *context)
+static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
{
- struct hv_device *device_ctx = (struct hv_device *)context;
-
- /*
- * Kick off the process of unregistering the device.
- * This will call vmbus_remove() and eventually vmbus_device_release()
- */
- device_unregister(&device_ctx->device);
- /* put_device(&device_ctx->device); */
-}
-
-/*
- * vmbus_probe - Add the new vmbus's child device
- */
-static int vmbus_probe(struct device *child_device)
-{
- int ret = 0;
- struct hv_driver *drv =
- drv_to_hv_drv(child_device->driver);
- struct hv_device *dev = device_to_hv_device(child_device);
+ if (res->type == ACPI_RESOURCE_TYPE_IRQ) {
+ struct acpi_resource_irq *irqp;
+ irqp = &res->data.irq;
- /* Let the specific open-source driver handles the probe if it can */
- if (drv->driver.probe) {
- ret = dev->probe_error =
- drv->driver.probe(child_device);
- if (ret != 0) {
- DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s "
- "(%p) on driver %s (%d)...",
- dev_name(child_device), child_device,
- child_device->driver->name, ret);
-
- INIT_WORK(&dev->probe_failed_work_item,
- vmbus_probe_failed_cb);
- schedule_work(&dev->probe_failed_work_item);
- }
- } else {
- DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s",
- child_device->driver->name);
- ret = -1;
+ *((unsigned int *)irq) = irqp->interrupts[0];
}
- return ret;
+
+ return AE_OK;
}
-/*
- * vmbus_remove - Remove a vmbus device
- */
-static int vmbus_remove(struct device *child_device)
+static int vmbus_acpi_add(struct acpi_device *device)
{
- int ret;
- struct hv_driver *drv;
+ acpi_status result;
- /* Special case root bus device */
- if (child_device->parent == NULL) {
- /*
- * No-op since it is statically defined and handle in
- * vmbus_bus_exit()
- */
- return 0;
- }
-
- if (child_device->driver) {
- drv = drv_to_hv_drv(child_device->driver);
+ result =
+ acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+ vmbus_walk_resources, &irq);
- /*
- * Let the specific open-source driver handles the removal if
- * it can
- */
- if (drv->driver.remove) {
- ret = drv->driver.remove(child_device);
- } else {
- DPRINT_ERR(VMBUS_DRV,
- "remove() method not set for driver - %s",
- child_device->driver->name);
- ret = -1;
- }
+ if (ACPI_FAILURE(result)) {
+ complete(&probe_event);
+ return -ENODEV;
}
-
+ complete(&probe_event);
return 0;
}
-/*
- * vmbus_shutdown - Shutdown a vmbus device
- */
-static void vmbus_shutdown(struct device *child_device)
-{
- struct hv_driver *drv;
-
- /* Special case root bus device */
- if (child_device->parent == NULL) {
- /*
- * No-op since it is statically defined and handle in
- * vmbus_bus_exit()
- */
- return;
- }
+static const struct acpi_device_id vmbus_acpi_device_ids[] = {
+ {"VMBUS", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, vmbus_acpi_device_ids);
- /* The device may not be attached yet */
- if (!child_device->driver)
- return;
+static struct acpi_driver vmbus_acpi_driver = {
+ .name = "vmbus",
+ .ids = vmbus_acpi_device_ids,
+ .ops = {
+ .add = vmbus_acpi_add,
+ },
+};
- drv = drv_to_hv_drv(child_device->driver);
+static int vmbus_acpi_init(void)
+{
+ int result;
- /* Let the specific open-source driver handles the removal if it can */
- if (drv->driver.shutdown)
- drv->driver.shutdown(child_device);
- return;
-}
+ result = acpi_bus_register_driver(&vmbus_acpi_driver);
+ if (result < 0)
+ return result;
-/*
- * vmbus_bus_release - Final callback release of the vmbus root device
- */
-static void vmbus_bus_release(struct device *device)
-{
- /* FIXME */
- /* Empty release functions are a bug, or a major sign
- * of a problem design, this MUST BE FIXED! */
- dev_err(device, "%s needs to be fixed!\n", __func__);
- WARN_ON(1);
+ return 0;
}
-/*
- * vmbus_device_release - Final callback release of the vmbus child device
- */
-static void vmbus_device_release(struct device *device)
+static void vmbus_acpi_exit(void)
{
- struct hv_device *device_ctx = device_to_hv_device(device);
-
- kfree(device_ctx);
+ acpi_bus_unregister_driver(&vmbus_acpi_driver);
- /* !!DO NOT REFERENCE device_ctx anymore at this point!! */
+ return;
}
-
-static irqreturn_t vmbus_isr(int irq, void *dev_id)
+static int __devinit hv_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- int ret;
+ hv_pci_dev = pdev;
- ret = vmbus_on_isr();
+ pci_probe_error = pci_enable_device(pdev);
+ if (pci_probe_error)
+ goto probe_cleanup;
- /* Schedules a dpc if necessary */
- if (ret > 0) {
- if (test_bit(0, (unsigned long *)&ret))
- tasklet_schedule(&vmbus_drv.msg_dpc);
-
- if (test_bit(1, (unsigned long *)&ret))
- tasklet_schedule(&vmbus_drv.event_dpc);
-
- return IRQ_HANDLED;
- } else {
- return IRQ_NONE;
- }
-}
-
-static struct dmi_system_id __initdata microsoft_hv_dmi_table[] = {
- {
- .ident = "Hyper-V",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
- DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
- },
- },
- { },
-};
-MODULE_DEVICE_TABLE(dmi, microsoft_hv_dmi_table);
+ /*
+ * If the PCI sub-sytem did not assign us an
+ * irq, use the bios provided one.
+ */
-static int __init vmbus_init(void)
-{
- DPRINT_INFO(VMBUS_DRV,
- "Vmbus initializing.... current log level 0x%x (%x,%x)",
- vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
- /* Todo: it is used for loglevel, to be ported to new kernel. */
+ if (pdev->irq == 0)
+ pdev->irq = irq;
- if (!dmi_check_system(microsoft_hv_dmi_table))
- return -ENODEV;
+ pci_probe_error = vmbus_bus_init(pdev);
- return vmbus_bus_init();
-}
+ if (pci_probe_error)
+ pci_disable_device(pdev);
-static void __exit vmbus_exit(void)
-{
- vmbus_bus_exit();
- /* Todo: it is used for loglevel, to be ported to new kernel. */
+probe_cleanup:
+ complete(&probe_event);
+ return pci_probe_error;
}
/*
@@ -1021,10 +818,53 @@ static const struct pci_device_id microsoft_hv_pci_table[] = {
};
MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
+static struct pci_driver hv_bus_driver = {
+ .name = "hv_bus",
+ .probe = hv_pci_probe,
+ .id_table = microsoft_hv_pci_table,
+};
+
+static int __init hv_pci_init(void)
+{
+ int ret;
+
+ init_completion(&probe_event);
+
+ /*
+ * Get irq resources first.
+ */
+
+ ret = vmbus_acpi_init();
+ if (ret)
+ return ret;
+
+ wait_for_completion(&probe_event);
+
+ if (irq <= 0) {
+ vmbus_acpi_exit();
+ return -ENODEV;
+ }
+
+ vmbus_acpi_exit();
+ init_completion(&probe_event);
+ ret = pci_register_driver(&hv_bus_driver);
+ if (ret)
+ return ret;
+ /*
+ * All the vmbus initialization occurs within the
+ * hv_pci_probe() function. Wait for hv_pci_probe()
+ * to complete.
+ */
+ wait_for_completion(&probe_event);
+
+ if (pci_probe_error)
+ pci_unregister_driver(&hv_bus_driver);
+ return pci_probe_error;
+}
+
+
MODULE_LICENSE("GPL");
MODULE_VERSION(HV_DRV_VERSION);
-module_param(vmbus_irq, int, S_IRUGO);
-module_param(vmbus_loglevel, int, S_IRUGO);
+module_param(vmbus_loglevel, int, S_IRUGO|S_IWUSR);
-module_init(vmbus_init);
-module_exit(vmbus_exit);
+module_init(hv_pci_init);
diff --git a/drivers/staging/hv/vmbus_packet_format.h b/drivers/staging/hv/vmbus_packet_format.h
deleted file mode 100644
index c0b2c2b11646..000000000000
--- a/drivers/staging/hv/vmbus_packet_format.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-#ifndef _VMBUSPACKETFORMAT_H_
-#define _VMBUSPACKETFORMAT_H_
-
-struct vmpacket_descriptor {
- u16 type;
- u16 offset8;
- u16 len8;
- u16 flags;
- u64 trans_id;
-} __packed;
-
-struct vmpacket_header {
- u32 prev_pkt_start_offset;
- struct vmpacket_descriptor descriptor;
-} __packed;
-
-struct vmtransfer_page_range {
- u32 byte_count;
- u32 byte_offset;
-} __packed;
-
-struct vmtransfer_page_packet_header {
- struct vmpacket_descriptor d;
- u16 xfer_pageset_id;
- bool sender_owns_set;
- u8 reserved;
- u32 range_cnt;
- struct vmtransfer_page_range ranges[1];
-} __packed;
-
-struct vmgpadl_packet_header {
- struct vmpacket_descriptor d;
- u32 gpadl;
- u32 reserved;
-} __packed;
-
-struct vmadd_remove_transfer_page_set {
- struct vmpacket_descriptor d;
- u32 gpadl;
- u16 xfer_pageset_id;
- u16 reserved;
-} __packed;
-
-/*
- * This structure defines a range in guest physical space that can be made to
- * look virtually contiguous.
- */
-struct gpa_range {
- u32 byte_count;
- u32 byte_offset;
- u64 pfn_array[0];
-};
-
-/*
- * This is the format for an Establish Gpadl packet, which contains a handle by
- * which this GPADL will be known and a set of GPA ranges associated with it.
- * This can be converted to a MDL by the guest OS. If there are multiple GPA
- * ranges, then the resulting MDL will be "chained," representing multiple VA
- * ranges.
- */
-struct vmestablish_gpadl {
- struct vmpacket_descriptor d;
- u32 gpadl;
- u32 range_cnt;
- struct gpa_range range[1];
-} __packed;
-
-/*
- * This is the format for a Teardown Gpadl packet, which indicates that the
- * GPADL handle in the Establish Gpadl packet will never be referenced again.
- */
-struct vmteardown_gpadl {
- struct vmpacket_descriptor d;
- u32 gpadl;
- u32 reserved; /* for alignment to a 8-byte boundary */
-} __packed;
-
-/*
- * This is the format for a GPA-Direct packet, which contains a set of GPA
- * ranges, in addition to commands and/or data.
- */
-struct vmdata_gpa_direct {
- struct vmpacket_descriptor d;
- u32 reserved;
- u32 range_cnt;
- struct gpa_range range[1];
-} __packed;
-
-/* This is the format for a Additional Data Packet. */
-struct vmadditional_data {
- struct vmpacket_descriptor d;
- u64 total_bytes;
- u32 offset;
- u32 byte_cnt;
- unsigned char data[1];
-} __packed;
-
-union vmpacket_largest_possible_header {
- struct vmpacket_descriptor simple_hdr;
- struct vmtransfer_page_packet_header xfer_page_hdr;
- struct vmgpadl_packet_header gpadl_hdr;
- struct vmadd_remove_transfer_page_set add_rm_xfer_page_hdr;
- struct vmestablish_gpadl establish_gpadl_hdr;
- struct vmteardown_gpadl teardown_gpadl_hdr;
- struct vmdata_gpa_direct data_gpa_direct_hdr;
-};
-
-#define VMPACKET_DATA_START_ADDRESS(__packet) \
- (void *)(((unsigned char *)__packet) + \
- ((struct vmpacket_descriptor)__packet)->offset8 * 8)
-
-#define VMPACKET_DATA_LENGTH(__packet) \
- ((((struct vmpacket_descriptor)__packet)->len8 - \
- ((struct vmpacket_descriptor)__packet)->offset8) * 8)
-
-#define VMPACKET_TRANSFER_MODE(__packet) \
- (((struct IMPACT)__packet)->type)
-
-enum vmbus_packet_type {
- VM_PKT_INVALID = 0x0,
- VM_PKT_SYNCH = 0x1,
- VM_PKT_ADD_XFER_PAGESET = 0x2,
- VM_PKT_RM_XFER_PAGESET = 0x3,
- VM_PKT_ESTABLISH_GPADL = 0x4,
- VM_PKT_TEARDOWN_GPADL = 0x5,
- VM_PKT_DATA_INBAND = 0x6,
- VM_PKT_DATA_USING_XFER_PAGES = 0x7,
- VM_PKT_DATA_USING_GPADL = 0x8,
- VM_PKT_DATA_USING_GPA_DIRECT = 0x9,
- VM_PKT_CANCEL_REQUEST = 0xa,
- VM_PKT_COMP = 0xb,
- VM_PKT_DATA_USING_ADDITIONAL_PKT = 0xc,
- VM_PKT_ADDITIONAL_DATA = 0xd
-};
-
-#define VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED 1
-
-#endif
diff --git a/drivers/staging/hv/vmbus_private.h b/drivers/staging/hv/vmbus_private.h
deleted file mode 100644
index 6f0d8df5e178..000000000000
--- a/drivers/staging/hv/vmbus_private.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _VMBUS_PRIVATE_H_
-#define _VMBUS_PRIVATE_H_
-
-#include "hv.h"
-#include "vmbus_api.h"
-#include "channel.h"
-#include "channel_mgmt.h"
-#include "ring_buffer.h"
-#include <linux/list.h>
-#include <asm/sync_bitops.h>
-
-
-/*
- * Maximum channels is determined by the size of the interrupt page
- * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt
- * and the other is receive endpoint interrupt
- */
-#define MAX_NUM_CHANNELS ((PAGE_SIZE >> 1) << 3) /* 16348 channels */
-
-/* The value here must be in multiple of 32 */
-/* TODO: Need to make this configurable */
-#define MAX_NUM_CHANNELS_SUPPORTED 256
-
-
-enum vmbus_connect_state {
- DISCONNECTED,
- CONNECTING,
- CONNECTED,
- DISCONNECTING
-};
-
-#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT
-
-struct vmbus_connection {
- enum vmbus_connect_state conn_state;
-
- atomic_t next_gpadl_handle;
-
- /*
- * Represents channel interrupts. Each bit position represents a
- * channel. When a channel sends an interrupt via VMBUS, it finds its
- * bit in the sendInterruptPage, set it and calls Hv to generate a port
- * event. The other end receives the port event and parse the
- * recvInterruptPage to see which bit is set
- */
- void *int_page;
- void *send_int_page;
- void *recv_int_page;
-
- /*
- * 2 pages - 1st page for parent->child notification and 2nd
- * is child->parent notification
- */
- void *monitor_pages;
- struct list_head chn_msg_list;
- spinlock_t channelmsg_lock;
-
- /* List of channels */
- struct list_head chn_list;
- spinlock_t channel_lock;
-
- struct workqueue_struct *work_queue;
-};
-
-
-struct vmbus_msginfo {
- /* Bookkeeping stuff */
- struct list_head msglist_entry;
-
- /* Synchronize the request/response if needed */
- int wait_condition;
- wait_queue_head_t wait_event;
-
- /* The message itself */
- unsigned char msg[0];
-};
-
-
-extern struct vmbus_connection vmbus_connection;
-
-/* General vmbus interface */
-
-struct hv_device *vmbus_child_device_create(struct hv_guid *type,
- struct hv_guid *instance,
- struct vmbus_channel *channel);
-
-int vmbus_child_device_register(struct hv_device *child_device_obj);
-void vmbus_child_device_unregister(struct hv_device *device_obj);
-
-/* static void */
-/* VmbusChildDeviceDestroy( */
-/* struct hv_device *); */
-
-struct vmbus_channel *relid2channel(u32 relid);
-
-
-/* Connection interface */
-
-int vmbus_connect(void);
-
-int vmbus_disconnect(void);
-
-int vmbus_post_msg(void *buffer, size_t buflen);
-
-int vmbus_set_event(u32 child_relid);
-
-void vmbus_on_event(unsigned long data);
-
-
-#endif /* _VMBUS_PRIVATE_H_ */