diff options
Diffstat (limited to 'drivers/staging/hv')
| -rw-r--r-- | drivers/staging/hv/Kconfig | 17 | ||||
| -rw-r--r-- | drivers/staging/hv/Makefile | 6 | ||||
| -rw-r--r-- | drivers/staging/hv/TODO | 7 | ||||
| -rw-r--r-- | drivers/staging/hv/hv_mouse.c | 599 | ||||
| -rw-r--r-- | drivers/staging/hv/hyperv_net.h | 1058 | ||||
| -rw-r--r-- | drivers/staging/hv/netvsc.c | 944 | ||||
| -rw-r--r-- | drivers/staging/hv/netvsc_drv.c | 456 | ||||
| -rw-r--r-- | drivers/staging/hv/rndis_filter.c | 855 | ||||
| -rw-r--r-- | drivers/staging/hv/storvsc_drv.c | 1486 |
9 files changed, 0 insertions, 5428 deletions
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig deleted file mode 100644 index 072185ebe95..00000000000 --- a/drivers/staging/hv/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config HYPERV_STORAGE - tristate "Microsoft Hyper-V virtual storage driver" - depends on HYPERV && SCSI - help - Select this option to enable the Hyper-V virtual storage driver. - -config HYPERV_NET - tristate "Microsoft Hyper-V virtual network driver" - depends on HYPERV && NET - help - Select this option to enable the Hyper-V virtual network driver. - -config HYPERV_MOUSE - tristate "Microsoft Hyper-V mouse driver" - depends on HYPERV && HID - help - Select this option to enable the Hyper-V mouse driver. diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile deleted file mode 100644 index 0f55ceee919..00000000000 --- a/drivers/staging/hv/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o -obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o -obj-$(CONFIG_HYPERV_MOUSE) += hv_mouse.o - -hv_storvsc-y := storvsc_drv.o -hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o diff --git a/drivers/staging/hv/TODO b/drivers/staging/hv/TODO deleted file mode 100644 index ed4d63619df..00000000000 --- a/drivers/staging/hv/TODO +++ /dev/null @@ -1,7 +0,0 @@ -TODO: - - audit the network driver - - audit the scsi driver - -Please send patches for this code to Greg Kroah-Hartman <gregkh@suse.de>, -Hank Janssen <hjanssen@microsoft.com>, Haiyang Zhang <haiyangz@microsoft.com>, -K. Y. Srinivasan <kys@microsoft.com> diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c deleted file mode 100644 index ccd39c70c52..00000000000 --- a/drivers/staging/hv/hv_mouse.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * Copyright (c) 2009, Citrix Systems, Inc. - * Copyright (c) 2010, Microsoft Corporation. - * Copyright (c) 2011, Novell Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/workqueue.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/input.h> -#include <linux/hid.h> -#include <linux/hiddev.h> -#include <linux/hyperv.h> - - -struct hv_input_dev_info { - unsigned int size; - unsigned short vendor; - unsigned short product; - unsigned short version; - unsigned short reserved[11]; -}; - -/* The maximum size of a synthetic input message. */ -#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16 - -/* - * Current version - * - * History: - * Beta, RC < 2008/1/22 1,0 - * RC > 2008/1/22 2,0 - */ -#define SYNTHHID_INPUT_VERSION_MAJOR 2 -#define SYNTHHID_INPUT_VERSION_MINOR 0 -#define SYNTHHID_INPUT_VERSION (SYNTHHID_INPUT_VERSION_MINOR | \ - (SYNTHHID_INPUT_VERSION_MAJOR << 16)) - - -#pragma pack(push, 1) -/* - * Message types in the synthetic input protocol - */ -enum synthhid_msg_type { - SYNTH_HID_PROTOCOL_REQUEST, - SYNTH_HID_PROTOCOL_RESPONSE, - SYNTH_HID_INITIAL_DEVICE_INFO, - SYNTH_HID_INITIAL_DEVICE_INFO_ACK, - SYNTH_HID_INPUT_REPORT, - SYNTH_HID_MAX -}; - -/* - * Basic message structures. - */ -struct synthhid_msg_hdr { - enum synthhid_msg_type type; - u32 size; -}; - -struct synthhid_msg { - struct synthhid_msg_hdr header; - char data[1]; /* Enclosed message */ -}; - -union synthhid_version { - struct { - u16 minor_version; - u16 major_version; - }; - u32 version; -}; - -/* - * Protocol messages - */ -struct synthhid_protocol_request { - struct synthhid_msg_hdr header; - union synthhid_version version_requested; -}; - -struct synthhid_protocol_response { - struct synthhid_msg_hdr header; - union synthhid_version version_requested; - unsigned char approved; -}; - -struct synthhid_device_info { - struct synthhid_msg_hdr header; - struct hv_input_dev_info hid_dev_info; - struct hid_descriptor hid_descriptor; -}; - -struct synthhid_device_info_ack { - struct synthhid_msg_hdr header; - unsigned char reserved; -}; - -struct synthhid_input_report { - struct synthhid_msg_hdr header; - char buffer[1]; -}; - -#pragma pack(pop) - -#define INPUTVSC_SEND_RING_BUFFER_SIZE (10*PAGE_SIZE) -#define INPUTVSC_RECV_RING_BUFFER_SIZE (10*PAGE_SIZE) - -#define NBITS(x) (((x)/BITS_PER_LONG)+1) - -enum pipe_prot_msg_type { - PIPE_MESSAGE_INVALID, - PIPE_MESSAGE_DATA, - PIPE_MESSAGE_MAXIMUM -}; - - -struct pipe_prt_msg { - enum pipe_prot_msg_type type; - u32 size; - char data[1]; -}; - -struct mousevsc_prt_msg { - enum pipe_prot_msg_type type; - u32 size; - union { - struct synthhid_protocol_request request; - struct synthhid_protocol_response response; - struct synthhid_device_info_ack ack; - }; -}; - -/* - * Represents an mousevsc device - */ -struct mousevsc_dev { - struct hv_device *device; - unsigned char init_complete; - struct mousevsc_prt_msg protocol_req; - struct mousevsc_prt_msg protocol_resp; - /* Synchronize the request/response if needed */ - struct completion wait_event; - int dev_info_status; - - struct hid_descriptor *hid_desc; - unsigned char *report_desc; - u32 report_desc_size; - struct hv_input_dev_info hid_dev_info; - int connected; - struct hid_device *hid_device; -}; - - -static struct mousevsc_dev *alloc_input_device(struct hv_device *device) -{ - struct mousevsc_dev *input_dev; - - input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL); - - if (!input_dev) - return NULL; - - input_dev->device = device; - hv_set_drvdata(device, input_dev); - init_completion(&input_dev->wait_event); - - return input_dev; -} - -static void free_input_device(struct mousevsc_dev *device) -{ - kfree(device->hid_desc); - kfree(device->report_desc); - hv_set_drvdata(device->device, NULL); - kfree(device); -} - - -static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, - struct synthhid_device_info *device_info) -{ - int ret = 0; - struct hid_descriptor *desc; - struct mousevsc_prt_msg ack; - - /* Assume success for now */ - input_device->dev_info_status = 0; - - memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info, - sizeof(struct hv_input_dev_info)); - - desc = &device_info->hid_descriptor; - WARN_ON(desc->bLength == 0); - - input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC); - - if (!input_device->hid_desc) - goto cleanup; - - memcpy(input_device->hid_desc, desc, desc->bLength); - - input_device->report_desc_size = desc->desc[0].wDescriptorLength; - if (input_device->report_desc_size == 0) - goto cleanup; - input_device->report_desc = kzalloc(input_device->report_desc_size, - GFP_ATOMIC); - - if (!input_device->report_desc) - goto cleanup; - - memcpy(input_device->report_desc, - ((unsigned char *)desc) + desc->bLength, - desc->desc[0].wDescriptorLength); - - /* Send the ack */ - memset(&ack, 0, sizeof(struct mousevsc_prt_msg)); - - ack.type = PIPE_MESSAGE_DATA; - ack.size = sizeof(struct synthhid_device_info_ack); - - ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK; - ack.ack.header.size = 1; - ack.ack.reserved = 0; - - ret = vmbus_sendpacket(input_device->device->channel, - &ack, - sizeof(struct pipe_prt_msg) - sizeof(unsigned char) + - sizeof(struct synthhid_device_info_ack), - (unsigned long)&ack, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; - - complete(&input_device->wait_event); - - return; - -cleanup: - kfree(input_device->hid_desc); - input_device->hid_desc = NULL; - - kfree(input_device->report_desc); - input_device->report_desc = NULL; - - input_device->dev_info_status = -1; - complete(&input_device->wait_event); -} - -static void mousevsc_on_receive(struct hv_device *device, - struct vmpacket_descriptor *packet) -{ - struct pipe_prt_msg *pipe_msg; - struct synthhid_msg *hid_msg; - struct mousevsc_dev *input_dev = hv_get_drvdata(device); - struct synthhid_input_report *input_report; - - pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet + - (packet->offset8 << 3)); - - if (pipe_msg->type != PIPE_MESSAGE_DATA) - return; - - hid_msg = (struct synthhid_msg *)&pipe_msg->data[0]; - - switch (hid_msg->header.type) { - case SYNTH_HID_PROTOCOL_RESPONSE: - memcpy(&input_dev->protocol_resp, pipe_msg, - pipe_msg->size + sizeof(struct pipe_prt_msg) - - sizeof(unsigned char)); - complete(&input_dev->wait_event); - break; - - case SYNTH_HID_INITIAL_DEVICE_INFO: - WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info)); - - /* - * Parse out the device info into device attr, - * hid desc and report desc - */ - mousevsc_on_receive_device_info(input_dev, - (struct synthhid_device_info *)&pipe_msg->data[0]); - break; - case SYNTH_HID_INPUT_REPORT: - input_report = - (struct synthhid_input_report *)&pipe_msg->data[0]; - if (!input_dev->init_complete) - break; - hid_input_report(input_dev->hid_device, - HID_INPUT_REPORT, input_report->buffer, - input_report->header.size, 1); - break; - default: - pr_err("unsupported hid msg type - type %d len %d", - hid_msg->header.type, hid_msg->header.size); - break; - } - -} - -static void mousevsc_on_channel_callback(void *context) -{ - const int packetSize = 0x100; - int ret = 0; - struct hv_device *device = (struct hv_device *)context; - - u32 bytes_recvd; - u64 req_id; - unsigned char packet[0x100]; - struct vmpacket_descriptor *desc; - unsigned char *buffer = packet; - int bufferlen = packetSize; - - - do { - ret = vmbus_recvpacket_raw(device->channel, buffer, - bufferlen, &bytes_recvd, &req_id); - - if (ret == 0) { - if (bytes_recvd > 0) { - desc = (struct vmpacket_descriptor *)buffer; - - switch (desc->type) { - case VM_PKT_COMP: - break; - - case VM_PKT_DATA_INBAND: - mousevsc_on_receive( - device, desc); - break; - - default: - pr_err("unhandled packet type %d, tid %llx len %d\n", - desc->type, - req_id, - bytes_recvd); - break; - } - - /* reset */ - if (bufferlen > packetSize) { - kfree(buffer); - - buffer = packet; - bufferlen = packetSize; - } - } else { - if (bufferlen > packetSize) { - kfree(buffer); - - buffer = packet; - bufferlen = packetSize; - } - break; - } - } else if (ret == -ENOBUFS) { - /* Handle large packet */ - bufferlen = bytes_recvd; - buffer = kzalloc(bytes_recvd, GFP_ATOMIC); - - if (buffer == NULL) { - buffer = packet; - bufferlen = packetSize; - break; - } - } - } while (1); - - return; -} - -static int mousevsc_connect_to_vsp(struct hv_device *device) -{ - int ret = 0; - int t; - struct mousevsc_dev *input_dev = hv_get_drvdata(device); - struct mousevsc_prt_msg *request; - struct mousevsc_prt_msg *response; - - - request = &input_dev->protocol_req; - - memset(request, 0, sizeof(struct mousevsc_prt_msg)); - - request->type = PIPE_MESSAGE_DATA; - request->size = sizeof(struct synthhid_protocol_request); - - request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST; - request->request.header.size = sizeof(unsigned int); - request->request.version_requested.version = SYNTHHID_INPUT_VERSION; - - - ret = vmbus_sendpacket(device->channel, request, - sizeof(struct pipe_prt_msg) - - sizeof(unsigned char) + - sizeof(struct synthhid_protocol_request), - (unsigned long)request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - response = &input_dev->protocol_resp; - - if (!response->response.approved) { - pr_err("synthhid protocol request failed (version %d)", - SYNTHHID_INPUT_VERSION); - ret = -ENODEV; - goto cleanup; - } - - t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - /* - * We should have gotten the device attr, hid desc and report - * desc at this point - */ - if (input_dev->dev_info_status) - ret = -ENOMEM; - -cleanup: - - return ret; -} - -static int mousevsc_hid_open(struct hid_device *hid) -{ - return 0; -} - -static void mousevsc_hid_close(struct hid_device *hid) -{ -} - -static struct hid_ll_driver mousevsc_ll_driver = { - .open = mousevsc_hid_open, - .close = mousevsc_hid_close, -}; - -static struct hid_driver mousevsc_hid_driver; - -static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len) -{ - struct hid_device *hid_dev; - struct mousevsc_dev *input_device = hv_get_drvdata(dev); - - hid_dev = hid_allocate_device(); - if (IS_ERR(hid_dev)) - return; - - hid_dev->ll_driver = &mousevsc_ll_driver; - hid_dev->driver = &mousevsc_hid_driver; - - if (hid_parse_report(hid_dev, packet, len)) - return; - - hid_dev->bus = BUS_VIRTUAL; - hid_dev->vendor = input_device->hid_dev_info.vendor; - hid_dev->product = input_device->hid_dev_info.product; - hid_dev->version = input_device->hid_dev_info.version; - - sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse"); - - if (!hidinput_connect(hid_dev, 0)) { - hid_dev->claimed |= HID_CLAIMED_INPUT; - - input_device->connected = 1; - - } - - input_device->hid_device = hid_dev; -} - -static int mousevsc_on_device_add(struct hv_device *device) -{ - int ret = 0; - struct mousevsc_dev *input_dev; - - input_dev = alloc_input_device(device); - - if (!input_dev) - return -ENOMEM; - - input_dev->init_complete = false; - - ret = vmbus_open(device->channel, - INPUTVSC_SEND_RING_BUFFER_SIZE, - INPUTVSC_RECV_RING_BUFFER_SIZE, - NULL, - 0, - mousevsc_on_channel_callback, - device - ); - - if (ret != 0) { - free_input_device(input_dev); - return ret; - } - - - ret = mousevsc_connect_to_vsp(device); - - if (ret != 0) { - vmbus_close(device->channel); - free_input_device(input_dev); - return ret; - } - - - /* workaround SA-167 */ - if (input_dev->report_desc[14] == 0x25) - input_dev->report_desc[14] = 0x29; - - reportdesc_callback(device, input_dev->report_desc, - input_dev->report_desc_size); - - input_dev->init_complete = true; - - return ret; -} - -static int mousevsc_probe(struct hv_device *dev, - const struct hv_vmbus_device_id *dev_id) -{ - - return mousevsc_on_device_add(dev); - -} - -static int mousevsc_remove(struct hv_device *dev) -{ - struct mousevsc_dev *input_dev = hv_get_drvdata(dev); - - vmbus_close(dev->channel); - - if (input_dev->connected) { - hidinput_disconnect(input_dev->hid_device); - input_dev->connected = 0; - hid_destroy_device(input_dev->hid_device); - } - - free_input_device(input_dev); - - return 0; -} - -static const struct hv_vmbus_device_id id_table[] = { - /* Mouse guid */ - { VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, - 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) }, - { }, -}; - -MODULE_DEVICE_TABLE(vmbus, id_table); - -static struct hv_driver mousevsc_drv = { - .name = "mousevsc", - .id_table = id_table, - .probe = mousevsc_probe, - .remove = mousevsc_remove, -}; - -static int __init mousevsc_init(void) -{ - return vmbus_driver_register(&mousevsc_drv); -} - -static void __exit mousevsc_exit(void) -{ - vmbus_driver_unregister(&mousevsc_drv); -} - -MODULE_LICENSE("GPL"); -MODULE_VERSION(HV_DRV_VERSION); -module_init(mousevsc_init); -module_exit(mousevsc_exit); diff --git a/drivers/staging/hv/hyperv_net.h b/drivers/staging/hv/hyperv_net.h deleted file mode 100644 index ac1ec840512..00000000000 --- a/drivers/staging/hv/hyperv_net.h +++ /dev/null @@ -1,1058 +0,0 @@ -/* - * - * Copyright (c) 2011, Microsoft Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - * - * Authors: - * Haiyang Zhang <haiyangz@microsoft.com> - * Hank Janssen <hjanssen@microsoft.com> - * K. Y. Srinivasan <kys@microsoft.com> - * - */ - -#ifndef _HYPERV_NET_H -#define _HYPERV_NET_H - -#include <linux/list.h> -#include <linux/hyperv.h> - -/* Fwd declaration */ -struct hv_netvsc_packet; - -/* Represent the xfer page packet which contains 1 or more netvsc packet */ -struct xferpage_packet { - struct list_head list_ent; - - /* # of netvsc packets this xfer packet contains */ - u32 count; -}; - -/* The number of pages which are enough to cover jumbo frame buffer. */ -#define NETVSC_PACKET_MAXPAGE 4 - -/* - * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame - * within the RNDIS - */ -struct hv_netvsc_packet { - /* Bookkeeping stuff */ - struct list_head list_ent; - - struct hv_device *device; - bool is_data_pkt; - - /* - * Valid only for receives when we break a xfer page packet - * into multiple netvsc packets - */ - struct xferpage_packet *xfer_page_pkt; - - union { - struct { - u64 recv_completion_tid; - void *recv_completion_ctx; - void (*recv_completion)(void *context); - } recv; - struct { - u64 send_completion_tid; - void *send_completion_ctx; - void (*send_completion)(void *context); - } send; - } completion; - - /* This points to the memory after page_buf */ - void *extension; - - u32 total_data_buflen; - /* Points to the send/receive buffer where the ethernet frame is */ - u32 page_buf_cnt; - struct hv_page_buffer page_buf[NETVSC_PACKET_MAXPAGE]; -}; - -struct netvsc_device_info { - unsigned char mac_adr[6]; - bool link_state; /* 0 - link up, 1 - link down */ - int ring_size; -}; - -/* Interface */ -int netvsc_device_add(struct hv_device *device, void *additional_info); -int netvsc_device_remove(struct hv_device *device); -int netvsc_send(struct hv_device *device, - struct hv_netvsc_packet *packet); -void netvsc_linkstatus_callback(struct hv_device *device_obj, - unsigned int status); -int netvsc_recv_callback(struct hv_device *device_obj, - struct hv_netvsc_packet *packet); -int rndis_filter_open(struct hv_device *dev); -int rndis_filter_close(struct hv_device *dev); -int rndis_filter_device_add(struct hv_device *dev, - void *additional_info); -void rndis_filter_device_remove(struct hv_device *dev); -int rndis_filter_receive(struct hv_device *dev, - struct hv_netvsc_packet *pkt); - - - -int rndis_filter_send(struct hv_device *dev, - struct hv_netvsc_packet *pkt); - -#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF) - -#define NVSP_PROTOCOL_VERSION_1 2 -#define NVSP_MIN_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 -#define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 - -enum { - NVSP_MSG_TYPE_NONE = 0, - - /* Init Messages */ - NVSP_MSG_TYPE_INIT = 1, - NVSP_MSG_TYPE_INIT_COMPLETE = 2, - - NVSP_VERSION_MSG_START = 100, - - /* Version 1 Messages */ - NVSP_MSG1_TYPE_SEND_NDIS_VER = NVSP_VERSION_MSG_START, - - NVSP_MSG1_TYPE_SEND_RECV_BUF, - NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE, - NVSP_MSG1_TYPE_REVOKE_RECV_BUF, - - NVSP_MSG1_TYPE_SEND_SEND_BUF, - NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE, - NVSP_MSG1_TYPE_REVOKE_SEND_BUF, - - NVSP_MSG1_TYPE_SEND_RNDIS_PKT, - NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE, - - /* - * This should be set to the number of messages for the version with - * the maximum number of messages. - */ - NVSP_NUM_MSG_PER_VERSION = 9, -}; - -enum { - NVSP_STAT_NONE = 0, - NVSP_STAT_SUCCESS, - NVSP_STAT_FAIL, - NVSP_STAT_PROTOCOL_TOO_NEW, - NVSP_STAT_PROTOCOL_TOO_OLD, - NVSP_STAT_INVALID_RNDIS_PKT, - NVSP_STAT_BUSY, - NVSP_STAT_MAX, -}; - -struct nvsp_message_header { - u32 msg_type; -}; - -/* Init Messages */ - -/* - * This message is used by the VSC to initialize the channel after the channels - * has been opened. This message should never include anything other then - * versioning (i.e. this message will be the same for ever). - */ -struct nvsp_message_init { - u32 min_protocol_ver; - u32 max_protocol_ver; -} __packed; - -/* - * This message is used by the VSP to complete the initialization of the - * channel. This message should never include anything other then versioning - * (i.e. this message will be the same for ever). - */ -struct nvsp_message_init_complete { - u32 negotiated_protocol_ver; - u32 max_mdl_chain_len; - u32 status; -} __packed; - -union nvsp_message_init_uber { - struct nvsp_message_init init; - struct nvsp_message_init_complete init_complete; -} __packed; - -/* Version 1 Messages */ - -/* - * This message is used by the VSC to send the NDIS version to the VSP. The VSP - * can use this information when handling OIDs sent by the VSC. - */ -struct nvsp_1_message_send_ndis_version { - u32 ndis_major_ver; - u32 ndis_minor_ver; -} __packed; - -/* - * This message is used by the VSC to send a receive buffer to the VSP. The VSP - * can then use the receive buffer to send data to the VSC. - */ -struct nvsp_1_message_send_receive_buffer { - u32 gpadl_handle; - u16 id; -} __packed; - -struct nvsp_1_receive_buffer_section { - u32 offset; - u32 sub_alloc_size; - u32 num_sub_allocs; - u32 end_offset; -} __packed; - -/* - * This message is used by the VSP to acknowledge a receive buffer send by the - * VSC. This message must be sent by the VSP before the VSP uses the receive - * buffer. - */ -struct nvsp_1_message_send_receive_buffer_complete { - u32 status; - u32 num_sections; - - /* - * The receive buffer is split into two parts, a large suballocation - * section and a small suballocation section. These sections are then - * suballocated by a certain size. - */ - - /* - * For example, the following break up of the receive buffer has 6 - * large suballocations and 10 small suballocations. - */ - - /* - * | Large Section | | Small Section | - * ------------------------------------------------------------ - * | | | | | | | | | | | | | | | | | | - * | | - * LargeOffset SmallOffset - */ - - struct nvsp_1_receive_buffer_section sections[1]; -} __packed; - -/* - * This message is sent by the VSC to revoke the receive buffer. After the VSP - * completes this transaction, the vsp should never use the receive buffer - * again. - */ -struct nvsp_1_message_revoke_receive_buffer { - u16 id; -}; - -/* - * This message is used by the VSC to send a send buffer to the VSP. The VSC - * can then use the send buffer to send data to the VSP. - */ -struct nvsp_1_message_send_send_buffer { - u32 gpadl_handle; - u16 id; -} __packed; - -/* - * This message is used by the VSP to acknowledge a send buffer sent by the - * VSC. This message must be sent by the VSP before the VSP uses the sent - * buffer. - */ -struct nvsp_1_message_send_send_buffer_complete { - u32 status; - - /* - * The VSC gets to choose the size of the send buffer and the VSP gets - * to choose the sections size of the buffer. This was done to enable - * dynamic reconfigurations when the cost of GPA-direct buffers - * decreases. - */ - u32 section_size; -} __packed; - -/* - * This message is sent by the VSC to revoke the send buffer. After the VSP - * completes this transaction, the vsp should never use the send buffer again. - */ -struct nvsp_1_message_revoke_send_buffer { - u16 id; -}; - -/* - * This message is used by both the VSP and the VSC to send a RNDIS message to - * the opposite channel endpoint. - */ -struct nvsp_1_message_send_rndis_packet { - /* - * This field is specified by RNIDS. They assume there's two different - * channels of communication. However, the Network VSP only has one. - * Therefore, the channel travels with the RNDIS packet. - */ - u32 channel_type; - - /* - * This field is used to send part or all of the data through a send - * buffer. This values specifies an index into the send buffer. If the - * index is 0xFFFFFFFF, then the send buffer is not being used and all - * of the data was sent through other VMBus mechanisms. - */ - u32 send_buf_section_index; - u32 send_buf_section_size; -} __packed; - -/* - * This message is used by both the VSP and the VSC to complete a RNDIS message - * to the opposite channel endpoint. At this point, the initiator of this - * message cannot use any resources associated with the original RNDIS packet. - */ -struct nvsp_1_message_send_rndis_packet_complete { - u32 status; -}; - -union nvsp_1_message_uber { - struct nvsp_1_message_send_ndis_version send_ndis_ver; - - struct nvsp_1_message_send_receive_buffer send_recv_buf; - struct nvsp_1_message_send_receive_buffer_complete - send_recv_buf_complete; - struct nvsp_1_message_revoke_receive_buffer revoke_recv_buf; - - struct nvsp_1_message_send_send_buffer send_send_buf; - struct nvsp_1_message_send_send_buffer_complete send_send_buf_complete; - struct nvsp_1_message_revoke_send_buffer revoke_send_buf; - - struct nvsp_1_message_send_rndis_packet send_rndis_pkt; - struct nvsp_1_message_send_rndis_packet_complete - send_rndis_pkt_complete; -} __packed; - -union nvsp_all_messages { - union nvsp_message_init_uber init_msg; - union nvsp_1_message_uber v1_msg; -} __packed; - -/* ALL Messages */ -struct nvsp_message { - struct nvsp_message_header hdr; - union nvsp_all_messages msg; -} __packed; - - - - -/* #define NVSC_MIN_PROTOCOL_VERSION 1 */ -/* #define NVSC_MAX_PROTOCOL_VERSION 1 */ - -#define NETVSC_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 num_outstanding_sends; - bool destroy; - /* - * List of free preallocated hv_netvsc_packet to represent receive - * packet - */ - struct list_head recv_pkt_list; - spinlock_t recv_pkt_list_lock; - - /* Receive buffer allocated by us but manages by NetVSP */ - void *recv_buf; - u32 recv_buf_size; - u32 recv_buf_gpadl_handle; - u32 recv_section_cnt; - struct nvsp_1_receive_buffer_section *recv_section; - - /* Used for NetVSP initialization protocol */ - struct completion channel_init_wait; - struct nvsp_message channel_init_pkt; - - struct nvsp_message revoke_packet; - /* unsigned char HwMacAddr[HW_MACADDR_LEN]; */ - - struct net_device *ndev; - - /* Holds rndis device info */ - void *extension; -}; - - -/* 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; -}; - - -struct rndis_filter_packet { - void *completion_ctx; - void (*completion)(void *context); - struct rndis_message msg; -}; - -/* Handy macros */ - -/* get the size of an RNDIS message. Pass in the message type, */ -/* 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) - - -#define __struct_bcount(x) - - - -#define RNDIS_HEADER_SIZE (sizeof(struct rndis_message) - \ - sizeof(union rndis_message_container)) - -#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 -#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 -#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 -#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 -#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 -#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 -#define NDIS_PACKET_TYPE_SMT 0x00000040 -#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 -#define NDIS_PACKET_TYPE_GROUP 0x00000100 -#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 -#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 -#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 - - - -#endif /* _HYPERV_NET_H */ diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c deleted file mode 100644 index b902579c7fe..00000000000 --- a/drivers/staging/hv/netvsc.c +++ /dev/null @@ -1,944 +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> - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/mm.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/netdevice.h> - -#include "hyperv_net.h" - - -static struct netvsc_device *alloc_net_device(struct hv_device *device) -{ - struct netvsc_device *net_device; - struct net_device *ndev = hv_get_drvdata(device); - - net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL); - if (!net_device) - return NULL; - - - net_device->destroy = false; - net_device->dev = device; - net_device->ndev = ndev; - - hv_set_drvdata(device, net_device); - return net_device; -} - -static struct netvsc_device *get_outbound_net_device(struct hv_device *device) -{ - struct netvsc_device *net_device; - - net_device = hv_get_drvdata(device); - if (net_device && net_device->destroy) - net_device = NULL; - - return net_device; -} - -static struct netvsc_device *get_inbound_net_device(struct hv_device *device) -{ - struct netvsc_device *net_device; - - net_device = hv_get_drvdata(device); - - if (!net_device) - goto get_in_err; - - if (net_device->destroy && - atomic_read(&net_device->num_outstanding_sends) == 0) - net_device = NULL; - -get_in_err: - return net_device; -} - - -static int netvsc_destroy_recv_buf(struct netvsc_device *net_device) -{ - struct nvsp_message *revoke_packet; - int ret = 0; - struct net_device *ndev = net_device->ndev; - - /* - * If we got a section count, it means we received a - * SendReceiveBufferComplete msg (ie sent - * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need - * to send a revoke msg here - */ - if (net_device->recv_section_cnt) { - /* Send the revoke receive buffer */ - revoke_packet = &net_device->revoke_packet; - memset(revoke_packet, 0, sizeof(struct nvsp_message)); - - revoke_packet->hdr.msg_type = - NVSP_MSG1_TYPE_REVOKE_RECV_BUF; - revoke_packet->msg.v1_msg. - revoke_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; - - ret = vmbus_sendpacket(net_device->dev->channel, - revoke_packet, - sizeof(struct nvsp_message), - (unsigned long)revoke_packet, - VM_PKT_DATA_INBAND, 0); - /* - * If we failed here, we might as well return and - * have a leak rather than continue and a bugchk - */ - if (ret != 0) { - netdev_err(ndev, "unable to send " - "revoke receive buffer to netvsp\n"); - return ret; - } - } - - /* Teardown the gpadl on the vsp end */ - if (net_device->recv_buf_gpadl_handle) { - ret = vmbus_teardown_gpadl(net_device->dev->channel, - net_device->recv_buf_gpadl_handle); - - /* If we failed here, we might as well return and have a leak - * rather than continue and a bugchk - */ - if (ret != 0) { - netdev_err(ndev, - "unable to teardown receive buffer's gpadl\n"); - return ret; - } - net_device->recv_buf_gpadl_handle = 0; - } - - if (net_device->recv_buf) { - /* Free up the receive buffer */ - free_pages((unsigned long)net_device->recv_buf, - get_order(net_device->recv_buf_size)); - net_device->recv_buf = NULL; - } - - if (net_device->recv_section) { - net_device->recv_section_cnt = 0; - kfree(net_device->recv_section); - net_device->recv_section = NULL; - } - - return ret; -} - -static int netvsc_init_recv_buf(struct hv_device *device) -{ - int ret = 0; - int t; - struct netvsc_device *net_device; - struct nvsp_message *init_packet; - struct net_device *ndev; - - net_device = get_outbound_net_device(device); - if (!net_device) - return -ENODEV; - ndev = net_device->ndev; - - net_device->recv_buf = - (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, - get_order(net_device->recv_buf_size)); - if (!net_device->recv_buf) { - netdev_err(ndev, "unable to allocate receive " - "buffer of size %d\n", net_device->recv_buf_size); - ret = -ENOMEM; - goto cleanup; - } - - /* - * 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) { - netdev_err(ndev, - "unable to establish receive buffer's gpadl\n"); - goto cleanup; - } - - - /* Notify the NetVsp of the gpadl handle */ - 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, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) { - netdev_err(ndev, - "unable to send receive buffer's gpadl to netvsp\n"); - goto cleanup; - } - - t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); - BUG_ON(t == 0); - - - /* Check the response */ - if (init_packet->msg.v1_msg. - send_recv_buf_complete.status != NVSP_STAT_SUCCESS) { - netdev_err(ndev, "Unable to complete receive buffer " - "initialization with NetVsp - status %d\n", - init_packet->msg.v1_msg. - send_recv_buf_complete.status); - ret = -EINVAL; - goto cleanup; - } - - /* Parse the response */ - - 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 = -EINVAL; - goto cleanup; - } - - memcpy(net_device->recv_section, - init_packet->msg.v1_msg. - send_recv_buf_complete.sections, - net_device->recv_section_cnt * - sizeof(struct nvsp_1_receive_buffer_section)); - - /* - * For 1st release, there should only be 1 section that represents the - * entire receive buffer - */ - if (net_device->recv_section_cnt != 1 || - net_device->recv_section->offset != 0) { - ret = -EINVAL; - goto cleanup; - } - - goto exit; - -cleanup: - netvsc_destroy_recv_buf(net_device); - -exit: - return ret; -} - - -static int netvsc_connect_vsp(struct hv_device *device) -{ - int ret, t; - struct netvsc_device *net_device; - struct nvsp_message *init_packet; - int ndis_version; - struct net_device *ndev; - - net_device = get_outbound_net_device(device); - if (!net_device) - return -ENODEV; - ndev = net_device->ndev; - - init_packet = &net_device->channel_init_pkt; - - memset(init_packet, 0, sizeof(struct nvsp_message)); - init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; - init_packet->msg.init_msg.init.min_protocol_ver = - NVSP_MIN_PROTOCOL_VERSION; - init_packet->msg.init_msg.init.max_protocol_ver = - NVSP_MAX_PROTOCOL_VERSION; - - /* Send the init request */ - ret = vmbus_sendpacket(device->channel, init_packet, - sizeof(struct nvsp_message), - (unsigned long)init_packet, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); - - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - if (init_packet->msg.init_msg.init_complete.status != - NVSP_STAT_SUCCESS) { - ret = -EINVAL; - goto cleanup; - } - - if (init_packet->msg.init_msg.init_complete. - negotiated_protocol_ver != NVSP_PROTOCOL_VERSION_1) { - ret = -EPROTO; - goto cleanup; - } - /* 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, - VM_PKT_DATA_INBAND, 0); - if (ret != 0) - goto cleanup; - - /* Post the big receive buffer to NetVSP */ - ret = netvsc_init_recv_buf(device); - -cleanup: - return ret; -} - -static void netvsc_disconnect_vsp(struct netvsc_device *net_device) -{ - netvsc_destroy_recv_buf(net_device); -} - -/* - * netvsc_device_remove - Callback when the root bus device is removed - */ -int netvsc_device_remove(struct hv_device *device) -{ - struct netvsc_device *net_device; - struct hv_netvsc_packet *netvsc_packet, *pos; - unsigned long flags; - - net_device = hv_get_drvdata(device); - spin_lock_irqsave(&device->channel->inbound_lock, flags); - net_device->destroy = true; - spin_unlock_irqrestore(&device->channel->inbound_lock, flags); - - /* Wait for all send completions */ - while (atomic_read(&net_device->num_outstanding_sends)) { - dev_info(&device->device, - "waiting for %d requests to complete...\n", - atomic_read(&net_device->num_outstanding_sends)); - udelay(100); - } - - netvsc_disconnect_vsp(net_device); - - /* - * Since we have already drained, we don't need to busy wait - * as was done in final_release_stor_device() - * Note that we cannot set the ext pointer to NULL until - * we have drained - to drain the outgoing packets, we need to - * allow incoming packets. - */ - - spin_lock_irqsave(&device->channel->inbound_lock, flags); - hv_set_drvdata(device, NULL); - spin_unlock_irqrestore(&device->channel->inbound_lock, flags); - - /* - * At this point, no one should be accessing net_device - * except in here - */ - dev_notice(&device->device, "net device safe to remove\n"); - - /* 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); - return 0; -} - -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; - struct net_device *ndev; - - net_device = get_inbound_net_device(device); - if (!net_device) - return; - ndev = net_device->ndev; - - nvsp_packet = (struct nvsp_message *)((unsigned long)packet + - (packet->offset8 << 3)); - - 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)); - complete(&net_device->channel_init_wait); - } 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->trans_id; - - /* 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 { - netdev_err(ndev, "Unknown send completion packet type- " - "%d received!!\n", nvsp_packet->hdr.msg_type); - } - -} - -int netvsc_send(struct hv_device *device, - struct hv_netvsc_packet *packet) -{ - struct netvsc_device *net_device; - int ret = 0; - struct nvsp_message sendMessage; - struct net_device *ndev; - - net_device = get_outbound_net_device(device); - if (!net_device) - return -ENODEV; - ndev = net_device->ndev; - - 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, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - } - - if (ret != 0) - netdev_err(ndev, "Unable to send packet %p ret %d\n", - packet, ret); - else - atomic_inc(&net_device->num_outstanding_sends); - - return ret; -} - -static void netvsc_send_recv_completion(struct hv_device *device, - u64 transaction_id) -{ - struct nvsp_message recvcompMessage; - int retries = 0; - int ret; - struct net_device *ndev; - struct netvsc_device *net_device = hv_get_drvdata(device); - - ndev = net_device->ndev; - - recvcompMessage.hdr.msg_type = - NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE; - - /* FIXME: Pass in the status */ - recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = - NVSP_STAT_SUCCESS; - -retry_send_cmplt: - /* Send the completion */ - ret = vmbus_sendpacket(device->channel, &recvcompMessage, - sizeof(struct nvsp_message), transaction_id, - VM_PKT_COMP, 0); - if (ret == 0) { - /* success */ - /* no-op */ - } else if (ret == -EAGAIN) { - /* no more room...wait a bit and attempt to retry 3 times */ - retries++; - netdev_err(ndev, "unable to send receive completion pkt" - " (tid %llx)...retrying %d\n", transaction_id, retries); - - if (retries < 4) { - udelay(100); - goto retry_send_cmplt; - } else { - netdev_err(ndev, "unable to send receive " - "completion pkt (tid %llx)...give up retrying\n", - transaction_id); - } - } else { - netdev_err(ndev, "unable to send receive " - "completion pkt - %llx\n", 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; - struct net_device *ndev; - - /* - * 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) - return; - ndev = net_device->ndev; - - /* Overloading use of the lock. */ - spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); - - packet->xfer_page_pkt->count--; - - /* - * Last one in the line that represent 1 xfer page packet. - * Return the xfer page packet itself to the freelist - */ - if (packet->xfer_page_pkt->count == 0) { - fsend_receive_comp = true; - transaction_id = packet->completion.recv.recv_completion_tid; - list_add_tail(&packet->xfer_page_pkt->list_ent, - &net_device->recv_pkt_list); - - } - - /* Put the packet back */ - list_add_tail(&packet->list_ent, &net_device->recv_pkt_list); - spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags); - - /* Send a receive completion for the xfer page packet */ - if (fsend_receive_comp) - netvsc_send_recv_completion(device, transaction_id); - -} - -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; - struct net_device *ndev; - - LIST_HEAD(listHead); - - net_device = get_inbound_net_device(device); - if (!net_device) - return; - ndev = net_device->ndev; - - /* - * All inbound packets other than send completion should be xfer page - * packet - */ - if (packet->type != VM_PKT_DATA_USING_XFER_PAGES) { - netdev_err(ndev, "Unknown packet type received - %d\n", - packet->type); - return; - } - - nvsp_packet = (struct nvsp_message *)((unsigned long)packet + - (packet->offset8 << 3)); - - /* Make sure this is a valid nvsp packet */ - if (nvsp_packet->hdr.msg_type != - NVSP_MSG1_TYPE_SEND_RNDIS_PKT) { - netdev_err(ndev, "Unknown nvsp packet type received-" - " %d\n", nvsp_packet->hdr.msg_type); - return; - } - - vmxferpage_packet = (struct vmtransfer_page_packet_header *)packet; - - if (vmxferpage_packet->xfer_pageset_id != NETVSC_RECEIVE_BUFFER_ID) { - netdev_err(ndev, "Invalid xfer page set id - " - "expecting %x got %x\n", NETVSC_RECEIVE_BUFFER_ID, - vmxferpage_packet->xfer_pageset_id); - return; - } - - /* - * 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->range_cnt + 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) { - netdev_err(ndev, "Got only %d netvsc pkt...needed " - "%d pkts. Dropping this xfer page packet completely!\n", - count, vmxferpage_packet->range_cnt + 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.trans_id); - - 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; - - if (xferpage_packet->count != vmxferpage_packet->range_cnt) { - netdev_err(ndev, "Needed %d netvsc pkts to satisfy " - "this xfer page...got %d\n", - vmxferpage_packet->range_cnt, 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.trans_id; - - netvsc_packet->total_data_buflen = - vmxferpage_packet->ranges[i].byte_count; - netvsc_packet->page_buf_cnt = 1; - - netvsc_packet->page_buf[0].len = - vmxferpage_packet->ranges[i].byte_count; - - start = virt_to_phys((void *)((unsigned long)net_device-> - recv_buf + vmxferpage_packet->ranges[i].byte_offset)); - - netvsc_packet->page_buf[0].pfn = start >> PAGE_SHIFT; - end_virtual = (unsigned long)net_device->recv_buf - + vmxferpage_packet->ranges[i].byte_offset - + vmxferpage_packet->ranges[i].byte_count - 1; - end = virt_to_phys((void *)end_virtual); - - /* Calculate the page relative offset */ - netvsc_packet->page_buf[0].offset = - vmxferpage_packet->ranges[i].byte_offset & - (PAGE_SIZE - 1); - if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) { - /* Handle frame across multiple pages: */ - netvsc_packet->page_buf[0].len = - (netvsc_packet->page_buf[0].pfn << - PAGE_SHIFT) - + PAGE_SIZE - start; - bytes_remain = netvsc_packet->total_data_buflen - - netvsc_packet->page_buf[0].len; - for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) { - netvsc_packet->page_buf[j].offset = 0; - if (bytes_remain <= PAGE_SIZE) { - netvsc_packet->page_buf[j].len = - bytes_remain; - bytes_remain = 0; - } else { - netvsc_packet->page_buf[j].len = - PAGE_SIZE; - bytes_remain -= PAGE_SIZE; - } - netvsc_packet->page_buf[j].pfn = - virt_to_phys((void *)(end_virtual - - bytes_remain)) >> PAGE_SHIFT; - netvsc_packet->page_buf_cnt++; - if (bytes_remain == 0) - break; - } - } - - /* Pass it to the upper layer */ - rndis_filter_receive(device, netvsc_packet); - - netvsc_receive_completion(netvsc_packet-> - completion.recv.recv_completion_ctx); - } - -} - -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; - struct net_device *ndev; - - 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) - goto out; - ndev = net_device->ndev; - - do { - ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, - &bytes_recvd, &request_id); - if (ret == 0) { - if (bytes_recvd > 0) { - desc = (struct vmpacket_descriptor *)buffer; - switch (desc->type) { - case VM_PKT_COMP: - netvsc_send_completion(device, desc); - break; - - case VM_PKT_DATA_USING_XFER_PAGES: - netvsc_receive(device, desc); - break; - - default: - netdev_err(ndev, - "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 == -ENOBUFS) { - /* Handle large packet */ - buffer = kmalloc(bytes_recvd, GFP_ATOMIC); - if (buffer == NULL) { - /* Try again next time around */ - netdev_err(ndev, - "unable to allocate buffer of size " - "(%d)!!\n", bytes_recvd); - break; - } - - bufferlen = bytes_recvd; - } - } while (1); - -out: - kfree(buffer); - return; -} - -/* - * netvsc_device_add - Callback when the device belonging to this - * driver is added - */ -int netvsc_device_add(struct hv_device *device, void *additional_info) -{ - int ret = 0; - int i; - int ring_size = - ((struct netvsc_device_info *)additional_info)->ring_size; - struct netvsc_device *net_device; - struct hv_netvsc_packet *packet, *pos; - struct net_device *ndev; - - net_device = alloc_net_device(device); - if (!net_device) { - ret = -ENOMEM; - goto cleanup; - } - - /* - * Coming into this function, struct net_device * is - * registered as the driver private data. - * In alloc_net_device(), we register struct netvsc_device * - * as the driver private data and stash away struct net_device * - * in struct netvsc_device *. - */ - ndev = net_device->ndev; - - /* Initialize the NetVSC channel extension */ - net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; - spin_lock_init(&net_device->recv_pkt_list_lock); - - INIT_LIST_HEAD(&net_device->recv_pkt_list); - - for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) { - packet = kzalloc(sizeof(struct hv_netvsc_packet) + - (NETVSC_RECEIVE_SG_COUNT * - sizeof(struct hv_page_buffer)), GFP_KERNEL); - if (!packet) - break; - - list_add_tail(&packet->list_ent, - &net_device->recv_pkt_list); - } - init_completion(&net_device->channel_init_wait); - - /* Open the channel */ - ret = vmbus_open(device->channel, ring_size * PAGE_SIZE, - ring_size * PAGE_SIZE, NULL, 0, - netvsc_channel_cb, device); - - if (ret != 0) { - netdev_err(ndev, "unable to open channel: %d\n", ret); - goto cleanup; - } - - /* Channel is opened */ - pr_info("hv_netvsc channel opened successfully\n"); - - /* Connect with the NetVsp */ - ret = netvsc_connect_vsp(device); - if (ret != 0) { - netdev_err(ndev, - "unable to connect to NetVSP - %d\n", ret); - goto close; - } - - return ret; - -close: - /* Now, we can close the channel safely */ - vmbus_close(device->channel); - -cleanup: - - if (net_device) { - list_for_each_entry_safe(packet, pos, - &net_device->recv_pkt_list, - list_ent) { - list_del(&packet->list_ent); - kfree(packet); - } - - kfree(net_device); - } - - return ret; -} diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c deleted file mode 100644 index 93b0e91cbf9..00000000000 --- a/drivers/staging/hv/netvsc_drv.c +++ /dev/null @@ -1,456 +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> - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/init.h> -#include <linux/atomic.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 <net/arp.h> -#include <net/route.h> -#include <net/sock.h> -#include <net/pkt_sched.h> - -#include "hyperv_net.h" - -struct net_device_context { - /* point back to our device context */ - struct hv_device *device_ctx; - atomic_t avail; - struct delayed_work dwork; -}; - - -#define PACKET_PAGES_LOWATER 8 -/* Need this many pages to handle worst case fragmented packet */ -#define PACKET_PAGES_HIWATER (MAX_SKB_FRAGS + 2) - -static int ring_size = 128; -module_param(ring_size, int, S_IRUGO); -MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)"); - -/* 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; - int ret = 0; - - /* Open up the device */ - ret = rndis_filter_open(device_obj); - if (ret != 0) { - netdev_err(net, "unable to open device (ret %d).\n", ret); - return ret; - } - - netif_start_queue(net); - - 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; - int ret; - - netif_stop_queue(net); - - ret = rndis_filter_close(device_obj); - if (ret != 0) - netdev_err(net, "unable to close device (ret %d).\n", 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); - - atomic_add(num_pages, &net_device_ctx->avail); - if (atomic_read(&net_device_ctx->avail) >= - PACKET_PAGES_HIWATER) - netif_wake_queue(net); - } -} - -static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) -{ - struct net_device_context *net_device_ctx = netdev_priv(net); - struct hv_netvsc_packet *packet; - int ret; - unsigned int i, num_pages; - - /* Add 1 for skb->data and additional one for RNDIS */ - num_pages = skb_shinfo(skb)->nr_frags + 1 + 1; - if (num_pages > atomic_read(&net_device_ctx->avail)) - return NETDEV_TX_BUSY; - - /* Allocate a netvsc packet based on # of frags. */ - packet = kzalloc(sizeof(struct hv_netvsc_packet) + - (num_pages * sizeof(struct hv_page_buffer)) + - sizeof(struct rndis_filter_packet), GFP_ATOMIC); - if (!packet) { - /* out of memory, drop packet */ - netdev_err(net, "unable to allocate hv_netvsc_packet\n"); - - dev_kfree_skb(skb); - net->stats.tx_dropped++; - return NETDEV_TX_BUSY; - } - - 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; - - /* 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].len = skb_headlen(skb); - - /* Additional fragments are after SKB data */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - const skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - - packet->page_buf[i+2].pfn = page_to_pfn(skb_frag_page(f)); - packet->page_buf[i+2].offset = f->page_offset; - packet->page_buf[i+2].len = skb_frag_size(f); - } - - /* 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 = rndis_filter_send(net_device_ctx->device_ctx, - packet); - if (ret == 0) { - net->stats.tx_bytes += skb->len; - net->stats.tx_packets++; - - atomic_sub(num_pages, &net_device_ctx->avail); - if (atomic_read(&net_device_ctx->avail) < PACKET_PAGES_LOWATER) - netif_stop_queue(net); - } else { - /* we are shutting down or bus overloaded, just drop packet */ - net->stats.tx_dropped++; - kfree(packet); - dev_kfree_skb_any(skb); - } - - return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK; -} - -/* - * netvsc_linkstatus_callback - Link up/down notification - */ -void netvsc_linkstatus_callback(struct hv_device *device_obj, - unsigned int status) -{ - struct net_device *net; - struct net_device_context *ndev_ctx; - struct netvsc_device *net_device; - - net_device = hv_get_drvdata(device_obj); - net = net_device->ndev; - - if (!net) { - netdev_err(net, "got link status but net device " - "not initialized yet\n"); - return; - } - - if (status == 1) { - netif_carrier_on(net); - netif_wake_queue(net); - ndev_ctx = netdev_priv(net); - schedule_delayed_work(&ndev_ctx->dwork, 0); - schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20)); - } 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. - */ -int netvsc_recv_callback(struct hv_device *device_obj, - struct hv_netvsc_packet *packet) -{ - struct net_device *net = dev_get_drvdata(&device_obj->device); - struct sk_buff *skb; - void *data; - int i; - unsigned long flags; - struct netvsc_device *net_device; - - net_device = hv_get_drvdata(device_obj); - net = net_device->ndev; - - if (!net) { - netdev_err(net, "got receive callback but net device" - " not initialized yet\n"); - 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].len), data, - packet->page_buf[i].len); - - 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); - - 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_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_rx_mode = netvsc_set_multicast_list, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, -}; - -/* - * Send GARP packet to network peers after migrations. - * After Quick Migration, the network is not immediately operational in the - * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add - * another netif_notify_peers() into a delayed work, otherwise GARP packet - * will not be sent after quick migration, and cause network disconnection. - */ -static void netvsc_send_garp(struct work_struct *w) -{ - struct net_device_context *ndev_ctx; - struct net_device *net; - struct netvsc_device *net_device; - - ndev_ctx = container_of(w, struct net_device_context, dwork.work); - net_device = hv_get_drvdata(ndev_ctx->device_ctx); - net = net_device->ndev; - netif_notify_peers(net); -} - - -static int netvsc_probe(struct hv_device *dev, - const struct hv_vmbus_device_id *dev_id) -{ - struct net_device *net = NULL; - struct net_device_context *net_device_ctx; - struct netvsc_device_info device_info; - int ret; - - net = alloc_etherdev(sizeof(struct net_device_context)); - if (!net) - return -ENOMEM; - - /* Set initial state */ - netif_carrier_off(net); - - net_device_ctx = netdev_priv(net); - net_device_ctx->device_ctx = dev; - atomic_set(&net_device_ctx->avail, ring_size); - hv_set_drvdata(dev, net); - INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp); - - net->netdev_ops = &device_ops; - - /* TODO: Add GSO and Checksum offload */ - net->hw_features = NETIF_F_SG; - net->features = NETIF_F_SG; - - SET_ETHTOOL_OPS(net, ðtool_ops); - SET_NETDEV_DEV(net, &dev->device); - - ret = register_netdev(net); - if (ret != 0) { - pr_err("Unable to register netdev.\n"); - free_netdev(net); - goto out; - } - - /* Notify the netvsc driver of the new device */ - device_info.ring_size = ring_size; - ret = rndis_filter_device_add(dev, &device_info); - if (ret != 0) { - netdev_err(net, "unable to add netvsc device (ret %d)\n", ret); - unregister_netdev(net); - free_netdev(net); - hv_set_drvdata(dev, NULL); - return ret; - } - memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); - - netif_carrier_on(net); - -out: - return ret; -} - -static int netvsc_remove(struct hv_device *dev) -{ - struct net_device *net; - struct net_device_context *ndev_ctx; - struct netvsc_device *net_device; - - net_device = hv_get_drvdata(dev); - net = net_device->ndev; - - if (net == NULL) { - dev_err(&dev->device, "No net device to remove\n"); - return 0; - } - - ndev_ctx = netdev_priv(net); - cancel_delayed_work_sync(&ndev_ctx->dwork); - - /* Stop outbound asap */ - netif_stop_queue(net); - - unregister_netdev(net); - - /* - * Call to the vsc driver to let it know that the device is being - * removed - */ - rndis_filter_device_remove(dev); - - free_netdev(net); - return 0; -} - -static const struct hv_vmbus_device_id id_table[] = { - /* Network guid */ - { VMBUS_DEVICE(0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, - 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E) }, - { }, -}; - -MODULE_DEVICE_TABLE(vmbus, id_table); - -/* The one and only one */ -static struct hv_driver netvsc_drv = { - .name = "netvsc", - .id_table = id_table, - .probe = netvsc_probe, - .remove = netvsc_remove, -}; - -static void __exit netvsc_drv_exit(void) -{ - vmbus_driver_unregister(&netvsc_drv); -} - -static int __init netvsc_drv_init(void) -{ - return vmbus_driver_register(&netvsc_drv); -} - -MODULE_LICENSE("GPL"); -MODULE_VERSION(HV_DRV_VERSION); -MODULE_DESCRIPTION("Microsoft Hyper-V network driver"); - -module_init(netvsc_drv_init); -module_exit(netvsc_drv_exit); diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c deleted file mode 100644 index bafccb36004..00000000000 --- a/drivers/staging/hv/rndis_filter.c +++ /dev/null @@ -1,855 +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/sched.h> -#include <linux/wait.h> -#include <linux/highmem.h> -#include <linux/slab.h> -#include <linux/io.h> -#include <linux/if_ether.h> -#include <linux/netdevice.h> - -#include "hyperv_net.h" - - -enum rndis_device_state { - RNDIS_DEV_UNINITIALIZED = 0, - RNDIS_DEV_INITIALIZING, - RNDIS_DEV_INITIALIZED, - RNDIS_DEV_DATAINITIALIZED, -}; - -struct rndis_device { - struct netvsc_device *net_dev; - - enum rndis_device_state state; - bool link_state; - atomic_t new_req_id; - - spinlock_t request_lock; - struct list_head req_list; - - unsigned char hw_mac_adr[ETH_ALEN]; -}; - -struct rndis_request { - struct list_head list_ent; - struct completion wait_event; - - /* - * 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; -}; - -static void rndis_filter_send_completion(void *ctx); - -static void rndis_filter_send_request_completion(void *ctx); - - - -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; - - init_completion(&request->wait_event); - - 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); -} - -static void dump_rndis_message(struct hv_device *hv_dev, - struct rndis_message *rndis_msg) -{ - struct net_device *netdev; - struct netvsc_device *net_device; - - net_device = hv_get_drvdata(hv_dev); - netdev = net_device->ndev; - - switch (rndis_msg->ndis_msg_type) { - case REMOTE_NDIS_PACKET_MSG: - netdev_dbg(netdev, "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\n", - 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: - netdev_dbg(netdev, "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)\n", - 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: - netdev_dbg(netdev, "REMOTE_NDIS_QUERY_CMPLT " - "(len %u, id 0x%x, status 0x%x, buf len %u, " - "buf offset %u)\n", - 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: - netdev_dbg(netdev, - "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)\n", - rndis_msg->msg_len, - rndis_msg->msg.set_complete.req_id, - rndis_msg->msg.set_complete.status); - break; - - case REMOTE_NDIS_INDICATE_STATUS_MSG: - netdev_dbg(netdev, "REMOTE_NDIS_INDICATE_STATUS_MSG " - "(len %u, status 0x%x, buf len %u, buf offset %u)\n", - 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: - netdev_dbg(netdev, "0x%x (len %u)\n", - 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].len = 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 = netvsc_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; - struct net_device *ndev; - - ndev = dev->net_dev->ndev; - - 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) { - 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 { - netdev_err(ndev, - "rndis response buffer overflow " - "detected (size %u max %zu)\n", - resp->msg_len, - sizeof(struct rndis_filter_packet)); - - if (resp->ndis_msg_type == - REMOTE_NDIS_RESET_CMPLT) { - /* 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; - } - } - - complete(&request->wait_event); - } else { - netdev_err(ndev, - "no rndis request found for this response " - "(id 0x%x res type 0x%x)\n", - resp->msg.init_complete.req_id, - resp->ndis_msg_type); - } -} - -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) { - netvsc_linkstatus_callback( - dev->net_dev->dev, 1); - } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) { - netvsc_linkstatus_callback( - 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; - int i; - - 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].len -= data_offset; - - /* Drop the 0th page, if rndis data go beyond page boundary */ - if (pkt->page_buf[0].offset >= PAGE_SIZE) { - pkt->page_buf[1].offset = pkt->page_buf[0].offset - PAGE_SIZE; - pkt->page_buf[1].len -= pkt->page_buf[1].offset; - pkt->page_buf_cnt--; - for (i = 0; i < pkt->page_buf_cnt; i++) - pkt->page_buf[i] = pkt->page_buf[i+1]; - } - - pkt->is_data_pkt = true; - - netvsc_recv_callback(dev->net_dev->dev, pkt); -} - -int rndis_filter_receive(struct hv_device *dev, - struct hv_netvsc_packet *pkt) -{ - struct netvsc_device *net_dev = hv_get_drvdata(dev); - struct rndis_device *rndis_dev; - struct rndis_message rndis_msg; - struct rndis_message *rndis_hdr; - struct net_device *ndev; - - if (!net_dev) - return -EINVAL; - - ndev = net_dev->ndev; - - /* Make sure the rndis device state is initialized */ - if (!net_dev->extension) { - netdev_err(ndev, "got rndis message but no rndis device - " - "dropping this message!\n"); - return -ENODEV; - } - - rndis_dev = (struct rndis_device *)net_dev->extension; - if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { - netdev_err(ndev, "got rndis message but rndis device " - "uninitialized...dropping this message!\n"); - return -ENODEV; - } - - rndis_hdr = (struct rndis_message *)kmap_atomic( - pfn_to_page(pkt->page_buf[0].pfn), KM_IRQ0); - - rndis_hdr = (void *)((unsigned long)rndis_hdr + - pkt->page_buf[0].offset); - - /* Make sure we got a valid rndis message */ - if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) && - (rndis_hdr->msg_len > sizeof(struct rndis_message))) { - netdev_err(ndev, "incoming rndis message buffer overflow " - "detected (got %u, max %zu)..marking it an error!\n", - rndis_hdr->msg_len, - sizeof(struct rndis_message)); - } - - 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(dev, &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: - /* 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: - netdev_err(ndev, - "unhandled rndis message (type %u len %u)\n", - 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; - int t; - - 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 = -ENOMEM; - 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; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - /* 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); - u32 link_status; - int ret; - - ret = rndis_filter_query_device(dev, - RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, - &link_status, &size); - dev->link_state = (link_status != 0) ? true : false; - - return ret; -} - -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, t; - struct net_device *ndev; - - ndev = dev->net_dev->ndev; - - request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_set_request) + - sizeof(u32)); - if (!request) { - ret = -ENOMEM; - 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; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - - if (t == 0) { - netdev_err(ndev, - "timeout before we got a set response...\n"); - /* - * We can't deallocate the request since we may still receive a - * send completion for it. - */ - goto exit; - } else { - set_complete = &request->response_msg.msg.set_complete; - status = set_complete->status; - } - -cleanup: - if (request) - put_rndis_request(dev, request); -exit: - return ret; -} - - -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, t; - - request = get_rndis_request(dev, REMOTE_NDIS_INITIALIZE_MSG, - RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); - if (!request) { - ret = -ENOMEM; - 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; - } - - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - 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 = -EINVAL; - } - -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; -} - -int rndis_filter_device_add(struct hv_device *dev, - void *additional_info) -{ - int ret; - struct netvsc_device *net_device; - struct rndis_device *rndis_device; - struct netvsc_device_info *device_info = additional_info; - - rndis_device = get_rndis_device(); - if (!rndis_device) - return -ENODEV; - - /* - * 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 = netvsc_device_add(dev, additional_info); - if (ret != 0) { - kfree(rndis_device); - return ret; - } - - - /* Initialize the rndis device */ - net_device = hv_get_drvdata(dev); - - net_device->extension = rndis_device; - rndis_device->net_dev = net_device; - - /* Send the rndis initialization message */ - ret = rndis_filter_init_device(rndis_device); - 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(rndis_device); - if (ret != 0) { - /* - * TODO: shutdown rndis device and the channel - */ - } - - memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); - - rndis_filter_query_device_link_status(rndis_device); - - device_info->link_state = rndis_device->link_state; - - dev_info(&dev->device, "Device MAC %pM link state %s\n", - rndis_device->hw_mac_adr, - device_info->link_state ? "down" : "up"); - - return ret; -} - -void rndis_filter_device_remove(struct hv_device *dev) -{ - struct netvsc_device *net_dev = hv_get_drvdata(dev); - 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; - - netvsc_device_remove(dev); -} - - -int rndis_filter_open(struct hv_device *dev) -{ - struct netvsc_device *net_device = hv_get_drvdata(dev); - - if (!net_device) - return -EINVAL; - - return rndis_filter_open_device(net_device->extension); -} - -int rndis_filter_close(struct hv_device *dev) -{ - struct netvsc_device *netDevice = hv_get_drvdata(dev); - - if (!netDevice) - return -EINVAL; - - return rndis_filter_close_device(netDevice->extension); -} - -int rndis_filter_send(struct hv_device *dev, - struct hv_netvsc_packet *pkt) -{ - int ret; - struct rndis_filter_packet *filterPacket; - struct rndis_message *rndisMessage; - struct rndis_packet *rndisPacket; - u32 rndisMessageSize; - - /* Add the rndis header */ - filterPacket = (struct rndis_filter_packet *)pkt->extension; - - 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].len = 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 = netvsc_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/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c deleted file mode 100644 index 8960f1a7354..00000000000 --- a/drivers/staging/hv/storvsc_drv.c +++ /dev/null @@ -1,1486 +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> - * K. Y. Srinivasan <kys@microsoft.com> - */ - -#include <linux/kernel.h> -#include <linux/wait.h> -#include <linux/sched.h> -#include <linux/completion.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/hyperv.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> - - -#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE) -static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE; - -module_param(storvsc_ringbuffer_size, int, S_IRUGO); -MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)"); - -/* to alert the user that structure sizes may be mismatched even though the */ -/* protocol versions match. */ - - -#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; -} __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; -} __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; - }; -} __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) - - -/* Defines */ - -#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 -#define STORVSC_MAX_CMD_LEN 16 - -struct hv_storvsc_request; - -/* Matches Windows-end */ -enum storvsc_request_type { - WRITE_TYPE, - READ_TYPE, - UNKNOWN_TYPE, -}; - - -struct hv_storvsc_request { - struct hv_device *device; - - /* Synchronize the request/response if needed */ - struct completion wait_event; - - unsigned char *sense_buffer; - void *context; - void (*on_io_completion)(struct hv_storvsc_request *request); - struct hv_multipage_buffer data_buffer; - - struct vstor_packet vstor_packet; -}; - - -/* A storvsc device is a device object that contains a vmbus channel */ -struct storvsc_device { - struct hv_device *device; - - bool destroy; - bool drain_notify; - atomic_t num_outstanding_req; - struct Scsi_Host *host; - - wait_queue_head_t waiting_to_drain; - - /* - * Each unique Port/Path/Target represents 1 channel ie scsi - * controller. In reality, the pathid, targetid is always 0 - * and the port is set by us - */ - unsigned int port_number; - unsigned char path_id; - unsigned char target_id; - - /* Used for vsc/vsp channel reset process */ - struct hv_storvsc_request init_request; - struct hv_storvsc_request reset_request; -}; - -struct hv_host_device { - struct hv_device *dev; - 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; -}; - -static inline struct storvsc_device *get_out_stor_device( - struct hv_device *device) -{ - struct storvsc_device *stor_device; - - stor_device = hv_get_drvdata(device); - - if (stor_device && stor_device->destroy) - stor_device = NULL; - - return stor_device; -} - - -static inline void storvsc_wait_to_drain(struct storvsc_device *dev) -{ - dev->drain_notify = true; - wait_event(dev->waiting_to_drain, - atomic_read(&dev->num_outstanding_req) == 0); - dev->drain_notify = false; -} - -static inline struct storvsc_device *get_in_stor_device( - struct hv_device *device) -{ - struct storvsc_device *stor_device; - - stor_device = hv_get_drvdata(device); - - if (!stor_device) - goto get_in_err; - - /* - * If the device is being destroyed; allow incoming - * traffic only to cleanup outstanding requests. - */ - - if (stor_device->destroy && - (atomic_read(&stor_device->num_outstanding_req) == 0)) - stor_device = NULL; - -get_in_err: - return stor_device; - -} - -static int storvsc_channel_init(struct hv_device *device) -{ - struct storvsc_device *stor_device; - struct hv_storvsc_request *request; - struct vstor_packet *vstor_packet; - int ret, t; - - stor_device = get_out_stor_device(device); - if (!stor_device) - return -ENODEV; - - 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 hv_storvsc_request)); - init_completion(&request->wait_event); - vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) - goto cleanup; - - - /* 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, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) - goto cleanup; - - - 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, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) - goto cleanup; - - stor_device->path_id = vstor_packet->storage_channel_properties.path_id; - stor_device->target_id - = vstor_packet->storage_channel_properties.target_id; - - 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, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) - goto cleanup; - - -cleanup: - return ret; -} - -static void storvsc_on_io_completion(struct hv_device *device, - struct vstor_packet *vstor_packet, - struct hv_storvsc_request *request) -{ - struct storvsc_device *stor_device; - struct vstor_packet *stor_pkt; - - stor_device = hv_get_drvdata(device); - stor_pkt = &request->vstor_packet; - - /* - * The current SCSI handling on the host side does - * not correctly handle: - * INQUIRY command with page code parameter set to 0x80 - * MODE_SENSE command with cmd[2] == 0x1c - * - * Setup srb and scsi status so this won't be fatal. - * We do this so we can distinguish truly fatal failues - * (srb status == 0x4) and off-line the device in that case. - */ - - if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || - (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) { - vstor_packet->vm_srb.scsi_status = 0; - vstor_packet->vm_srb.srb_status = 0x1; - } - - - /* Copy over the status...etc */ - stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status; - stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status; - stor_pkt->vm_srb.sense_info_length = - vstor_packet->vm_srb.sense_info_length; - - if (vstor_packet->vm_srb.scsi_status != 0 || - vstor_packet->vm_srb.srb_status != 1){ - dev_warn(&device->device, - "cmd 0x%x scsi status 0x%x srb status 0x%x\n", - stor_pkt->vm_srb.cdb[0], - vstor_packet->vm_srb.scsi_status, - vstor_packet->vm_srb.srb_status); - } - - if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) { - /* CHECK_CONDITION */ - if (vstor_packet->vm_srb.srb_status & 0x80) { - /* autosense data available */ - dev_warn(&device->device, - "stor pkt %p autosense data valid - len %d\n", - request, - vstor_packet->vm_srb.sense_info_length); - - memcpy(request->sense_buffer, - vstor_packet->vm_srb.sense_data, - vstor_packet->vm_srb.sense_info_length); - - } - } - - stor_pkt->vm_srb.data_transfer_length = - vstor_packet->vm_srb.data_transfer_length; - - request->on_io_completion(request); - - if (atomic_dec_and_test(&stor_device->num_outstanding_req) && - stor_device->drain_notify) - wake_up(&stor_device->waiting_to_drain); - - -} - -static void storvsc_on_receive(struct hv_device *device, - struct vstor_packet *vstor_packet, - struct hv_storvsc_request *request) -{ - switch (vstor_packet->operation) { - case VSTOR_OPERATION_COMPLETE_IO: - storvsc_on_io_completion(device, vstor_packet, request); - break; - case VSTOR_OPERATION_REMOVE_DEVICE: - - default: - break; - } -} - -static void storvsc_on_channel_callback(void *context) -{ - struct hv_device *device = (struct hv_device *)context; - struct storvsc_device *stor_device; - u32 bytes_recvd; - u64 request_id; - unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)]; - struct hv_storvsc_request *request; - int ret; - - - stor_device = get_in_stor_device(device); - if (!stor_device) - return; - - do { - ret = vmbus_recvpacket(device->channel, packet, - ALIGN(sizeof(struct vstor_packet), 8), - &bytes_recvd, &request_id); - if (ret == 0 && bytes_recvd > 0) { - - request = (struct hv_storvsc_request *) - (unsigned long)request_id; - - if ((request == &stor_device->init_request) || - (request == &stor_device->reset_request)) { - - memcpy(&request->vstor_packet, packet, - sizeof(struct vstor_packet)); - complete(&request->wait_event); - } else { - storvsc_on_receive(device, - (struct vstor_packet *)packet, - request); - } - } else { - break; - } - } while (1); - - return; -} - -static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size) -{ - struct vmstorage_channel_properties props; - int ret; - - memset(&props, 0, sizeof(struct vmstorage_channel_properties)); - - /* Open the channel */ - ret = vmbus_open(device->channel, - ring_size, - ring_size, - (void *)&props, - sizeof(struct vmstorage_channel_properties), - storvsc_on_channel_callback, device); - - if (ret != 0) - return ret; - - ret = storvsc_channel_init(device); - - return ret; -} - -static int storvsc_dev_remove(struct hv_device *device) -{ - struct storvsc_device *stor_device; - unsigned long flags; - - stor_device = hv_get_drvdata(device); - - spin_lock_irqsave(&device->channel->inbound_lock, flags); - stor_device->destroy = true; - spin_unlock_irqrestore(&device->channel->inbound_lock, flags); - - /* - * At this point, all outbound traffic should be disable. We - * only allow inbound traffic (responses) to proceed so that - * outstanding requests can be completed. - */ - - storvsc_wait_to_drain(stor_device); - - /* - * Since we have already drained, we don't need to busy wait - * as was done in final_release_stor_device() - * Note that we cannot set the ext pointer to NULL until - * we have drained - to drain the outgoing packets, we need to - * allow incoming packets. - */ - spin_lock_irqsave(&device->channel->inbound_lock, flags); - hv_set_drvdata(device, NULL); - spin_unlock_irqrestore(&device->channel->inbound_lock, flags); - - /* Close the channel */ - vmbus_close(device->channel); - - kfree(stor_device); - return 0; -} - -static int storvsc_do_io(struct hv_device *device, - struct hv_storvsc_request *request) -{ - struct storvsc_device *stor_device; - struct vstor_packet *vstor_packet; - int ret = 0; - - vstor_packet = &request->vstor_packet; - stor_device = get_out_stor_device(device); - - if (!stor_device) - return -ENODEV; - - - request->device = device; - - - vstor_packet->flags |= REQUEST_COMPLETION_FLAG; - - vstor_packet->vm_srb.length = sizeof(struct vmscsi_request); - - - vstor_packet->vm_srb.sense_info_length = SENSE_BUFFER_SIZE; - - - vstor_packet->vm_srb.data_transfer_length = - request->data_buffer.len; - - vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB; - - if (request->data_buffer.len) { - ret = vmbus_sendpacket_multipagebuffer(device->channel, - &request->data_buffer, - vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request); - } else { - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - } - - if (ret != 0) - return ret; - - atomic_inc(&stor_device->num_outstanding_req); - - return ret; -} - -static void storvsc_get_ide_info(struct hv_device *dev, int *target, int *path) -{ - *target = - dev->dev_instance.b[5] << 8 | dev->dev_instance.b[4]; - - *path = - dev->dev_instance.b[3] << 24 | - dev->dev_instance.b[2] << 16 | - dev->dev_instance.b[1] << 8 | dev->dev_instance.b[0]; -} - - -static int storvsc_device_alloc(struct scsi_device *sdevice) -{ - /* - * 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_merge_bvec(struct request_queue *q, - struct bvec_merge_data *bmd, struct bio_vec *bvec) -{ - /* checking done by caller. */ - return bvec->bv_len; -} - -static int storvsc_device_configure(struct scsi_device *sdevice) -{ - scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG, - STORVSC_MAX_IO_REQUESTS); - - blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE); - - blk_queue_merge_bvec(sdevice->request_queue, storvsc_merge_bvec); - - blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY); - - return 0; -} - -static void destroy_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count) -{ - int i; - struct page *page_buf; - - for (i = 0; i < sg_count; i++) { - page_buf = sg_page((&sgl[i])); - if (page_buf != NULL) - __free_page(page_buf); - } - - kfree(sgl); -} - -static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count) -{ - int i; - - /* No need to check */ - if (sg_count < 2) - return -1; - - /* We have at least 2 sg entries */ - for (i = 0; i < sg_count; i++) { - if (i == 0) { - /* make sure 1st one does not have hole */ - if (sgl[i].offset + sgl[i].length != PAGE_SIZE) - return i; - } else if (i == sg_count - 1) { - /* make sure last one does not have hole */ - if (sgl[i].offset != 0) - return i; - } else { - /* make sure no hole in the middle */ - if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0) - return i; - } - } - return -1; -} - -static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count, - unsigned int len) -{ - int i; - int num_pages; - struct scatterlist *bounce_sgl; - struct page *page_buf; - - num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT; - - bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC); - if (!bounce_sgl) - return NULL; - - sg_init_table(bounce_sgl, num_pages); - 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; -} - - -/* 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; - - 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; -} - - -/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */ -static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, - struct scatterlist *bounce_sgl, - unsigned int orig_sgl_count) -{ - int i; - int j = 0; - unsigned long src, dest; - unsigned int srclen, destlen, copylen; - unsigned int total_copied = 0; - unsigned long bounce_addr = 0; - unsigned long src_addr = 0; - unsigned long flags; - - local_irq_save(flags); - - for (i = 0; i < orig_sgl_count; i++) { - src_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])), - KM_IRQ0) + orig_sgl[i].offset; - src = src_addr; - srclen = orig_sgl[i].length; - - if (bounce_addr == 0) - bounce_addr = - (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), - KM_IRQ0); - - while (srclen) { - /* assume bounce offset always == 0 */ - dest = bounce_addr + bounce_sgl[j].length; - destlen = PAGE_SIZE - bounce_sgl[j].length; - - copylen = min(srclen, destlen); - memcpy((void *)dest, (void *)src, copylen); - - total_copied += copylen; - bounce_sgl[j].length += copylen; - srclen -= copylen; - src += copylen; - - if (bounce_sgl[j].length == PAGE_SIZE) { - /* full..move to next entry */ - kunmap_atomic((void *)bounce_addr, KM_IRQ0); - j++; - - /* if we need to use another bounce buffer */ - if (srclen || i != orig_sgl_count - 1) - bounce_addr = - (unsigned long)kmap_atomic( - sg_page((&bounce_sgl[j])), KM_IRQ0); - - } else if (srclen == 0 && i == orig_sgl_count - 1) { - /* unmap the last bounce that is < PAGE_SIZE */ - kunmap_atomic((void *)bounce_addr, KM_IRQ0); - } - } - - kunmap_atomic((void *)(src_addr - orig_sgl[i].offset), KM_IRQ0); - } - - local_irq_restore(flags); - - return total_copied; -} - - -static int storvsc_remove(struct hv_device *dev) -{ - struct storvsc_device *stor_device = hv_get_drvdata(dev); - struct Scsi_Host *host = stor_device->host; - struct hv_host_device *host_dev = - (struct hv_host_device *)host->hostdata; - - scsi_remove_host(host); - - scsi_host_put(host); - - storvsc_dev_remove(dev); - if (host_dev->request_pool) { - kmem_cache_destroy(host_dev->request_pool); - host_dev->request_pool = NULL; - } - return 0; -} - - -static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev, - sector_t capacity, int *info) -{ - sector_t nsect = capacity; - sector_t cylinders = nsect; - int heads, sectors_pt; - - /* - * We are making up these values; let us keep it simple. - */ - heads = 0xff; - sectors_pt = 0x3f; /* Sectors per track */ - sector_div(cylinders, heads * sectors_pt); - if ((sector_t)(cylinders + 1) * heads * sectors_pt < nsect) - cylinders = 0xffff; - - info[0] = heads; - info[1] = sectors_pt; - info[2] = (int)cylinders; - - return 0; -} - -static int storvsc_host_reset(struct hv_device *device) -{ - struct storvsc_device *stor_device; - struct hv_storvsc_request *request; - struct vstor_packet *vstor_packet; - int ret, t; - - - stor_device = get_out_stor_device(device); - if (!stor_device) - return -ENODEV; - - request = &stor_device->reset_request; - vstor_packet = &request->vstor_packet; - - init_completion(&request->wait_event); - - vstor_packet->operation = VSTOR_OPERATION_RESET_BUS; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - vstor_packet->vm_srb.path_id = stor_device->path_id; - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)&stor_device->reset_request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - - /* - * At this point, all outstanding requests in the adapter - * should have been flushed out and return to us - * There is a potential race here where the host may be in - * the process of responding when we return from here. - * Just wait for all in-transit packets to be accounted for - * before we return from here. - */ - storvsc_wait_to_drain(stor_device); - -cleanup: - return ret; -} - - -/* - * storvsc_host_reset_handler - Reset the scsi HBA - */ -static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) -{ - int ret; - struct hv_host_device *host_dev = - (struct hv_host_device *)scmnd->device->host->hostdata; - struct hv_device *dev = host_dev->dev; - - ret = storvsc_host_reset(dev); - if (ret != 0) - return ret; - - return ret; -} - - -/* - * storvsc_command_completion - Command completion processing - */ -static void storvsc_command_completion(struct hv_storvsc_request *request) -{ - struct storvsc_cmd_request *cmd_request = - (struct storvsc_cmd_request *)request->context; - struct scsi_cmnd *scmnd = cmd_request->cmd; - struct hv_host_device *host_dev = - (struct hv_host_device *)scmnd->device->host->hostdata; - void (*scsi_done_fn)(struct scsi_cmnd *); - struct scsi_sense_hdr sense_hdr; - struct vmscsi_request *vm_srb; - - vm_srb = &request->vstor_packet.vm_srb; - if (cmd_request->bounce_sgl_count) { - if (vm_srb->data_in == READ_TYPE) { - copy_from_bounce_buffer(scsi_sglist(scmnd), - cmd_request->bounce_sgl, - scsi_sg_count(scmnd)); - destroy_bounce_buffer(cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - } - } - - /* - * If there is an error; offline the device since all - * error recovery strategies would have already been - * deployed on the host side. - */ - if (vm_srb->srb_status == 0x4) - scmnd->result = DID_TARGET_FAILURE << 16; - else - scmnd->result = vm_srb->scsi_status; - - if (scmnd->result) { - if (scsi_normalize_sense(scmnd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, &sense_hdr)) - scsi_print_sense_hdr("storvsc", &sense_hdr); - } - - scsi_set_resid(scmnd, - request->data_buffer.len - - vm_srb->data_transfer_length); - - scsi_done_fn = scmnd->scsi_done; - - scmnd->host_scribble = NULL; - scmnd->scsi_done = NULL; - - scsi_done_fn(scmnd); - - kmem_cache_free(host_dev->request_pool, cmd_request); -} - -static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd) -{ - bool allowed = true; - u8 scsi_op = scmnd->cmnd[0]; - - switch (scsi_op) { - /* smartd sends this command, which will offline the device */ - case SET_WINDOW: - scmnd->result = DID_ERROR << 16; - allowed = false; - break; - default: - break; - } - return allowed; -} - -/* - * storvsc_queuecommand - Initiate command processing - */ -static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd, - void (*done)(struct scsi_cmnd *)) -{ - int ret; - struct hv_host_device *host_dev = - (struct hv_host_device *)scmnd->device->host->hostdata; - struct hv_device *dev = host_dev->dev; - struct hv_storvsc_request *request; - struct storvsc_cmd_request *cmd_request; - unsigned int request_size = 0; - int i; - struct scatterlist *sgl; - unsigned int sg_count = 0; - struct vmscsi_request *vm_srb; - - if (storvsc_check_scsi_cmd(scmnd) == false) { - done(scmnd); - return 0; - } - - /* If retrying, no need to prep the cmd */ - if (scmnd->host_scribble) { - - cmd_request = - (struct storvsc_cmd_request *)scmnd->host_scribble; - - goto retry_request; - } - - scmnd->scsi_done = done; - - request_size = sizeof(struct storvsc_cmd_request); - - cmd_request = kmem_cache_zalloc(host_dev->request_pool, - GFP_ATOMIC); - if (!cmd_request) { - 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; - vm_srb = &request->vstor_packet.vm_srb; - - - /* Build the SRB */ - switch (scmnd->sc_data_direction) { - case DMA_TO_DEVICE: - vm_srb->data_in = WRITE_TYPE; - break; - case DMA_FROM_DEVICE: - vm_srb->data_in = READ_TYPE; - break; - default: - vm_srb->data_in = UNKNOWN_TYPE; - break; - } - - request->on_io_completion = storvsc_command_completion; - request->context = cmd_request;/* scmnd; */ - - vm_srb->port_number = host_dev->port; - vm_srb->path_id = scmnd->device->channel; - vm_srb->target_id = scmnd->device->id; - vm_srb->lun = scmnd->device->lun; - - vm_srb->cdb_length = scmnd->cmd_len; - - memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length); - - request->sense_buffer = scmnd->sense_buffer; - - - request->data_buffer.len = 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) { - cmd_request->bounce_sgl = - create_bounce_buffer(sgl, scsi_sg_count(scmnd), - scsi_bufflen(scmnd)); - if (!cmd_request->bounce_sgl) { - scmnd->scsi_done = NULL; - scmnd->host_scribble = NULL; - kmem_cache_free(host_dev->request_pool, - cmd_request); - - return SCSI_MLQUEUE_HOST_BUSY; - } - - cmd_request->bounce_sgl_count = - ALIGN(scsi_bufflen(scmnd), PAGE_SIZE) >> - PAGE_SHIFT; - - if (vm_srb->data_in == WRITE_TYPE) - 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++) - request->data_buffer.pfn_array[i] = - page_to_pfn(sg_page((&sgl[i]))); - - } else if (scsi_sglist(scmnd)) { - request->data_buffer.offset = - virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1); - request->data_buffer.pfn_array[0] = - virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT; - } - -retry_request: - /* Invokes the vsc to start an IO */ - ret = storvsc_do_io(dev, &cmd_request->request); - - if (ret == -EAGAIN) { - /* no more space */ - - if (cmd_request->bounce_sgl_count) - destroy_bounce_buffer(cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - - kmem_cache_free(host_dev->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) - - -/* 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, -}; - -enum { - SCSI_GUID, - IDE_GUID, -}; - -static const struct hv_vmbus_device_id id_table[] = { - /* SCSI guid */ - { VMBUS_DEVICE(0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, - 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f) - .driver_data = SCSI_GUID }, - /* IDE guid */ - { VMBUS_DEVICE(0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, - 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5) - .driver_data = IDE_GUID }, - { }, -}; - -MODULE_DEVICE_TABLE(vmbus, id_table); - - -/* - * storvsc_probe - Add a new device for this driver - */ - -static int storvsc_probe(struct hv_device *device, - const struct hv_vmbus_device_id *dev_id) -{ - int ret; - struct Scsi_Host *host; - struct hv_host_device *host_dev; - bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false); - int path = 0; - int target = 0; - struct storvsc_device *stor_device; - - host = scsi_host_alloc(&scsi_driver, - sizeof(struct hv_host_device)); - if (!host) - return -ENOMEM; - - host_dev = (struct hv_host_device *)host->hostdata; - memset(host_dev, 0, sizeof(struct hv_host_device)); - - host_dev->port = host->host_no; - host_dev->dev = device; - - host_dev->request_pool = - kmem_cache_create(dev_name(&device->device), - sizeof(struct storvsc_cmd_request), 0, - SLAB_HWCACHE_ALIGN, NULL); - - if (!host_dev->request_pool) { - scsi_host_put(host); - return -ENOMEM; - } - - stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL); - if (!stor_device) { - kmem_cache_destroy(host_dev->request_pool); - scsi_host_put(host); - return -ENOMEM; - } - - stor_device->destroy = false; - init_waitqueue_head(&stor_device->waiting_to_drain); - stor_device->device = device; - stor_device->host = host; - hv_set_drvdata(device, stor_device); - - stor_device->port_number = host->host_no; - ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size); - if (ret) { - kmem_cache_destroy(host_dev->request_pool); - scsi_host_put(host); - kfree(stor_device); - return ret; - } - - if (dev_is_ide) - storvsc_get_ide_info(device, &target, &path); - - host_dev->path = stor_device->path_id; - host_dev->target = stor_device->target_id; - - /* 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; - /* max cmd length */ - host->max_cmd_len = STORVSC_MAX_CMD_LEN; - - /* Register the HBA and start the scsi bus scan */ - ret = scsi_add_host(host, &device->device); - if (ret != 0) - goto err_out; - - if (!dev_is_ide) { - scsi_scan_host(host); - return 0; - } - ret = scsi_add_device(host, 0, target, 0); - if (ret) { - scsi_remove_host(host); - goto err_out; - } - return 0; - -err_out: - storvsc_dev_remove(device); - kmem_cache_destroy(host_dev->request_pool); - scsi_host_put(host); - return -ENODEV; -} - -/* The one and only one */ - -static struct hv_driver storvsc_drv = { - .name = "storvsc", - .id_table = id_table, - .probe = storvsc_probe, - .remove = storvsc_remove, -}; - -static int __init storvsc_drv_init(void) -{ - u32 max_outstanding_req_per_channel; - - /* - * 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) - */ - max_outstanding_req_per_channel = - ((storvsc_ringbuffer_size - PAGE_SIZE) / - ALIGN(MAX_MULTIPAGE_BUFFER_PACKET + - sizeof(struct vstor_packet) + sizeof(u64), - sizeof(u64))); - - if (max_outstanding_req_per_channel < - STORVSC_MAX_IO_REQUESTS) - return -EINVAL; - - return vmbus_driver_register(&storvsc_drv); -} - -static void __exit storvsc_drv_exit(void) -{ - vmbus_driver_unregister(&storvsc_drv); -} - -MODULE_LICENSE("GPL"); -MODULE_VERSION(HV_DRV_VERSION); -MODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver"); -module_init(storvsc_drv_init); -module_exit(storvsc_drv_exit); |
