diff options
Diffstat (limited to 'drivers/staging/hv')
39 files changed, 0 insertions, 15355 deletions
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig deleted file mode 100644 index 7455c804962..00000000000 --- a/drivers/staging/hv/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -config HYPERV - tristate "Microsoft Hyper-V client drivers" - depends on X86 && m - default n - help - Select this option to run Linux as a Hyper-V client operating - system. - -if HYPERV - -config HYPERV_STORAGE - tristate "Microsoft Hyper-V virtual storage driver" - depends on SCSI - default HYPERV - help - Select this option to enable the Hyper-V virtual storage driver. - -config HYPERV_BLOCK - tristate "Microsoft Hyper-V virtual block driver" - depends on BLOCK && SCSI && (LBDAF || 64BIT) - default HYPERV - help - Select this option to enable the Hyper-V virtual block driver. - -config HYPERV_NET - tristate "Microsoft Hyper-V virtual network driver" - depends on NET - default HYPERV - help - Select this option to enable the Hyper-V virtual network driver. - -config HYPERV_UTILS - tristate "Microsoft Hyper-V Utilities driver" - default HYPERV - help - Select this option to enable the Hyper-V Utilities. - -endif diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile deleted file mode 100644 index acd39bd75b1..00000000000 --- a/drivers/staging/hv/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -obj-$(CONFIG_HYPERV) += hv_vmbus.o hv_timesource.o -obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o -obj-$(CONFIG_HYPERV_BLOCK) += hv_blkvsc.o -obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o -obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o - -hv_vmbus-y := vmbus_drv.o osd.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_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o diff --git a/drivers/staging/hv/TODO b/drivers/staging/hv/TODO deleted file mode 100644 index 582fd4ab3f1..00000000000 --- a/drivers/staging/hv/TODO +++ /dev/null @@ -1,14 +0,0 @@ -TODO: - - fix remaining checkpatch warnings and errors - - audit the vmbus to verify it is working properly with the - driver model - - see if the vmbus can be merged with the other virtual busses - in the kernel - - audit the network driver - - checking for carrier inside open is wrong, network device API - confusion?? - - audit the block driver - - audit the scsi driver - -Please send patches for this code to Greg Kroah-Hartman <gregkh@suse.de>, -Hank Janssen <hjanssen@microsoft.com>, and Haiyang Zhang <haiyangz@microsoft.com>. diff --git a/drivers/staging/hv/blkvsc.c b/drivers/staging/hv/blkvsc.c deleted file mode 100644 index bc16d9172eb..00000000000 --- 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 "osd.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->deviceInstance.data[3] << 24 | - device->deviceInstance.data[2] << 16 | - device->deviceInstance.data[1] << 8 | - device->deviceInstance.data[0]; - - device_info->target_id = device->deviceInstance.data[5] << 8 | - device->deviceInstance.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->deviceType, &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_UP(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.OnDeviceAdd = blk_vsc_on_device_add; - stor_driver->base.OnDeviceRemove = stor_vsc_on_device_remove; - stor_driver->base.OnCleanup = 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 deleted file mode 100644 index 4fb809485d9..00000000000 --- a/drivers/staging/hv/blkvsc_drv.c +++ /dev/null @@ -1,1505 +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/init.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/blkdev.h> -#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 "osd.h" -#include "logging.h" -#include "version_info.h" -#include "vmbus.h" -#include "storvsc_api.h" - - -#define BLKVSC_MINORS 64 - -enum blkvsc_device_type { - UNKNOWN_DEV_TYPE, - HARDDISK_TYPE, - DVD_TYPE, -}; - -/* - * This request ties the struct request and struct - * blkvsc_request/hv_storvsc_request together A struct request may be - * represented by 1 or more struct blkvsc_request - */ -struct blkvsc_request_group { - int outstanding; - int status; - struct list_head blkvsc_req_list; /* list of blkvsc_requests */ -}; - -struct blkvsc_request { - /* blkvsc_request_group.blkvsc_req_list */ - struct list_head req_entry; - - /* block_device_context.pending_list */ - struct list_head pend_entry; - - /* This may be null if we generate a request internally */ - struct request *req; - - struct block_device_context *dev; - - /* 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; - - unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; - unsigned char cmd_len; - 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 */ -struct block_device_context { - /* point back to our device context */ - struct vm_device *device_ctx; - struct kmem_cache *request_pool; - spinlock_t lock; - struct gendisk *gd; - enum blkvsc_device_type device_type; - struct list_head pending_list; - - unsigned char device_id[64]; - 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; - unsigned char path; - unsigned char target; - int users; -}; - -/* Per driver */ -struct blkvsc_driver_context { - /* !! These must be the first 2 fields !! */ - /* FIXME this is a bug! */ - struct driver_context drv_ctx; - struct storvsc_driver_object drv_obj; -}; - -/* 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); - -static int blkvsc_open(struct block_device *bdev, fmode_t mode); -static int blkvsc_release(struct gendisk *disk, fmode_t mode); -static int blkvsc_media_changed(struct gendisk *gd); -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); -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 blkvsc_driver_context g_blkvsc_drv; - -static const struct block_device_operations block_ops = { - .owner = THIS_MODULE, - .open = blkvsc_open, - .release = blkvsc_release, - .media_changed = blkvsc_media_changed, - .revalidate_disk = blkvsc_revalidate_disk, - .getgeo = blkvsc_getgeo, - .ioctl = blkvsc_ioctl, -}; - -/* - * blkvsc_drv_init - BlkVsc driver initialization. - */ -static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv)) -{ - struct storvsc_driver_object *storvsc_drv_obj = &g_blkvsc_drv.drv_obj; - struct driver_context *drv_ctx = &g_blkvsc_drv.drv_ctx; - int ret; - - storvsc_drv_obj->ring_buffer_size = blkvsc_ringbuffer_size; - - /* Callback to client driver to complete the initialization */ - drv_init(&storvsc_drv_obj->base); - - drv_ctx->driver.name = storvsc_drv_obj->base.name; - memcpy(&drv_ctx->class_id, &storvsc_drv_obj->base.deviceType, - sizeof(struct hv_guid)); - - drv_ctx->probe = blkvsc_probe; - drv_ctx->remove = blkvsc_remove; - drv_ctx->shutdown = blkvsc_shutdown; - - /* The driver belongs to vmbus */ - ret = vmbus_child_driver_register(drv_ctx); - - 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) -{ - struct storvsc_driver_object *storvsc_drv_obj = &g_blkvsc_drv.drv_obj; - struct driver_context *drv_ctx = &g_blkvsc_drv.drv_ctx; - struct device *current_dev; - int ret; - - while (1) { - current_dev = NULL; - - /* Get the device */ - ret = driver_for_each_device(&drv_ctx->driver, NULL, - (void *) ¤t_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.OnCleanup) - storvsc_drv_obj->base.OnCleanup(&storvsc_drv_obj->base); - - vmbus_child_driver_unregister(drv_ctx); - - return; -} - -/* - * blkvsc_probe - Add a new device for this driver - */ -static int blkvsc_probe(struct device *device) -{ - struct driver_context *driver_ctx = - driver_to_driver_context(device->driver); - struct blkvsc_driver_context *blkvsc_drv_ctx = - (struct blkvsc_driver_context *)driver_ctx; - struct storvsc_driver_object *storvsc_drv_obj = - &blkvsc_drv_ctx->drv_obj; - struct vm_device *device_ctx = device_to_vm_device(device); - struct hv_device *device_obj = &device_ctx->device_obj; - - 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; - - DPRINT_DBG(BLKVSC_DRV, "blkvsc_probe - enter"); - - if (!storvsc_drv_obj->base.OnDeviceAdd) { - DPRINT_ERR(BLKVSC_DRV, "OnDeviceAdd() not set"); - ret = -1; - goto Cleanup; - } - - blkdev = kzalloc(sizeof(struct block_device_context), GFP_KERNEL); - if (!blkdev) { - ret = -ENOMEM; - goto Cleanup; - } - - INIT_LIST_HEAD(&blkdev->pending_list); - - /* Initialize what we can here */ - spin_lock_init(&blkdev->lock); - - /* ASSERT(sizeof(struct blkvsc_request_group) <= */ - /* sizeof(struct blkvsc_request)); */ - - blkdev->request_pool = kmem_cache_create(dev_name(&device_ctx->device), - sizeof(struct blkvsc_request) + - storvsc_drv_obj->request_ext_size, 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!blkdev->request_pool) { - ret = -ENOMEM; - goto Cleanup; - } - - - /* Call to the vsc driver to add the device */ - ret = storvsc_drv_obj->base.OnDeviceAdd(device_obj, &device_info); - if (ret != 0) { - DPRINT_ERR(BLKVSC_DRV, "unable to add blkvsc device"); - goto Cleanup; - } - - blkdev->device_ctx = device_ctx; - /* 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; - - dev_set_drvdata(device, blkdev); - - /* Calculate the major and device num */ - if (blkdev->path == 0) { - major = IDE0_MAJOR; - devnum = blkdev->path + blkdev->target; /* 0 or 1 */ - - if (!ide0_registered) { - ret = register_blkdev(major, "ide"); - if (ret != 0) { - DPRINT_ERR(BLKVSC_DRV, - "register_blkdev() failed! ret %d", - ret); - goto Remove; - } - - 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; - } - - DPRINT_INFO(BLKVSC_DRV, "blkvsc registered for major %d!!", major); - - 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); - - 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->private_data = blkdev; - blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device); - sprintf(blkdev->gd->disk_name, "hd%c", 'a' + devnum); - - 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); - } else { - blkvsc_do_read_capacity16(blkdev); - } - - 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); - - 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_drv_obj->base.OnDeviceRemove(device_obj); - -Cleanup: - if (blkdev) { - if (blkdev->request_pool) { - kmem_cache_destroy(blkdev->request_pool); - blkdev->request_pool = NULL; - } - kfree(blkdev); - blkdev = NULL; - } - - return ret; -} - -static void blkvsc_shutdown(struct device *device) -{ - struct block_device_context *blkdev = dev_get_drvdata(device); - unsigned long flags; - - if (!blkdev) - return; - - DPRINT_DBG(BLKVSC_DRV, "blkvsc_shutdown - users %d disk %s\n", - blkdev->users, blkdev->gd->disk_name); - - spin_lock_irqsave(&blkdev->lock, flags); - - blkdev->shutting_down = 1; - - 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); -} - -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.PfnArray[0] = 0; - blkvsc_req->request.data_buffer.Offset = 0; - blkvsc_req->request.data_buffer.Length = 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) -{ - struct blkvsc_request *blkvsc_req; - struct page *page_buf; - unsigned char *buf; - unsigned char device_type; - - DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_inquiry()\n"); - - 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; - } - - init_waitqueue_head(&blkvsc_req->wevent); - blkvsc_req->dev = blkdev; - blkvsc_req->req = NULL; - blkvsc_req->write = 0; - - blkvsc_req->request.data_buffer.PfnArray[0] = page_to_pfn(page_buf); - blkvsc_req->request.data_buffer.Offset = 0; - blkvsc_req->request.data_buffer.Length = 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); - - buf = kmap(page_buf); - - /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, 64); */ - /* be to le */ - device_type = buf[0] & 0x1F; - - 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; - } - - 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"); - - 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; - } - - init_waitqueue_head(&blkvsc_req->wevent); - blkvsc_req->dev = blkdev; - blkvsc_req->req = NULL; - blkvsc_req->write = 0; - - blkvsc_req->request.data_buffer.PfnArray[0] = page_to_pfn(page_buf); - blkvsc_req->request.data_buffer.Offset = 0; - blkvsc_req->request.data_buffer.Length = 8; - - blkvsc_req->cmnd[0] = READ_CAPACITY; - blkvsc_req->cmd_len = 16; - - /* - * 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); - - /* 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; - } - 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]; - - kunmap(page_buf); - - __free_page(page_buf); - - kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req); - - return 0; -} - -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; - } - - init_waitqueue_head(&blkvsc_req->wevent); - blkvsc_req->dev = blkdev; - blkvsc_req->req = NULL; - blkvsc_req->write = 0; - - blkvsc_req->request.data_buffer.PfnArray[0] = page_to_pfn(page_buf); - blkvsc_req->request.data_buffer.Offset = 0; - blkvsc_req->request.data_buffer.Length = 12; - - blkvsc_req->cmnd[0] = 0x9E; /* READ_CAPACITY16; */ - blkvsc_req->cmd_len = 16; - - /* - * 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); - - /* 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; - } - 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 - - kunmap(page_buf); - - __free_page(page_buf); - - kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req); - - return 0; -} - -/* - * blkvsc_remove() - Callback when our device is removed - */ -static int blkvsc_remove(struct device *device) -{ - struct driver_context *driver_ctx = - driver_to_driver_context(device->driver); - struct blkvsc_driver_context *blkvsc_drv_ctx = - (struct blkvsc_driver_context *)driver_ctx; - struct storvsc_driver_object *storvsc_drv_obj = - &blkvsc_drv_ctx->drv_obj; - struct vm_device *device_ctx = device_to_vm_device(device); - struct hv_device *device_obj = &device_ctx->device_obj; - struct block_device_context *blkdev = dev_get_drvdata(device); - unsigned long flags; - int ret; - - DPRINT_DBG(BLKVSC_DRV, "blkvsc_remove()\n"); - - if (!storvsc_drv_obj->base.OnDeviceRemove) - return -1; - - /* - * Call to the vsc driver to let it know that the device is being - * removed - */ - ret = storvsc_drv_obj->base.OnDeviceRemove(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); - - blkdev->shutting_down = 1; - - 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); - - blk_cleanup_queue(blkdev->gd->queue); - - del_gendisk(blkdev->gd); - - kmem_cache_destroy(blkdev->request_pool); - - kfree(blkdev); - - return ret; -} - -static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req) -{ - /* 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; - } - - blkvsc_req->cmnd[1] |= - (blkvsc_req->req->cmd_flags & REQ_FUA) ? 0x8 : 0; - - *(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; - } - - *(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; - } -} - -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 vm_device *device_ctx = blkdev->device_ctx; - struct driver_context *driver_ctx = - driver_to_driver_context(device_ctx->device.driver); - struct blkvsc_driver_context *blkvsc_drv_ctx = - (struct blkvsc_driver_context *)driver_ctx; - struct storvsc_driver_object *storvsc_drv_obj = - &blkvsc_drv_ctx->drv_obj; - struct hv_storvsc_request *storvsc_req; - int ret; - - 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.Length); -#if 0 - for (i = 0; i < (blkvsc_req->request.data_buffer.Length >> 12); i++) { - DPRINT_DBG(BLKVSC_DRV, "blkvsc_submit_request() - " - "req %p pfn[%d] %llx\n", - blkvsc_req, i, - blkvsc_req->request.data_buffer.PfnArray[i]); - } -#endif - - storvsc_req = &blkvsc_req->request; - storvsc_req->extension = (void *)((unsigned long)blkvsc_req + - sizeof(struct blkvsc_request)); - - storvsc_req->type = blkvsc_req->write ? WRITE_TYPE : READ_TYPE; - - storvsc_req->on_io_completion = request_completion; - storvsc_req->context = blkvsc_req; - - 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; - - storvsc_req->sense_buffer = blkvsc_req->sense_buffer; - storvsc_req->sense_buffer_size = SCSI_SENSE_BUFFERSIZE; - - ret = storvsc_drv_obj->on_io_request(&blkdev->device_ctx->device_obj, - &blkvsc_req->request); - if (ret == 0) - blkdev->num_outstanding_reqs++; - - return ret; -} - -/* - * We break the request into 1 or more blkvsc_requests and submit - * 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, - struct request *req) -{ - struct bio *bio = NULL; - struct bio_vec *bvec = NULL; - struct bio_vec *prev_bvec = NULL; - struct blkvsc_request *blkvsc_req = NULL; - struct blkvsc_request *tmp; - int databuf_idx = 0; - int seg_idx = 0; - sector_t start_sector; - unsigned long num_sectors = 0; - int ret = 0; - 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); - if (!group) - return -ENOMEM; - - INIT_LIST_HEAD(&group->blkvsc_req_list); - group->outstanding = group->status = 0; - - start_sector = blk_rq_pos(req); - - /* foreach bio in the request */ - if (req->bio) { - for (bio = req->bio; bio; bio = bio->bi_next) { - /* - * 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) || - (databuf_idx >= MAX_MULTIPAGE_BUFFER_COUNT) - /* hole at the begin of page */ - || (bvec->bv_offset != 0) || - /* hold at the end of page */ - (prev_bvec && - (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_init_rw(blkvsc_req); - } - - /* - * Create new blkvsc_req to represent - * the current bvec - */ - blkvsc_req = kmem_cache_alloc(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); - } - - kmem_cache_free(blkdev->request_pool, group); - return -ENOMEM; - } - - memset(blkvsc_req, 0, - sizeof(struct blkvsc_request)); - - blkvsc_req->dev = blkdev; - blkvsc_req->req = req; - blkvsc_req->request.data_buffer.Offset - = bvec->bv_offset; - blkvsc_req->request.data_buffer.Length - = 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); - - start_sector += num_sectors; - num_sectors = 0; - databuf_idx = 0; - } - - /* Add the curr bvec/segment to the curr blkvsc_req */ - blkvsc_req->request.data_buffer. - PfnArray[databuf_idx] - = page_to_pfn(bvec->bv_page); - blkvsc_req->request.data_buffer.Length - += bvec->bv_len; - - prev_bvec = bvec; - - databuf_idx++; - num_sectors += bvec->bv_len >> 9; - - } /* bio_for_each_segment */ - - } /* rq_for_each_bio */ - } - - /* 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)); - - blkvsc_req->sector_count = num_sectors / - (blkdev->sector_size >> 9); - - blkvsc_init_rw(blkvsc_req); - } - - 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); - } else { - ret = blkvsc_submit_request(blkvsc_req, - blkvsc_request_completion); - if (ret == -1) { - pending = 1; - list_add_tail(&blkvsc_req->pend_entry, - &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.Length, - 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; - int ret = 0; - - /* 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); - if (ret != 0) - break; - else - list_del(&pend_req->pend_entry); - } - - 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) { - __blk_end_request_cur(req, 0); - continue; - } - - 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; - } - - blk_start_request(req); - - 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; - } - } -} - -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++; - - spin_unlock(&blkdev->lock); - mutex_unlock(&blkvsc_mutex); - return 0; -} - -static int blkvsc_release(struct gendisk *disk, fmode_t mode) -{ - struct block_device_context *blkdev = 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 == 1) { - spin_unlock(&blkdev->lock); - blkvsc_do_flush(blkdev); - spin_lock(&blkdev->lock); - } - - blkdev->users--; - - spin_unlock(&blkdev->lock); - mutex_unlock(&blkvsc_mutex); - return 0; -} - -static int blkvsc_media_changed(struct gendisk *gd) -{ - DPRINT_DBG(BLKVSC_DRV, "- enter\n"); - return 1; -} - -static int blkvsc_revalidate_disk(struct gendisk *gd) -{ - struct block_device_context *blkdev = gd->private_data; - - DPRINT_DBG(BLKVSC_DRV, "- enter\n"); - - 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); - } - 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; - - int sectors_per_track = 0; - int heads = 0; - int cylinders = 0; - int rem = 0; - - if (total_sectors > (65535 * 16 * 255)) - total_sectors = (65535 * 16 * 255); - - if (total_sectors >= (65535 * 16 * 63)) { - sectors_per_track = 255; - heads = 16; - - 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); - - temp = cylinder_times_heads + 1023; - /* sector_div stores the quotient in temp */ - rem = sector_div(temp, 1024); - - heads = temp; - - if (heads < 4) - heads = 4; - - - if (cylinder_times_heads >= (heads * 1024) || (heads > 16)) { - sectors_per_track = 31; - heads = 16; - - cylinder_times_heads = total_sectors; - /* - * sector_div stores the quotient in - * cylinder_times_heads - */ - rem = sector_div(cylinder_times_heads, - sectors_per_track); - } - - if (cylinder_times_heads >= (heads * 1024)) { - sectors_per_track = 63; - heads = 16; - - cylinder_times_heads = total_sectors; - /* - * sector_div stores the quotient in - * cylinder_times_heads - */ - rem = sector_div(cylinder_times_heads, - sectors_per_track); - } - } - - temp = cylinder_times_heads; - /* sector_div stores the quotient in temp */ - rem = sector_div(temp, heads); - cylinders = temp; - - hg->heads = heads; - hg->sectors = sectors_per_track; - hg->cylinders = cylinders; - - DPRINT_INFO(BLKVSC_DRV, "CHS (%d, %d, %d)", cylinders, heads, - sectors_per_track); - - return 0; -} - -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; - - 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; - } - - return ret; -} - -static int __init blkvsc_init(void) -{ - int ret; - - BUILD_BUG_ON(sizeof(sector_t) != 8); - - DPRINT_INFO(BLKVSC_DRV, "Blkvsc initializing...."); - - ret = blkvsc_drv_init(blk_vsc_initialize); - - return ret; -} - -static void __exit blkvsc_exit(void) -{ - blkvsc_drv_exit(); -} - -MODULE_LICENSE("GPL"); -MODULE_VERSION(HV_DRV_VERSION); -MODULE_DESCRIPTION("Microsoft Hyper-V virtual block driver"); -module_init(blkvsc_init); -module_exit(blkvsc_exit); diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c deleted file mode 100644 index 45a627d77b4..00000000000 --- a/drivers/staging/hv/channel.c +++ /dev/null @@ -1,1057 +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 <linux/slab.h> -#include <linux/module.h> -#include "osd.h" -#include "logging.h" -#include "vmbus_private.h" - -/* Internal routines */ -static int create_gpadl_header( - void *kbuffer, /* must be phys and virt contiguous */ - u32 size, /* page-size multiple */ - struct vmbus_channel_msginfo **msginfo, - u32 *messagecount); -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. - */ -static void vmbus_setevent(struct vmbus_channel *channel) -{ - struct hv_monitor_page *monitorpage; - - if (channel->offermsg.monitor_allocated) { - /* Each u32 represents 32 channels */ - set_bit(channel->offermsg.child_relid & 31, - (unsigned long *) gVmbusConnection.SendInterruptPage + - (channel->offermsg.child_relid >> 5)); - - monitorpage = gVmbusConnection.MonitorPages; - monitorpage++; /* Get the child to parent monitor page */ - - set_bit(channel->monitor_bit, - (unsigned long *)&monitorpage->trigger_group - [channel->monitor_grp].pending); - - } else { - VmbusSetEvent(channel->offermsg.child_relid); - } -} - -#if 0 -static void VmbusChannelClearEvent(struct vmbus_channel *channel) -{ - struct hv_monitor_page *monitorPage; - - if (Channel->offermsg.monitor_allocated) { - /* Each u32 represents 32 channels */ - clear_bit(Channel->offermsg.child_relid & 31, - (unsigned long *)gVmbusConnection.SendInterruptPage + - (Channel->offermsg.child_relid >> 5)); - - monitorPage = - (struct hv_monitor_page *)gVmbusConnection.MonitorPages; - monitorPage++; /* Get the child to parent monitor page */ - - clear_bit(Channel->monitor_bit, - (unsigned long *)&monitorPage->trigger_group - [Channel->monitor_grp].Pending); - } -} - -#endif -/* - * vmbus_get_debug_info -Retrieve various channel debug info - */ -void vmbus_get_debug_info(struct vmbus_channel *channel, - struct vmbus_channel_debug_info *debuginfo) -{ - struct hv_monitor_page *monitorpage; - u8 monitor_group = (u8)channel->offermsg.monitorid / 32; - u8 monitor_offset = (u8)channel->offermsg.monitorid % 32; - /* u32 monitorBit = 1 << monitorOffset; */ - - debuginfo->relid = channel->offermsg.child_relid; - debuginfo->state = channel->state; - memcpy(&debuginfo->interfacetype, - &channel->offermsg.offer.InterfaceType, sizeof(struct hv_guid)); - memcpy(&debuginfo->interface_instance, - &channel->offermsg.offer.InterfaceInstance, - sizeof(struct hv_guid)); - - monitorpage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages; - - debuginfo->monitorid = channel->offermsg.monitorid; - - debuginfo->servermonitor_pending = - monitorpage->trigger_group[monitor_group].pending; - debuginfo->servermonitor_latency = - monitorpage->latency[monitor_group][monitor_offset]; - debuginfo->servermonitor_connectionid = - monitorpage->parameter[monitor_group] - [monitor_offset].connectionid.u.id; - - monitorpage++; - - debuginfo->clientmonitor_pending = - monitorpage->trigger_group[monitor_group].pending; - debuginfo->clientmonitor_latency = - monitorpage->latency[monitor_group][monitor_offset]; - debuginfo->clientmonitor_connectionid = - monitorpage->parameter[monitor_group] - [monitor_offset].connectionid.u.id; - - ringbuffer_get_debuginfo(&channel->inbound, &debuginfo->inbound); - ringbuffer_get_debuginfo(&channel->outbound, &debuginfo->outbound); -} - -/* - * vmbus_open - Open the specified channel. - */ -int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, - u32 recv_ringbuffer_size, void *userdata, u32 userdatalen, - void (*onchannelcallback)(void *context), void *context) -{ - struct vmbus_channel_open_channel *openMsg; - 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))); */ - - newchannel->onchannel_callback = onchannelcallback; - newchannel->channel_callback_context = context; - - /* Allocate the ring buffer */ - out = osd_page_alloc((send_ringbuffer_size + recv_ringbuffer_size) - >> PAGE_SHIFT); - if (!out) - return -ENOMEM; - - /* ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0); */ - - in = (void *)((unsigned long)out + send_ringbuffer_size); - - newchannel->ringbuffer_pages = out; - newchannel->ringbuffer_pagecount = (send_ringbuffer_size + - recv_ringbuffer_size) >> PAGE_SHIFT; - - ret = ringbuffer_init(&newchannel->outbound, out, send_ringbuffer_size); - if (ret != 0) { - err = ret; - goto errorout; - } - - ret = ringbuffer_init(&newchannel->inbound, in, recv_ringbuffer_size); - if (ret != 0) { - err = ret; - goto errorout; - } - - - /* 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, - newchannel->outbound.ring_buffer, - send_ringbuffer_size + - recv_ringbuffer_size, - &newchannel->ringbuffer_gpadlhandle); - - if (ret != 0) { - err = ret; - 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), - GFP_KERNEL); - if (!openInfo) { - err = -ENOMEM; - goto errorout; - } - - openInfo->waitevent = osd_waitevent_create(); - if (!openInfo->waitevent) { - err = -ENOMEM; - goto errorout; - } - - openMsg = (struct vmbus_channel_open_channel *)openInfo->msg; - openMsg->header.msgtype = CHANNELMSG_OPENCHANNEL; - openMsg->openid = newchannel->offermsg.child_relid; /* FIXME */ - openMsg->child_relid = newchannel->offermsg.child_relid; - openMsg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle; - openMsg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >> - PAGE_SHIFT; - openMsg->server_contextarea_gpadlhandle = 0; /* TODO */ - - if (userdatalen > MAX_USER_DEFINED_BYTES) { - err = -EINVAL; - goto errorout; - } - - if (userdatalen) - memcpy(openMsg->userdata, userdata, userdatalen); - - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_add_tail(&openInfo->msglistentry, - &gVmbusConnection.ChannelMsgList); - spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); - - DPRINT_DBG(VMBUS, "Sending channel open msg..."); - - ret = VmbusPostMessage(openMsg, - sizeof(struct vmbus_channel_open_channel)); - if (ret != 0) { - DPRINT_ERR(VMBUS, "unable to open channel - %d", ret); - goto Cleanup; - } - - /* FIXME: Need to time-out here */ - osd_waitevent_wait(openInfo->waitevent); - - 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); - -Cleanup: - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_del(&openInfo->msglistentry); - spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); - - kfree(openInfo->waitevent); - kfree(openInfo); - return 0; - -errorout: - ringbuffer_cleanup(&newchannel->outbound); - ringbuffer_cleanup(&newchannel->inbound); - osd_page_free(out, (send_ringbuffer_size + recv_ringbuffer_size) - >> PAGE_SHIFT); - kfree(openInfo); - return err; -} -EXPORT_SYMBOL_GPL(vmbus_open); - -/* - * dump_gpadl_body - Dump the gpadl body message to the console for - * debugging purposes. - */ -static void dump_gpadl_body(struct vmbus_channel_gpadl_body *gpadl, u32 len) -{ - int i; - int pfncount; - - 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++) - DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu", - i, gpadl->pfn[i]); -} - -/* - * dump_gpadl_header - Dump the gpadl header message to the console for - * debugging purposes. - */ -static void dump_gpadl_header(struct vmbus_channel_gpadl_header *gpadl) -{ - int i, j; - int pagecount; - - DPRINT_DBG(VMBUS, - "gpadl header - relid %d, range count %d, range buflen %d", - gpadl->child_relid, gpadl->rangecount, gpadl->range_buflen); - for (i = 0; i < gpadl->rangecount; i++) { - pagecount = gpadl->range[i].ByteCount >> PAGE_SHIFT; - pagecount = (pagecount > 26) ? 26 : pagecount; - - DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d " - "page count %d", i, gpadl->range[i].ByteCount, - gpadl->range[i].ByteOffset, pagecount); - - for (j = 0; j < pagecount; j++) - DPRINT_DBG(VMBUS, "%d) pfn %llu", j, - gpadl->range[i].PfnArray[j]); - } -} - -/* - * create_gpadl_header - Creates a gpadl for the specified buffer - */ -static int create_gpadl_header(void *kbuffer, u32 size, - struct vmbus_channel_msginfo **msginfo, - u32 *messagecount) -{ - int i; - int pagecount; - unsigned long long pfn; - struct vmbus_channel_gpadl_header *gpadl_header; - struct vmbus_channel_gpadl_body *gpadl_body; - struct vmbus_channel_msginfo *msgheader; - struct vmbus_channel_msginfo *msgbody = NULL; - u32 msgsize; - - 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; - - /* do we need a gpadl body msg */ - pfnsize = MAX_SIZE_CHANNEL_MESSAGE - - sizeof(struct vmbus_channel_gpadl_header) - - sizeof(struct gpa_range); - pfncount = pfnsize / sizeof(u64); - - if (pagecount > pfncount) { - /* we need a gpadl body */ - /* fill in the header */ - msgsize = sizeof(struct vmbus_channel_msginfo) + - sizeof(struct vmbus_channel_gpadl_header) + - sizeof(struct gpa_range) + pfncount * sizeof(u64); - msgheader = kzalloc(msgsize, GFP_KERNEL); - if (!msgheader) - goto nomem; - - INIT_LIST_HEAD(&msgheader->submsglist); - msgheader->msgsize = msgsize; - - gpadl_header = (struct vmbus_channel_gpadl_header *) - msgheader->msg; - gpadl_header->rangecount = 1; - gpadl_header->range_buflen = sizeof(struct gpa_range) + - pagecount * sizeof(u64); - gpadl_header->range[0].ByteOffset = 0; - gpadl_header->range[0].ByteCount = size; - for (i = 0; i < pfncount; i++) - gpadl_header->range[0].PfnArray[i] = pfn+i; - *msginfo = msgheader; - *messagecount = 1; - - pfnsum = pfncount; - pfnleft = pagecount - pfncount; - - /* how many pfns can we fit */ - pfnsize = MAX_SIZE_CHANNEL_MESSAGE - - sizeof(struct vmbus_channel_gpadl_body); - pfncount = pfnsize / sizeof(u64); - - /* fill in the body */ - while (pfnleft) { - if (pfnleft > pfncount) - pfncurr = pfncount; - else - pfncurr = pfnleft; - - msgsize = sizeof(struct vmbus_channel_msginfo) + - sizeof(struct vmbus_channel_gpadl_body) + - pfncurr * sizeof(u64); - msgbody = kzalloc(msgsize, GFP_KERNEL); - /* FIXME: we probably need to more if this fails */ - if (!msgbody) - goto nomem; - msgbody->msgsize = msgsize; - (*messagecount)++; - gpadl_body = - (struct vmbus_channel_gpadl_body *)msgbody->msg; - - /* - * FIXME: - * Gpadl is u32 and we are using a pointer which could - * be 64-bit - */ - /* gpadl_body->Gpadl = kbuffer; */ - for (i = 0; i < pfncurr; i++) - gpadl_body->pfn[i] = pfn + pfnsum + i; - - /* add to msg header */ - list_add_tail(&msgbody->msglistentry, - &msgheader->submsglist); - pfnsum += pfncurr; - pfnleft -= pfncurr; - } - } else { - /* everything fits in a header */ - msgsize = sizeof(struct vmbus_channel_msginfo) + - sizeof(struct vmbus_channel_gpadl_header) + - sizeof(struct gpa_range) + pagecount * sizeof(u64); - msgheader = kzalloc(msgsize, GFP_KERNEL); - if (msgheader == NULL) - goto nomem; - msgheader->msgsize = msgsize; - - gpadl_header = (struct vmbus_channel_gpadl_header *) - msgheader->msg; - gpadl_header->rangecount = 1; - gpadl_header->range_buflen = sizeof(struct gpa_range) + - pagecount * sizeof(u64); - gpadl_header->range[0].ByteOffset = 0; - gpadl_header->range[0].ByteCount = size; - for (i = 0; i < pagecount; i++) - gpadl_header->range[0].PfnArray[i] = pfn+i; - - *msginfo = msgheader; - *messagecount = 1; - } - - return 0; -nomem: - kfree(msgheader); - kfree(msgbody); - return -ENOMEM; -} - -/* - * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer - * - * @channel: a channel - * @kbuffer: from kmalloc - * @size: page-size multiple - * @gpadl_handle: some funky thing - */ -int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, - u32 size, u32 *gpadl_handle) -{ - struct vmbus_channel_gpadl_header *gpadlmsg; - struct vmbus_channel_gpadl_body *gpadl_body; - /* struct vmbus_channel_gpadl_created *gpadlCreated; */ - struct vmbus_channel_msginfo *msginfo = NULL; - struct vmbus_channel_msginfo *submsginfo; - u32 msgcount; - struct list_head *curr; - u32 next_gpadl_handle; - unsigned long flags; - int ret = 0; - - next_gpadl_handle = atomic_read(&gVmbusConnection.NextGpadlHandle); - atomic_inc(&gVmbusConnection.NextGpadlHandle); - - ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount); - if (ret) - return ret; - - msginfo->waitevent = osd_waitevent_create(); - if (!msginfo->waitevent) { - ret = -ENOMEM; - goto Cleanup; - } - - gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg; - gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER; - gpadlmsg->child_relid = channel->offermsg.child_relid; - gpadlmsg->gpadl = next_gpadl_handle; - - dump_gpadl_header(gpadlmsg); - - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_add_tail(&msginfo->msglistentry, - &gVmbusConnection.ChannelMsgList); - - spin_unlock_irqrestore(&gVmbusConnection.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)); - - ret = VmbusPostMessage(gpadlmsg, msginfo->msgsize - - sizeof(*msginfo)); - if (ret != 0) { - DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret); - goto Cleanup; - } - - if (msgcount > 1) { - list_for_each(curr, &msginfo->submsglist) { - - /* FIXME: should this use list_entry() instead ? */ - submsginfo = (struct vmbus_channel_msginfo *)curr; - gpadl_body = - (struct vmbus_channel_gpadl_body *)submsginfo->msg; - - gpadl_body->header.msgtype = - 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 = VmbusPostMessage(gpadl_body, - submsginfo->msgsize - - sizeof(*submsginfo)); - if (ret != 0) - goto Cleanup; - - } - } - osd_waitevent_wait(msginfo->waitevent); - - /* 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: - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_del(&msginfo->msglistentry); - spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); - - kfree(msginfo->waitevent); - kfree(msginfo); - return ret; -} -EXPORT_SYMBOL_GPL(vmbus_establish_gpadl); - -/* - * vmbus_teardown_gpadl -Teardown the specified GPADL handle - */ -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; - - /* ASSERT(gpadl_handle != 0); */ - - info = kmalloc(sizeof(*info) + - sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->waitevent = osd_waitevent_create(); - if (!info->waitevent) { - kfree(info); - return -ENOMEM; - } - - msg = (struct vmbus_channel_gpadl_teardown *)info->msg; - - msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN; - msg->child_relid = channel->offermsg.child_relid; - msg->gpadl = gpadl_handle; - - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_add_tail(&info->msglistentry, - &gVmbusConnection.ChannelMsgList); - spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); - - ret = VmbusPostMessage(msg, - sizeof(struct vmbus_channel_gpadl_teardown)); - if (ret != 0) { - /* TODO: */ - /* something... */ - } - - osd_waitevent_wait(info->waitevent); - - /* Received a torndown response */ - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_del(&info->msglistentry); - spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); - - kfree(info->waitevent); - kfree(info); - return ret; -} -EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); - -/* - * vmbus_close - Close the specified channel - */ -void vmbus_close(struct vmbus_channel *channel) -{ - struct vmbus_channel_close_channel *msg; - struct vmbus_channel_msginfo *info; - unsigned long flags; - int ret; - - /* Stop callback and cancel the timer asap */ - channel->onchannel_callback = NULL; - del_timer_sync(&channel->poll_timer); - - /* Send a closing message */ - info = kmalloc(sizeof(*info) + - sizeof(struct vmbus_channel_close_channel), GFP_KERNEL); - /* FIXME: can't do anything other than return here because the - * function is void */ - if (!info) - return; - - /* info->waitEvent = osd_waitevent_create(); */ - - msg = (struct vmbus_channel_close_channel *)info->msg; - msg->header.msgtype = CHANNELMSG_CLOSECHANNEL; - msg->child_relid = channel->offermsg.child_relid; - - ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_close_channel)); - if (ret != 0) { - /* TODO: */ - /* something... */ - } - - /* Tear down the gpadl for the channel's ring buffer */ - if (channel->ringbuffer_gpadlhandle) - vmbus_teardown_gpadl(channel, - channel->ringbuffer_gpadlhandle); - - /* TODO: Send a msg to release the childRelId */ - - /* Cleanup the ring buffers for this channel */ - ringbuffer_cleanup(&channel->outbound); - ringbuffer_cleanup(&channel->inbound); - - osd_page_free(channel->ringbuffer_pages, channel->ringbuffer_pagecount); - - kfree(info); - - /* - * If we are closing the channel during an error path in - * opening the channel, don't free the channel since the - * caller will free the channel - */ - - if (channel->state == CHANNEL_OPEN_STATE) { - spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); - list_del(&channel->listentry); - spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); - - free_channel(channel); - } -} -EXPORT_SYMBOL_GPL(vmbus_close); - -/** - * vmbus_sendpacket() - Send the specified buffer on the given channel - * @channel: Pointer to vmbus_channel structure. - * @buffer: Pointer to the buffer you want to receive the data into. - * @bufferlen: Maximum size of what the the buffer will hold - * @requestid: Identifier of the request - * @type: Type of packet that is being send e.g. negotiate, time - * packet etc. - * - * Sends data in @buffer directly to hyper-v via the vmbus - * This will send the data unparsed to hyper-v. - * - * Mainly used by Hyper-V drivers. - */ -int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer, - u32 bufferlen, u64 requestid, - enum vmbus_packet_type type, u32 flags) -{ - struct vmpacket_descriptor desc; - u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen; - u32 packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64)); - struct scatterlist bufferlist[3]; - 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; */ - /* in 8-bytes granularity */ - desc.DataOffset8 = sizeof(struct vmpacket_descriptor) >> 3; - desc.Length8 = (u16)(packetlen_aligned >> 3); - desc.TransactionId = requestid; - - sg_init_table(bufferlist, 3); - sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor)); - sg_set_buf(&bufferlist[1], buffer, bufferlen); - sg_set_buf(&bufferlist[2], &aligned_data, - packetlen_aligned - packetlen); - - ret = ringbuffer_write(&channel->outbound, bufferlist, 3); - - /* TODO: We should determine if this is optional */ - if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound)) - vmbus_setevent(channel); - - return ret; -} -EXPORT_SYMBOL(vmbus_sendpacket); - -/* - * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer - * packets using a GPADL Direct packet type. - */ -int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, - struct hv_page_buffer pagebuffers[], - u32 pagecount, void *buffer, u32 bufferlen, - u64 requestid) -{ - int ret; - int i; - struct vmbus_channel_packet_page_buffer desc; - u32 descsize; - u32 packetlen; - u32 packetlen_aligned; - struct scatterlist bufferlist[3]; - u64 aligned_data = 0; - - if (pagecount > MAX_PAGE_BUFFER_COUNT) - return -EINVAL; - - dump_vmbus_channel(channel); - - /* - * Adjust the size down since vmbus_channel_packet_page_buffer is the - * largest size we support - */ - descsize = sizeof(struct vmbus_channel_packet_page_buffer) - - ((MAX_PAGE_BUFFER_COUNT - pagecount) * - sizeof(struct hv_page_buffer)); - packetlen = descsize + bufferlen; - packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64)); - - /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */ - - /* Setup the descriptor */ - desc.type = VmbusPacketTypeDataUsingGpaDirect; - desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; - desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */ - desc.length8 = (u16)(packetlen_aligned >> 3); - desc.transactionid = requestid; - desc.rangecount = pagecount; - - for (i = 0; i < pagecount; i++) { - desc.range[i].Length = pagebuffers[i].Length; - desc.range[i].Offset = pagebuffers[i].Offset; - desc.range[i].Pfn = pagebuffers[i].Pfn; - } - - sg_init_table(bufferlist, 3); - sg_set_buf(&bufferlist[0], &desc, descsize); - sg_set_buf(&bufferlist[1], buffer, bufferlen); - sg_set_buf(&bufferlist[2], &aligned_data, - packetlen_aligned - packetlen); - - ret = ringbuffer_write(&channel->outbound, bufferlist, 3); - - /* TODO: We should determine if this is optional */ - if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound)) - vmbus_setevent(channel); - - return ret; -} -EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer); - -/* - * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet - * using a GPADL Direct packet type. - */ -int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, - struct hv_multipage_buffer *multi_pagebuffer, - void *buffer, u32 bufferlen, u64 requestid) -{ - int ret; - struct vmbus_channel_packet_multipage_buffer desc; - u32 descsize; - u32 packetlen; - u32 packetlen_aligned; - struct scatterlist bufferlist[3]; - u64 aligned_data = 0; - u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->Offset, - multi_pagebuffer->Length); - - dump_vmbus_channel(channel); - - DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u", - multi_pagebuffer->Offset, - multi_pagebuffer->Length, pfncount); - - if ((pfncount < 0) || (pfncount > MAX_MULTIPAGE_BUFFER_COUNT)) - return -EINVAL; - - /* - * Adjust the size down since vmbus_channel_packet_multipage_buffer is - * the largest size we support - */ - descsize = sizeof(struct vmbus_channel_packet_multipage_buffer) - - ((MAX_MULTIPAGE_BUFFER_COUNT - pfncount) * - sizeof(u64)); - packetlen = descsize + bufferlen; - packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64)); - - /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */ - - /* Setup the descriptor */ - desc.type = VmbusPacketTypeDataUsingGpaDirect; - desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; - desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */ - desc.length8 = (u16)(packetlen_aligned >> 3); - desc.transactionid = requestid; - desc.rangecount = 1; - - desc.range.Length = multi_pagebuffer->Length; - desc.range.Offset = multi_pagebuffer->Offset; - - memcpy(desc.range.PfnArray, multi_pagebuffer->PfnArray, - pfncount * sizeof(u64)); - - sg_init_table(bufferlist, 3); - sg_set_buf(&bufferlist[0], &desc, descsize); - sg_set_buf(&bufferlist[1], buffer, bufferlen); - sg_set_buf(&bufferlist[2], &aligned_data, - packetlen_aligned - packetlen); - - ret = ringbuffer_write(&channel->outbound, bufferlist, 3); - - /* TODO: We should determine if this is optional */ - if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound)) - vmbus_setevent(channel); - - return ret; -} -EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer); - -/** - * vmbus_recvpacket() - Retrieve the user packet on the specified channel - * @channel: Pointer to vmbus_channel structure. - * @buffer: Pointer to the buffer you want to receive the data into. - * @bufferlen: Maximum size of what the the buffer will hold - * @buffer_actual_len: The actual size of the data after it was received - * @requestid: Identifier of the request - * - * Receives directly from the hyper-v vmbus and puts the data it received - * into Buffer. This will receive the data unparsed from hyper-v. - * - * Mainly used by Hyper-V drivers. - */ -int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, - u32 bufferlen, u32 *buffer_actual_len, u64 *requestid) -{ - struct vmpacket_descriptor desc; - u32 packetlen; - u32 userlen; - int ret; - unsigned long flags; - - *buffer_actual_len = 0; - *requestid = 0; - - spin_lock_irqsave(&channel->inbound_lock, flags); - - ret = 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.Length8 << 3; - userlen = packetlen - (desc.DataOffset8 << 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.TransactionId, 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", - bufferlen, userlen); - return -1; - } - - *requestid = desc.TransactionId; - - /* Copy over the packet to the user buffer */ - ret = ringbuffer_read(&channel->inbound, buffer, userlen, - (desc.DataOffset8 << 3)); - - spin_unlock_irqrestore(&channel->inbound_lock, flags); - - return 0; -} -EXPORT_SYMBOL(vmbus_recvpacket); - -/* - * vmbus_recvpacket_raw - Retrieve the raw packet on the specified channel - */ -int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, - u32 bufferlen, u32 *buffer_actual_len, - u64 *requestid) -{ - struct vmpacket_descriptor desc; - u32 packetlen; - u32 userlen; - int ret; - unsigned long flags; - - *buffer_actual_len = 0; - *requestid = 0; - - spin_lock_irqsave(&channel->inbound_lock, flags); - - ret = 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.Length8 << 3; - userlen = packetlen - (desc.DataOffset8 << 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.TransactionId, 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); - return -2; - } - - *requestid = desc.TransactionId; - - /* Copy over the entire packet to the user buffer */ - ret = ringbuffer_read(&channel->inbound, buffer, packetlen, 0); - - spin_unlock_irqrestore(&channel->inbound_lock, flags); - return 0; -} -EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw); - -/* - * vmbus_onchannel_event - Channel event callback - */ -void vmbus_onchannel_event(struct vmbus_channel *channel) -{ - dump_vmbus_channel(channel); - /* ASSERT(Channel->OnChannelCallback); */ - - channel->onchannel_callback(channel->channel_callback_context); - - mod_timer(&channel->poll_timer, jiffies + usecs_to_jiffies(100)); -} - -/* - * vmbus_ontimer - Timer event callback - */ -void vmbus_ontimer(unsigned long data) -{ - struct vmbus_channel *channel = (struct vmbus_channel *)data; - - if (channel->onchannel_callback) - channel->onchannel_callback(channel->channel_callback_context); -} - -/* - * dump_vmbus_channel- Dump vmbus channel info to the console - */ -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 "); -} diff --git a/drivers/staging/hv/channel.h b/drivers/staging/hv/channel.h deleted file mode 100644 index 7997056734d..00000000000 --- 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]; -} __attribute__((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; -} __attribute__((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 deleted file mode 100644 index d44d5c39f68..00000000000 --- a/drivers/staging/hv/channel_mgmt.c +++ /dev/null @@ -1,865 +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 <linux/slab.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/completion.h> -#include "osd.h" -#include "logging.h" -#include "vmbus_private.h" -#include "utils.h" - -struct vmbus_channel_message_table_entry { - enum vmbus_channel_message_type messageType; - void (*messageHandler)(struct vmbus_channel_message_header *msg); -}; - -#define MAX_MSG_TYPES 3 -#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 7 - -static const struct hv_guid - gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = { - /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */ - /* Storage - SCSI */ - { - .data = { - 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, - 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f - } - }, - - /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ - /* Network */ - { - .data = { - 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, - 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E - } - }, - - /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */ - /* Input */ - { - .data = { - 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, - 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A - } - }, - - /* {32412632-86cb-44a2-9b5c-50d1417354f5} */ - /* IDE */ - { - .data = { - 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, - 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5 - } - }, - /* 0E0B6031-5213-4934-818B-38D90CED39DB */ - /* Shutdown */ - { - .data = { - 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49, - 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB - } - }, - /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */ - /* TimeSync */ - { - .data = { - 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49, - 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf - } - }, - /* {57164f39-9115-4e78-ab55-382f3bd5422d} */ - /* Heartbeat */ - { - .data = { - 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, - 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d - } - }, -}; - - -/** - * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message - * @icmsghdrp: Pointer to msg header structure - * @icmsg_negotiate: Pointer to negotiate message structure - * @buf: Raw buffer channel data - * - * @icmsghdrp is of type &struct icmsg_hdr. - * @negop is of type &struct icmsg_negotiate. - * Set up and fill in default negotiate response message. This response can - * come from both the vmbus driver and the hv_utils driver. The current api - * will respond properly to both Windows 2008 and Windows 2008-R2 operating - * systems. - * - * Mainly used by Hyper-V drivers. - */ -void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, - struct icmsg_negotiate *negop, - u8 *buf) -{ - if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { - icmsghdrp->icmsgsize = 0x10; - - negop = (struct icmsg_negotiate *)&buf[ - sizeof(struct vmbuspipe_hdr) + - sizeof(struct icmsg_hdr)]; - - if (negop->icframe_vercnt == 2 && - negop->icversion_data[1].major == 3) { - negop->icversion_data[0].major = 3; - negop->icversion_data[0].minor = 0; - negop->icversion_data[1].major = 3; - negop->icversion_data[1].minor = 0; - } else { - negop->icversion_data[0].major = 1; - negop->icversion_data[0].minor = 0; - negop->icversion_data[1].major = 1; - negop->icversion_data[1].minor = 0; - } - - negop->icframe_vercnt = 1; - negop->icmsg_vercnt = 1; - } -} -EXPORT_SYMBOL(prep_negotiate_resp); - -/** - * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK - * Hyper-V requests - * @context: Pointer to argument structure. - * - * Set up the default handler for non device driver specific requests - * from Hyper-V. This stub responds to the default negotiate messages - * that come in for every non IDE/SCSI/Network request. - * This behavior is normally overwritten in the hv_utils driver. That - * driver handles requests like gracefull shutdown, heartbeats etc. - * - * Mainly used by Hyper-V drivers. - */ -void chn_cb_negotiate(void *context) -{ - struct vmbus_channel *channel = context; - u8 *buf; - u32 buflen, recvlen; - u64 requestid; - - struct icmsg_hdr *icmsghdrp; - struct icmsg_negotiate *negop = NULL; - - buflen = PAGE_SIZE; - buf = kmalloc(buflen, GFP_ATOMIC); - - vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid); - - if (recvlen > 0) { - icmsghdrp = (struct icmsg_hdr *)&buf[ - sizeof(struct vmbuspipe_hdr)]; - - prep_negotiate_resp(icmsghdrp, negop, buf); - - icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION - | ICMSGHDRFLAG_RESPONSE; - - vmbus_sendpacket(channel, buf, - recvlen, requestid, - VmbusPacketTypeDataInBand, 0); - } - - kfree(buf); -} -EXPORT_SYMBOL(chn_cb_negotiate); - -/* - * Function table used for message responses for non IDE/SCSI/Network type - * messages. (Such as KVP/Shutdown etc) - */ -struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = { - /* 0E0B6031-5213-4934-818B-38D90CED39DB */ - /* Shutdown */ - { - .msg_type = HV_SHUTDOWN_MSG, - .data = { - 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" - }, - - /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */ - /* TimeSync */ - { - .msg_type = HV_TIMESYNC_MSG, - .data = { - 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} */ - /* Heartbeat */ - { - .msg_type = HV_HEARTBEAT_MSG, - .data = { - 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" - }, -}; -EXPORT_SYMBOL(hv_cb_utils); - -/* - * alloc_channel - Allocate and initialize a vmbus channel object - */ -static struct vmbus_channel *alloc_channel(void) -{ - struct vmbus_channel *channel; - - channel = kzalloc(sizeof(*channel), GFP_ATOMIC); - if (!channel) - return NULL; - - spin_lock_init(&channel->inbound_lock); - - init_timer(&channel->poll_timer); - channel->poll_timer.data = (unsigned long)channel; - channel->poll_timer.function = vmbus_ontimer; - - channel->controlwq = create_workqueue("hv_vmbus_ctl"); - if (!channel->controlwq) { - kfree(channel); - return NULL; - } - - return channel; -} - -/* - * release_hannel - Release the vmbus channel object itself - */ -static void release_channel(struct work_struct *work) -{ - struct vmbus_channel *channel = container_of(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); -} - -/* - * free_channel - Release the resources used by the vmbus channel object - */ -void free_channel(struct vmbus_channel *channel) -{ - del_timer_sync(&channel->poll_timer); - - /* - * We have to release the channel's workqueue/thread in the vmbus's - * workqueue/thread context - * ie we can't destroy ourselves. - */ - INIT_WORK(&channel->work, release_channel); - queue_work(gVmbusConnection.WorkQueue, &channel->work); -} - - -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(&gVmbusConnection.channel_lock, flags); - if (++counter == MAX_MSG_TYPES) - complete(&hv_channel_ready); - spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); -} - -/* - * vmbus_process_rescind_offer - - * Rescind the offer by initiating a device removal - */ -static void vmbus_process_rescind_offer(struct work_struct *work) -{ - struct vmbus_channel *channel = container_of(work, - struct vmbus_channel, - work); - - vmbus_child_device_unregister(channel->device_obj); -} - -/* - * vmbus_process_offer - Process the offer by creating a channel/device - * associated with this offer - */ -static void vmbus_process_offer(struct work_struct *work) -{ - struct vmbus_channel *newchannel = container_of(work, - struct vmbus_channel, - work); - struct vmbus_channel *channel; - bool fnew = true; - int ret; - int cnt; - unsigned long flags; - - /* The next possible work is rescind handling */ - INIT_WORK(&newchannel->work, vmbus_process_rescind_offer); - - /* Make sure this is a new offer */ - spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); - - list_for_each_entry(channel, &gVmbusConnection.ChannelList, listentry) { - if (!memcmp(&channel->offermsg.offer.InterfaceType, - &newchannel->offermsg.offer.InterfaceType, - sizeof(struct hv_guid)) && - !memcmp(&channel->offermsg.offer.InterfaceInstance, - &newchannel->offermsg.offer.InterfaceInstance, - sizeof(struct hv_guid))) { - fnew = false; - break; - } - } - - if (fnew) - list_add_tail(&newchannel->listentry, - &gVmbusConnection.ChannelList); - - spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); - - if (!fnew) { - DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", - newchannel->offermsg.child_relid); - free_channel(newchannel); - return; - } - - /* - * Start the process of binding this offer to the driver - * We need to set the DeviceObject field before calling - * VmbusChildDeviceAdd() - */ - newchannel->device_obj = vmbus_child_device_create( - &newchannel->offermsg.offer.InterfaceType, - &newchannel->offermsg.offer.InterfaceInstance, - 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() - * method. - */ - ret = VmbusChildDeviceAdd(newchannel->device_obj); - if (ret != 0) { - DPRINT_ERR(VMBUS, - "unable to add child device object (relid %d)", - newchannel->offermsg.child_relid); - - spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); - list_del(&newchannel->listentry); - spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); - - free_channel(newchannel); - } else { - /* - * This state is used to indicate a successful open - * so that when we do close the channel normally, we - * can cleanup properly - */ - newchannel->state = CHANNEL_OPEN_STATE; - - /* Open IC channels */ - for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) { - if (memcmp(&newchannel->offermsg.offer.InterfaceType, - &hv_cb_utils[cnt].data, - sizeof(struct hv_guid)) == 0 && - vmbus_open(newchannel, 2 * PAGE_SIZE, - 2 * PAGE_SIZE, NULL, 0, - hv_cb_utils[cnt].callback, - newchannel) == 0) { - hv_cb_utils[cnt].channel = newchannel; - DPRINT_INFO(VMBUS, "%s", - hv_cb_utils[cnt].log_msg); - count_hv_channel(); - } - } - } -} - -/* - * vmbus_onoffer - Handler for channel offers from vmbus in parent partition. - * - * We ignore all offers except network and storage offers. For each network and - * storage offers, we create a channel object and queue a work item to the - * channel object to process the offer synchronously - */ -static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) -{ - struct vmbus_channel_offer_channel *offer; - struct vmbus_channel *newchannel; - struct hv_guid *guidtype; - struct hv_guid *guidinstance; - int i; - int fsupported = 0; - - offer = (struct vmbus_channel_offer_channel *)hdr; - for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) { - if (memcmp(&offer->offer.InterfaceType, - &gSupportedDeviceClasses[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); - return; - } - - guidtype = &offer->offer.InterfaceType; - guidinstance = &offer->offer.InterfaceInstance; - - 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"); - 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; - newchannel->monitor_bit = (u8)offer->monitorid % 32; - - /* TODO: Make sure the offer comes from our parent partition */ - INIT_WORK(&newchannel->work, vmbus_process_offer); - queue_work(newchannel->controlwq, &newchannel->work); -} - -/* - * vmbus_onoffer_rescind - Rescind offer handler. - * - * We queue a work item to process this offer synchronously - */ -static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) -{ - struct vmbus_channel_rescind_offer *rescind; - struct vmbus_channel *channel; - - rescind = (struct vmbus_channel_rescind_offer *)hdr; - channel = GetChannelFromRelId(rescind->child_relid); - if (channel == NULL) { - DPRINT_DBG(VMBUS, "channel not found for relId %d", - rescind->child_relid); - return; - } - - /* work is initialized for vmbus_process_rescind_offer() from - * vmbus_process_offer() where the channel got created */ - queue_work(channel->controlwq, &channel->work); -} - -/* - * vmbus_onoffers_delivered - - * This is invoked when all offers have been delivered. - * - * Nothing to do here. - */ -static void vmbus_onoffers_delivered( - struct vmbus_channel_message_header *hdr) -{ -} - -/* - * vmbus_onopen_result - Open result handler. - * - * This is invoked when we received a response to our channel open request. - * Find the matching request, copy the response and signal the requesting - * thread. - */ -static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr) -{ - struct vmbus_channel_open_result *result; - struct list_head *curr; - struct vmbus_channel_msginfo *msginfo; - struct vmbus_channel_message_header *requestheader; - struct vmbus_channel_open_channel *openmsg; - 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 - */ - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - - list_for_each(curr, &gVmbusConnection.ChannelMsgList) { -/* FIXME: this should probably use list_entry() instead */ - msginfo = (struct vmbus_channel_msginfo *)curr; - requestheader = - (struct vmbus_channel_message_header *)msginfo->msg; - - if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) { - openmsg = - (struct vmbus_channel_open_channel *)msginfo->msg; - if (openmsg->child_relid == result->child_relid && - openmsg->openid == result->openid) { - memcpy(&msginfo->response.open_result, - result, - sizeof(struct vmbus_channel_open_result)); - osd_waitevent_set(msginfo->waitevent); - break; - } - } - } - spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); -} - -/* - * vmbus_ongpadl_created - GPADL created handler. - * - * This is invoked when we received a response to our gpadl create request. - * Find the matching request, copy the response and signal the requesting - * thread. - */ -static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr) -{ - struct vmbus_channel_gpadl_created *gpadlcreated; - struct list_head *curr; - struct vmbus_channel_msginfo *msginfo; - struct vmbus_channel_message_header *requestheader; - struct vmbus_channel_gpadl_header *gpadlheader; - 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 - * event - */ - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - - list_for_each(curr, &gVmbusConnection.ChannelMsgList) { -/* FIXME: this should probably use list_entry() instead */ - msginfo = (struct vmbus_channel_msginfo *)curr; - requestheader = - (struct vmbus_channel_message_header *)msginfo->msg; - - if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) { - gpadlheader = - (struct vmbus_channel_gpadl_header *)requestheader; - - if ((gpadlcreated->child_relid == - gpadlheader->child_relid) && - (gpadlcreated->gpadl == gpadlheader->gpadl)) { - memcpy(&msginfo->response.gpadl_created, - gpadlcreated, - sizeof(struct vmbus_channel_gpadl_created)); - osd_waitevent_set(msginfo->waitevent); - break; - } - } - } - spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); -} - -/* - * vmbus_ongpadl_torndown - GPADL torndown handler. - * - * This is invoked when we received a response to our gpadl teardown request. - * Find the matching request, copy the response and signal the requesting - * thread. - */ -static void vmbus_ongpadl_torndown( - struct vmbus_channel_message_header *hdr) -{ - struct vmbus_channel_gpadl_torndown *gpadl_torndown; - struct list_head *curr; - struct vmbus_channel_msginfo *msginfo; - struct vmbus_channel_message_header *requestheader; - struct vmbus_channel_gpadl_teardown *gpadl_teardown; - unsigned long flags; - - gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr; - - /* - * Find the open msg, copy the result and signal/unblock the wait event - */ - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - - list_for_each(curr, &gVmbusConnection.ChannelMsgList) { -/* FIXME: this should probably use list_entry() instead */ - msginfo = (struct vmbus_channel_msginfo *)curr; - requestheader = - (struct vmbus_channel_message_header *)msginfo->msg; - - if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) { - gpadl_teardown = - (struct vmbus_channel_gpadl_teardown *)requestheader; - - if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) { - memcpy(&msginfo->response.gpadl_torndown, - gpadl_torndown, - sizeof(struct vmbus_channel_gpadl_torndown)); - osd_waitevent_set(msginfo->waitevent); - break; - } - } - } - spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); -} - -/* - * vmbus_onversion_response - Version response handler - * - * This is invoked when we received a response to our initiate contact request. - * Find the matching request, copy the response and signal the requesting - * thread. - */ -static void vmbus_onversion_response( - struct vmbus_channel_message_header *hdr) -{ - struct list_head *curr; - struct vmbus_channel_msginfo *msginfo; - struct vmbus_channel_message_header *requestheader; - struct vmbus_channel_initiate_contact *initiate; - struct vmbus_channel_version_response *version_response; - unsigned long flags; - - version_response = (struct vmbus_channel_version_response *)hdr; - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - - list_for_each(curr, &gVmbusConnection.ChannelMsgList) { -/* FIXME: this should probably use list_entry() instead */ - msginfo = (struct vmbus_channel_msginfo *)curr; - requestheader = - (struct vmbus_channel_message_header *)msginfo->msg; - - if (requestheader->msgtype == - CHANNELMSG_INITIATE_CONTACT) { - initiate = - (struct vmbus_channel_initiate_contact *)requestheader; - memcpy(&msginfo->response.version_response, - version_response, - sizeof(struct vmbus_channel_version_response)); - osd_waitevent_set(msginfo->waitevent); - } - } - spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); -} - -/* Channel message dispatch table */ -static struct vmbus_channel_message_table_entry - gChannelMessageTable[CHANNELMSG_COUNT] = { - {CHANNELMSG_INVALID, NULL}, - {CHANNELMSG_OFFERCHANNEL, vmbus_onoffer}, - {CHANNELMSG_RESCIND_CHANNELOFFER, vmbus_onoffer_rescind}, - {CHANNELMSG_REQUESTOFFERS, NULL}, - {CHANNELMSG_ALLOFFERS_DELIVERED, vmbus_onoffers_delivered}, - {CHANNELMSG_OPENCHANNEL, NULL}, - {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result}, - {CHANNELMSG_CLOSECHANNEL, NULL}, - {CHANNELMSG_GPADL_HEADER, NULL}, - {CHANNELMSG_GPADL_BODY, NULL}, - {CHANNELMSG_GPADL_CREATED, vmbus_ongpadl_created}, - {CHANNELMSG_GPADL_TEARDOWN, NULL}, - {CHANNELMSG_GPADL_TORNDOWN, vmbus_ongpadl_torndown}, - {CHANNELMSG_RELID_RELEASED, NULL}, - {CHANNELMSG_INITIATE_CONTACT, NULL}, - {CHANNELMSG_VERSION_RESPONSE, vmbus_onversion_response}, - {CHANNELMSG_UNLOAD, NULL}, -}; - -/* - * vmbus_onmessage - Handler for channel protocol messages. - * - * This is invoked in the vmbus worker thread context. - */ -void vmbus_onmessage(void *context) -{ - struct hv_message *msg = context; - struct vmbus_channel_message_header *hdr; - int size; - - 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", - 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); - else - DPRINT_ERR(VMBUS, "Unhandled channel message type %d", - hdr->msgtype); -} - -/* - * vmbus_request_offers - Send a request to get all our pending offers. - */ -int vmbus_request_offers(void) -{ - struct vmbus_channel_message_header *msg; - struct vmbus_channel_msginfo *msginfo; - int ret; - - msginfo = kmalloc(sizeof(*msginfo) + - sizeof(struct vmbus_channel_message_header), - GFP_KERNEL); - if (!msginfo) - return -ENOMEM; - - msginfo->waitevent = osd_waitevent_create(); - if (!msginfo->waitevent) { - kfree(msginfo); - return -ENOMEM; - } - - msg = (struct vmbus_channel_message_header *)msginfo->msg; - - msg->msgtype = CHANNELMSG_REQUESTOFFERS; - - /*SpinlockAcquire(gVmbusConnection.channelMsgLock); - INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, - &msgInfo->msgListEntry); - SpinlockRelease(gVmbusConnection.channelMsgLock);*/ - - ret = VmbusPostMessage(msg, - sizeof(struct vmbus_channel_message_header)); - if (ret != 0) { - DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret); - - /*SpinlockAcquire(gVmbusConnection.channelMsgLock); - REMOVE_ENTRY_LIST(&msgInfo->msgListEntry); - SpinlockRelease(gVmbusConnection.channelMsgLock);*/ - - goto Cleanup; - } - /* osd_waitevent_wait(msgInfo->waitEvent); */ - - /*SpinlockAcquire(gVmbusConnection.channelMsgLock); - REMOVE_ENTRY_LIST(&msgInfo->msgListEntry); - SpinlockRelease(gVmbusConnection.channelMsgLock);*/ - - -Cleanup: - if (msginfo) { - kfree(msginfo->waitevent); - kfree(msginfo); - } - - 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(&gVmbusConnection.channel_lock, flags); - - list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList, - listentry) { - if (channel == start) - break; - - if (!channel->device_obj->Driver) { - 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(&gVmbusConnection.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 de6b2a0ebf7..00000000000 --- a/drivers/staging/hv/channel_mgmt.h +++ /dev/null @@ -1,319 +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 "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; -} __attribute__((packed)); - -/* Query VMBus Version parameters */ -struct vmbus_channel_query_vmbus_version { - struct vmbus_channel_message_header header; - u32 version; -} __attribute__((packed)); - -/* VMBus Version Supported parameters */ -struct vmbus_channel_version_supported { - struct vmbus_channel_message_header header; - bool version_supported; -} __attribute__((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; -} __attribute__((packed)); - -/* Rescind Offer parameters */ -struct vmbus_channel_rescind_offer { - struct vmbus_channel_message_header header; - u32 child_relid; -} __attribute__((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]; -} __attribute__((packed)); - -/* Open Channel Result parameters */ -struct vmbus_channel_open_result { - struct vmbus_channel_message_header header; - u32 child_relid; - u32 openid; - u32 status; -} __attribute__((packed)); - -/* Close channel parameters; */ -struct vmbus_channel_close_channel { - struct vmbus_channel_message_header header; - u32 child_relid; -} __attribute__((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]; -} __attribute__((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]; -} __attribute__((packed)); - -struct vmbus_channel_gpadl_created { - struct vmbus_channel_message_header header; - u32 child_relid; - u32 gpadl; - u32 creation_status; -} __attribute__((packed)); - -struct vmbus_channel_gpadl_teardown { - struct vmbus_channel_message_header header; - u32 child_relid; - u32 gpadl; -} __attribute__((packed)); - -struct vmbus_channel_gpadl_torndown { - struct vmbus_channel_message_header header; - u32 gpadl; -} __attribute__((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; -} __attribute__((packed)); - -struct vmbus_channel_view_range_remove { - struct vmbus_channel_message_header header; - PHYSICAL_ADDRESS viewrange_base; - u32 child_relid; -} __attribute__((packed)); -#endif - -struct vmbus_channel_relid_released { - struct vmbus_channel_message_header header; - u32 child_relid; -} __attribute__((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; -} __attribute__((packed)); - -struct vmbus_channel_version_response { - struct vmbus_channel_message_header header; - bool version_supported; -} __attribute__((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 */ - struct osd_waitevent *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 deleted file mode 100644 index c2e298ff483..00000000000 --- a/drivers/staging/hv/connection.c +++ /dev/null @@ -1,328 +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 <linux/slab.h> -#include <linux/vmalloc.h> -#include "osd.h" -#include "logging.h" -#include "vmbus_private.h" - - -struct VMBUS_CONNECTION gVmbusConnection = { - .ConnectState = Disconnected, - .NextGpadlHandle = ATOMIC_INIT(0xE1E10), -}; - -/* - * VmbusConnect - Sends a connect request on the partition service connection - */ -int VmbusConnect(void) -{ - int ret = 0; - struct vmbus_channel_msginfo *msgInfo = NULL; - struct vmbus_channel_initiate_contact *msg; - unsigned long flags; - - /* Make sure we are not connecting or connected */ - if (gVmbusConnection.ConnectState != Disconnected) - return -1; - - /* Initialize the vmbus connection */ - gVmbusConnection.ConnectState = Connecting; - gVmbusConnection.WorkQueue = create_workqueue("hv_vmbus_con"); - if (!gVmbusConnection.WorkQueue) { - ret = -1; - goto Cleanup; - } - - INIT_LIST_HEAD(&gVmbusConnection.ChannelMsgList); - spin_lock_init(&gVmbusConnection.channelmsg_lock); - - INIT_LIST_HEAD(&gVmbusConnection.ChannelList); - spin_lock_init(&gVmbusConnection.channel_lock); - - /* - * Setup the vmbus event connection for channel interrupt - * abstraction stuff - */ - gVmbusConnection.InterruptPage = osd_page_alloc(1); - if (gVmbusConnection.InterruptPage == NULL) { - ret = -1; - goto Cleanup; - } - - gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage; - gVmbusConnection.SendInterruptPage = - (void *)((unsigned long)gVmbusConnection.InterruptPage + - (PAGE_SIZE >> 1)); - - /* - * Setup the monitor notification facility. The 1st page for - * parent->child and the 2nd page for child->parent - */ - gVmbusConnection.MonitorPages = osd_page_alloc(2); - if (gVmbusConnection.MonitorPages == NULL) { - ret = -1; - goto Cleanup; - } - - msgInfo = kzalloc(sizeof(*msgInfo) + - sizeof(struct vmbus_channel_initiate_contact), - GFP_KERNEL); - if (msgInfo == NULL) { - ret = -ENOMEM; - goto Cleanup; - } - - msgInfo->waitevent = osd_waitevent_create(); - if (!msgInfo->waitevent) { - ret = -ENOMEM; - goto Cleanup; - } - - msg = (struct vmbus_channel_initiate_contact *)msgInfo->msg; - - msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; - msg->vmbus_version_requested = VMBUS_REVISION_NUMBER; - msg->interrupt_page = virt_to_phys(gVmbusConnection.InterruptPage); - msg->monitor_page1 = virt_to_phys(gVmbusConnection.MonitorPages); - msg->monitor_page2 = virt_to_phys( - (void *)((unsigned long)gVmbusConnection.MonitorPages + - PAGE_SIZE)); - - /* - * Add to list before we send the request since we may - * receive the response before returning from this routine - */ - spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_add_tail(&msgInfo->msglistentry, - &gVmbusConnection.ChannelMsgList); - - spin_unlock_irqrestore(&gVmbusConnection.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 = VmbusPostMessage(msg, - sizeof(struct vmbus_channel_initiate_contact)); - if (ret != 0) { - list_del(&msgInfo->msglistentry); - goto Cleanup; - } - - /* Wait for the connection response */ - osd_waitevent_wait(msgInfo->waitevent); - - list_del(&msgInfo->msglistentry); - - /* Check if successful */ - if (msgInfo->response.version_response.version_supported) { - DPRINT_INFO(VMBUS, "Vmbus connected!!"); - gVmbusConnection.ConnectState = Connected; - - } else { - DPRINT_ERR(VMBUS, "Vmbus connection failed!!..." - "current version (%d) not supported", - VMBUS_REVISION_NUMBER); - ret = -1; - goto Cleanup; - } - - kfree(msgInfo->waitevent); - kfree(msgInfo); - return 0; - -Cleanup: - gVmbusConnection.ConnectState = Disconnected; - - if (gVmbusConnection.WorkQueue) - destroy_workqueue(gVmbusConnection.WorkQueue); - - if (gVmbusConnection.InterruptPage) { - osd_page_free(gVmbusConnection.InterruptPage, 1); - gVmbusConnection.InterruptPage = NULL; - } - - if (gVmbusConnection.MonitorPages) { - osd_page_free(gVmbusConnection.MonitorPages, 2); - gVmbusConnection.MonitorPages = NULL; - } - - if (msgInfo) { - kfree(msgInfo->waitevent); - kfree(msgInfo); - } - - return ret; -} - -/* - * VmbusDisconnect - Sends a disconnect request on the partition service connection - */ -int VmbusDisconnect(void) -{ - int ret = 0; - struct vmbus_channel_message_header *msg; - - /* Make sure we are connected */ - if (gVmbusConnection.ConnectState != Connected) - return -1; - - msg = kzalloc(sizeof(struct vmbus_channel_message_header), GFP_KERNEL); - if (!msg) - return -ENOMEM; - - msg->msgtype = CHANNELMSG_UNLOAD; - - ret = VmbusPostMessage(msg, - sizeof(struct vmbus_channel_message_header)); - if (ret != 0) - goto Cleanup; - - osd_page_free(gVmbusConnection.InterruptPage, 1); - - /* TODO: iterate thru the msg list and free up */ - destroy_workqueue(gVmbusConnection.WorkQueue); - - gVmbusConnection.ConnectState = Disconnected; - - DPRINT_INFO(VMBUS, "Vmbus disconnected!!"); - -Cleanup: - kfree(msg); - return ret; -} - -/* - * GetChannelFromRelId - Get the channel object given its child relative id (ie channel id) - */ -struct vmbus_channel *GetChannelFromRelId(u32 relId) -{ - struct vmbus_channel *channel; - struct vmbus_channel *foundChannel = NULL; - unsigned long flags; - - spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); - list_for_each_entry(channel, &gVmbusConnection.ChannelList, listentry) { - if (channel->offermsg.child_relid == relId) { - foundChannel = channel; - break; - } - } - spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); - - return foundChannel; -} - -/* - * VmbusProcessChannelEvent - Process a channel event notification - */ -static void VmbusProcessChannelEvent(void *context) -{ - struct vmbus_channel *channel; - u32 relId = (u32)(unsigned long)context; - - /* ASSERT(relId > 0); */ - - /* - * Find the channel based on this relid and invokes the - * channel callback to process the event - */ - channel = GetChannelFromRelId(relId); - - 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); - } -} - -/* - * VmbusOnEvents - Handler for events - */ -void VmbusOnEvents(void) -{ - int dword; - int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5; - int bit; - int relid; - u32 *recvInterruptPage = gVmbusConnection.RecvInterruptPage; - - /* Check events */ - if (recvInterruptPage) { - for (dword = 0; dword < maxdword; dword++) { - if (recvInterruptPage[dword]) { - for (bit = 0; bit < 32; bit++) { - if (test_and_clear_bit(bit, (unsigned long *)&recvInterruptPage[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); */ - VmbusProcessChannelEvent((void *)(unsigned long)relid); - } - } - } - } - } - } - return; -} - -/* - * VmbusPostMessage - Send a msg on the vmbus's message connection - */ -int VmbusPostMessage(void *buffer, size_t bufferLen) -{ - union hv_connection_id connId; - - connId.asu32 = 0; - connId.u.id = VMBUS_MESSAGE_CONNECTION_ID; - return hv_post_message(connId, 1, buffer, bufferLen); -} - -/* - * VmbusSetEvent - Send an event notification to the parent - */ -int VmbusSetEvent(u32 childRelId) -{ - /* Each u32 represents 32 channels */ - set_bit(childRelId & 31, - (unsigned long *)gVmbusConnection.SendInterruptPage + - (childRelId >> 5)); - - return hv_signal_event(); -} diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c deleted file mode 100644 index a34d713d9c5..00000000000 --- a/drivers/staging/hv/hv.c +++ /dev/null @@ -1,507 +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 <linux/slab.h> -#include <linux/vmalloc.h> -#include "osd.h" -#include "logging.h" -#include "vmbus_private.h" - -/* The one and only */ -struct hv_context hv_context = { - .synic_initialized = false, - .hypercall_page = NULL, - .signal_event_param = NULL, - .signal_event_buffer = NULL, -}; - -/* - * query_hypervisor_presence - * - Query the cpuid for presense of windows hypervisor - */ -static int query_hypervisor_presence(void) -{ - unsigned int eax; - unsigned int ebx; - unsigned int ecx; - unsigned int edx; - unsigned int op; - - eax = 0; - ebx = 0; - ecx = 0; - edx = 0; - op = HVCPUID_VERSION_FEATURES; - cpuid(op, &eax, &ebx, &ecx, &edx); - - return ecx & HV_PRESENT_BIT; -} - -/* - * query_hypervisor_info - Get version info of the windows hypervisor - */ -static int query_hypervisor_info(void) -{ - unsigned int eax; - unsigned int ebx; - unsigned int ecx; - unsigned int edx; - unsigned int max_leaf; - unsigned int op; - - /* - * Its assumed that this is called after confirming that Viridian - * is present. Query id and revision. - */ - eax = 0; - ebx = 0; - ecx = 0; - edx = 0; - 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; - ebx = 0; - ecx = 0; - edx = 0; - op = HVCPUID_VERSION; - cpuid(op, &eax, &ebx, &ecx, &edx); - DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",\ - eax, - ebx >> 16, - ebx & 0xFFFF, - ecx, - edx >> 24, - edx & 0xFFFFFF); - } - return max_leaf; -} - -/* - * do_hypercall- Invoke the specified hypercall - */ -static u64 do_hypercall(u64 control, void *input, void *output) -{ -#ifdef CONFIG_X86_64 - u64 hv_status = 0; - u64 input_address = (input) ? virt_to_phys(input) : 0; - 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 - - u32 control_hi = control >> 32; - u32 control_lo = control & 0xFFFFFFFF; - u32 hv_status_hi = 1; - u32 hv_status_lo = 1; - u64 input_address = (input) ? virt_to_phys(input) : 0; - u32 input_address_hi = input_address >> 32; - u32 input_address_lo = input_address & 0xFFFFFFFF; - u64 output_address = (output) ? virt_to_phys(output) : 0; - u32 output_address_hi = output_address >> 32; - 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 */ -} - -/* - * hv_init - Main initialization routine. - * - * This routine must be called before any other routines in here are called - */ -int hv_init(void) -{ - int ret = 0; - int max_leaf; - union hv_x64_msr_hypercall_contents hypercall_msr; - void *virtaddr = NULL; - - memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS); - memset(hv_context.synic_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..."); - - max_leaf = query_hypervisor_info(); - /* HvQueryHypervisorFeatures(maxLeaf); */ - - /* - * We only support running on top of Hyper-V - */ - 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; - } - - /* Write our OS info */ - wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); - hv_context.guestid = HV_LINUX_GUEST_ID; - - /* See if the hypercall page is already set */ - rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); - - /* - * Allocate the hypercall page memory - * virtaddr = osd_page_alloc(1); - */ - virtaddr = osd_virtual_alloc_exec(PAGE_SIZE); - - if (!virtaddr) { - DPRINT_ERR(VMBUS, - "unable to allocate hypercall page!!"); - goto Cleanup; - } - - hypercall_msr.enable = 1; - - hypercall_msr.guest_physical_address = vmalloc_to_pfn(virtaddr); - wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); - - /* Confirm that hypercall page did get setup. */ - 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; - } - - 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; - - hv_context.signal_event_param = - (struct hv_input_signal_event *) - (ALIGN_UP((unsigned long) - hv_context.signal_event_buffer, - HV_HYPERCALL_PARAM_ALIGN)); - hv_context.signal_event_param->connectionid.asu32 = 0; - hv_context.signal_event_param->connectionid.u.id = - VMBUS_EVENT_CONNECTION_ID; - hv_context.signal_event_param->flag_number = 0; - hv_context.signal_event_param->rsvdz = 0; - - return ret; - -Cleanup: - if (virtaddr) { - if (hypercall_msr.enable) { - hypercall_msr.as_uint64 = 0; - wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); - } - - vfree(virtaddr); - } - ret = -1; - return ret; -} - -/* - * hv_cleanup - Cleanup routine. - * - * This routine is called normally during driver unloading or exiting. - */ -void hv_cleanup(void) -{ - union hv_x64_msr_hypercall_contents hypercall_msr; - - kfree(hv_context.signal_event_buffer); - hv_context.signal_event_buffer = NULL; - hv_context.signal_event_param = NULL; - - if (hv_context.hypercall_page) { - hypercall_msr.as_uint64 = 0; - wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); - vfree(hv_context.hypercall_page); - hv_context.hypercall_page = NULL; - } -} - -/* - * hv_post_message - Post a message using the hypervisor message IPC. - * - * This involves a hypercall. - */ -u16 hv_post_message(union hv_connection_id connection_id, - enum hv_message_type message_type, - void *payload, size_t payload_size) -{ - struct aligned_input { - u64 alignment8; - struct hv_input_post_message msg; - }; - - struct hv_input_post_message *aligned_msg; - u16 status; - unsigned long addr; - - if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) - return -1; - - addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC); - if (!addr) - return -1; - - aligned_msg = (struct hv_input_post_message *) - (ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN)); - - aligned_msg->connectionid = connection_id; - aligned_msg->message_type = message_type; - aligned_msg->payload_size = payload_size; - memcpy((void *)aligned_msg->payload, payload, payload_size); - - status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL) - & 0xFFFF; - - kfree((void *)addr); - - return status; -} - - -/* - * hv_signal_event - - * Signal an event on the specified connection using the hypervisor event IPC. - * - * This involves a hypercall. - */ -u16 hv_signal_event(void) -{ - u16 status; - - status = do_hypercall(HVCALL_SIGNAL_EVENT, - hv_context.signal_event_param, - NULL) & 0xFFFF; - return status; -} - -/* - * hv_synic_init - Initialize the Synthethic Interrupt Controller. - * - * If it is already initialized by another entity (ie x2v shim), we need to - * retrieve the initialized message and event pages. Otherwise, we create and - * initialize the message and event pages. - */ -void hv_synic_init(void *irqarg) -{ - u64 version; - union hv_synic_simp simp; - union hv_synic_siefp siefp; - union hv_synic_sint shared_sint; - union hv_synic_scontrol sctrl; - - u32 irq_vector = *((u32 *)(irqarg)); - int cpu = smp_processor_id(); - - if (!hv_context.hypercall_page) - return; - - /* 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; - } - - 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; - } - - /* Setup the Synic's message page */ - rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64); - simp.simp_enabled = 1; - 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 */ - rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); - siefp.siefp_enabled = 1; - 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); - - shared_sint.as_uint64 = 0; - shared_sint.vector = irq_vector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */ - 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 */ - rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); - sctrl.enable = 1; - - wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); - - hv_context.synic_initialized = true; - return; - -Cleanup: - if (hv_context.synic_event_page[cpu]) - osd_page_free(hv_context.synic_event_page[cpu], 1); - - if (hv_context.synic_message_page[cpu]) - osd_page_free(hv_context.synic_message_page[cpu], 1); - return; -} - -/* - * hv_synic_cleanup - Cleanup routine for hv_synic_init(). - */ -void hv_synic_cleanup(void *arg) -{ - union hv_synic_sint shared_sint; - union hv_synic_simp simp; - union hv_synic_siefp siefp; - int cpu = smp_processor_id(); - - if (!hv_context.synic_initialized) - return; - - rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); - - shared_sint.masked = 1; - - /* Need to correctly cleanup in the case of SMP!!! */ - /* Disable the interrupt */ - wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); - - rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64); - simp.simp_enabled = 0; - simp.base_simp_gpa = 0; - - wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64); - - rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); - siefp.siefp_enabled = 0; - siefp.base_siefp_gpa = 0; - - wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); - - osd_page_free(hv_context.synic_message_page[cpu], 1); - osd_page_free(hv_context.synic_event_page[cpu], 1); -} diff --git a/drivers/staging/hv/hv.h b/drivers/staging/hv/hv.h deleted file mode 100644 index 829aff81bb3..00000000000 --- 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 70e863ad046..00000000000 --- a/drivers/staging/hv/hv_api.h +++ /dev/null @@ -1,905 +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 - - -/* 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 beacuse a parameter has an - * invalid alignment. - */ -#define HV_STATUS_INVALID_ALIGNMENT ((u16)0x0004) - -/* - * HV_STATUS_INVALID_PARAMETER - * The hypervisor could not perform the operation beacuse 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_timesource.c b/drivers/staging/hv/hv_timesource.c deleted file mode 100644 index a7ee533303b..00000000000 --- a/drivers/staging/hv/hv_timesource.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * A clocksource for Linux running on HyperV. - * - * - * Copyright (C) 2010, Novell, Inc. - * Author : K. Y. Srinivasan <ksrinivasan@novell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include <linux/version.h> -#include <linux/clocksource.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/dmi.h> -#include <asm/hyperv.h> -#include <asm/mshyperv.h> -#include <asm/hypervisor.h> - -#define HV_CLOCK_SHIFT 22 - -static cycle_t read_hv_clock(struct clocksource *arg) -{ - cycle_t current_tick; - /* - * Read the partition counter to get the current tick count. This count - * is set to 0 when the partition is created and is incremented in - * 100 nanosecond units. - */ - rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); - return current_tick; -} - -static struct clocksource hyperv_cs = { - .name = "hyperv_clocksource", - .rating = 400, /* use this when running on Hyperv*/ - .read = read_hv_clock, - .mask = CLOCKSOURCE_MASK(64), - /* - * The time ref counter in HyperV is in 100ns units. - * The definition of mult is: - * mult/2^shift = ns/cyc = 100 - * mult = (100 << shift) - */ - .mult = (100 << HV_CLOCK_SHIFT), - .shift = HV_CLOCK_SHIFT, -}; - -static const struct dmi_system_id __initconst -hv_timesource_dmi_table[] __maybe_unused = { - { - .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, hv_timesource_dmi_table); - -static const struct pci_device_id __initconst -hv_timesource_pci_table[] __maybe_unused = { - { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */ - { 0 } -}; -MODULE_DEVICE_TABLE(pci, hv_timesource_pci_table); - - -static int __init init_hv_clocksource(void) -{ - if ((x86_hyper != &x86_hyper_ms_hyperv) || - !(ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)) - return -ENODEV; - - if (!dmi_check_system(hv_timesource_dmi_table)) - return -ENODEV; - - printk(KERN_INFO "Registering HyperV clock source\n"); - return clocksource_register(&hyperv_cs); -} - -module_init(init_hv_clocksource); -MODULE_DESCRIPTION("HyperV based clocksource"); -MODULE_AUTHOR("K. Y. Srinivasan <ksrinivasan@novell.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/hv/hv_utils.c b/drivers/staging/hv/hv_utils.c deleted file mode 100644 index 0074581f20e..00000000000 --- a/drivers/staging/hv/hv_utils.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2010, 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/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/sysctl.h> -#include <linux/reboot.h> -#include <linux/dmi.h> -#include <linux/pci.h> - -#include "logging.h" -#include "osd.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" - -static u8 *shut_txf_buf; -static u8 *time_txf_buf; -static u8 *hbeat_txf_buf; - -static void shutdown_onchannelcallback(void *context) -{ - struct vmbus_channel *channel = context; - u32 recvlen; - u64 requestid; - u8 execute_shutdown = false; - - struct shutdown_msg_data *shutdown_msg; - - struct icmsg_hdr *icmsghdrp; - struct icmsg_negotiate *negop = NULL; - - vmbus_recvpacket(channel, shut_txf_buf, - 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)]; - - if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { - prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf); - } else { - shutdown_msg = - (struct shutdown_msg_data *)&shut_txf_buf[ - sizeof(struct vmbuspipe_hdr) + - sizeof(struct icmsg_hdr)]; - - switch (shutdown_msg->flags) { - case 0: - case 1: - icmsghdrp->status = HV_S_OK; - execute_shutdown = true; - - DPRINT_INFO(VMBUS, "Shutdown request received -" - " gracefull shutdown initiated"); - break; - default: - icmsghdrp->status = HV_E_FAIL; - execute_shutdown = false; - - DPRINT_INFO(VMBUS, "Shutdown request received -" - " Invalid request"); - break; - }; - } - - icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION - | ICMSGHDRFLAG_RESPONSE; - - vmbus_sendpacket(channel, shut_txf_buf, - recvlen, requestid, - VmbusPacketTypeDataInBand, 0); - } - - if (execute_shutdown == true) - orderly_poweroff(false); -} - -/* - * Set guest time to host UTC time. - */ -static inline void do_adj_guesttime(u64 hosttime) -{ - s64 host_tns; - struct timespec host_ts; - - host_tns = (hosttime - WLTIMEDELTA) * 100; - host_ts = ns_to_timespec(host_tns); - - do_settimeofday(&host_ts); -} - -/* - * Synchronize time with host after reboot, restore, etc. - * - * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM. - * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time - * message after the timesync channel is opened. Since the hv_utils module is - * loaded after hv_vmbus, the first message is usually missed. The other - * thing is, systime is automatically set to emulated hardware clock which may - * not be UTC time or in the same time zone. So, to override these effects, we - * use the first 50 time samples for initial system time setting. - */ -static inline void adj_guesttime(u64 hosttime, u8 flags) -{ - static s32 scnt = 50; - - if ((flags & ICTIMESYNCFLAG_SYNC) != 0) { - do_adj_guesttime(hosttime); - return; - } - - if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) { - scnt--; - do_adj_guesttime(hosttime); - } -} - -/* - * Time Sync Channel message handler. - */ -static void timesync_onchannelcallback(void *context) -{ - struct vmbus_channel *channel = context; - u32 recvlen; - u64 requestid; - struct icmsg_hdr *icmsghdrp; - struct ictimesync_data *timedatap; - - vmbus_recvpacket(channel, time_txf_buf, - 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)]; - - if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { - prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf); - } else { - timedatap = (struct ictimesync_data *)&time_txf_buf[ - sizeof(struct vmbuspipe_hdr) + - sizeof(struct icmsg_hdr)]; - adj_guesttime(timedatap->parenttime, timedatap->flags); - } - - icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION - | ICMSGHDRFLAG_RESPONSE; - - vmbus_sendpacket(channel, time_txf_buf, - recvlen, requestid, - VmbusPacketTypeDataInBand, 0); - } -} - -/* - * Heartbeat functionality. - * Every two seconds, Hyper-V send us a heartbeat request message. - * we respond to this message, and Hyper-V knows we are alive. - */ -static void heartbeat_onchannelcallback(void *context) -{ - struct vmbus_channel *channel = context; - u32 recvlen; - u64 requestid; - struct icmsg_hdr *icmsghdrp; - struct heartbeat_msg_data *heartbeat_msg; - - vmbus_recvpacket(channel, hbeat_txf_buf, - 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)]; - - if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { - prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf); - } else { - heartbeat_msg = - (struct heartbeat_msg_data *)&hbeat_txf_buf[ - sizeof(struct vmbuspipe_hdr) + - sizeof(struct icmsg_hdr)]; - - DPRINT_DBG(VMBUS, "heartbeat seq = %lld", - heartbeat_msg->seq_num); - - heartbeat_msg->seq_num += 1; - } - - icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION - | ICMSGHDRFLAG_RESPONSE; - - vmbus_sendpacket(channel, hbeat_txf_buf, - recvlen, requestid, - VmbusPacketTypeDataInBand, 0); - } -} - -static const struct pci_device_id __initconst -hv_utils_pci_table[] __maybe_unused = { - { PCI_DEVICE(0x1414, 0x5353) }, /* Hyper-V emulated VGA controller */ - { 0 } -}; -MODULE_DEVICE_TABLE(pci, hv_utils_pci_table); - - -static const struct dmi_system_id __initconst -hv_utils_dmi_table[] __maybe_unused = { - { - .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, hv_utils_dmi_table); - - -static int __init init_hyperv_utils(void) -{ - printk(KERN_INFO "Registering HyperV Utility Driver\n"); - - if (!dmi_check_system(hv_utils_dmi_table)) - return -ENODEV; - - shut_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - time_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - 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"); - 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 = - ×ync_onchannelcallback; - hv_cb_utils[HV_TIMESYNC_MSG].callback = ×ync_onchannelcallback; - - hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback = - &heartbeat_onchannelcallback; - hv_cb_utils[HV_HEARTBEAT_MSG].callback = &heartbeat_onchannelcallback; - - return 0; -} - -static void exit_hyperv_utils(void) -{ - printk(KERN_INFO "De-Registered HyperV Utility Driver\n"); - - hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback = - &chn_cb_negotiate; - hv_cb_utils[HV_SHUTDOWN_MSG].callback = &chn_cb_negotiate; - - hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback = - &chn_cb_negotiate; - hv_cb_utils[HV_TIMESYNC_MSG].callback = &chn_cb_negotiate; - - hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback = - &chn_cb_negotiate; - hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate; - - kfree(shut_txf_buf); - kfree(time_txf_buf); - kfree(hbeat_txf_buf); -} - -module_init(init_hyperv_utils); -module_exit(exit_hyperv_utils); - -MODULE_DESCRIPTION("Hyper-V Utilities"); -MODULE_VERSION(HV_DRV_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/hv/logging.h b/drivers/staging/hv/logging.h deleted file mode 100644 index 20d4d12023d..00000000000 --- a/drivers/staging/hv/logging.h +++ /dev/null @@ -1,95 +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_ - -/* #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 deleted file mode 100644 index 0edbe7483a4..00000000000 --- a/drivers/staging/hv/netvsc.c +++ /dev/null @@ -1,1356 +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 <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> -#include "osd.h" -#include "logging.h" -#include "netvsc.h" -#include "rndis_filter.h" -#include "channel.h" - - -/* Globals */ -static const char *driver_name = "netvsc"; - -/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ -static const struct hv_guid netvsc_device_type = { - .data = { - 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, - 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E - } -}; - -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) -{ - struct netvsc_device *net_device; - - net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL); - if (!net_device) - return NULL; - - /* Set to 2 to allow both inbound and outbound traffic */ - atomic_cmpxchg(&net_device->refcnt, 0, 2); - - net_device->dev = device; - device->Extension = net_device; - - return net_device; -} - -static void free_net_device(struct netvsc_device *device) -{ - WARN_ON(atomic_read(&device->refcnt) == 0); - device->dev->Extension = NULL; - kfree(device); -} - - -/* Get the net device object iff exists and its refcount > 1 */ -static struct netvsc_device *get_outbound_net_device(struct hv_device *device) -{ - struct netvsc_device *net_device; - - net_device = device->Extension; - if (net_device && atomic_read(&net_device->refcnt) > 1) - atomic_inc(&net_device->refcnt); - else - net_device = NULL; - - return net_device; -} - -/* Get the net device object iff exists and its refcount > 0 */ -static struct netvsc_device *get_inbound_net_device(struct hv_device *device) -{ - struct netvsc_device *net_device; - - net_device = device->Extension; - if (net_device && atomic_read(&net_device->refcnt)) - atomic_inc(&net_device->refcnt); - else - net_device = NULL; - - return net_device; -} - -static void put_net_device(struct hv_device *device) -{ - struct netvsc_device *net_device; - - net_device = device->Extension; - /* ASSERT(netDevice); */ - - atomic_dec(&net_device->refcnt); -} - -static struct netvsc_device *release_outbound_net_device( - struct hv_device *device) -{ - struct netvsc_device *net_device; - - net_device = device->Extension; - if (net_device == NULL) - return NULL; - - /* Busy wait until the ref drop to 2, then set it to 1 */ - while (atomic_cmpxchg(&net_device->refcnt, 2, 1) != 2) - udelay(100); - - return net_device; -} - -static struct netvsc_device *release_inbound_net_device( - struct hv_device *device) -{ - struct netvsc_device *net_device; - - net_device = device->Extension; - if (net_device == NULL) - return NULL; - - /* Busy wait until the ref drop to 1, then set it to 0 */ - while (atomic_cmpxchg(&net_device->refcnt, 1, 0) != 1) - udelay(100); - - device->Extension = NULL; - return net_device; -} - -/* - * netvsc_initialize - Main entry point - */ -int netvsc_initialize(struct hv_driver *drv) -{ - struct netvsc_driver *driver = (struct netvsc_driver *)drv; - - 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)); - - /* Make sure we are at least 2 pages since 1 page is used for control */ - /* ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); */ - - drv->name = driver_name; - memcpy(&drv->deviceType, &netvsc_device_type, sizeof(struct hv_guid)); - - /* Make sure it is set by the caller */ - /* FIXME: These probably should still be tested in some way */ - /* ASSERT(driver->OnReceiveCallback); */ - /* ASSERT(driver->OnLinkStatusChanged); */ - - /* Setup the dispatch table */ - driver->base.OnDeviceAdd = netvsc_device_add; - driver->base.OnDeviceRemove = netvsc_device_remove; - driver->base.OnCleanup = netvsc_cleanup; - - driver->send = netvsc_send; - - rndis_filter_init(driver); - return 0; -} - -static int netvsc_init_recv_buf(struct hv_device *device) -{ - int ret = 0; - 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..." - "device being destroyed?"); - return -1; - } - /* ASSERT(netDevice->ReceiveBufferSize > 0); */ - /* page-size grandularity */ - /* ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE - 1)) == 0); */ - - net_device->recv_buf = - osd_page_alloc(net_device->recv_buf_size >> PAGE_SHIFT); - if (!net_device->recv_buf) { - DPRINT_ERR(NETVSC, - "unable to allocate receive buffer of size %d", - net_device->recv_buf_size); - ret = -1; - goto Cleanup; - } - /* page-aligned buffer */ - /* ASSERT(((unsigned long)netDevice->ReceiveBuffer & (PAGE_SIZE - 1)) == */ - /* 0); */ - - 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 - * than the channel to establish the gpadl handle. - */ - ret = vmbus_establish_gpadl(device->channel, net_device->recv_buf, - net_device->recv_buf_size, - &net_device->recv_buf_gpadl_handle); - if (ret != 0) { - DPRINT_ERR(NETVSC, - "unable to establish receive buffer's gpadl"); - goto Cleanup; - } - - /* osd_waitevent_wait(ext->ChannelInitEvent); */ - - /* 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)); - - init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF; - init_packet->msg.v1_msg.send_recv_buf. - gpadl_handle = net_device->recv_buf_gpadl_handle; - init_packet->msg.v1_msg. - send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; - - /* Send the gpadl notification request */ - ret = vmbus_sendpacket(device->channel, init_packet, - sizeof(struct nvsp_message), - (unsigned long)init_packet, - VmbusPacketTypeDataInBand, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) { - DPRINT_ERR(NETVSC, - "unable to send receive buffer's gpadl to netvsp"); - goto Cleanup; - } - - osd_waitevent_wait(net_device->channel_init_event); - - /* 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 " - "initialzation with NetVsp - status %d", - init_packet->msg.v1_msg. - send_recv_buf_complete.status); - ret = -1; - goto Cleanup; - } - - /* Parse the response */ - /* ASSERT(netDevice->ReceiveSectionCount == 0); */ - /* ASSERT(netDevice->ReceiveSections == NULL); */ - - net_device->recv_section_cnt = init_packet->msg. - v1_msg.send_recv_buf_complete.num_sections; - - net_device->recv_section = kmalloc(net_device->recv_section_cnt - * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL); - if (net_device->recv_section == NULL) { - ret = -1; - goto Cleanup; - } - - memcpy(net_device->recv_section, - init_packet->msg.v1_msg. - send_recv_buf_complete.sections, - net_device->recv_section_cnt * - sizeof(struct nvsp_1_receive_buffer_section)); - - 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 - */ - if (net_device->recv_section_cnt != 1 || - net_device->recv_section->offset != 0) { - ret = -1; - goto Cleanup; - } - - goto Exit; - -Cleanup: - netvsc_destroy_recv_buf(net_device); - -Exit: - put_net_device(device); - return ret; -} - -static int netvsc_init_send_buf(struct hv_device *device) -{ - int ret = 0; - 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..." - "device being destroyed?"); - return -1; - } - if (net_device->send_buf_size <= 0) { - ret = -EINVAL; - goto Cleanup; - } - - /* page-size grandularity */ - /* ASSERT((netDevice->SendBufferSize & (PAGE_SIZE - 1)) == 0); */ - - net_device->send_buf = - osd_page_alloc(net_device->send_buf_size >> PAGE_SHIFT); - if (!net_device->send_buf) { - DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d", - net_device->send_buf_size); - ret = -1; - goto Cleanup; - } - /* page-aligned buffer */ - /* ASSERT(((unsigned long)netDevice->SendBuffer & (PAGE_SIZE - 1)) == 0); */ - - 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 - * than the channel to establish the gpadl handle. - */ - ret = vmbus_establish_gpadl(device->channel, net_device->send_buf, - net_device->send_buf_size, - &net_device->send_buf_gpadl_handle); - if (ret != 0) { - DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl"); - goto Cleanup; - } - - /* osd_waitevent_wait(ext->ChannelInitEvent); */ - - /* 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)); - - init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; - init_packet->msg.v1_msg.send_recv_buf. - gpadl_handle = net_device->send_buf_gpadl_handle; - init_packet->msg.v1_msg.send_recv_buf.id = - NETVSC_SEND_BUFFER_ID; - - /* Send the gpadl notification request */ - ret = vmbus_sendpacket(device->channel, init_packet, - sizeof(struct nvsp_message), - (unsigned long)init_packet, - VmbusPacketTypeDataInBand, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) { - DPRINT_ERR(NETVSC, - "unable to send receive buffer's gpadl to netvsp"); - goto Cleanup; - } - - osd_waitevent_wait(net_device->channel_init_event); - - /* 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 " - "initialzation with NetVsp - status %d", - init_packet->msg.v1_msg. - send_send_buf_complete.status); - ret = -1; - goto Cleanup; - } - - net_device->send_section_size = init_packet-> - msg.v1_msg.send_send_buf_complete.section_size; - - goto Exit; - -Cleanup: - netvsc_destroy_send_buf(net_device); - -Exit: - put_net_device(device); - 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, - VmbusPacketTypeDataInBand, 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 */ - osd_page_free(net_device->recv_buf, - net_device->recv_buf_size >> PAGE_SHIFT); - 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, - VmbusPacketTypeDataInBand, 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 */ - osd_page_free(net_device->send_buf, - net_device->send_buf_size >> PAGE_SHIFT); - net_device->send_buf = NULL; - } - - return ret; -} - - -static int netvsc_connect_vsp(struct hv_device *device) -{ - int ret; - struct netvsc_device *net_device; - struct nvsp_message *init_packet; - int ndis_version; - - net_device = get_outbound_net_device(device); - if (!net_device) { - DPRINT_ERR(NETVSC, "unable to get net device..." - "device being destroyed?"); - return -1; - } - - init_packet = &net_device->channel_init_pkt; - - memset(init_packet, 0, sizeof(struct nvsp_message)); - init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; - init_packet->msg.init_msg.init.min_protocol_ver = - NVSP_MIN_PROTOCOL_VERSION; - init_packet->msg.init_msg.init.max_protocol_ver = - NVSP_MAX_PROTOCOL_VERSION; - - DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit..."); - - /* Send the init request */ - ret = vmbus_sendpacket(device->channel, init_packet, - sizeof(struct nvsp_message), - (unsigned long)init_packet, - VmbusPacketTypeDataInBand, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - if (ret != 0) { - DPRINT_ERR(NETVSC, "unable to send NvspMessageTypeInit"); - goto Cleanup; - } - - osd_waitevent_wait(net_device->channel_init_event); - - /* Now, check the response */ - /* ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT); */ - 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)); - - ndis_version = 0x00050000; - - init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER; - init_packet->msg.v1_msg. - send_ndis_ver.ndis_major_ver = - (ndis_version & 0xFFFF0000) >> 16; - init_packet->msg.v1_msg. - send_ndis_ver.ndis_minor_ver = - ndis_version & 0xFFFF; - - /* Send the init request */ - ret = vmbus_sendpacket(device->channel, init_packet, - sizeof(struct nvsp_message), - (unsigned long)init_packet, - VmbusPacketTypeDataInBand, 0); - if (ret != 0) { - DPRINT_ERR(NETVSC, - "unable to send NvspMessage1TypeSendNdisVersion"); - ret = -1; - goto Cleanup; - } - /* - * BUGBUG - We have to wait for the above msg since the - * netvsp uses KMCL which acknowledges packet (completion - * packet) since our Vmbus always set the - * VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag - */ - /* osd_waitevent_wait(NetVscChannel->ChannelInitEvent); */ - - /* Post the big receive buffer to NetVSP */ - ret = netvsc_init_recv_buf(device); - if (ret == 0) - ret = netvsc_init_send_buf(device); - -Cleanup: - put_net_device(device); - return ret; -} - -static void NetVscDisconnectFromVsp(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->Driver; - - 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); - } - net_device->channel_init_event = osd_waitevent_create(); - if (!net_device->channel_init_event) { - ret = -ENOMEM; - goto Cleanup; - } - - /* 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) { - kfree(net_device->channel_init_event); - - 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) -{ - struct netvsc_device *net_device; - struct hv_netvsc_packet *netvsc_packet, *pos; - - DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...", - device->Extension); - - /* 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!!"); - 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)); - udelay(100); - } - - DPRINT_INFO(NETVSC, "Disconnecting from netvsp..."); - - NetVscDisconnectFromVsp(net_device); - - DPRINT_INFO(NETVSC, "Disabling inbound traffic on net device (%p)...", - device->Extension); - - /* 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); - - /* Now, we can close the channel safely */ - vmbus_close(device->channel); - - /* Release all resources */ - list_for_each_entry_safe(netvsc_packet, pos, - &net_device->recv_pkt_list, list_ent) { - list_del(&netvsc_packet->list_ent); - kfree(netvsc_packet); - } - - kfree(net_device->channel_init_event); - free_net_device(net_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) -{ - struct netvsc_device *net_device; - struct nvsp_message *nvsp_packet; - struct hv_netvsc_packet *nvsc_packet; - - net_device = get_inbound_net_device(device); - if (!net_device) { - DPRINT_ERR(NETVSC, "unable to get net device..." - "device being destroyed?"); - return; - } - - nvsp_packet = (struct nvsp_message *)((unsigned long)packet + - (packet->DataOffset8 << 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) || - (nvsp_packet->hdr.msg_type == - NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE)) { - /* Copy the response back */ - memcpy(&net_device->channel_init_pkt, nvsp_packet, - sizeof(struct nvsp_message)); - osd_waitevent_set(net_device->channel_init_event); - } else if (nvsp_packet->hdr.msg_type == - NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) { - /* Get the send context */ - nvsc_packet = (struct hv_netvsc_packet *)(unsigned long) - packet->TransactionId; - /* ASSERT(nvscPacket); */ - - /* Notify the layer above us */ - nvsc_packet->completion.send.send_completion( - nvsc_packet->completion.send.send_completion_ctx); - - atomic_dec(&net_device->num_outstanding_sends); - } else { - DPRINT_ERR(NETVSC, "Unknown send completion packet type - " - "%d received!!", nvsp_packet->hdr.msg_type); - } - - put_net_device(device); -} - -static int netvsc_send(struct hv_device *device, - struct hv_netvsc_packet *packet) -{ - struct netvsc_device *net_device; - int ret = 0; - - struct nvsp_message sendMessage; - - net_device = get_outbound_net_device(device); - if (!net_device) { - DPRINT_ERR(NETVSC, "net device (%p) shutting down..." - "ignoring outbound packets", net_device); - return -2; - } - - sendMessage.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT; - if (packet->is_data_pkt) { - /* 0 is RMC_DATA; */ - sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 0; - } else { - /* 1 is RMC_CONTROL; */ - sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 1; - } - - /* Not using send buffer section */ - sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_index = - 0xFFFFFFFF; - sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0; - - if (packet->page_buf_cnt) { - ret = vmbus_sendpacket_pagebuffer(device->channel, - packet->page_buf, - packet->page_buf_cnt, - &sendMessage, - sizeof(struct nvsp_message), - (unsigned long)packet); - } else { - ret = vmbus_sendpacket(device->channel, &sendMessage, - sizeof(struct nvsp_message), - (unsigned long)packet, - VmbusPacketTypeDataInBand, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - } - - if (ret != 0) - DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d", - packet, ret); - - atomic_inc(&net_device->num_outstanding_sends); - put_net_device(device); - return ret; -} - -static void netvsc_receive(struct hv_device *device, - struct vmpacket_descriptor *packet) -{ - struct netvsc_device *net_device; - struct vmtransfer_page_packet_header *vmxferpage_packet; - struct nvsp_message *nvsp_packet; - struct hv_netvsc_packet *netvsc_packet = NULL; - unsigned long start; - unsigned long end, end_virtual; - /* struct netvsc_driver *netvscDriver; */ - struct xferpage_packet *xferpage_packet = NULL; - int i, j; - int count = 0, bytes_remain = 0; - unsigned long flags; - LIST_HEAD(listHead); - - net_device = get_inbound_net_device(device); - if (!net_device) { - DPRINT_ERR(NETVSC, "unable to get net device..." - "device being destroyed?"); - return; - } - - /* - * All inbound packets other than send completion should be xfer page - * packet - */ - if (packet->Type != VmbusPacketTypeDataUsingTransferPages) { - DPRINT_ERR(NETVSC, "Unknown packet type received - %d", - packet->Type); - put_net_device(device); - return; - } - - nvsp_packet = (struct nvsp_message *)((unsigned long)packet + - (packet->DataOffset8 << 3)); - - /* 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); - 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->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID) { - DPRINT_ERR(NETVSC, "Invalid xfer page set id - " - "expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID, - vmxferpage_packet->TransferPageSetId); - put_net_device(device); - return; - } - - DPRINT_DBG(NETVSC, "xfer page - range count %d", - vmxferpage_packet->RangeCount); - - /* - * Grab free packets (range count + 1) to represent this xfer - * page packet. +1 to represent the xfer page packet itself. - * We grab it here so that we know exactly how many we can - * fulfil - */ - spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); - while (!list_empty(&net_device->recv_pkt_list)) { - list_move_tail(net_device->recv_pkt_list.next, &listHead); - if (++count == vmxferpage_packet->RangeCount + 1) - break; - } - spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags); - - /* - * We need at least 2 netvsc pkts (1 to represent the xfer - * page and at least 1 for the range) i.e. we can handled - * 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->RangeCount + 1); - - /* Return it to the freelist */ - spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); - for (i = count; i != 0; i--) { - list_move_tail(listHead.next, - &net_device->recv_pkt_list); - } - spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, - flags); - - netvsc_send_recv_completion(device, - vmxferpage_packet->d.TransactionId); - - put_net_device(device); - return; - } - - /* Remove the 1st packet to represent the xfer page packet itself */ - xferpage_packet = (struct xferpage_packet *)listHead.next; - list_del(&xferpage_packet->list_ent); - - /* This is how much we can satisfy */ - xferpage_packet->count = count - 1; - /* ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= */ - /* vmxferpagePacket->RangeCount); */ - - if (xferpage_packet->count != vmxferpage_packet->RangeCount) { - DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer " - "page...got %d", vmxferpage_packet->RangeCount, - xferpage_packet->count); - } - - /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */ - for (i = 0; i < (count - 1); i++) { - netvsc_packet = (struct hv_netvsc_packet *)listHead.next; - list_del(&netvsc_packet->list_ent); - - /* Initialize the netvsc packet */ - netvsc_packet->xfer_page_pkt = xferpage_packet; - netvsc_packet->completion.recv.recv_completion = - netvsc_receive_completion; - netvsc_packet->completion.recv.recv_completion_ctx = - netvsc_packet; - netvsc_packet->device = device; - /* Save this so that we can send it back */ - netvsc_packet->completion.recv.recv_completion_tid = - vmxferpage_packet->d.TransactionId; - - netvsc_packet->total_data_buflen = - vmxferpage_packet->Ranges[i].ByteCount; - netvsc_packet->page_buf_cnt = 1; - - /* ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + */ - /* vmxferpagePacket->Ranges[i].ByteCount < */ - /* netDevice->ReceiveBufferSize); */ - - netvsc_packet->page_buf[0].Length = - vmxferpage_packet->Ranges[i].ByteCount; - - start = virt_to_phys((void *)((unsigned long)net_device-> - recv_buf + vmxferpage_packet->Ranges[i].ByteOffset)); - - netvsc_packet->page_buf[0].Pfn = start >> PAGE_SHIFT; - end_virtual = (unsigned long)net_device->recv_buf - + vmxferpage_packet->Ranges[i].ByteOffset - + vmxferpage_packet->Ranges[i].ByteCount - 1; - end = virt_to_phys((void *)end_virtual); - - /* Calculate the page relative offset */ - netvsc_packet->page_buf[0].Offset = - vmxferpage_packet->Ranges[i].ByteOffset & - (PAGE_SIZE - 1); - if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) { - /* Handle frame across multiple pages: */ - netvsc_packet->page_buf[0].Length = - (netvsc_packet->page_buf[0].Pfn << - PAGE_SHIFT) - + PAGE_SIZE - start; - bytes_remain = netvsc_packet->total_data_buflen - - netvsc_packet->page_buf[0].Length; - for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) { - netvsc_packet->page_buf[j].Offset = 0; - if (bytes_remain <= PAGE_SIZE) { - netvsc_packet->page_buf[j].Length = - bytes_remain; - bytes_remain = 0; - } else { - netvsc_packet->page_buf[j].Length = - PAGE_SIZE; - bytes_remain -= PAGE_SIZE; - } - netvsc_packet->page_buf[j].Pfn = - virt_to_phys((void *)(end_virtual - - bytes_remain)) >> PAGE_SHIFT; - netvsc_packet->page_buf_cnt++; - if (bytes_remain == 0) - break; - } - /* ASSERT(bytesRemain == 0); */ - } - DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => " - "(pfn %llx, offset %u, len %u)", i, - vmxferpage_packet->Ranges[i].ByteOffset, - vmxferpage_packet->Ranges[i].ByteCount, - netvsc_packet->page_buf[0].Pfn, - netvsc_packet->page_buf[0].Offset, - netvsc_packet->page_buf[0].Length); - - /* Pass it to the upper layer */ - ((struct netvsc_driver *)device->Driver)-> - recv_cb(device, netvsc_packet); - - netvsc_receive_completion(netvsc_packet-> - completion.recv.recv_completion_ctx); - } - - /* ASSERT(list_empty(&listHead)); */ - - 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, - VmbusPacketTypeCompletion, 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; - - /* ASSERT(packet->XferPagePacket); */ - - /* - * 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); - - /* ASSERT(packet->XferPagePacket->Count > 0); */ - 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; - struct hv_device *device = context; - struct netvsc_device *net_device; - u32 bytes_recvd; - u64 request_id; - unsigned char *packet; - struct vmpacket_descriptor *desc; - unsigned char *buffer; - int bufferlen = NETVSC_PACKET_SIZE; - - /* ASSERT(device); */ - - packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char), - GFP_ATOMIC); - if (!packet) - return; - buffer = packet; - - net_device = get_inbound_net_device(device); - if (!net_device) { - DPRINT_ERR(NETVSC, "net device (%p) shutting down..." - "ignoring inbound packets", net_device); - goto out; - } - - do { - ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, - &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 VmbusPacketTypeCompletion: - netvsc_send_completion(device, desc); - break; - - case VmbusPacketTypeDataUsingTransferPages: - netvsc_receive(device, desc); - break; - - default: - DPRINT_ERR(NETVSC, - "unhandled packet type %d, " - "tid %llx len %d\n", - desc->Type, request_id, - bytes_recvd); - break; - } - - /* reset */ - if (bufferlen > NETVSC_PACKET_SIZE) { - kfree(buffer); - buffer = packet; - bufferlen = NETVSC_PACKET_SIZE; - } - } else { - /* reset */ - if (bufferlen > NETVSC_PACKET_SIZE) { - kfree(buffer); - buffer = packet; - bufferlen = NETVSC_PACKET_SIZE; - } - - break; - } - } else if (ret == -2) { - /* Handle large packet */ - buffer = kmalloc(bytes_recvd, GFP_ATOMIC); - if (buffer == NULL) { - /* Try again next time around */ - DPRINT_ERR(NETVSC, - "unable to allocate buffer of size " - "(%d)!!", bytes_recvd); - break; - } - - bufferlen = bytes_recvd; - } - } while (1); - - put_net_device(device); -out: - kfree(buffer); - return; -} diff --git a/drivers/staging/hv/netvsc.h b/drivers/staging/hv/netvsc.h deleted file mode 100644 index 932a77ccdc0..00000000000 --- a/drivers/staging/hv/netvsc.h +++ /dev/null @@ -1,331 +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; -} __attribute__((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; -} __attribute__((packed)); - -union nvsp_message_init_uber { - struct nvsp_message_init init; - struct nvsp_message_init_complete init_complete; -} __attribute__((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; -} __attribute__((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; -} __attribute__((packed)); - -struct nvsp_1_receive_buffer_section { - u32 offset; - u32 sub_alloc_size; - u32 num_sub_allocs; - u32 end_offset; -} __attribute__((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]; -} __attribute__((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; -} __attribute__((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; -} __attribute__((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; -} __attribute__((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; -} __attribute__((packed)); - -union nvsp_all_messages { - union nvsp_message_init_uber init_msg; - union nvsp_1_message_uber v1_msg; -} __attribute__((packed)); - -/* ALL Messages */ -struct nvsp_message { - struct nvsp_message_header hdr; - union nvsp_all_messages msg; -} __attribute__((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 osd_waitevent *channel_init_event; - 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 b4bed363659..00000000000 --- 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 deleted file mode 100644 index b41c9640b72..00000000000 --- a/drivers/staging/hv/netvsc_drv.c +++ /dev/null @@ -1,562 +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/init.h> -#include <linux/module.h> -#include <linux/highmem.h> -#include <linux/device.h> -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/inetdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/in.h> -#include <linux/slab.h> -#include <linux/dmi.h> -#include <linux/pci.h> -#include <net/arp.h> -#include <net/route.h> -#include <net/sock.h> -#include <net/pkt_sched.h> -#include "osd.h" -#include "logging.h" -#include "version_info.h" -#include "vmbus.h" -#include "netvsc_api.h" - -struct net_device_context { - /* point back to our device context */ - struct vm_device *device_ctx; - unsigned long avail; -}; - -struct netvsc_driver_context { - /* !! These must be the first 2 fields !! */ - /* Which is a bug FIXME! */ - struct driver_context drv_ctx; - struct netvsc_driver drv_obj; -}; - -#define PACKET_PAGES_LOWATER 8 -/* Need this many pages to handle worst case fragmented packet */ -#define PACKET_PAGES_HIWATER (MAX_SKB_FRAGS + 2) - -static int ring_size = 128; -module_param(ring_size, int, S_IRUGO); -MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)"); - -/* The one and only one */ -static struct netvsc_driver_context 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() */ -static void netvsc_set_multicast_list(struct net_device *net) -{ -} - -static int netvsc_open(struct net_device *net) -{ - struct net_device_context *net_device_ctx = netdev_priv(net); - struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj; - int ret = 0; - - if (netif_carrier_ok(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); - return ret; - } - - netif_start_queue(net); - } else { - DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down."); - } - - return ret; -} - -static int netvsc_close(struct net_device *net) -{ - struct net_device_context *net_device_ctx = netdev_priv(net); - struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj; - int ret; - - netif_stop_queue(net); - - ret = rndis_filter_close(device_obj); - if (ret != 0) - DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret); - - return ret; -} - -static void netvsc_xmit_completion(void *context) -{ - struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; - struct sk_buff *skb = (struct sk_buff *) - (unsigned long)packet->completion.send.send_completion_tid; - - kfree(packet); - - if (skb) { - struct net_device *net = skb->dev; - struct net_device_context *net_device_ctx = netdev_priv(net); - unsigned int num_pages = skb_shinfo(skb)->nr_frags + 2; - - dev_kfree_skb_any(skb); - - if ((net_device_ctx->avail += num_pages) >= PACKET_PAGES_HIWATER) - netif_wake_queue(net); - } -} - -static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) -{ - struct net_device_context *net_device_ctx = netdev_priv(net); - struct driver_context *driver_ctx = - driver_to_driver_context(net_device_ctx->device_ctx->device.driver); - struct netvsc_driver_context *net_drv_ctx = - (struct netvsc_driver_context *)driver_ctx; - struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj; - 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) - return NETDEV_TX_BUSY; - - /* 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); - if (!packet) { - /* out of memory, silently drop packet */ - DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet"); - - dev_kfree_skb(skb); - net->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - packet->extension = (void *)(unsigned long)packet + - sizeof(struct hv_netvsc_packet) + - (num_pages * sizeof(struct hv_page_buffer)); - - /* Setup the rndis header */ - packet->page_buf_cnt = num_pages; - - /* TODO: Flush all write buffers/ memory fence ??? */ - /* wmb(); */ - - /* Initialize it from the skb */ - packet->total_data_buflen = skb->len; - - /* Start filling in the page buffers starting after RNDIS buffer. */ - packet->page_buf[1].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; - packet->page_buf[1].Offset - = (unsigned long)skb->data & (PAGE_SIZE - 1); - packet->page_buf[1].Length = skb_headlen(skb); - - /* Additional fragments are after SKB data */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - - packet->page_buf[i+2].Pfn = page_to_pfn(f->page); - packet->page_buf[i+2].Offset = f->page_offset; - packet->page_buf[i+2].Length = f->size; - } - - /* Set the completion routine */ - packet->completion.send.send_completion = netvsc_xmit_completion; - 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->device_obj, - 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); - - if ((net_device_ctx->avail -= num_pages) < PACKET_PAGES_LOWATER) - netif_stop_queue(net); - } else { - /* we are shutting down or bus overloaded, just drop packet */ - net->stats.tx_dropped++; - netvsc_xmit_completion(packet); - } - - return NETDEV_TX_OK; -} - -/* - * netvsc_linkstatus_callback - Link up/down notification - */ -static void netvsc_linkstatus_callback(struct hv_device *device_obj, - unsigned int status) -{ - struct vm_device *device_ctx = to_vm_device(device_obj); - struct net_device *net = dev_get_drvdata(&device_ctx->device); - - if (!net) { - DPRINT_ERR(NETVSC_DRV, "got link status but net device " - "not initialized yet"); - return; - } - - if (status == 1) { - netif_carrier_on(net); - netif_wake_queue(net); - netif_notify_peers(net); - } else { - netif_carrier_off(net); - netif_stop_queue(net); - } -} - -/* - * 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, - struct hv_netvsc_packet *packet) -{ - struct vm_device *device_ctx = to_vm_device(device_obj); - struct net_device *net = dev_get_drvdata(&device_ctx->device); - struct sk_buff *skb; - void *data; - int i; - unsigned long flags; - - if (!net) { - DPRINT_ERR(NETVSC_DRV, "got receive callback but net device " - "not initialized yet"); - return 0; - } - - /* Allocate a skb - TODO direct I/O to pages? */ - skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen); - if (unlikely(!skb)) { - ++net->stats.rx_dropped; - return 0; - } - - /* for kmap_atomic */ - local_irq_save(flags); - - /* - * Copy to skb. This copy is needed here since the memory pointed by - * hv_netvsc_packet cannot be deallocated - */ - for (i = 0; i < packet->page_buf_cnt; i++) { - data = kmap_atomic(pfn_to_page(packet->page_buf[i].Pfn), - KM_IRQ1); - data = (void *)(unsigned long)data + - packet->page_buf[i].Offset; - - memcpy(skb_put(skb, packet->page_buf[i].Length), data, - packet->page_buf[i].Length); - - kunmap_atomic((void *)((unsigned long)data - - packet->page_buf[i].Offset), KM_IRQ1); - } - - local_irq_restore(flags); - - skb->protocol = eth_type_trans(skb, net); - skb->ip_summed = CHECKSUM_NONE; - - net->stats.rx_packets++; - net->stats.rx_bytes += skb->len; - - /* - * Pass the skb back up. Network stack will deallocate the skb when it - * is done. - * TODO - use NAPI? - */ - netif_rx(skb); - - DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu", - net->stats.rx_packets, net->stats.rx_bytes); - - return 0; -} - -static void netvsc_get_drvinfo(struct net_device *net, - struct ethtool_drvinfo *info) -{ - strcpy(info->driver, "hv_netvsc"); - strcpy(info->version, HV_DRV_VERSION); - strcpy(info->fw_version, "N/A"); -} - -static const struct ethtool_ops ethtool_ops = { - .get_drvinfo = netvsc_get_drvinfo, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_link = ethtool_op_get_link, -}; - -static const struct net_device_ops device_ops = { - .ndo_open = netvsc_open, - .ndo_stop = netvsc_close, - .ndo_start_xmit = netvsc_start_xmit, - .ndo_set_multicast_list = netvsc_set_multicast_list, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, -}; - -static int netvsc_probe(struct device *device) -{ - struct driver_context *driver_ctx = - driver_to_driver_context(device->driver); - struct netvsc_driver_context *net_drv_ctx = - (struct netvsc_driver_context *)driver_ctx; - struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj; - struct vm_device *device_ctx = device_to_vm_device(device); - struct hv_device *device_obj = &device_ctx->device_obj; - 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.OnDeviceAdd) - return -1; - - net = alloc_etherdev(sizeof(struct net_device_context)); - if (!net) - return -1; - - /* Set initial state */ - netif_carrier_off(net); - - net_device_ctx = netdev_priv(net); - net_device_ctx->device_ctx = device_ctx; - net_device_ctx->avail = ring_size; - dev_set_drvdata(device, net); - - /* Notify the netvsc driver of the new device */ - ret = net_drv_obj->base.OnDeviceAdd(device_obj, &device_info); - if (ret != 0) { - free_netdev(net); - dev_set_drvdata(device, NULL); - - DPRINT_ERR(NETVSC_DRV, "unable to add netvsc device (ret %d)", - ret); - return ret; - } - - /* - * If carrier is still off ie we did not get a link status callback, - * update it if necessary - */ - /* - * FIXME: We should use a atomic or test/set instead to avoid getting - * out of sync with the device's link status - */ - if (!netif_carrier_ok(net)) - if (!device_info.link_state) - netif_carrier_on(net); - - memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); - - net->netdev_ops = &device_ops; - - /* TODO: Add GSO and Checksum offload */ - net->features = NETIF_F_SG; - - SET_ETHTOOL_OPS(net, ðtool_ops); - SET_NETDEV_DEV(net, device); - - ret = register_netdev(net); - if (ret != 0) { - /* Remove the device and release the resource */ - net_drv_obj->base.OnDeviceRemove(device_obj); - free_netdev(net); - } - - return ret; -} - -static int netvsc_remove(struct device *device) -{ - struct driver_context *driver_ctx = - driver_to_driver_context(device->driver); - struct netvsc_driver_context *net_drv_ctx = - (struct netvsc_driver_context *)driver_ctx; - struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj; - struct vm_device *device_ctx = device_to_vm_device(device); - struct net_device *net = dev_get_drvdata(&device_ctx->device); - struct hv_device *device_obj = &device_ctx->device_obj; - int ret; - - if (net == NULL) { - DPRINT_INFO(NETVSC, "no net device to remove"); - return 0; - } - - if (!net_drv_obj->base.OnDeviceRemove) - return -1; - - /* Stop outbound asap */ - netif_stop_queue(net); - /* netif_carrier_off(net); */ - - unregister_netdev(net); - - /* - * Call to the vsc driver to let it know that the device is being - * removed - */ - ret = net_drv_obj->base.OnDeviceRemove(device_obj); - if (ret != 0) { - /* TODO: */ - DPRINT_ERR(NETVSC, "unable to remove vsc device (ret %d)", 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; -} - -static void netvsc_drv_exit(void) -{ - struct netvsc_driver *netvsc_drv_obj = &g_netvsc_drv.drv_obj; - struct driver_context *drv_ctx = &g_netvsc_drv.drv_ctx; - struct device *current_dev; - int ret; - - while (1) { - current_dev = NULL; - - /* Get the device */ - ret = driver_for_each_device(&drv_ctx->driver, NULL, - ¤t_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.OnCleanup) - netvsc_drv_obj->base.OnCleanup(&netvsc_drv_obj->base); - - vmbus_child_driver_unregister(drv_ctx); - - return; -} - -static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv)) -{ - struct netvsc_driver *net_drv_obj = &g_netvsc_drv.drv_obj; - struct driver_context *drv_ctx = &g_netvsc_drv.drv_ctx; - 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; - - /* Callback to client driver to complete the initialization */ - drv_init(&net_drv_obj->base); - - drv_ctx->driver.name = net_drv_obj->base.name; - memcpy(&drv_ctx->class_id, &net_drv_obj->base.deviceType, - sizeof(struct hv_guid)); - - drv_ctx->probe = netvsc_probe; - drv_ctx->remove = netvsc_remove; - - /* The driver belongs to vmbus */ - ret = vmbus_child_driver_register(drv_ctx); - - return ret; -} - -static const struct dmi_system_id __initconst -hv_netvsc_dmi_table[] __maybe_unused = { - { - .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, hv_netvsc_dmi_table); - -static int __init netvsc_init(void) -{ - DPRINT_INFO(NETVSC_DRV, "Netvsc 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(); -} - -static const struct pci_device_id __initconst -hv_netvsc_pci_table[] __maybe_unused = { - { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */ - { 0 } -}; -MODULE_DEVICE_TABLE(pci, hv_netvsc_pci_table); - -MODULE_LICENSE("GPL"); -MODULE_VERSION(HV_DRV_VERSION); -MODULE_DESCRIPTION("Microsoft Hyper-V network driver"); - -module_init(netvsc_init); -module_exit(netvsc_exit); diff --git a/drivers/staging/hv/osd.c b/drivers/staging/hv/osd.c deleted file mode 100644 index b5a3940331b..00000000000 --- a/drivers/staging/hv/osd.c +++ /dev/null @@ -1,194 +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/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/highmem.h> -#include <linux/vmalloc.h> -#include <linux/ioport.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/spinlock.h> -#include <linux/workqueue.h> -#include <linux/kernel.h> -#include <linux/jiffies.h> -#include <linux/delay.h> -#include <linux/time.h> -#include <linux/io.h> -#include <linux/bitops.h> -#include <linux/slab.h> -#include "osd.h" - -void *osd_virtual_alloc_exec(unsigned int size) -{ -#ifdef __x86_64__ - return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC); -#else - return __vmalloc(size, GFP_KERNEL, - __pgprot(__PAGE_KERNEL & (~_PAGE_NX))); -#endif -} - -/** - * osd_page_alloc() - Allocate pages - * @count: Total number of Kernel pages you want to allocate - * - * Tries to allocate @count number of consecutive free kernel pages. - * And if successful, it will set the pages to 0 before returning. - * If successfull it will return pointer to the @count pages. - * Mainly used by Hyper-V drivers. - */ -void *osd_page_alloc(unsigned int count) -{ - void *p; - - p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE)); - if (p) - memset(p, 0, count * PAGE_SIZE); - return p; - - /* struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO); */ - /* void *p; */ - - /* BUGBUG: We need to use kmap in case we are in HIMEM region */ - /* p = page_address(page); */ - /* if (p) memset(p, 0, PAGE_SIZE); */ - /* return p; */ -} -EXPORT_SYMBOL_GPL(osd_page_alloc); - -/** - * osd_page_free() - Free pages - * @page: Pointer to the first page to be freed - * @count: Total number of Kernel pages you free - * - * Frees the pages allocated by osd_page_alloc() - * Mainly used by Hyper-V drivers. - */ -void osd_page_free(void *page, unsigned int count) -{ - free_pages((unsigned long)page, get_order(count * PAGE_SIZE)); - /*struct page* p = virt_to_page(page); - __free_page(p);*/ -} -EXPORT_SYMBOL_GPL(osd_page_free); - -/** - * osd_waitevent_create() - Create the event queue - * - * Allocates memory for a &struct osd_waitevent. And then calls - * init_waitqueue_head to set up the wait queue for the event. - * This structure is usually part of a another structure that contains - * the actual Hyper-V device driver structure. - * - * Returns pointer to &struct osd_waitevent - * Mainly used by Hyper-V drivers. - */ -struct osd_waitevent *osd_waitevent_create(void) -{ - struct osd_waitevent *wait = kmalloc(sizeof(struct osd_waitevent), - GFP_KERNEL); - if (!wait) - return NULL; - - wait->condition = 0; - init_waitqueue_head(&wait->event); - return wait; -} -EXPORT_SYMBOL_GPL(osd_waitevent_create); - - -/** - * osd_waitevent_set() - Wake up the process - * @wait_event: Structure to event to be woken up - * - * @wait_event is of type &struct osd_waitevent - * - * Wake up the sleeping process so it can do some work. - * And set condition indicator in &struct osd_waitevent to indicate - * the process is in a woken state. - * - * Only used by Network and Storage Hyper-V drivers. - */ -void osd_waitevent_set(struct osd_waitevent *wait_event) -{ - wait_event->condition = 1; - wake_up_interruptible(&wait_event->event); -} -EXPORT_SYMBOL_GPL(osd_waitevent_set); - -/** - * osd_waitevent_wait() - Wait for event till condition is true - * @wait_event: Structure to event to be put to sleep - * - * @wait_event is of type &struct osd_waitevent - * - * Set up the process to sleep until waitEvent->condition get true. - * And set condition indicator in &struct osd_waitevent to indicate - * the process is in a sleeping state. - * - * Returns the status of 'wait_event_interruptible()' system call - * - * Mainly used by Hyper-V drivers. - */ -int osd_waitevent_wait(struct osd_waitevent *wait_event) -{ - int ret = 0; - - ret = wait_event_interruptible(wait_event->event, - wait_event->condition); - wait_event->condition = 0; - return ret; -} -EXPORT_SYMBOL_GPL(osd_waitevent_wait); - -/** - * osd_waitevent_waitex() - Wait for event or timeout for process wakeup - * @wait_event: Structure to event to be put to sleep - * @timeout_in_ms: Total number of Milliseconds to wait before waking up - * - * @wait_event is of type &struct osd_waitevent - * Set up the process to sleep until @waitEvent->condition get true or - * @timeout_in_ms (Time out in Milliseconds) has been reached. - * And set condition indicator in &struct osd_waitevent to indicate - * the process is in a sleeping state. - * - * Returns the status of 'wait_event_interruptible_timeout()' system call - * - * Mainly used by Hyper-V drivers. - */ -int osd_waitevent_waitex(struct osd_waitevent *wait_event, u32 timeout_in_ms) -{ - int ret = 0; - - ret = wait_event_interruptible_timeout(wait_event->event, - wait_event->condition, - msecs_to_jiffies(timeout_in_ms)); - wait_event->condition = 0; - return ret; -} -EXPORT_SYMBOL_GPL(osd_waitevent_waitex); diff --git a/drivers/staging/hv/osd.h b/drivers/staging/hv/osd.h deleted file mode 100644 index 870ef076883..00000000000 --- a/drivers/staging/hv/osd.h +++ /dev/null @@ -1,66 +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 _OSD_H_ -#define _OSD_H_ - -#include <linux/workqueue.h> - -/* Defines */ -#define ALIGN_UP(value, align) (((value) & (align-1)) ? \ - (((value) + (align-1)) & ~(align-1)) : \ - (value)) -#define ALIGN_DOWN(value, align) ((value) & ~(align-1)) -#define NUM_PAGES_SPANNED(addr, len) ((ALIGN_UP(addr+len, PAGE_SIZE) - \ - ALIGN_DOWN(addr, PAGE_SIZE)) >> \ - PAGE_SHIFT) - -#define LOWORD(dw) ((unsigned short)(dw)) -#define HIWORD(dw) ((unsigned short)(((unsigned int) (dw) >> 16) & 0xFFFF)) - -struct hv_guid { - unsigned char data[16]; -}; - -struct osd_waitevent { - int condition; - wait_queue_head_t event; -}; - -/* Osd routines */ - -extern void *osd_virtual_alloc_exec(unsigned int size); - -extern void *osd_page_alloc(unsigned int count); -extern void osd_page_free(void *page, unsigned int count); - -extern struct osd_waitevent *osd_waitevent_create(void); -extern void osd_waitevent_set(struct osd_waitevent *wait_event); -extern int osd_waitevent_wait(struct osd_waitevent *wait_event); - -/* If >0, wait_event got signaled. If ==0, timeout. If < 0, error */ -extern int osd_waitevent_waitex(struct osd_waitevent *wait_event, - u32 timeout_in_ms); - -#endif /* _OSD_H_ */ diff --git a/drivers/staging/hv/ring_buffer.c b/drivers/staging/hv/ring_buffer.c deleted file mode 100644 index 4d53392f1e6..00000000000 --- a/drivers/staging/hv/ring_buffer.c +++ /dev/null @@ -1,629 +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 "osd.h" -#include "logging.h" -#include "ring_buffer.h" - - -/* #defines */ - - -/* Amount of space to write to */ -#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 - ---*/ -static inline void -get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi, - u32 *read, u32 *write) -{ - u32 read_loc, write_loc; - - /* Capture the read/write indices before they changed */ - read_loc = rbi->ring_buffer->read_index; - write_loc = rbi->ring_buffer->write_index; - - *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->ring_datasize); - *read = rbi->ring_datasize - *write; -} - -/*++ - -Name: - get_next_write_location() - -Description: - Get the next write location for the specified ring buffer - ---*/ -static inline u32 -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 - ---*/ -static inline void -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 - ---*/ -static inline u32 -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 - ---*/ -static inline u32 -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 - ---*/ -static inline void -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 - ---*/ -static inline void * -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 - ---*/ -static inline u32 -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 - ---*/ -static inline u64 -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) -{ - u32 bytes_avail_towrite; - u32 bytes_avail_toread; - - get_ringbuffer_availbytes(ring_info, - &bytes_avail_toread, - &bytes_avail_towrite); - - DPRINT(VMBUS, - DEBUG_RING_LVL, - "%s <<ringinfo %p buffer %p avail write %u " - "avail read %u read idx %u write idx %u>>", - prefix, - ring_info, - ring_info->ring_buffer->buffer, - bytes_avail_towrite, - bytes_avail_toread, - ring_info->ring_buffer->read_index, - ring_info->ring_buffer->write_index); -} - - -/* 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( - struct hv_ring_buffer_info *ring_info, - void *dest, - u32 destlen, - u32 start_read_offset); - - - -/*++ - -Name: - ringbuffer_get_debuginfo() - -Description: - Get various debug metrics for the specified ring buffer - ---*/ -void 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, - &bytes_avail_toread, - &bytes_avail_towrite); - - debug_info->bytes_avail_toread = bytes_avail_toread; - debug_info->bytes_avail_towrite = bytes_avail_towrite; - debug_info->current_read_index = - ring_info->ring_buffer->read_index; - debug_info->current_write_index = - ring_info->ring_buffer->write_index; - debug_info->current_interrupt_mask = - ring_info->ring_buffer->interrupt_mask; - } -} - - -/*++ - -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) -{ - return rbi->ring_buffer->interrupt_mask; -} - -/*++ - -Name: - ringbuffer_init() - -Description: - Initialize the ring buffer - ---*/ -int ringbuffer_init(struct hv_ring_buffer_info *ring_info, - void *buffer, u32 buflen) -{ - if (sizeof(struct hv_ring_buffer) != PAGE_SIZE) - return -EINVAL; - - memset(ring_info, 0, sizeof(struct hv_ring_buffer_info)); - - ring_info->ring_buffer = (struct hv_ring_buffer *)buffer; - ring_info->ring_buffer->read_index = - ring_info->ring_buffer->write_index = 0; - - ring_info->ring_size = buflen; - ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer); - - spin_lock_init(&ring_info->ring_lock); - - return 0; -} - -/*++ - -Name: - ringbuffer_cleanup() - -Description: - Cleanup the ring buffer - ---*/ -void 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, - struct scatterlist *sglist, u32 sgcount) -{ - int i = 0; - u32 bytes_avail_towrite; - u32 bytes_avail_toread; - u32 totalbytes_towrite = 0; - - struct scatterlist *sg; - volatile u32 next_write_location; - u64 prev_indices = 0; - unsigned long flags; - - for_each_sg(sglist, sg, sgcount, i) - { - totalbytes_towrite += sg->length; - } - - totalbytes_towrite += sizeof(u64); - - spin_lock_irqsave(&outring_info->ring_lock, flags); - - 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); - - for_each_sg(sglist, sg, sgcount, i) - { - next_write_location = copyto_ringbuffer(outring_info, - next_write_location, - sg_virt(sg), - sg->length); - } - - /* Set previous packet start */ - prev_indices = get_ring_bufferindices(outring_info); - - next_write_location = copyto_ringbuffer(outring_info, - next_write_location, - &prev_indices, - sizeof(u64)); - - /* Make sure we flush all writes before updating the writeIndex */ - mb(); - - /* Now, update the write location */ - 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, - void *Buffer, u32 buflen) -{ - u32 bytes_avail_towrite; - u32 bytes_avail_toread; - u32 next_read_location = 0; - unsigned long flags; - - spin_lock_irqsave(&Inring_info->ring_lock, flags); - - 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); - - return -1; - } - - /* Convert to byte offset */ - next_read_location = get_next_read_location(Inring_info); - - next_read_location = copyfrom_ringbuffer(Inring_info, - Buffer, - buflen, - next_read_location); - - spin_unlock_irqrestore(&Inring_info->ring_lock, flags); - - return 0; -} - - -/*++ - -Name: - ringbuffer_read() - -Description: - Read and advance the read index - ---*/ -int ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, - u32 buflen, u32 offset) -{ - u32 bytes_avail_towrite; - u32 bytes_avail_toread; - u32 next_read_location = 0; - u64 prev_indices = 0; - unsigned long flags; - - if (buflen <= 0) - return -EINVAL; - - spin_lock_irqsave(&inring_info->ring_lock, flags); - - 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); - - next_read_location = copyfrom_ringbuffer(inring_info, - buffer, - buflen, - next_read_location); - - next_read_location = copyfrom_ringbuffer(inring_info, - &prev_indices, - sizeof(u64), - next_read_location); - - /* Make sure all reads are done before we update the read index since */ - /* the writer may start writing to the read area once the read index */ - /*is updated */ - mb(); - - /* Update the read index */ - set_next_read_location(inring_info, next_read_location); - - /* Dumpring_info(Inring_info, "AFTER "); */ - - 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 7bd6ecf2f01..00000000000 --- 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]; -} __attribute__((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.h b/drivers/staging/hv/rndis.h deleted file mode 100644 index 014de047b86..00000000000 --- a/drivers/staging/hv/rndis.h +++ /dev/null @@ -1,653 +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 _RNDIS_H_ -#define _RNDIS_H_ - -/* Status codes */ - - -#ifndef STATUS_SUCCESS -#define STATUS_SUCCESS (0x00000000L) -#endif - -#ifndef STATUS_UNSUCCESSFUL -#define STATUS_UNSUCCESSFUL (0xC0000001L) -#endif - -#ifndef STATUS_PENDING -#define STATUS_PENDING (0x00000103L) -#endif - -#ifndef STATUS_INSUFFICIENT_RESOURCES -#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AL) -#endif - -#ifndef STATUS_BUFFER_OVERFLOW -#define STATUS_BUFFER_OVERFLOW (0x80000005L) -#endif - -#ifndef STATUS_NOT_SUPPORTED -#define STATUS_NOT_SUPPORTED (0xC00000BBL) -#endif - -#define RNDIS_STATUS_SUCCESS (STATUS_SUCCESS) -#define RNDIS_STATUS_PENDING (STATUS_PENDING) -#define RNDIS_STATUS_NOT_RECOGNIZED (0x00010001L) -#define RNDIS_STATUS_NOT_COPIED (0x00010002L) -#define RNDIS_STATUS_NOT_ACCEPTED (0x00010003L) -#define RNDIS_STATUS_CALL_ACTIVE (0x00010007L) - -#define RNDIS_STATUS_ONLINE (0x40010003L) -#define RNDIS_STATUS_RESET_START (0x40010004L) -#define RNDIS_STATUS_RESET_END (0x40010005L) -#define RNDIS_STATUS_RING_STATUS (0x40010006L) -#define RNDIS_STATUS_CLOSED (0x40010007L) -#define RNDIS_STATUS_WAN_LINE_UP (0x40010008L) -#define RNDIS_STATUS_WAN_LINE_DOWN (0x40010009L) -#define RNDIS_STATUS_WAN_FRAGMENT (0x4001000AL) -#define RNDIS_STATUS_MEDIA_CONNECT (0x4001000BL) -#define RNDIS_STATUS_MEDIA_DISCONNECT (0x4001000CL) -#define RNDIS_STATUS_HARDWARE_LINE_UP (0x4001000DL) -#define RNDIS_STATUS_HARDWARE_LINE_DOWN (0x4001000EL) -#define RNDIS_STATUS_INTERFACE_UP (0x4001000FL) -#define RNDIS_STATUS_INTERFACE_DOWN (0x40010010L) -#define RNDIS_STATUS_MEDIA_BUSY (0x40010011L) -#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION (0x40010012L) -#define RNDIS_STATUS_WW_INDICATION RDIA_SPECIFIC_INDICATION -#define RNDIS_STATUS_LINK_SPEED_CHANGE (0x40010013L) - -#define RNDIS_STATUS_NOT_RESETTABLE (0x80010001L) -#define RNDIS_STATUS_SOFT_ERRORS (0x80010003L) -#define RNDIS_STATUS_HARD_ERRORS (0x80010004L) -#define RNDIS_STATUS_BUFFER_OVERFLOW (STATUS_BUFFER_OVERFLOW) - -#define RNDIS_STATUS_FAILURE (STATUS_UNSUCCESSFUL) -#define RNDIS_STATUS_RESOURCES (STATUS_INSUFFICIENT_RESOURCES) -#define RNDIS_STATUS_CLOSING (0xC0010002L) -#define RNDIS_STATUS_BAD_VERSION (0xC0010004L) -#define RNDIS_STATUS_BAD_CHARACTERISTICS (0xC0010005L) -#define RNDIS_STATUS_ADAPTER_NOT_FOUND (0xC0010006L) -#define RNDIS_STATUS_OPEN_FAILED (0xC0010007L) -#define RNDIS_STATUS_DEVICE_FAILED (0xC0010008L) -#define RNDIS_STATUS_MULTICAST_FULL (0xC0010009L) -#define RNDIS_STATUS_MULTICAST_EXISTS (0xC001000AL) -#define RNDIS_STATUS_MULTICAST_NOT_FOUND (0xC001000BL) -#define RNDIS_STATUS_REQUEST_ABORTED (0xC001000CL) -#define RNDIS_STATUS_RESET_IN_PROGRESS (0xC001000DL) -#define RNDIS_STATUS_CLOSING_INDICATING (0xC001000EL) -#define RNDIS_STATUS_NOT_SUPPORTED (STATUS_NOT_SUPPORTED) -#define RNDIS_STATUS_INVALID_PACKET (0xC001000FL) -#define RNDIS_STATUS_OPEN_LIST_FULL (0xC0010010L) -#define RNDIS_STATUS_ADAPTER_NOT_READY (0xC0010011L) -#define RNDIS_STATUS_ADAPTER_NOT_OPEN (0xC0010012L) -#define RNDIS_STATUS_NOT_INDICATING (0xC0010013L) -#define RNDIS_STATUS_INVALID_LENGTH (0xC0010014L) -#define RNDIS_STATUS_INVALID_DATA (0xC0010015L) -#define RNDIS_STATUS_BUFFER_TOO_SHORT (0xC0010016L) -#define RNDIS_STATUS_INVALID_OID (0xC0010017L) -#define RNDIS_STATUS_ADAPTER_REMOVED (0xC0010018L) -#define RNDIS_STATUS_UNSUPPORTED_MEDIA (0xC0010019L) -#define RNDIS_STATUS_GROUP_ADDRESS_IN_USE (0xC001001AL) -#define RNDIS_STATUS_FILE_NOT_FOUND (0xC001001BL) -#define RNDIS_STATUS_ERROR_READING_FILE (0xC001001CL) -#define RNDIS_STATUS_ALREADY_MAPPED (0xC001001DL) -#define RNDIS_STATUS_RESOURCE_CONFLICT (0xC001001EL) -#define RNDIS_STATUS_NO_CABLE (0xC001001FL) - -#define RNDIS_STATUS_INVALID_SAP (0xC0010020L) -#define RNDIS_STATUS_SAP_IN_USE (0xC0010021L) -#define RNDIS_STATUS_INVALID_ADDRESS (0xC0010022L) -#define RNDIS_STATUS_VC_NOT_ACTIVATED (0xC0010023L) -#define RNDIS_STATUS_DEST_OUT_OF_ORDER (0xC0010024L) -#define RNDIS_STATUS_VC_NOT_AVAILABLE (0xC0010025L) -#define RNDIS_STATUS_CELLRATE_NOT_AVAILABLE (0xC0010026L) -#define RNDIS_STATUS_INCOMPATABLE_QOS (0xC0010027L) -#define RNDIS_STATUS_AAL_PARAMS_UNSUPPORTED (0xC0010028L) -#define RNDIS_STATUS_NO_ROUTE_TO_DESTINATION (0xC0010029L) - -#define RNDIS_STATUS_TOKEN_RING_OPEN_ERROR (0xC0011000L) - -/* Object Identifiers used by NdisRequest Query/Set Information */ -/* General Objects */ -#define RNDIS_OID_GEN_SUPPORTED_LIST 0x00010101 -#define RNDIS_OID_GEN_HARDWARE_STATUS 0x00010102 -#define RNDIS_OID_GEN_MEDIA_SUPPORTED 0x00010103 -#define RNDIS_OID_GEN_MEDIA_IN_USE 0x00010104 -#define RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 -#define RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 -#define RNDIS_OID_GEN_LINK_SPEED 0x00010107 -#define RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 -#define RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 -#define RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A -#define RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B -#define RNDIS_OID_GEN_VENDOR_ID 0x0001010C -#define RNDIS_OID_GEN_VENDOR_DESCRIPTION 0x0001010D -#define RNDIS_OID_GEN_CURRENT_PACKET_FILTER 0x0001010E -#define RNDIS_OID_GEN_CURRENT_LOOKAHEAD 0x0001010F -#define RNDIS_OID_GEN_DRIVER_VERSION 0x00010110 -#define RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 -#define RNDIS_OID_GEN_PROTOCOL_OPTIONS 0x00010112 -#define RNDIS_OID_GEN_MAC_OPTIONS 0x00010113 -#define RNDIS_OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 -#define RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 -#define RNDIS_OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 -#define RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 -#define RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 -#define RNDIS_OID_GEN_MACHINE_NAME 0x0001021A -#define RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B - -#define RNDIS_OID_GEN_XMIT_OK 0x00020101 -#define RNDIS_OID_GEN_RCV_OK 0x00020102 -#define RNDIS_OID_GEN_XMIT_ERROR 0x00020103 -#define RNDIS_OID_GEN_RCV_ERROR 0x00020104 -#define RNDIS_OID_GEN_RCV_NO_BUFFER 0x00020105 - -#define RNDIS_OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 -#define RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 -#define RNDIS_OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 -#define RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 -#define RNDIS_OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 -#define RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 -#define RNDIS_OID_GEN_DIRECTED_BYTES_RCV 0x00020207 -#define RNDIS_OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 -#define RNDIS_OID_GEN_MULTICAST_BYTES_RCV 0x00020209 -#define RNDIS_OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A -#define RNDIS_OID_GEN_BROADCAST_BYTES_RCV 0x0002020B -#define RNDIS_OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C - -#define RNDIS_OID_GEN_RCV_CRC_ERROR 0x0002020D -#define RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E - -#define RNDIS_OID_GEN_GET_TIME_CAPS 0x0002020F -#define RNDIS_OID_GEN_GET_NETCARD_TIME 0x00020210 - -/* These are connection-oriented general OIDs. */ -/* These replace the above OIDs for connection-oriented media. */ -#define RNDIS_OID_GEN_CO_SUPPORTED_LIST 0x00010101 -#define RNDIS_OID_GEN_CO_HARDWARE_STATUS 0x00010102 -#define RNDIS_OID_GEN_CO_MEDIA_SUPPORTED 0x00010103 -#define RNDIS_OID_GEN_CO_MEDIA_IN_USE 0x00010104 -#define RNDIS_OID_GEN_CO_LINK_SPEED 0x00010105 -#define RNDIS_OID_GEN_CO_VENDOR_ID 0x00010106 -#define RNDIS_OID_GEN_CO_VENDOR_DESCRIPTION 0x00010107 -#define RNDIS_OID_GEN_CO_DRIVER_VERSION 0x00010108 -#define RNDIS_OID_GEN_CO_PROTOCOL_OPTIONS 0x00010109 -#define RNDIS_OID_GEN_CO_MAC_OPTIONS 0x0001010A -#define RNDIS_OID_GEN_CO_MEDIA_CONNECT_STATUS 0x0001010B -#define RNDIS_OID_GEN_CO_VENDOR_DRIVER_VERSION 0x0001010C -#define RNDIS_OID_GEN_CO_MINIMUM_LINK_SPEED 0x0001010D - -#define RNDIS_OID_GEN_CO_GET_TIME_CAPS 0x00010201 -#define RNDIS_OID_GEN_CO_GET_NETCARD_TIME 0x00010202 - -/* These are connection-oriented statistics OIDs. */ -#define RNDIS_OID_GEN_CO_XMIT_PDUS_OK 0x00020101 -#define RNDIS_OID_GEN_CO_RCV_PDUS_OK 0x00020102 -#define RNDIS_OID_GEN_CO_XMIT_PDUS_ERROR 0x00020103 -#define RNDIS_OID_GEN_CO_RCV_PDUS_ERROR 0x00020104 -#define RNDIS_OID_GEN_CO_RCV_PDUS_NO_BUFFER 0x00020105 - - -#define RNDIS_OID_GEN_CO_RCV_CRC_ERROR 0x00020201 -#define RNDIS_OID_GEN_CO_TRANSMIT_QUEUE_LENGTH 0x00020202 -#define RNDIS_OID_GEN_CO_BYTES_XMIT 0x00020203 -#define RNDIS_OID_GEN_CO_BYTES_RCV 0x00020204 -#define RNDIS_OID_GEN_CO_BYTES_XMIT_OUTSTANDING 0x00020205 -#define RNDIS_OID_GEN_CO_NETCARD_LOAD 0x00020206 - -/* These are objects for Connection-oriented media call-managers. */ -#define RNDIS_OID_CO_ADD_PVC 0xFF000001 -#define RNDIS_OID_CO_DELETE_PVC 0xFF000002 -#define RNDIS_OID_CO_GET_CALL_INFORMATION 0xFF000003 -#define RNDIS_OID_CO_ADD_ADDRESS 0xFF000004 -#define RNDIS_OID_CO_DELETE_ADDRESS 0xFF000005 -#define RNDIS_OID_CO_GET_ADDRESSES 0xFF000006 -#define RNDIS_OID_CO_ADDRESS_CHANGE 0xFF000007 -#define RNDIS_OID_CO_SIGNALING_ENABLED 0xFF000008 -#define RNDIS_OID_CO_SIGNALING_DISABLED 0xFF000009 - -/* 802.3 Objects (Ethernet) */ -#define RNDIS_OID_802_3_PERMANENT_ADDRESS 0x01010101 -#define RNDIS_OID_802_3_CURRENT_ADDRESS 0x01010102 -#define RNDIS_OID_802_3_MULTICAST_LIST 0x01010103 -#define RNDIS_OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 -#define RNDIS_OID_802_3_MAC_OPTIONS 0x01010105 - -#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 - -#define RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 -#define RNDIS_OID_802_3_XMIT_ONE_COLLISION 0x01020102 -#define RNDIS_OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 - -#define RNDIS_OID_802_3_XMIT_DEFERRED 0x01020201 -#define RNDIS_OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 -#define RNDIS_OID_802_3_RCV_OVERRUN 0x01020203 -#define RNDIS_OID_802_3_XMIT_UNDERRUN 0x01020204 -#define RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 -#define RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 -#define RNDIS_OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 - -/* Remote NDIS message types */ -#define REMOTE_NDIS_PACKET_MSG 0x00000001 -#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002 -#define REMOTE_NDIS_HALT_MSG 0x00000003 -#define REMOTE_NDIS_QUERY_MSG 0x00000004 -#define REMOTE_NDIS_SET_MSG 0x00000005 -#define REMOTE_NDIS_RESET_MSG 0x00000006 -#define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007 -#define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008 - -#define REMOTE_CONDIS_MP_CREATE_VC_MSG 0x00008001 -#define REMOTE_CONDIS_MP_DELETE_VC_MSG 0x00008002 -#define REMOTE_CONDIS_MP_ACTIVATE_VC_MSG 0x00008005 -#define REMOTE_CONDIS_MP_DEACTIVATE_VC_MSG 0x00008006 -#define REMOTE_CONDIS_INDICATE_STATUS_MSG 0x00008007 - -/* Remote NDIS message completion types */ -#define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002 -#define REMOTE_NDIS_QUERY_CMPLT 0x80000004 -#define REMOTE_NDIS_SET_CMPLT 0x80000005 -#define REMOTE_NDIS_RESET_CMPLT 0x80000006 -#define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008 - -#define REMOTE_CONDIS_MP_CREATE_VC_CMPLT 0x80008001 -#define REMOTE_CONDIS_MP_DELETE_VC_CMPLT 0x80008002 -#define REMOTE_CONDIS_MP_ACTIVATE_VC_CMPLT 0x80008005 -#define REMOTE_CONDIS_MP_DEACTIVATE_VC_CMPLT 0x80008006 - -/* - * Reserved message type for private communication between lower-layer host - * driver and remote device, if necessary. - */ -#define REMOTE_NDIS_BUS_MSG 0xff000001 - -/* Defines for DeviceFlags in struct rndis_initialize_complete */ -#define RNDIS_DF_CONNECTIONLESS 0x00000001 -#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002 -#define RNDIS_DF_RAW_DATA 0x00000004 - -/* Remote NDIS medium types. */ -#define RNDIS_MEDIUM_802_3 0x00000000 -#define RNDIS_MEDIUM_802_5 0x00000001 -#define RNDIS_MEDIUM_FDDI 0x00000002 -#define RNDIS_MEDIUM_WAN 0x00000003 -#define RNDIS_MEDIUM_LOCAL_TALK 0x00000004 -#define RNDIS_MEDIUM_ARCNET_RAW 0x00000006 -#define RNDIS_MEDIUM_ARCNET_878_2 0x00000007 -#define RNDIS_MEDIUM_ATM 0x00000008 -#define RNDIS_MEDIUM_WIRELESS_WAN 0x00000009 -#define RNDIS_MEDIUM_IRDA 0x0000000a -#define RNDIS_MEDIUM_CO_WAN 0x0000000b -/* Not a real medium, defined as an upper-bound */ -#define RNDIS_MEDIUM_MAX 0x0000000d - - -/* Remote NDIS medium connection states. */ -#define RNDIS_MEDIA_STATE_CONNECTED 0x00000000 -#define RNDIS_MEDIA_STATE_DISCONNECTED 0x00000001 - -/* Remote NDIS version numbers */ -#define RNDIS_MAJOR_VERSION 0x00000001 -#define RNDIS_MINOR_VERSION 0x00000000 - - -/* NdisInitialize message */ -struct rndis_initialize_request { - u32 req_id; - u32 major_ver; - u32 minor_ver; - u32 max_xfer_size; -}; - -/* Response to NdisInitialize */ -struct rndis_initialize_complete { - u32 req_id; - u32 status; - u32 major_ver; - u32 minor_ver; - u32 dev_flags; - u32 medium; - u32 max_pkt_per_msg; - u32 max_xfer_size; - u32 pkt_alignment_factor; - u32 af_list_offset; - u32 af_list_size; -}; - -/* Call manager devices only: Information about an address family */ -/* supported by the device is appended to the response to NdisInitialize. */ -struct rndis_co_address_family { - u32 address_family; - u32 major_ver; - u32 minor_ver; -}; - -/* NdisHalt message */ -struct rndis_halt_request { - u32 req_id; -}; - -/* NdisQueryRequest message */ -struct rndis_query_request { - u32 req_id; - u32 oid; - u32 info_buflen; - u32 info_buf_offset; - u32 dev_vc_handle; -}; - -/* Response to NdisQueryRequest */ -struct rndis_query_complete { - u32 req_id; - u32 status; - u32 info_buflen; - u32 info_buf_offset; -}; - -/* NdisSetRequest message */ -struct rndis_set_request { - u32 req_id; - u32 oid; - u32 info_buflen; - u32 info_buf_offset; - u32 dev_vc_handle; -}; - -/* Response to NdisSetRequest */ -struct rndis_set_complete { - u32 req_id; - u32 status; -}; - -/* NdisReset message */ -struct rndis_reset_request { - u32 reserved; -}; - -/* Response to NdisReset */ -struct rndis_reset_complete { - u32 status; - u32 addressing_reset; -}; - -/* NdisMIndicateStatus message */ -struct rndis_indicate_status { - u32 status; - u32 status_buflen; - u32 status_buf_offset; -}; - -/* Diagnostic information passed as the status buffer in */ -/* struct rndis_indicate_status messages signifying error conditions. */ -struct rndis_diagnostic_info { - u32 diag_status; - u32 error_offset; -}; - -/* NdisKeepAlive message */ -struct rndis_keepalive_request { - u32 req_id; -}; - -/* Response to NdisKeepAlive */ -struct rndis_keepalive_complete { - u32 req_id; - u32 status; -}; - -/* - * Data message. All Offset fields contain byte offsets from the beginning of - * struct rndis_packet. All Length fields are in bytes. VcHandle is set - * to 0 for connectionless data, otherwise it contains the VC handle. - */ -struct rndis_packet { - u32 data_offset; - u32 data_len; - u32 oob_data_offset; - u32 oob_data_len; - u32 num_oob_data_elements; - u32 per_pkt_info_offset; - u32 per_pkt_info_len; - u32 vc_handle; - u32 reserved; -}; - -/* Optional Out of Band data associated with a Data message. */ -struct rndis_oobd { - u32 size; - u32 type; - u32 class_info_offset; -}; - -/* Packet extension field contents associated with a Data message. */ -struct rndis_per_packet_info { - u32 size; - u32 type; - u32 per_pkt_info_offset; -}; - -/* Format of Information buffer passed in a SetRequest for the OID */ -/* OID_GEN_RNDIS_CONFIG_PARAMETER. */ -struct rndis_config_parameter_info { - u32 parameter_name_offset; - u32 parameter_name_length; - u32 parameter_type; - u32 parameter_value_offset; - u32 parameter_value_length; -}; - -/* Values for ParameterType in struct rndis_config_parameter_info */ -#define RNDIS_CONFIG_PARAM_TYPE_INTEGER 0 -#define RNDIS_CONFIG_PARAM_TYPE_STRING 2 - -/* CONDIS Miniport messages for connection oriented devices */ -/* that do not implement a call manager. */ - -/* CoNdisMiniportCreateVc message */ -struct rcondis_mp_create_vc { - u32 req_id; - u32 ndis_vc_handle; -}; - -/* Response to CoNdisMiniportCreateVc */ -struct rcondis_mp_create_vc_complete { - u32 req_id; - u32 dev_vc_handle; - u32 status; -}; - -/* CoNdisMiniportDeleteVc message */ -struct rcondis_mp_delete_vc { - u32 req_id; - u32 dev_vc_handle; -}; - -/* Response to CoNdisMiniportDeleteVc */ -struct rcondis_mp_delete_vc_complete { - u32 req_id; - u32 status; -}; - -/* CoNdisMiniportQueryRequest message */ -struct rcondis_mp_query_request { - u32 req_id; - u32 request_type; - u32 oid; - u32 dev_vc_handle; - u32 info_buflen; - u32 info_buf_offset; -}; - -/* CoNdisMiniportSetRequest message */ -struct rcondis_mp_set_request { - u32 req_id; - u32 request_type; - u32 oid; - u32 dev_vc_handle; - u32 info_buflen; - u32 info_buf_offset; -}; - -/* CoNdisIndicateStatus message */ -struct rcondis_indicate_status { - u32 ndis_vc_handle; - u32 status; - u32 status_buflen; - u32 status_buf_offset; -}; - -/* CONDIS Call/VC parameters */ -struct rcondis_specific_parameters { - u32 parameter_type; - u32 parameter_length; - u32 parameter_lffset; -}; - -struct rcondis_media_parameters { - u32 flags; - u32 reserved1; - u32 reserved2; - struct rcondis_specific_parameters media_specific; -}; - -struct rndis_flowspec { - u32 token_rate; - u32 token_bucket_size; - u32 peak_bandwidth; - u32 latency; - u32 delay_variation; - u32 service_type; - u32 max_sdu_size; - u32 minimum_policed_size; -}; - -struct rcondis_call_manager_parameters { - struct rndis_flowspec transmit; - struct rndis_flowspec receive; - struct rcondis_specific_parameters call_mgr_specific; -}; - -/* CoNdisMiniportActivateVc message */ -struct rcondis_mp_activate_vc_request { - u32 req_id; - u32 flags; - u32 dev_vc_handle; - u32 media_params_offset; - u32 media_params_length; - u32 call_mgr_params_offset; - u32 call_mgr_params_length; -}; - -/* Response to CoNdisMiniportActivateVc */ -struct rcondis_mp_activate_vc_complete { - u32 req_id; - u32 status; -}; - -/* CoNdisMiniportDeactivateVc message */ -struct rcondis_mp_deactivate_vc_request { - u32 req_id; - u32 flags; - u32 dev_vc_handle; -}; - -/* Response to CoNdisMiniportDeactivateVc */ -struct rcondis_mp_deactivate_vc_complete { - u32 req_id; - u32 status; -}; - - -/* union with all of the RNDIS messages */ -union rndis_message_container { - struct rndis_packet pkt; - struct rndis_initialize_request init_req; - struct rndis_halt_request halt_req; - struct rndis_query_request query_req; - struct rndis_set_request set_req; - struct rndis_reset_request reset_req; - struct rndis_keepalive_request keep_alive_req; - struct rndis_indicate_status indicate_status; - struct rndis_initialize_complete init_complete; - struct rndis_query_complete query_complete; - struct rndis_set_complete set_complete; - struct rndis_reset_complete reset_complete; - struct rndis_keepalive_complete keep_alive_complete; - struct rcondis_mp_create_vc co_miniport_create_vc; - struct rcondis_mp_delete_vc co_miniport_delete_vc; - struct rcondis_indicate_status co_indicate_status; - struct rcondis_mp_activate_vc_request co_miniport_activate_vc; - struct rcondis_mp_deactivate_vc_request co_miniport_deactivate_vc; - struct rcondis_mp_create_vc_complete co_miniport_create_vc_complete; - struct rcondis_mp_delete_vc_complete co_miniport_delete_vc_complete; - struct rcondis_mp_activate_vc_complete co_miniport_activate_vc_complete; - struct rcondis_mp_deactivate_vc_complete - co_miniport_deactivate_vc_complete; -}; - -/* Remote NDIS message format */ -struct rndis_message { - u32 ndis_msg_type; - - /* Total length of this message, from the beginning */ - /* of the sruct rndis_message, in bytes. */ - u32 msg_len; - - /* Actual message */ - union rndis_message_container msg; -}; - -/* Handy macros */ - -/* get the size of an RNDIS message. Pass in the message type, */ -/* struct rndis_set_request, struct rndis_packet for example */ -#define RNDIS_MESSAGE_SIZE(msg) \ - (sizeof(msg) + (sizeof(struct rndis_message) - \ - sizeof(union rndis_message_container))) - -/* get pointer to info buffer with message pointer */ -#define MESSAGE_TO_INFO_BUFFER(msg) \ - (((unsigned char *)(msg)) + msg->info_buf_offset) - -/* get pointer to status buffer with message pointer */ -#define MESSAGE_TO_STATUS_BUFFER(msg) \ - (((unsigned char *)(msg)) + msg->status_buf_offset) - -/* get pointer to OOBD buffer with message pointer */ -#define MESSAGE_TO_OOBD_BUFFER(msg) \ - (((unsigned char *)(msg)) + msg->oob_data_offset) - -/* get pointer to data buffer with message pointer */ -#define MESSAGE_TO_DATA_BUFFER(msg) \ - (((unsigned char *)(msg)) + msg->per_pkt_info_offset) - -/* get pointer to contained message from NDIS_MESSAGE pointer */ -#define RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(rndis_msg) \ - ((void *) &rndis_msg->msg) - -/* get pointer to contained message from NDIS_MESSAGE pointer */ -#define RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(rndis_msg) \ - ((void *) rndis_msg) - -#endif /* _RNDIS_H_ */ diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c deleted file mode 100644 index 53676dcbf38..00000000000 --- a/drivers/staging/hv/rndis_filter.c +++ /dev/null @@ -1,928 +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/highmem.h> -#include <linux/slab.h> -#include <linux/io.h> -#include <linux/if_ether.h> - -#include "osd.h" -#include "logging.h" -#include "netvsc_api.h" -#include "rndis_filter.h" - -/* Data types */ -struct rndis_filter_driver_object { - /* The original driver */ - struct netvsc_driver inner_drv; -}; - -enum rndis_device_state { - RNDIS_DEV_UNINITIALIZED = 0, - RNDIS_DEV_INITIALIZING, - RNDIS_DEV_INITIALIZED, - RNDIS_DEV_DATAINITIALIZED, -}; - -struct rndis_device { - struct netvsc_device *net_dev; - - enum rndis_device_state state; - u32 link_stat; - atomic_t new_req_id; - - spinlock_t request_lock; - struct list_head req_list; - - unsigned char hw_mac_adr[ETH_ALEN]; -}; - -struct rndis_request { - struct list_head list_ent; - struct osd_waitevent *waitevent; - - /* - * FIXME: We assumed a fixed size response here. If we do ever need to - * handle a bigger response, we can either define a max response - * message or add a response buffer variable above this field - */ - struct rndis_message response_msg; - - /* Simplify allocation by having a netvsc packet inline */ - struct hv_netvsc_packet pkt; - struct hv_page_buffer buf; - /* FIXME: We assumed a fixed size request here. */ - 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) -{ - struct rndis_device *device; - - device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL); - if (!device) - return NULL; - - spin_lock_init(&device->request_lock); - - INIT_LIST_HEAD(&device->req_list); - - device->state = RNDIS_DEV_UNINITIALIZED; - - return device; -} - -static struct rndis_request *get_rndis_request(struct rndis_device *dev, - u32 msg_type, - u32 msg_len) -{ - struct rndis_request *request; - struct rndis_message *rndis_msg; - struct rndis_set_request *set; - unsigned long flags; - - request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL); - if (!request) - return NULL; - - request->waitevent = osd_waitevent_create(); - if (!request->waitevent) { - kfree(request); - return NULL; - } - - rndis_msg = &request->request_msg; - rndis_msg->ndis_msg_type = msg_type; - rndis_msg->msg_len = msg_len; - - /* - * Set the request id. This field is always after the rndis header for - * request/response packet types so we just used the SetRequest as a - * template - */ - set = &rndis_msg->msg.set_req; - set->req_id = atomic_inc_return(&dev->new_req_id); - - /* Add to the request list */ - spin_lock_irqsave(&dev->request_lock, flags); - list_add_tail(&request->list_ent, &dev->req_list); - spin_unlock_irqrestore(&dev->request_lock, flags); - - return request; -} - -static void put_rndis_request(struct rndis_device *dev, - struct rndis_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->request_lock, flags); - list_del(&req->list_ent); - spin_unlock_irqrestore(&dev->request_lock, flags); - - kfree(req->waitevent); - kfree(req); -} - -static void dump_rndis_message(struct rndis_message *rndis_msg) -{ - switch (rndis_msg->ndis_msg_type) { - case REMOTE_NDIS_PACKET_MSG: - DPRINT_DBG(NETVSC, "REMOTE_NDIS_PACKET_MSG (len %u, " - "data offset %u data len %u, # oob %u, " - "oob offset %u, oob len %u, pkt offset %u, " - "pkt len %u", - rndis_msg->msg_len, - rndis_msg->msg.pkt.data_offset, - rndis_msg->msg.pkt.data_len, - rndis_msg->msg.pkt.num_oob_data_elements, - rndis_msg->msg.pkt.oob_data_offset, - rndis_msg->msg.pkt.oob_data_len, - rndis_msg->msg.pkt.per_pkt_info_offset, - rndis_msg->msg.pkt.per_pkt_info_len); - break; - - case REMOTE_NDIS_INITIALIZE_CMPLT: - DPRINT_DBG(NETVSC, "REMOTE_NDIS_INITIALIZE_CMPLT " - "(len %u, id 0x%x, status 0x%x, major %d, minor %d, " - "device flags %d, max xfer size 0x%x, max pkts %u, " - "pkt aligned %u)", - rndis_msg->msg_len, - rndis_msg->msg.init_complete.req_id, - rndis_msg->msg.init_complete.status, - rndis_msg->msg.init_complete.major_ver, - rndis_msg->msg.init_complete.minor_ver, - rndis_msg->msg.init_complete.dev_flags, - rndis_msg->msg.init_complete.max_xfer_size, - rndis_msg->msg.init_complete. - max_pkt_per_msg, - rndis_msg->msg.init_complete. - pkt_alignment_factor); - break; - - case REMOTE_NDIS_QUERY_CMPLT: - DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT " - "(len %u, id 0x%x, status 0x%x, buf len %u, " - "buf offset %u)", - rndis_msg->msg_len, - rndis_msg->msg.query_complete.req_id, - rndis_msg->msg.query_complete.status, - rndis_msg->msg.query_complete. - info_buflen, - rndis_msg->msg.query_complete. - info_buf_offset); - break; - - case REMOTE_NDIS_SET_CMPLT: - DPRINT_DBG(NETVSC, - "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)", - rndis_msg->msg_len, - rndis_msg->msg.set_complete.req_id, - rndis_msg->msg.set_complete.status); - break; - - case REMOTE_NDIS_INDICATE_STATUS_MSG: - DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG " - "(len %u, status 0x%x, buf len %u, buf offset %u)", - rndis_msg->msg_len, - rndis_msg->msg.indicate_status.status, - rndis_msg->msg.indicate_status.status_buflen, - rndis_msg->msg.indicate_status.status_buf_offset); - break; - - default: - DPRINT_DBG(NETVSC, "0x%x (len %u)", - rndis_msg->ndis_msg_type, - rndis_msg->msg_len); - break; - } -} - -static int rndis_filter_send_request(struct rndis_device *dev, - struct rndis_request *req) -{ - int ret; - struct hv_netvsc_packet *packet; - - /* Setup the packet to send it */ - packet = &req->pkt; - - packet->is_data_pkt = false; - packet->total_data_buflen = req->request_msg.msg_len; - packet->page_buf_cnt = 1; - - packet->page_buf[0].Pfn = virt_to_phys(&req->request_msg) >> - PAGE_SHIFT; - packet->page_buf[0].Length = req->request_msg.msg_len; - packet->page_buf[0].Offset = - (unsigned long)&req->request_msg & (PAGE_SIZE - 1); - - packet->completion.send.send_completion_ctx = req;/* packet; */ - packet->completion.send.send_completion = - 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); - return ret; -} - -static void rndis_filter_receive_response(struct rndis_device *dev, - struct rndis_message *resp) -{ - struct rndis_request *request = NULL; - bool found = false; - unsigned long flags; - - spin_lock_irqsave(&dev->request_lock, flags); - list_for_each_entry(request, &dev->req_list, list_ent) { - /* - * All request/response message contains RequestId as the 1st - * field - */ - 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; - } - } - spin_unlock_irqrestore(&dev->request_lock, flags); - - if (found) { - if (resp->msg_len <= sizeof(struct rndis_message)) { - 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)); - - if (resp->ndis_msg_type == - REMOTE_NDIS_RESET_CMPLT) { - /* does not have a request id field */ - request->response_msg.msg.reset_complete. - status = STATUS_BUFFER_OVERFLOW; - } else { - request->response_msg.msg. - init_complete.status = - STATUS_BUFFER_OVERFLOW; - } - } - - osd_waitevent_set(request->waitevent); - } 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); - } -} - -static void rndis_filter_receive_indicate_status(struct rndis_device *dev, - struct rndis_message *resp) -{ - struct rndis_indicate_status *indicate = - &resp->msg.indicate_status; - - if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) { - rndis_filter.inner_drv.link_status_change( - dev->net_dev->dev, 1); - } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) { - rndis_filter.inner_drv.link_status_change( - dev->net_dev->dev, 0); - } else { - /* - * TODO: - */ - } -} - -static void rndis_filter_receive_data(struct rndis_device *dev, - struct rndis_message *msg, - struct hv_netvsc_packet *pkt) -{ - struct rndis_packet *rndis_pkt; - u32 data_offset; - - /* empty ethernet frame ?? */ - /* ASSERT(Packet->PageBuffers[0].Length > */ - /* RNDIS_MESSAGE_SIZE(struct rndis_packet)); */ - - rndis_pkt = &msg->msg.pkt; - - /* - * FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this - * netvsc packet (ie TotalDataBufferLength != MessageLength) - */ - - /* Remove the rndis header and pass it back up the stack */ - data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset; - - pkt->total_data_buflen -= data_offset; - pkt->page_buf[0].Offset += data_offset; - pkt->page_buf[0].Length -= data_offset; - - pkt->is_data_pkt = true; - - rndis_filter.inner_drv.recv_cb(dev->net_dev->dev, - pkt); -} - -static int rndis_filter_receive(struct hv_device *dev, - struct hv_netvsc_packet *pkt) -{ - struct netvsc_device *net_dev = dev->Extension; - struct rndis_device *rndis_dev; - struct rndis_message rndis_msg; - struct rndis_message *rndis_hdr; - - if (!net_dev) - return -EINVAL; - - /* 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!"); - 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!"); - return -1; - } - - rndis_hdr = (struct rndis_message *)kmap_atomic( - pfn_to_page(pkt->page_buf[0].Pfn), KM_IRQ0); - - rndis_hdr = (void *)((unsigned long)rndis_hdr + - pkt->page_buf[0].Offset); - - /* Make sure we got a valid rndis message */ - /* - * FIXME: There seems to be a bug in set completion msg where its - * MessageLength is 16 bytes but the ByteCount field in the xfer page - * range shows 52 bytes - * */ -#if 0 - if (pkt->total_data_buflen != rndis_hdr->msg_len) { - 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!", - rndis_hdr->msg_len, - pkt->total_data_buflen); - return -1; - } -#endif - - 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!", - rndis_hdr->msg_len, - sizeof(struct rndis_message)); - } - - memcpy(&rndis_msg, rndis_hdr, - (rndis_hdr->msg_len > sizeof(struct rndis_message)) ? - sizeof(struct rndis_message) : - rndis_hdr->msg_len); - - kunmap_atomic(rndis_hdr - pkt->page_buf[0].Offset, KM_IRQ0); - - dump_rndis_message(&rndis_msg); - - switch (rndis_msg.ndis_msg_type) { - case REMOTE_NDIS_PACKET_MSG: - /* data msg */ - rndis_filter_receive_data(rndis_dev, &rndis_msg, pkt); - break; - - case REMOTE_NDIS_INITIALIZE_CMPLT: - case REMOTE_NDIS_QUERY_CMPLT: - case REMOTE_NDIS_SET_CMPLT: - /* case REMOTE_NDIS_RESET_CMPLT: */ - /* case REMOTE_NDIS_KEEPALIVE_CMPLT: */ - /* completion msgs */ - rndis_filter_receive_response(rndis_dev, &rndis_msg); - break; - - case REMOTE_NDIS_INDICATE_STATUS_MSG: - /* notification msgs */ - rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg); - break; - default: - DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)", - rndis_msg.ndis_msg_type, - rndis_msg.msg_len); - break; - } - - return 0; -} - -static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, - void *result, u32 *result_size) -{ - struct rndis_request *request; - u32 inresult_size = *result_size; - struct rndis_query_request *query; - struct rndis_query_complete *query_complete; - int ret = 0; - - if (!result) - return -EINVAL; - - *result_size = 0; - request = get_rndis_request(dev, REMOTE_NDIS_QUERY_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_query_request)); - if (!request) { - ret = -1; - goto Cleanup; - } - - /* Setup the rndis query */ - query = &request->request_msg.msg.query_req; - query->oid = oid; - query->info_buf_offset = sizeof(struct rndis_query_request); - query->info_buflen = 0; - query->dev_vc_handle = 0; - - ret = rndis_filter_send_request(dev, request); - if (ret != 0) - goto Cleanup; - - osd_waitevent_wait(request->waitevent); - - /* Copy the response back */ - query_complete = &request->response_msg.msg.query_complete; - - if (query_complete->info_buflen > inresult_size) { - ret = -1; - goto Cleanup; - } - - memcpy(result, - (void *)((unsigned long)query_complete + - query_complete->info_buf_offset), - query_complete->info_buflen); - - *result_size = query_complete->info_buflen; - -Cleanup: - if (request) - put_rndis_request(dev, request); - - return ret; -} - -static int rndis_filter_query_device_mac(struct rndis_device *dev) -{ - u32 size = ETH_ALEN; - - return rndis_filter_query_device(dev, - RNDIS_OID_802_3_PERMANENT_ADDRESS, - dev->hw_mac_adr, &size); -} - -static int rndis_filter_query_device_link_status(struct rndis_device *dev) -{ - u32 size = sizeof(u32); - - return rndis_filter_query_device(dev, - RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, - &dev->link_stat, &size); -} - -static int rndis_filter_set_packet_filter(struct rndis_device *dev, - u32 new_filter) -{ - struct rndis_request *request; - struct rndis_set_request *set; - struct rndis_set_complete *set_complete; - u32 status; - int ret; - - /* ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= */ - /* sizeof(struct rndis_message)); */ - - request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_set_request) + - sizeof(u32)); - if (!request) { - ret = -1; - goto Cleanup; - } - - /* Setup the rndis set */ - set = &request->request_msg.msg.set_req; - set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; - set->info_buflen = sizeof(u32); - set->info_buf_offset = sizeof(struct rndis_set_request); - - memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), - &new_filter, sizeof(u32)); - - ret = rndis_filter_send_request(dev, request); - if (ret != 0) - goto Cleanup; - - ret = osd_waitevent_waitex(request->waitevent, 2000/*2sec*/); - if (!ret) { - ret = -1; - DPRINT_ERR(NETVSC, "timeout before we got a set response..."); - /* - * We cant deallocate the request since we may still receive a - * send completion for it. - */ - goto Exit; - } else { - if (ret > 0) - ret = 0; - set_complete = &request->response_msg.msg.set_complete; - status = set_complete->status; - } - -Cleanup: - if (request) - put_rndis_request(dev, request); -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.OnDeviceAdd = drv->base.OnDeviceAdd; - rndis_filter.inner_drv.base.OnDeviceRemove = - drv->base.OnDeviceRemove; - rndis_filter.inner_drv.base.OnCleanup = drv->base.OnCleanup; - - /* ASSERT(Driver->OnSend); */ - /* ASSERT(Driver->OnReceiveCallback); */ - 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.OnDeviceAdd = rndis_filte_device_add; - drv->base.OnDeviceRemove = rndis_filter_device_remove; - drv->base.OnCleanup = rndis_filter_cleanup; - drv->send = rndis_filter_send; - /* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */ - drv->recv_cb = rndis_filter_receive; - - return 0; -} - -static int rndis_filter_init_device(struct rndis_device *dev) -{ - struct rndis_request *request; - struct rndis_initialize_request *init; - struct rndis_initialize_complete *init_complete; - u32 status; - int ret; - - request = get_rndis_request(dev, REMOTE_NDIS_INITIALIZE_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); - if (!request) { - ret = -1; - goto Cleanup; - } - - /* Setup the rndis set */ - init = &request->request_msg.msg.init_req; - init->major_ver = RNDIS_MAJOR_VERSION; - init->minor_ver = RNDIS_MINOR_VERSION; - /* FIXME: Use 1536 - rounded ethernet frame size */ - init->max_xfer_size = 2048; - - dev->state = RNDIS_DEV_INITIALIZING; - - ret = rndis_filter_send_request(dev, request); - if (ret != 0) { - dev->state = RNDIS_DEV_UNINITIALIZED; - goto Cleanup; - } - - osd_waitevent_wait(request->waitevent); - - init_complete = &request->response_msg.msg.init_complete; - status = init_complete->status; - if (status == RNDIS_STATUS_SUCCESS) { - dev->state = RNDIS_DEV_INITIALIZED; - ret = 0; - } else { - dev->state = RNDIS_DEV_UNINITIALIZED; - ret = -1; - } - -Cleanup: - if (request) - put_rndis_request(dev, request); - - return ret; -} - -static void rndis_filter_halt_device(struct rndis_device *dev) -{ - struct rndis_request *request; - struct rndis_halt_request *halt; - - /* Attempt to do a rndis device halt */ - request = get_rndis_request(dev, REMOTE_NDIS_HALT_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); - if (!request) - goto Cleanup; - - /* Setup the rndis set */ - halt = &request->request_msg.msg.halt_req; - halt->req_id = atomic_inc_return(&dev->new_req_id); - - /* Ignore return since this msg is optional. */ - rndis_filter_send_request(dev, request); - - dev->state = RNDIS_DEV_UNINITIALIZED; - -Cleanup: - if (request) - put_rndis_request(dev, request); - return; -} - -static int rndis_filter_open_device(struct rndis_device *dev) -{ - int ret; - - if (dev->state != RNDIS_DEV_INITIALIZED) - return 0; - - ret = rndis_filter_set_packet_filter(dev, - NDIS_PACKET_TYPE_BROADCAST | - NDIS_PACKET_TYPE_ALL_MULTICAST | - NDIS_PACKET_TYPE_DIRECTED); - if (ret == 0) - dev->state = RNDIS_DEV_DATAINITIALIZED; - - return ret; -} - -static int rndis_filter_close_device(struct rndis_device *dev) -{ - int ret; - - if (dev->state != RNDIS_DEV_DATAINITIALIZED) - return 0; - - ret = rndis_filter_set_packet_filter(dev, 0); - if (ret == 0) - dev->state = RNDIS_DEV_INITIALIZED; - - return ret; -} - -static int rndis_filte_device_add(struct hv_device *dev, - void *additional_info) -{ - int ret; - struct netvsc_device *netDevice; - struct rndis_device *rndisDevice; - struct netvsc_device_info *deviceInfo = additional_info; - - rndisDevice = get_rndis_device(); - 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.OnDeviceAdd(dev, additional_info); - if (ret != 0) { - kfree(rndisDevice); - return ret; - } - - - /* Initialize the rndis device */ - netDevice = dev->Extension; - /* ASSERT(netDevice); */ - /* ASSERT(netDevice->Device); */ - - netDevice->extension = rndisDevice; - rndisDevice->net_dev = netDevice; - - /* Send the rndis initialization message */ - ret = rndis_filter_init_device(rndisDevice); - if (ret != 0) { - /* - * TODO: If rndis init failed, we will need to shut down the - * channel - */ - } - - /* Get the mac address */ - ret = rndis_filter_query_device_mac(rndisDevice); - if (ret != 0) { - /* - * TODO: shutdown rndis device and the channel - */ - } - - 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"))); - - return ret; -} - -static int rndis_filter_device_remove(struct hv_device *dev) -{ - struct netvsc_device *net_dev = dev->Extension; - struct rndis_device *rndis_dev = net_dev->extension; - - /* Halt and release the rndis device */ - rndis_filter_halt_device(rndis_dev); - - kfree(rndis_dev); - net_dev->extension = NULL; - - /* Pass control to inner driver to remove the device */ - rndis_filter.inner_drv.base.OnDeviceRemove(dev); - - return 0; -} - -static void rndis_filter_cleanup(struct hv_driver *drv) -{ -} - -int rndis_filter_open(struct hv_device *dev) -{ - struct netvsc_device *netDevice = dev->Extension; - - if (!netDevice) - return -EINVAL; - - return rndis_filter_open_device(netDevice->extension); -} - -int rndis_filter_close(struct hv_device *dev) -{ - struct netvsc_device *netDevice = dev->Extension; - - if (!netDevice) - return -EINVAL; - - return rndis_filter_close_device(netDevice->extension); -} - -static int rndis_filter_send(struct hv_device *dev, - struct hv_netvsc_packet *pkt) -{ - int ret; - struct rndis_filter_packet *filterPacket; - struct rndis_message *rndisMessage; - struct rndis_packet *rndisPacket; - u32 rndisMessageSize; - - /* Add the rndis header */ - filterPacket = (struct rndis_filter_packet *)pkt->extension; - /* ASSERT(filterPacket); */ - - memset(filterPacket, 0, sizeof(struct rndis_filter_packet)); - - rndisMessage = &filterPacket->msg; - rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet); - - rndisMessage->ndis_msg_type = REMOTE_NDIS_PACKET_MSG; - rndisMessage->msg_len = pkt->total_data_buflen + - rndisMessageSize; - - rndisPacket = &rndisMessage->msg.pkt; - rndisPacket->data_offset = sizeof(struct rndis_packet); - rndisPacket->data_len = pkt->total_data_buflen; - - pkt->is_data_pkt = true; - pkt->page_buf[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT; - pkt->page_buf[0].Offset = - (unsigned long)rndisMessage & (PAGE_SIZE-1); - pkt->page_buf[0].Length = rndisMessageSize; - - /* Save the packet send completion and context */ - filterPacket->completion = pkt->completion.send.send_completion; - filterPacket->completion_ctx = - pkt->completion.send.send_completion_ctx; - - /* Use ours */ - pkt->completion.send.send_completion = rndis_filter_send_completion; - pkt->completion.send.send_completion_ctx = filterPacket; - - ret = rndis_filter.inner_drv.send(dev, pkt); - if (ret != 0) { - /* - * Reset the completion to originals to allow retries from - * above - */ - pkt->completion.send.send_completion = - filterPacket->completion; - pkt->completion.send.send_completion_ctx = - filterPacket->completion_ctx; - } - - return ret; -} - -static void rndis_filter_send_completion(void *ctx) -{ - struct rndis_filter_packet *filterPacket = ctx; - - /* Pass it back to the original handler */ - filterPacket->completion(filterPacket->completion_ctx); -} - - -static void rndis_filter_send_request_completion(void *ctx) -{ - /* Noop */ -} diff --git a/drivers/staging/hv/rndis_filter.h b/drivers/staging/hv/rndis_filter.h deleted file mode 100644 index 4da18f3cbad..00000000000 --- 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 deleted file mode 100644 index 9295113e09b..00000000000 --- a/drivers/staging/hv/storvsc.c +++ /dev/null @@ -1,821 +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/string.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/delay.h> -#include "osd.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 */ - struct osd_waitevent *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 - } -}; - - -static inline struct storvsc_device *alloc_stor_device(struct hv_device *device) -{ - struct storvsc_device *stor_device; - - stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL); - if (!stor_device) - return NULL; - - /* Set to 2 to allow both inbound and outbound traffics */ - /* (ie get_stor_device() and must_get_stor_device()) to proceed. */ - atomic_cmpxchg(&stor_device->ref_count, 0, 2); - - stor_device->device = device; - device->Extension = stor_device; - - return stor_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->Extension; - 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) -{ - struct storvsc_device *stor_device; - - stor_device = (struct storvsc_device *)device->Extension; - if (stor_device && atomic_read(&stor_device->ref_count)) - 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->Extension; - /* 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) -{ - struct storvsc_device *stor_device; - - stor_device = (struct storvsc_device *)device->Extension; - /* 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) - udelay(100); - - return stor_device; -} - -/* Drop ref count to 0. No one can use stor_device object. */ -static inline struct storvsc_device *final_release_stor_device( - struct hv_device *device) -{ - struct storvsc_device *stor_device; - - stor_device = (struct storvsc_device *)device->Extension; - /* 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) - udelay(100); - - device->Extension = NULL; - return stor_device; -} - -static int stor_vsc_channel_init(struct hv_device *device) -{ - struct storvsc_device *stor_device; - struct storvsc_request_extension *request; - struct vstor_packet *vstor_packet; - int ret; - - 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->init_request; - vstor_packet = &request->vstor_packet; - - /* - * Now, initiate the vsc/vsp initialization protocol on the open - * channel - */ - memset(request, 0, sizeof(struct storvsc_request_extension)); - request->wait_event = osd_waitevent_create(); - if (!request->wait_event) { - ret = -ENOMEM; - goto nomem; - } - - vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - - /*SpinlockAcquire(gDriverExt.packetListLock); - INSERT_TAIL_LIST(&gDriverExt.packetList, &packet->listEntry.entry); - SpinlockRelease(gDriverExt.packetListLock);*/ - - DPRINT_INFO(STORVSC, "BEGIN_INITIALIZATION_OPERATION..."); - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VmbusPacketTypeDataInBand, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) { - DPRINT_ERR(STORVSC, - "unable to send BEGIN_INITIALIZATION_OPERATION"); - goto Cleanup; - } - - osd_waitevent_wait(request->wait_event); - - 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); - goto Cleanup; - } - - DPRINT_INFO(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION..."); - - /* reuse the packet for version range supported */ - memset(vstor_packet, 0, sizeof(struct vstor_packet)); - vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - - vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT; - FILL_VMSTOR_REVISION(vstor_packet->version.revision); - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VmbusPacketTypeDataInBand, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) { - DPRINT_ERR(STORVSC, - "unable to send BEGIN_INITIALIZATION_OPERATION"); - goto Cleanup; - } - - osd_waitevent_wait(request->wait_event); - - /* 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); - goto Cleanup; - } - - /* Query channel properties */ - DPRINT_INFO(STORVSC, "QUERY_PROPERTIES_OPERATION..."); - - memset(vstor_packet, 0, sizeof(struct vstor_packet)); - vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - vstor_packet->storage_channel_properties.port_number = - stor_device->port_number; - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VmbusPacketTypeDataInBand, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - if (ret != 0) { - DPRINT_ERR(STORVSC, - "unable to send QUERY_PROPERTIES_OPERATION"); - goto Cleanup; - } - - osd_waitevent_wait(request->wait_event); - - /* 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); - 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; - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VmbusPacketTypeDataInBand, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - if (ret != 0) { - DPRINT_ERR(STORVSC, - "unable to send END_INITIALIZATION_OPERATION"); - goto Cleanup; - } - - osd_waitevent_wait(request->wait_event); - - 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); - goto Cleanup; - } - - DPRINT_INFO(STORVSC, "**** storage channel up and running!! ****"); - -Cleanup: - kfree(request->wait_event); - request->wait_event = NULL; -nomem: - put_stor_device(device); - return ret; -} - -static void stor_vsc_on_io_completion(struct hv_device *device, - struct vstor_packet *vstor_packet, - struct storvsc_request_extension *request_ext) -{ - struct hv_storvsc_request *request; - struct storvsc_device *stor_device; - - stor_device = must_get_stor_device(device); - if (!stor_device) { - DPRINT_ERR(STORVSC, "unable to get stor device..." - "device being destroyed?"); - 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); */ - - request = request_ext->request; - - /* ASSERT(request->OnIOCompletion != NULL); */ - - /* Copy over the status...etc */ - request->status = vstor_packet->vm_srb.scsi_status; - - if (request->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, - vstor_packet->vm_srb.srb_status); - } - - if ((request->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, - 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; - - request->on_io_completion(request); - - atomic_dec(&stor_device->num_outstanding_req); - - put_stor_device(device); -} - -static void stor_vsc_on_receive(struct hv_device *device, - struct vstor_packet *vstor_packet, - struct storvsc_request_extension *request_ext) -{ - 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); - break; - case VSTOR_OPERATION_REMOVE_DEVICE: - DPRINT_INFO(STORVSC, "REMOVE_DEVICE_OPERATION"); - /* TODO: */ - break; - - default: - DPRINT_INFO(STORVSC, "Unknown operation received - %d", - vstor_packet->operation); - break; - } -} - -static void stor_vsc_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_UP(sizeof(struct vstor_packet), 8)]; - struct storvsc_request_extension *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?"); - return; - } - - do { - ret = vmbus_recvpacket(device->channel, packet, - ALIGN_UP(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 *) - (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)); - - osd_waitevent_set(request->wait_event); - } else { - stor_vsc_on_receive(device, - (struct vstor_packet *)packet, - request); - } - } else { - /* DPRINT_DBG(STORVSC, "nothing else to read..."); */ - break; - } - } while (1); - - put_stor_device(device); - return; -} - -static int stor_vsc_connect_to_vsp(struct hv_device *device) -{ - struct vmstorage_channel_properties props; - struct storvsc_driver_object *stor_driver; - int ret; - - stor_driver = (struct storvsc_driver_object *)device->Driver; - 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, - (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); - - if (ret != 0) { - DPRINT_ERR(STORVSC, "unable to open channel: %d", ret); - return -1; - } - - ret = stor_vsc_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, - void *additional_info) -{ - struct storvsc_device *stor_device; - /* struct vmstorage_channel_properties *props; */ - struct storvsc_device_info *device_info; - int ret = 0; - - device_info = (struct storvsc_device_info *)additional_info; - stor_device = alloc_stor_device(device); - if (!stor_device) { - ret = -1; - goto Cleanup; - } - - /* Save the channel properties to our storvsc channel */ - /* props = (struct vmstorage_channel_properties *) - * channel->offerMsg.Offer.u.Standard.UserDefined; */ - - /* FIXME: */ - /* - * If we support more than 1 scsi channel, we need to set the - * port number here to the scsi channel but how do we get the - * 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); - - /* 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) -{ - struct storvsc_device *stor_device; - - DPRINT_INFO(STORVSC, "disabling storage device (%p)...", - device->Extension); - - stor_device = release_stor_device(device); - - /* - * At this point, all outbound traffic should be disable. We - * 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->Extension); - - 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); - - free_stor_device(stor_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; - - request->wait_event = osd_waitevent_create(); - if (!request->wait_event) { - ret = -ENOMEM; - goto Cleanup; - } - - 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, - VmbusPacketTypeDataInBand, - 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; - } - - /* FIXME: Add a timeout */ - osd_waitevent_wait(request->wait_event); - - kfree(request->wait_event); - 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, - 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; - 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.Length, 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?"); - return -2; - } - - /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, request->Cdb, - * request->CdbLen); */ - - request_extension->request = request; - request_extension->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.Length; - - 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.Length) { - ret = vmbus_sendpacket_multipagebuffer(device->channel, - &request_extension->request->data_buffer, - vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request_extension); - } else { - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request_extension, - VmbusPacketTypeDataInBand, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - } - - if (ret != 0) { - DPRINT_DBG(STORVSC, "Unable to send packet %p ret %d", - vstor_packet, ret); - } - - atomic_inc(&stor_device->num_outstanding_req); - - put_stor_device(device); - return ret; -} - -/* - * stor_vsc_on_cleanup - Perform any cleanup when the driver is removed - */ -static void stor_vsc_on_cleanup(struct hv_driver *driver) -{ -} - -/* - * stor_vsc_initialize - Main entry point - */ -int stor_vsc_initialize(struct hv_driver *driver) -{ - 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->deviceType, &gStorVscDeviceType, - 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_UP(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.OnDeviceAdd = stor_vsc_on_device_add; - stor_driver->base.OnDeviceRemove = stor_vsc_on_device_remove; - stor_driver->base.OnCleanup = stor_vsc_on_cleanup; - - stor_driver->on_io_request = stor_vsc_on_io_request; - - return 0; -} diff --git a/drivers/staging/hv/storvsc_api.h b/drivers/staging/hv/storvsc_api.h deleted file mode 100644 index fbf57556d89..00000000000 --- 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 deleted file mode 100644 index 17f1b344fbc..00000000000 --- a/drivers/staging/hv/storvsc_drv.c +++ /dev/null @@ -1,956 +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/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/blkdev.h> -#include <scsi/scsi.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_tcq.h> -#include <scsi/scsi_eh.h> -#include <scsi/scsi_devinfo.h> -#include <scsi/scsi_dbg.h> -#include "osd.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 vm_device *device_ctx; - struct kmem_cache *request_pool; - unsigned int port; - unsigned char path; - unsigned char target; -}; - -struct storvsc_cmd_request { - struct list_head entry; - struct scsi_cmnd *cmd; - - unsigned int bounce_sgl_count; - struct scatterlist *bounce_sgl; - - struct hv_storvsc_request request; - /* !!!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... */ -}; - -struct storvsc_driver_context { - /* !! These must be the first 2 fields !! */ - /* FIXME this is a bug... */ - struct driver_context drv_ctx; - struct storvsc_driver_object drv_obj; -}; - -/* 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_context 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, - /* - * ENABLE_CLUSTERING allows mutiple physically contig bio_vecs to merge - * into 1 sg element. If set, we must limit the max_segment_size to - * PAGE_SIZE, otherwise we may get 1 sg element that represents - * multiple - */ - /* physically contig pfns (ie sg[x].length > PAGE_SIZE). */ - .use_clustering = ENABLE_CLUSTERING, - /* 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.drv_obj; - struct driver_context *drv_ctx = &g_storvsc_drv.drv_ctx; - - storvsc_drv_obj->ring_buffer_size = storvsc_ringbuffer_size; - - /* Callback to client driver to complete the initialization */ - drv_init(&storvsc_drv_obj->base); - - 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_ctx->driver.name = storvsc_drv_obj->base.name; - memcpy(&drv_ctx->class_id, &storvsc_drv_obj->base.deviceType, - sizeof(struct hv_guid)); - - drv_ctx->probe = storvsc_probe; - drv_ctx->remove = storvsc_remove; - - /* The driver belongs to vmbus */ - ret = vmbus_child_driver_register(drv_ctx); - - 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.drv_obj; - struct driver_context *drv_ctx = &g_storvsc_drv.drv_ctx; - struct device *current_dev = NULL; - int ret; - - while (1) { - current_dev = NULL; - - /* Get the device */ - ret = driver_for_each_device(&drv_ctx->driver, NULL, - (void *) ¤t_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.OnCleanup) - storvsc_drv_obj->base.OnCleanup(&storvsc_drv_obj->base); - - vmbus_child_driver_unregister(drv_ctx); - return; -} - -/* - * storvsc_probe - Add a new device for this driver - */ -static int storvsc_probe(struct device *device) -{ - int ret; - struct driver_context *driver_ctx = - driver_to_driver_context(device->driver); - struct storvsc_driver_context *storvsc_drv_ctx = - (struct storvsc_driver_context *)driver_ctx; - struct storvsc_driver_object *storvsc_drv_obj = - &storvsc_drv_ctx->drv_obj; - struct vm_device *device_ctx = device_to_vm_device(device); - struct hv_device *device_obj = &device_ctx->device_obj; - struct Scsi_Host *host; - struct host_device_context *host_device_ctx; - struct storvsc_device_info device_info; - - if (!storvsc_drv_obj->base.OnDeviceAdd) - 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_ctx; - - host_device_ctx->request_pool = - kmem_cache_create(dev_name(&device_ctx->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.OnDeviceAdd(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.OnDeviceRemove(device_obj); - - kmem_cache_destroy(host_device_ctx->request_pool); - scsi_host_put(host); - return -1; - } - - scsi_scan_host(host); - return ret; -} - -/* - * storvsc_remove - Callback when our device is removed - */ -static int storvsc_remove(struct device *device) -{ - int ret; - struct driver_context *driver_ctx = - driver_to_driver_context(device->driver); - struct storvsc_driver_context *storvsc_drv_ctx = - (struct storvsc_driver_context *)driver_ctx; - struct storvsc_driver_object *storvsc_drv_obj = - &storvsc_drv_ctx->drv_obj; - struct vm_device *device_ctx = device_to_vm_device(device); - struct hv_device *device_obj = &device_ctx->device_obj; - 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.OnDeviceRemove) - return -1; - - /* - * Call to the vsc driver to let it know that the device is being - * removed - */ - ret = storvsc_drv_obj->base.OnDeviceRemove(device_obj); - if (ret != 0) { - /* TODO: */ - DPRINT_ERR(STORVSC, "unable to remove vsc device (ret %d)", - ret); - } - - if (host_device_ctx->request_pool) { - kmem_cache_destroy(host_device_ctx->request_pool); - host_device_ctx->request_pool = NULL; - } - - DPRINT_INFO(STORVSC, "removing host adapter (%p)...", host); - scsi_remove_host(host); - - DPRINT_INFO(STORVSC, "releasing host adapter (%p)...", host); - scsi_host_put(host); - 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 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; - - if (scmnd->result) { - if (scsi_normalize_sense(scmnd->sense_buffer, - request->sense_buffer_size, &sense_hdr)) - scsi_print_sense_hdr("storvsc", &sense_hdr); - } - - /* ASSERT(request->BytesXfer <= request->data_buffer.Length); */ - scsi_set_resid(scmnd, - request->data_buffer.Length - 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); -} - -static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count) -{ - int i; - - /* No need to check */ - if (sg_count < 2) - return -1; - - /* We have at least 2 sg entries */ - for (i = 0; i < sg_count; i++) { - if (i == 0) { - /* make sure 1st one does not have hole */ - if (sgl[i].offset + sgl[i].length != PAGE_SIZE) - return i; - } else if (i == sg_count - 1) { - /* make sure last one does not have hole */ - if (sgl[i].offset != 0) - return i; - } else { - /* make sure no hole in the middle */ - if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0) - return i; - } - } - return -1; -} - -static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count, - unsigned int len) -{ - int i; - int num_pages; - struct scatterlist *bounce_sgl; - struct page *page_buf; - - num_pages = ALIGN_UP(len, PAGE_SIZE) >> PAGE_SHIFT; - - bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC); - if (!bounce_sgl) - return NULL; - - for (i = 0; i < num_pages; i++) { - page_buf = alloc_page(GFP_ATOMIC); - if (!page_buf) - goto cleanup; - sg_set_page(&bounce_sgl[i], page_buf, 0, 0); - } - - return bounce_sgl; - -cleanup: - destroy_bounce_buffer(bounce_sgl, num_pages); - return NULL; -} - -static void destroy_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count) -{ - int i; - struct page *page_buf; - - for (i = 0; i < sg_count; i++) { - page_buf = sg_page((&sgl[i])); - if (page_buf != NULL) - __free_page(page_buf); - } - - kfree(sgl); -} - -/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */ -static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, - struct scatterlist *bounce_sgl, - unsigned int orig_sgl_count) -{ - int i; - int j = 0; - unsigned long src, dest; - unsigned int srclen, destlen, copylen; - unsigned int total_copied = 0; - unsigned long bounce_addr = 0; - unsigned long src_addr = 0; - unsigned long flags; - - local_irq_save(flags); - - for (i = 0; i < orig_sgl_count; i++) { - src_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])), - KM_IRQ0) + orig_sgl[i].offset; - src = src_addr; - srclen = orig_sgl[i].length; - - /* 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); - - while (srclen) { - /* assume bounce offset always == 0 */ - dest = bounce_addr + bounce_sgl[j].length; - destlen = PAGE_SIZE - bounce_sgl[j].length; - - copylen = min(srclen, destlen); - memcpy((void *)dest, (void *)src, copylen); - - total_copied += copylen; - bounce_sgl[j].length += copylen; - srclen -= copylen; - src += copylen; - - if (bounce_sgl[j].length == PAGE_SIZE) { - /* full..move to next entry */ - kunmap_atomic((void *)bounce_addr, KM_IRQ0); - j++; - - /* if we need to use another bounce buffer */ - if (srclen || i != orig_sgl_count - 1) - bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0); - } else if (srclen == 0 && i == orig_sgl_count - 1) { - /* unmap the last bounce that is < PAGE_SIZE */ - kunmap_atomic((void *)bounce_addr, KM_IRQ0); - } - } - - kunmap_atomic((void *)(src_addr - orig_sgl[i].offset), KM_IRQ0); - } - - local_irq_restore(flags); - - return total_copied; -} - -/* 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; - int j = 0; - unsigned long src, dest; - unsigned int srclen, destlen, copylen; - unsigned int total_copied = 0; - unsigned long bounce_addr = 0; - unsigned long dest_addr = 0; - unsigned long flags; - - local_irq_save(flags); - - for (i = 0; i < orig_sgl_count; i++) { - dest_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])), - KM_IRQ0) + orig_sgl[i].offset; - dest = dest_addr; - destlen = orig_sgl[i].length; - /* 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); - - 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); - } - - local_irq_restore(flags); - - return total_copied; -} - -/* - * storvsc_queuecommand - Initiate command processing - */ -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 vm_device *device_ctx = host_device_ctx->device_ctx; - struct driver_context *driver_ctx = - driver_to_driver_context(device_ctx->device.driver); - struct storvsc_driver_context *storvsc_drv_ctx = - (struct storvsc_driver_context *)driver_ctx; - struct storvsc_driver_object *storvsc_drv_obj = - &storvsc_drv_ctx->drv_obj; - 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; - - 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; - DPRINT_INFO(STORVSC_DRV, "retrying scmnd %p cmd_request %p", - scmnd, cmd_request); - - 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, - 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; - } - - /* Setup the cmd request */ - cmd_request->bounce_sgl_count = 0; - cmd_request->bounce_sgl = NULL; - cmd_request->cmd = scmnd; - - scmnd->host_scribble = (unsigned char *)cmd_request; - - request = &cmd_request->request; - - 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; - break; - case DMA_FROM_DEVICE: - request->type = READ_TYPE; - break; - default: - request->type = 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; - - /* ASSERT(scmnd->cmd_len <= 16); */ - request->cdb_len = scmnd->cmd_len; - request->cdb = scmnd->cmnd; - - request->sense_buffer = scmnd->sense_buffer; - request->sense_buffer_size = SCSI_SENSE_BUFFERSIZE; - - - request->data_buffer.Length = scsi_bufflen(scmnd); - if (scsi_sg_count(scmnd)) { - sgl = (struct scatterlist *)scsi_sglist(scmnd); - sg_count = scsi_sg_count(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, - cmd_request); - - return SCSI_MLQUEUE_HOST_BUSY; - } - - cmd_request->bounce_sgl_count = - ALIGN_UP(scsi_bufflen(scmnd), PAGE_SIZE) >> - PAGE_SHIFT; - - /* - * FIXME: We can optimize on reads by just skipping - * this - */ - copy_to_bounce_buffer(sgl, cmd_request->bounce_sgl, - scsi_sg_count(scmnd)); - - sgl = cmd_request->bounce_sgl; - sg_count = cmd_request->bounce_sgl_count; - } - - 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); - request->data_buffer.PfnArray[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.PfnArray[0] = - virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT; - } - -retry_request: - /* Invokes the vsc to start an IO */ - ret = storvsc_drv_obj->on_io_request(&device_ctx->device_obj, - &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) { - /* - * 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); - } - - kmem_cache_free(host_device_ctx->request_pool, cmd_request); - - scmnd->scsi_done = NULL; - scmnd->host_scribble = NULL; - - ret = SCSI_MLQUEUE_DEVICE_BUSY; - } - - return ret; -} - -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); - /* - * This enables luns to be located sparsely. Otherwise, we may not - * discovered them. - */ - sdevice->sdev_bflags |= BLIST_SPARSELUN | BLIST_LARGELUN; - return 0; -} - -static int storvsc_device_configure(struct scsi_device *sdevice) -{ - DPRINT_INFO(STORVSC_DRV, "sdev (%p) - curr queue depth %d", sdevice, - sdevice->queue_depth); - - 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); - - 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); - - DPRINT_INFO(STORVSC_DRV, "sdev (%p) - adding merge bio vec routine", - sdevice); - blk_queue_merge_bvec(sdevice->request_queue, storvsc_merge_bvec); - - blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY); - /* sdevice->timeout = (2000 * HZ);//(75 * HZ); */ - - return 0; -} - -/* - * 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 vm_device *device_ctx = host_device_ctx->device_ctx; - - DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host resetting...", - scmnd->device, &device_ctx->device_obj); - - /* Invokes the vsc to reset the host/bus */ - ret = stor_vsc_on_host_reset(&device_ctx->device_obj); - if (ret != 0) - return ret; - - DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host reseted", - scmnd->device, &device_ctx->device_obj); - - return ret; -} - -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; - - int sectors_per_track = 0; - int heads = 0; - int cylinders = 0; - int rem = 0; - - if (total_sectors > (65535 * 16 * 255)) - total_sectors = (65535 * 16 * 255); - - if (total_sectors >= (65535 * 16 * 63)) { - sectors_per_track = 255; - heads = 16; - - 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); - - temp = cylinder_times_heads + 1023; - /* sector_div stores the quotient in temp */ - rem = sector_div(temp, 1024); - - heads = temp; - - if (heads < 4) - heads = 4; - - if (cylinder_times_heads >= (heads * 1024) || (heads > 16)) { - sectors_per_track = 31; - heads = 16; - - cylinder_times_heads = total_sectors; - /* - * sector_div stores the quotient in - * cylinder_times_heads - */ - rem = sector_div(cylinder_times_heads, - sectors_per_track); - } - - if (cylinder_times_heads >= (heads * 1024)) { - sectors_per_track = 63; - heads = 16; - - cylinder_times_heads = total_sectors; - /* - * sector_div stores the quotient in - * cylinder_times_heads - */ - rem = sector_div(cylinder_times_heads, - sectors_per_track); - } - } - - 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; - - DPRINT_INFO(STORVSC_DRV, "CHS (%d, %d, %d)", cylinders, heads, - sectors_per_track); - - return 0; -} - -static int __init storvsc_init(void) -{ - int ret; - - DPRINT_INFO(STORVSC_DRV, "Storvsc initializing...."); - ret = storvsc_drv_init(stor_vsc_initialize); - return ret; -} - -static void __exit storvsc_exit(void) -{ - storvsc_drv_exit(); -} - -MODULE_LICENSE("GPL"); -MODULE_VERSION(HV_DRV_VERSION); -MODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver"); -module_init(storvsc_init); -module_exit(storvsc_exit); diff --git a/drivers/staging/hv/utils.h b/drivers/staging/hv/utils.h deleted file mode 100644 index 7c0749999a6..00000000000 --- a/drivers/staging/hv/utils.h +++ /dev/null @@ -1,119 +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; -} __attribute__((packed)); - -struct ic_version { - u16 major; - u16 minor; -} __attribute__((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]; -} __attribute__((packed)); - -struct icmsg_negotiate { - u16 icframe_vercnt; - u16 icmsg_vercnt; - u32 reserved; - struct ic_version icversion_data[1]; /* any size array */ -} __attribute__((packed)); - -struct shutdown_msg_data { - u32 reason_code; - u32 timeout_seconds; - u32 flags; - u8 display_message[2048]; -} __attribute__((packed)); - -struct heartbeat_msg_data { - u64 seq_num; - u32 reserved[8]; -} __attribute__((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; -} __attribute__((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 - -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 35178f2c796..00000000000 --- 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 42f2adb9954..00000000000 --- a/drivers/staging/hv/vmbus.h +++ /dev/null @@ -1,77 +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" - -struct driver_context { - struct hv_guid class_id; - - struct device_driver driver; - - /* - * Use these methods instead of the struct device_driver so 2.6 kernel - * stops complaining - * TODO - fix this! - */ - int (*probe)(struct device *); - int (*remove)(struct device *); - void (*shutdown)(struct device *); -}; - -struct vm_device { - struct work_struct probe_failed_work_item; - struct hv_guid class_id; - struct hv_guid device_id; - int probe_error; - struct hv_device device_obj; - struct device device; -}; - -static inline struct vm_device *to_vm_device(struct hv_device *d) -{ - return container_of(d, struct vm_device, device_obj); -} - -static inline struct vm_device *device_to_vm_device(struct device *d) -{ - return container_of(d, struct vm_device, device); -} - -static inline struct driver_context *driver_to_driver_context(struct device_driver *d) -{ - return container_of(d, struct driver_context, driver); -} - - -/* Vmbus interface */ -int vmbus_child_driver_register(struct driver_context *driver_ctx); -void vmbus_child_driver_unregister(struct driver_context *driver_ctx); - -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 2da3f52610b..00000000000 --- a/drivers/staging/hv/vmbus_api.h +++ /dev/null @@ -1,118 +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_ - -#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 Length; - u32 Offset; - u64 Pfn; -}; - -/* Multiple-page buffer */ -struct hv_multipage_buffer { - /* Length and Offset determines the # of pfns in the array */ - u32 Length; - u32 Offset; - u64 PfnArray[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 InterruptMask; - u32 ReadIndex; - u32 WriteIndex; - u32 BytesAvailToRead; - u32 BytesAvailToWrite; -}; - -struct hv_device_info { - u32 ChannelId; - u32 ChannelState; - struct hv_guid ChannelType; - struct hv_guid ChannelInstance; - - u32 MonitorId; - u32 ServerMonitorPending; - u32 ServerMonitorLatency; - u32 ServerMonitorConnectionId; - u32 ClientMonitorPending; - u32 ClientMonitorLatency; - u32 ClientMonitorConnectionId; - - 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 deviceType; - - int (*OnDeviceAdd)(struct hv_device *device, void *data); - int (*OnDeviceRemove)(struct hv_device *device); - void (*OnCleanup)(struct hv_driver *driver); -}; - -/* Base device object */ -struct hv_device { - /* the driver for this device */ - struct hv_driver *Driver; - - char name[64]; - - /* the device type id of this device */ - struct hv_guid deviceType; - - /* the device instance id of this device */ - struct hv_guid deviceInstance; - - struct vmbus_channel *channel; - - /* Device extension; */ - void *Extension; -}; - -#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 26742823748..00000000000 --- 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 InterfaceType; - struct hv_guid InterfaceInstance; - u64 InterruptLatencyIn100nsUnits; - u32 InterfaceRevision; - u32 ServerContextAreaSize; /* in bytes */ - u16 ChannelFlags; - u16 MmioMegabytes; /* in bytes * 1024 * 1024 */ - - union { - /* Non-pipes: The user has MAX_USER_DEFINED_BYTES bytes. */ - struct { - unsigned char UserDefined[MAX_USER_DEFINED_BYTES]; - } Standard; - - /* - * 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 PipeMode; - unsigned char UserDefined[MAX_PIPE_USER_DEFINED_BYTES]; - } Pipe; - } u; - u32 Padding; -} __attribute__((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 deleted file mode 100644 index 84fdb64d3ce..00000000000 --- a/drivers/staging/hv/vmbus_drv.c +++ /dev/null @@ -1,1123 +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/init.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/sysctl.h> -#include <linux/pci.h> -#include <linux/dmi.h> -#include <linux/slab.h> -#include <linux/completion.h> -#include "version_info.h" -#include "osd.h" -#include "logging.h" -#include "vmbus.h" -#include "channel.h" -#include "vmbus_private.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 { - /* !! These must be the first 2 fields !! */ - /* FIXME, this is a bug */ - /* The driver field is not used in here. Instead, the bus field is */ - /* used to represent the driver */ - struct driver_context drv_ctx; - struct hv_driver drv_obj; - - struct bus_type bus; - struct tasklet_struct msg_dpc; - struct tasklet_struct event_dpc; - - /* The bus root device */ - struct vm_device device_ctx; -}; - -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); -static void vmbus_msg_dpc(unsigned long data); -static void vmbus_event_dpc(unsigned long data); - -static irqreturn_t vmbus_isr(int irq, void *dev_id); - -static void vmbus_device_release(struct device *device); -static void vmbus_bus_release(struct device *device); - -static ssize_t vmbus_show_device_attr(struct device *dev, - struct device_attribute *dev_attr, - char *buf); - - -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 vmbus_irq = VMBUS_IRQ; - -/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */ -static struct device_attribute vmbus_device_attrs[] = { - __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL), - - __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), - - __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), - - __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), - - __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), - __ATTR_NULL -}; - -/* The one and only one */ -static struct vmbus_driver_context g_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 *gDriverName = "hyperv"; - -/* - * Windows vmbus does not defined this. - * We defined this to be consistent with other devices - */ -/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */ -static const struct hv_guid gVmbusDeviceType = { - .data = { - 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, - 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85 - } -}; - -/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */ -static const struct hv_guid gVmbusDeviceId = { - .data = { - 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, - 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5 - } -}; - -static struct hv_device *gDevice; /* vmbus root device */ - -/* - * VmbusChildDeviceAdd - Registers the child device with the vmbus - */ -int VmbusChildDeviceAdd(struct hv_device *ChildDevice) -{ - return vmbus_child_device_register(gDevice, ChildDevice); -} - -/* - * VmbusOnDeviceAdd - Callback when the root bus device is added - */ -static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo) -{ - u32 *irqvector = AdditionalInfo; - int ret; - - gDevice = dev; - - memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); - memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, - sizeof(struct hv_guid)); - - /* strcpy(dev->name, "vmbus"); */ - /* SynIC setup... */ - on_each_cpu(hv_synic_init, (void *)irqvector, 1); - - /* Connect to VMBus in the root partition */ - ret = VmbusConnect(); - - /* VmbusSendEvent(device->localPortId+1); */ - return ret; -} - -/* - * VmbusOnDeviceRemove - Callback when the root bus device is removed - */ -static int VmbusOnDeviceRemove(struct hv_device *dev) -{ - int ret = 0; - - vmbus_release_unattached_channels(); - VmbusDisconnect(); - on_each_cpu(hv_synic_cleanup, NULL, 1); - return ret; -} - -/* - * VmbusOnCleanup - Perform any cleanup when the driver is removed - */ -static void VmbusOnCleanup(struct hv_driver *drv) -{ - /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */ - - hv_cleanup(); -} - -struct onmessage_work_context { - struct work_struct work; - struct hv_message msg; -}; - -static void vmbus_onmessage_work(struct work_struct *work) -{ - struct onmessage_work_context *ctx; - - ctx = container_of(work, struct onmessage_work_context, - work); - vmbus_onmessage(&ctx->msg); - kfree(ctx); -} - -/* - * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior - */ -static void vmbus_on_msg_dpc(struct hv_driver *drv) -{ - int cpu = smp_processor_id(); - void *page_addr = hv_context.synic_message_page[cpu]; - struct hv_message *msg = (struct hv_message *)page_addr + - VMBUS_MESSAGE_SINT; - struct onmessage_work_context *ctx; - - while (1) { - if (msg->header.message_type == HVMSG_NONE) { - /* no msg */ - break; - } else { - ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC); - if (ctx == NULL) - continue; - INIT_WORK(&ctx->work, vmbus_onmessage_work); - memcpy(&ctx->msg, msg, sizeof(*msg)); - queue_work(gVmbusConnection.WorkQueue, &ctx->work); - } - - msg->header.message_type = HVMSG_NONE; - - /* - * Make sure the write to MessageType (ie set to - * HVMSG_NONE) happens before we read the - * MessagePending and EOMing. Otherwise, the EOMing - * will not deliver any more messages since there is - * no empty slot - */ - mb(); - - if (msg->header.message_flags.msg_pending) { - /* - * This will cause message queue rescan to - * possibly deliver another msg from the - * hypervisor - */ - wrmsrl(HV_X64_MSR_EOM, 0); - } - } -} - -/* - * vmbus_on_isr - ISR routine - */ -static int vmbus_on_isr(struct hv_driver *drv) -{ - int ret = 0; - int cpu = smp_processor_id(); - void *page_addr; - struct hv_message *msg; - union hv_synic_event_flags *event; - - page_addr = hv_context.synic_message_page[cpu]; - 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); - 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 (test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) { - DPRINT_DBG(VMBUS, "received event %d", 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->ChannelId = debug_info.relid; - info->ChannelState = debug_info.state; - memcpy(&info->ChannelType, &debug_info.interfacetype, - sizeof(struct hv_guid)); - memcpy(&info->ChannelInstance, &debug_info.interface_instance, - sizeof(struct hv_guid)); - - info->MonitorId = debug_info.monitorid; - - info->ServerMonitorPending = debug_info.servermonitor_pending; - info->ServerMonitorLatency = debug_info.servermonitor_latency; - info->ServerMonitorConnectionId = debug_info.servermonitor_connectionid; - - info->ClientMonitorPending = debug_info.clientmonitor_pending; - info->ClientMonitorLatency = debug_info.clientmonitor_latency; - info->ClientMonitorConnectionId = debug_info.clientmonitor_connectionid; - - info->Inbound.InterruptMask = debug_info.inbound.current_interrupt_mask; - info->Inbound.ReadIndex = debug_info.inbound.current_read_index; - info->Inbound.WriteIndex = debug_info.inbound.current_write_index; - info->Inbound.BytesAvailToRead = debug_info.inbound.bytes_avail_toread; - info->Inbound.BytesAvailToWrite = - debug_info.inbound.bytes_avail_towrite; - - info->Outbound.InterruptMask = - debug_info.outbound.current_interrupt_mask; - info->Outbound.ReadIndex = debug_info.outbound.current_read_index; - info->Outbound.WriteIndex = debug_info.outbound.current_write_index; - info->Outbound.BytesAvailToRead = - debug_info.outbound.bytes_avail_toread; - info->Outbound.BytesAvailToWrite = - 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) -{ - struct vm_device *device_ctx = device_to_vm_device(dev); - struct hv_device_info device_info; - - memset(&device_info, 0, sizeof(struct hv_device_info)); - - get_channel_info(&device_ctx->device_obj, &device_info); - - 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.ChannelType.data[3], - device_info.ChannelType.data[2], - device_info.ChannelType.data[1], - device_info.ChannelType.data[0], - device_info.ChannelType.data[5], - device_info.ChannelType.data[4], - device_info.ChannelType.data[7], - device_info.ChannelType.data[6], - device_info.ChannelType.data[8], - device_info.ChannelType.data[9], - device_info.ChannelType.data[10], - device_info.ChannelType.data[11], - device_info.ChannelType.data[12], - device_info.ChannelType.data[13], - device_info.ChannelType.data[14], - device_info.ChannelType.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.ChannelInstance.data[3], - device_info.ChannelInstance.data[2], - device_info.ChannelInstance.data[1], - device_info.ChannelInstance.data[0], - device_info.ChannelInstance.data[5], - device_info.ChannelInstance.data[4], - device_info.ChannelInstance.data[7], - device_info.ChannelInstance.data[6], - device_info.ChannelInstance.data[8], - device_info.ChannelInstance.data[9], - device_info.ChannelInstance.data[10], - device_info.ChannelInstance.data[11], - device_info.ChannelInstance.data[12], - device_info.ChannelInstance.data[13], - device_info.ChannelInstance.data[14], - device_info.ChannelInstance.data[15]); - } else if (!strcmp(dev_attr->attr.name, "state")) { - return sprintf(buf, "%d\n", device_info.ChannelState); - } else if (!strcmp(dev_attr->attr.name, "id")) { - return sprintf(buf, "%d\n", device_info.ChannelId); - } else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) { - return sprintf(buf, "%d\n", device_info.Outbound.InterruptMask); - } else if (!strcmp(dev_attr->attr.name, "out_read_index")) { - return sprintf(buf, "%d\n", device_info.Outbound.ReadIndex); - } else if (!strcmp(dev_attr->attr.name, "out_write_index")) { - return sprintf(buf, "%d\n", device_info.Outbound.WriteIndex); - } else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) { - return sprintf(buf, "%d\n", - device_info.Outbound.BytesAvailToRead); - } else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) { - return sprintf(buf, "%d\n", - device_info.Outbound.BytesAvailToWrite); - } else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) { - return sprintf(buf, "%d\n", device_info.Inbound.InterruptMask); - } else if (!strcmp(dev_attr->attr.name, "in_read_index")) { - return sprintf(buf, "%d\n", device_info.Inbound.ReadIndex); - } else if (!strcmp(dev_attr->attr.name, "in_write_index")) { - return sprintf(buf, "%d\n", device_info.Inbound.WriteIndex); - } else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) { - return sprintf(buf, "%d\n", - device_info.Inbound.BytesAvailToRead); - } else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) { - return sprintf(buf, "%d\n", - device_info.Inbound.BytesAvailToWrite); - } else if (!strcmp(dev_attr->attr.name, "monitor_id")) { - return sprintf(buf, "%d\n", device_info.MonitorId); - } else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) { - return sprintf(buf, "%d\n", device_info.ServerMonitorPending); - } else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) { - return sprintf(buf, "%d\n", device_info.ServerMonitorLatency); - } else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) { - return sprintf(buf, "%d\n", - device_info.ServerMonitorConnectionId); - } else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) { - return sprintf(buf, "%d\n", device_info.ClientMonitorPending); - } else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) { - return sprintf(buf, "%d\n", device_info.ClientMonitorLatency); - } else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) { - return sprintf(buf, "%d\n", - device_info.ClientMonitorConnectionId); - } else { - return 0; - } -} - -/* - * vmbus_bus_init -Main vmbus driver initialization routine. - * - * 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) -{ - struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv; - struct hv_driver *driver = &g_vmbus_drv.drv_obj; - struct vm_device *dev_ctx = &g_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)); - - driver->name = gDriverName; - memcpy(&driver->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); - - /* Setup dispatch table */ - driver->OnDeviceAdd = VmbusOnDeviceAdd; - driver->OnDeviceRemove = VmbusOnDeviceRemove; - driver->OnCleanup = VmbusOnCleanup; - - /* Hypervisor initialization...setup hypercall page..etc */ - ret = hv_init(); - if (ret != 0) { - DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", - ret); - goto cleanup; - } - - /* Sanity checks */ - if (!driver->OnDeviceAdd) { - DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set"); - ret = -1; - goto cleanup; - } - - vmbus_drv_ctx->bus.name = driver->name; - - /* Initialize the bus context */ - tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc, - (unsigned long)driver); - tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc, - (unsigned long)driver); - - /* Now, register the bus driver with LDM */ - ret = bus_register(&vmbus_drv_ctx->bus); - if (ret) { - ret = -1; - goto cleanup; - } - - /* Get the interrupt resource */ - ret = request_irq(vmbus_irq, vmbus_isr, IRQF_SAMPLE_RANDOM, - driver->name, NULL); - - if (ret != 0) { - DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", - vmbus_irq); - - bus_unregister(&vmbus_drv_ctx->bus); - - ret = -1; - goto cleanup; - } - vector = VMBUS_IRQ_VECTOR; - - DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector); - - /* Call to bus driver to add the root device */ - memset(dev_ctx, 0, sizeof(struct vm_device)); - - ret = driver->OnDeviceAdd(&dev_ctx->device_obj, &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"); - memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.deviceType, - sizeof(struct hv_guid)); - memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.deviceInstance, - sizeof(struct hv_guid)); - - /* 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; - - /* Setup the bus as root device */ - ret = device_register(&dev_ctx->device); - 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; - 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 hv_driver *driver = &g_vmbus_drv.drv_obj; - struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv; - - struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx; - - /* Remove the root device */ - if (driver->OnDeviceRemove) - driver->OnDeviceRemove(&dev_ctx->device_obj); - - if (driver->OnCleanup) - driver->OnCleanup(driver); - - /* 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 - * @driver_ctx: Pointer to driver structure you want to register - * - * @driver_ctx is of type &struct driver_context - * - * Registers the given driver with Linux through the 'driver_register()' call - * And sets up the hyper-v vmbus handling for this driver. - * It will return the state of the 'driver_register()' call. - * - * Mainly used by Hyper-V drivers. - */ -int vmbus_child_driver_register(struct driver_context *driver_ctx) -{ - int ret; - - DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", - driver_ctx, driver_ctx->driver.name); - - /* The child driver on this vmbus */ - driver_ctx->driver.bus = &g_vmbus_drv.bus; - - ret = driver_register(&driver_ctx->driver); - - vmbus_request_offers(); - - return ret; -} -EXPORT_SYMBOL(vmbus_child_driver_register); - -/** - * vmbus_child_driver_unregister() - Unregister a vmbus's child driver - * @driver_ctx: Pointer to driver structure you want to un-register - * - * @driver_ctx is of type &struct driver_context - * - * Un-register the given driver with Linux through the 'driver_unregister()' - * call. And ungegisters the driver from the Hyper-V vmbus handler. - * - * Mainly used by Hyper-V drivers. - */ -void vmbus_child_driver_unregister(struct driver_context *driver_ctx) -{ - DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s", - driver_ctx, driver_ctx->driver.name); - - driver_unregister(&driver_ctx->driver); - - driver_ctx->driver.bus = NULL; -} -EXPORT_SYMBOL(vmbus_child_driver_unregister); - -/* - * vmbus_child_device_create - Creates and registers a new child device - * on the vmbus. - */ -struct hv_device *vmbus_child_device_create(struct hv_guid *type, - struct hv_guid *instance, - struct vmbus_channel *channel) -{ - struct vm_device *child_device_ctx; - struct hv_device *child_device_obj; - - /* Allocate the new child device */ - child_device_ctx = kzalloc(sizeof(struct vm_device), GFP_KERNEL); - if (!child_device_ctx) { - DPRINT_ERR(VMBUS_DRV, - "unable to allocate device_context for child device"); - 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_ctx->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 = &child_device_ctx->device_obj; - child_device_obj->channel = channel; - memcpy(&child_device_obj->deviceType, type, sizeof(struct hv_guid)); - memcpy(&child_device_obj->deviceInstance, instance, - sizeof(struct hv_guid)); - - memcpy(&child_device_ctx->class_id, type, sizeof(struct hv_guid)); - memcpy(&child_device_ctx->device_id, instance, sizeof(struct hv_guid)); - - return child_device_obj; -} - -/* - * vmbus_child_device_register - Register the child device on the specified bus - */ -int vmbus_child_device_register(struct hv_device *root_device_obj, - struct hv_device *child_device_obj) -{ - int ret = 0; - struct vm_device *root_device_ctx = - to_vm_device(root_device_obj); - struct vm_device *child_device_ctx = - to_vm_device(child_device_obj); - static atomic_t device_num = ATOMIC_INIT(0); - - DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", - child_device_ctx); - - /* Set the device name. Otherwise, device_register() will fail. */ - dev_set_name(&child_device_ctx->device, "vmbus_0_%d", - atomic_inc_return(&device_num)); - - /* The new device belongs to this bus */ - child_device_ctx->device.bus = &g_vmbus_drv.bus; /* device->dev.bus; */ - child_device_ctx->device.parent = &root_device_ctx->device; - child_device_ctx->device.release = vmbus_device_release; - - /* - * Register with the LDM. This will kick off the driver/device - * binding...which will eventually call vmbus_match() and vmbus_probe() - */ - ret = device_register(&child_device_ctx->device); - - /* vmbus_probe() error does not get propergate to device_register(). */ - ret = child_device_ctx->probe_error; - - if (ret) - DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p)", - &child_device_ctx->device); - else - DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", - &child_device_ctx->device); - - return ret; -} - -/* - * vmbus_child_device_unregister - Remove the specified child device - * from the vmbus. - */ -void vmbus_child_device_unregister(struct hv_device *device_obj) -{ - struct vm_device *device_ctx = to_vm_device(device_obj); - - DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)", - &device_ctx->device); - - /* - * Kick off the process of unregistering the device. - * This will call vmbus_remove() and eventually vmbus_device_release() - */ - device_unregister(&device_ctx->device); - - DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered", - &device_ctx->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 vm_device *device_ctx = device_to_vm_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}", - device_ctx->class_id.data[3], device_ctx->class_id.data[2], - device_ctx->class_id.data[1], device_ctx->class_id.data[0], - device_ctx->class_id.data[5], device_ctx->class_id.data[4], - device_ctx->class_id.data[7], device_ctx->class_id.data[6], - device_ctx->class_id.data[8], device_ctx->class_id.data[9], - device_ctx->class_id.data[10], - device_ctx->class_id.data[11], - device_ctx->class_id.data[12], - device_ctx->class_id.data[13], - device_ctx->class_id.data[14], - device_ctx->class_id.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}", - device_ctx->class_id.data[3], - device_ctx->class_id.data[2], - device_ctx->class_id.data[1], - device_ctx->class_id.data[0], - device_ctx->class_id.data[5], - device_ctx->class_id.data[4], - device_ctx->class_id.data[7], - device_ctx->class_id.data[6], - device_ctx->class_id.data[8], - device_ctx->class_id.data[9], - device_ctx->class_id.data[10], - device_ctx->class_id.data[11], - device_ctx->class_id.data[12], - device_ctx->class_id.data[13], - device_ctx->class_id.data[14], - device_ctx->class_id.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}", - device_ctx->device_id.data[3], - device_ctx->device_id.data[2], - device_ctx->device_id.data[1], - device_ctx->device_id.data[0], - device_ctx->device_id.data[5], - device_ctx->device_id.data[4], - device_ctx->device_id.data[7], - device_ctx->device_id.data[6], - device_ctx->device_id.data[8], - device_ctx->device_id.data[9], - device_ctx->device_id.data[10], - device_ctx->device_id.data[11], - device_ctx->device_id.data[12], - device_ctx->device_id.data[13], - device_ctx->device_id.data[14], - device_ctx->device_id.data[15]); - if (ret) - return ret; - - return 0; -} - -/* - * 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 driver_context *driver_ctx = driver_to_driver_context(driver); - struct vm_device *device_ctx = device_to_vm_device(device); - - /* We found our driver ? */ - if (memcmp(&device_ctx->class_id, &driver_ctx->class_id, - sizeof(struct hv_guid)) == 0) { - /* - * !! NOTE: The driver_ctx is not a vmbus_drv_ctx. We typecast - * it here to access the struct hv_driver field - */ - struct vmbus_driver_context *vmbus_drv_ctx = - (struct vmbus_driver_context *)driver_ctx; - - device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj; - DPRINT_INFO(VMBUS_DRV, - "device object (%p) set to driver object (%p)", - &device_ctx->device_obj, - device_ctx->device_obj.Driver); - - 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) -{ - struct vm_device *device_ctx = (struct vm_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 driver_context *driver_ctx = - driver_to_driver_context(child_device->driver); - struct vm_device *device_ctx = - device_to_vm_device(child_device); - - /* Let the specific open-source driver handles the probe if it can */ - if (driver_ctx->probe) { - ret = device_ctx->probe_error = driver_ctx->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(&device_ctx->probe_failed_work_item, - vmbus_probe_failed_cb); - schedule_work(&device_ctx->probe_failed_work_item); - } - } else { - DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s", - child_device->driver->name); - ret = -1; - } - return ret; -} - -/* - * vmbus_remove - Remove a vmbus device - */ -static int vmbus_remove(struct device *child_device) -{ - int ret; - struct driver_context *driver_ctx; - - /* 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) { - driver_ctx = driver_to_driver_context(child_device->driver); - - /* - * Let the specific open-source driver handles the removal if - * it can - */ - if (driver_ctx->remove) { - ret = driver_ctx->remove(child_device); - } else { - DPRINT_ERR(VMBUS_DRV, - "remove() method not set for driver - %s", - child_device->driver->name); - ret = -1; - } - } - - return 0; -} - -/* - * vmbus_shutdown - Shutdown a vmbus device - */ -static void vmbus_shutdown(struct device *child_device) -{ - struct driver_context *driver_ctx; - - /* Special case root bus device */ - if (child_device->parent == NULL) { - /* - * No-op since it is statically defined and handle in - * vmbus_bus_exit() - */ - return; - } - - /* The device may not be attached yet */ - if (!child_device->driver) - return; - - driver_ctx = driver_to_driver_context(child_device->driver); - - /* Let the specific open-source driver handles the removal if it can */ - if (driver_ctx->shutdown) - driver_ctx->shutdown(child_device); - - return; -} - -/* - * 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); -} - -/* - * vmbus_device_release - Final callback release of the vmbus child device - */ -static void vmbus_device_release(struct device *device) -{ - struct vm_device *device_ctx = device_to_vm_device(device); - - kfree(device_ctx); - - /* !!DO NOT REFERENCE device_ctx anymore at this point!! */ -} - -/* - * vmbus_msg_dpc - Tasklet routine to handle hypervisor messages - */ -static void vmbus_msg_dpc(unsigned long data) -{ - struct hv_driver *driver = (struct hv_driver *)data; - - /* Call to bus driver to handle interrupt */ - vmbus_on_msg_dpc(driver); -} - -/* - * vmbus_event_dpc - Tasklet routine to handle hypervisor events - */ -static void vmbus_event_dpc(unsigned long data) -{ - /* Call to bus driver to handle interrupt */ - VmbusOnEvents(); -} - -static irqreturn_t vmbus_isr(int irq, void *dev_id) -{ - struct hv_driver *driver = &g_vmbus_drv.drv_obj; - int ret; - - /* Call to bus driver to handle interrupt */ - ret = vmbus_on_isr(driver); - - /* Schedules a dpc if necessary */ - if (ret > 0) { - if (test_bit(0, (unsigned long *)&ret)) - tasklet_schedule(&g_vmbus_drv.msg_dpc); - - if (test_bit(1, (unsigned long *)&ret)) - tasklet_schedule(&g_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); - -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 (!dmi_check_system(microsoft_hv_dmi_table)) - return -ENODEV; - - return vmbus_bus_init(); -} - -static void __exit vmbus_exit(void) -{ - vmbus_bus_exit(); - /* Todo: it is used for loglevel, to be ported to new kernel. */ -} - -/* - * We use a PCI table to determine if we should autoload this driver This is - * needed by distro tools to determine if the hyperv drivers should be - * installed and/or configured. We don't do anything else with the table, but - * it needs to be present. - */ -static const struct pci_device_id microsoft_hv_pci_table[] = { - { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */ - { 0 } -}; -MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table); - -MODULE_LICENSE("GPL"); -MODULE_VERSION(HV_DRV_VERSION); -module_param(vmbus_irq, int, S_IRUGO); -module_param(vmbus_loglevel, int, S_IRUGO); - -module_init(vmbus_init); -module_exit(vmbus_exit); diff --git a/drivers/staging/hv/vmbus_packet_format.h b/drivers/staging/hv/vmbus_packet_format.h deleted file mode 100644 index f9f6b4bf6fb..00000000000 --- 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 DataOffset8; - u16 Length8; - u16 Flags; - u64 TransactionId; -} __attribute__((packed)); - -struct vmpacket_header { - u32 PreviousPacketStartOffset; - struct vmpacket_descriptor Descriptor; -} __attribute__((packed)); - -struct vmtransfer_page_range { - u32 ByteCount; - u32 ByteOffset; -} __attribute__((packed)); - -struct vmtransfer_page_packet_header { - struct vmpacket_descriptor d; - u16 TransferPageSetId; - bool SenderOwnsSet; - u8 Reserved; - u32 RangeCount; - struct vmtransfer_page_range Ranges[1]; -} __attribute__((packed)); - -struct vmgpadl_packet_header { - struct vmpacket_descriptor d; - u32 Gpadl; - u32 Reserved; -} __attribute__((packed)); - -struct vmadd_remove_transfer_page_set { - struct vmpacket_descriptor d; - u32 Gpadl; - u16 TransferPageSetId; - u16 Reserved; -} __attribute__((packed)); - -/* - * This structure defines a range in guest physical space that can be made to - * look virtually contiguous. - */ -struct gpa_range { - u32 ByteCount; - u32 ByteOffset; - u64 PfnArray[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 RangeCount; - struct gpa_range Range[1]; -} __attribute__((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 */ -} __attribute__((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 RangeCount; - struct gpa_range Range[1]; -} __attribute__((packed)); - -/* This is the format for a Additional Data Packet. */ -struct vmadditional_data { - struct vmpacket_descriptor d; - u64 TotalBytes; - u32 ByteOffset; - u32 ByteCount; - unsigned char Data[1]; -} __attribute__((packed)); - -union vmpacket_largest_possible_header { - struct vmpacket_descriptor SimpleHeader; - struct vmtransfer_page_packet_header TransferPageHeader; - struct vmgpadl_packet_header GpadlHeader; - struct vmadd_remove_transfer_page_set AddRemoveTransferPageHeader; - struct vmestablish_gpadl EstablishGpadlHeader; - struct vmteardown_gpadl TeardownGpadlHeader; - struct vmdata_gpa_direct DataGpaDirectHeader; -}; - -#define VMPACKET_DATA_START_ADDRESS(__packet) \ - (void *)(((unsigned char *)__packet) + \ - ((struct vmpacket_descriptor)__packet)->DataOffset8 * 8) - -#define VMPACKET_DATA_LENGTH(__packet) \ - ((((struct vmpacket_descriptor)__packet)->Length8 - \ - ((struct vmpacket_descriptor)__packet)->DataOffset8) * 8) - -#define VMPACKET_TRANSFER_MODE(__packet) \ - (((struct IMPACT)__packet)->Type) - -enum vmbus_packet_type { - VmbusPacketTypeInvalid = 0x0, - VmbusPacketTypeSynch = 0x1, - VmbusPacketTypeAddTransferPageSet = 0x2, - VmbusPacketTypeRemoveTransferPageSet = 0x3, - VmbusPacketTypeEstablishGpadl = 0x4, - VmbusPacketTypeTearDownGpadl = 0x5, - VmbusPacketTypeDataInBand = 0x6, - VmbusPacketTypeDataUsingTransferPages = 0x7, - VmbusPacketTypeDataUsingGpadl = 0x8, - VmbusPacketTypeDataUsingGpaDirect = 0x9, - VmbusPacketTypeCancelRequest = 0xa, - VmbusPacketTypeCompletion = 0xb, - VmbusPacketTypeDataUsingAdditionalPackets = 0xc, - VmbusPacketTypeAdditionalData = 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 07f6d22eeab..00000000000 --- 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> - - -/* - * 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 ConnectState; - - atomic_t NextGpadlHandle; - - /* - * 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 *InterruptPage; - void *SendInterruptPage; - void *RecvInterruptPage; - - /* - * 2 pages - 1st page for parent->child notification and 2nd - * is child->parent notification - */ - void *MonitorPages; - struct list_head ChannelMsgList; - spinlock_t channelmsg_lock; - - /* List of channels */ - struct list_head ChannelList; - spinlock_t channel_lock; - - struct workqueue_struct *WorkQueue; -}; - - -struct VMBUS_MSGINFO { - /* Bookkeeping stuff */ - struct list_head MsgListEntry; - - /* Synchronize the request/response if needed */ - struct osd_waitevent *WaitEvent; - - /* The message itself */ - unsigned char Msg[0]; -}; - - -extern struct VMBUS_CONNECTION gVmbusConnection; - -/* General vmbus interface */ - -struct hv_device *vmbus_child_device_create(struct hv_guid *deviceType, - struct hv_guid *deviceInstance, - struct vmbus_channel *channel); - -int VmbusChildDeviceAdd(struct hv_device *Device); -int vmbus_child_device_register(struct hv_device *root_device_obj, - 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 *GetChannelFromRelId(u32 relId); - - -/* Connection interface */ - -int VmbusConnect(void); - -int VmbusDisconnect(void); - -int VmbusPostMessage(void *buffer, size_t bufSize); - -int VmbusSetEvent(u32 childRelId); - -void VmbusOnEvents(void); - - -#endif /* _VMBUS_PRIVATE_H_ */ diff --git a/drivers/staging/hv/vstorage.h b/drivers/staging/hv/vstorage.h deleted file mode 100644 index ae8be84394d..00000000000 --- a/drivers/staging/hv/vstorage.h +++ /dev/null @@ -1,192 +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> - * - */ - -/* 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 { \ - char *revision_string \ - = REVISION_STRING($Rev : 6 $) + 6; \ - RESULT_LVALUE_ = 0; \ - while (*revision_string >= '0' \ - && *revision_string <= '9') { \ - RESULT_LVALUE_ *= 10; \ - RESULT_LVALUE_ += *revision_string - '0'; \ - revision_string++; \ - } \ - } while (0) - -/* Major/minor macros. Minor version is in LSB, meaning that earlier flat */ -/* version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). */ -#define VMSTOR_PROTOCOL_MAJOR(VERSION_) (((VERSION_) >> 8) & 0xff) -#define VMSTOR_PROTOCOL_MINOR(VERSION_) (((VERSION_)) & 0xff) -#define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \ - (((MINOR_) & 0xff))) -#define VMSTOR_INVALID_PROTOCOL_VERSION (-1) - -/* Version history: */ -/* V1 Beta 0.1 */ -/* V1 RC < 2008/1/31 1.0 */ -/* V1 RC > 2008/1/31 2.0 */ -#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(2, 0) - - - - -/* This will get replaced with the max transfer length that is possible on */ -/* the host adapter. */ -/* The max transfer length will be published when we offer a vmbus channel. */ -#define MAX_TRANSFER_LENGTH 0x40000 -#define DEFAULT_PACKET_SIZE (sizeof(struct vmdata_gpa_direct) + \ - sizeof(struct vstor_packet) + \ - sizesizeof(u64) * (MAX_TRANSFER_LENGTH / PAGE_SIZE))) - - -/* Packet structure describing virtual storage requests. */ -enum vstor_packet_operation { - VSTOR_OPERATION_COMPLETE_IO = 1, - VSTOR_OPERATION_REMOVE_DEVICE = 2, - VSTOR_OPERATION_EXECUTE_SRB = 3, - VSTOR_OPERATION_RESET_LUN = 4, - VSTOR_OPERATION_RESET_ADAPTER = 5, - VSTOR_OPERATION_RESET_BUS = 6, - VSTOR_OPERATION_BEGIN_INITIALIZATION = 7, - VSTOR_OPERATION_END_INITIALIZATION = 8, - VSTOR_OPERATION_QUERY_PROTOCOL_VERSION = 9, - VSTOR_OPERATION_QUERY_PROPERTIES = 10, - VSTOR_OPERATION_MAXIMUM = 10 -}; - -/* - * Platform neutral description of a scsi request - - * this remains the same across the write regardless of 32/64 bit - * note: it's patterned off the SCSI_PASS_THROUGH structure - */ -#define CDB16GENERIC_LENGTH 0x10 - -#ifndef SENSE_BUFFER_SIZE -#define SENSE_BUFFER_SIZE 0x12 -#endif - -#define MAX_DATA_BUF_LEN_WITH_PADDING 0x14 - -struct vmscsi_request { - unsigned short length; - unsigned char srb_status; - unsigned char scsi_status; - - unsigned char port_number; - unsigned char path_id; - unsigned char target_id; - unsigned char lun; - - unsigned char cdb_length; - unsigned char sense_info_length; - unsigned char data_in; - unsigned char reserved; - - unsigned int data_transfer_length; - - union { - unsigned char cdb[CDB16GENERIC_LENGTH]; - unsigned char sense_data[SENSE_BUFFER_SIZE]; - unsigned char reserved_array[MAX_DATA_BUF_LEN_WITH_PADDING]; - }; -} __attribute((packed)); - - -/* - * This structure is sent during the intialization phase to get the different - * properties of the channel. - */ -struct vmstorage_channel_properties { - unsigned short protocol_version; - unsigned char path_id; - unsigned char target_id; - - /* Note: port number is only really known on the client side */ - unsigned int port_number; - unsigned int flags; - unsigned int max_transfer_bytes; - - /* This id is unique for each channel and will correspond with */ - /* vendor specific data in the inquirydata */ - unsigned long long unique_id; -} __attribute__((packed)); - -/* This structure is sent during the storage protocol negotiations. */ -struct vmstorage_protocol_version { - /* Major (MSW) and minor (LSW) version numbers. */ - unsigned short major_minor; - - /* - * Revision number is auto-incremented whenever this file is changed - * (See FILL_VMSTOR_REVISION macro above). Mismatch does not - * definitely indicate incompatibility--but it does indicate mismatched - * builds. - */ - unsigned short revision; -} __attribute__((packed)); - -/* Channel Property Flags */ -#define STORAGE_CHANNEL_REMOVABLE_FLAG 0x1 -#define STORAGE_CHANNEL_EMULATED_IDE_FLAG 0x2 - -struct vstor_packet { - /* Requested operation type */ - enum vstor_packet_operation operation; - - /* Flags - see below for values */ - unsigned int flags; - - /* Status of the request returned from the server side. */ - unsigned int status; - - /* Data payload area */ - union { - /* - * Structure used to forward SCSI commands from the - * client to the server. - */ - struct vmscsi_request vm_srb; - - /* Structure used to query channel properties. */ - struct vmstorage_channel_properties storage_channel_properties; - - /* Used during version negotiations. */ - struct vmstorage_protocol_version version; - }; -} __attribute__((packed)); - -/* Packet flags */ -/* - * This flag indicates that the server should send back a completion for this - * packet. - */ -#define REQUEST_COMPLETION_FLAG 0x1 - -/* This is the set of flags that the vsc can set in any packets it sends */ -#define VSC_LEGAL_FLAGS (REQUEST_COMPLETION_FLAG) |
