Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlaf Hering <ohering@suse.de>2011-06-15 20:58:57 +0200
committerOlaf Hering <ohering@suse.de>2011-06-15 20:58:57 +0200
commit88265a8485765665958b7218808c7f30be5b102e (patch)
treeb67c842bf8f78d80ed99ade40fc878bc7607caaf
parentc63333ec3dfd8bf4dea6f178e57b4f0e529aeb0a (diff)
- patches.suse/staging-hv-update-to-3.0.patchrpm-2.6.32.41-0.5
Update hyperv drivers to current mainline state (bnc#662432). - patches.xen/xen3-patch-2.6.32: Refresh. suse-commit: 131ee6958a09a04cdde272d9c67a1089b77638c1
-rw-r--r--drivers/staging/hv/BlkVsc.c102
-rw-r--r--drivers/staging/hv/Channel.c1044
-rw-r--r--drivers/staging/hv/Channel.h112
-rw-r--r--drivers/staging/hv/ChannelInterface.c152
-rw-r--r--drivers/staging/hv/ChannelInterface.h35
-rw-r--r--drivers/staging/hv/ChannelMgmt.c851
-rw-r--r--drivers/staging/hv/ChannelMgmt.h320
-rw-r--r--drivers/staging/hv/Connection.c330
-rw-r--r--drivers/staging/hv/Hv.c499
-rw-r--r--drivers/staging/hv/Hv.h140
-rw-r--r--drivers/staging/hv/Kconfig12
-rw-r--r--drivers/staging/hv/Makefile17
-rw-r--r--drivers/staging/hv/NetVsc.c1328
-rw-r--r--drivers/staging/hv/NetVsc.h331
-rw-r--r--drivers/staging/hv/NetVscApi.h116
-rw-r--r--drivers/staging/hv/RingBuffer.c619
-rw-r--r--drivers/staging/hv/RingBuffer.h102
-rw-r--r--drivers/staging/hv/RndisFilter.c918
-rw-r--r--drivers/staging/hv/RndisFilter.h55
-rw-r--r--drivers/staging/hv/StorVsc.c856
-rw-r--r--drivers/staging/hv/StorVscApi.h110
-rw-r--r--drivers/staging/hv/TODO5
-rw-r--r--drivers/staging/hv/VersionInfo.h48
-rw-r--r--drivers/staging/hv/Vmbus.c293
-rw-r--r--drivers/staging/hv/VmbusApi.h193
-rw-r--r--drivers/staging/hv/VmbusChannelInterface.h89
-rw-r--r--drivers/staging/hv/VmbusPacketFormat.h161
-rw-r--r--drivers/staging/hv/VmbusPrivate.h135
-rw-r--r--drivers/staging/hv/blkvsc_drv.c1488
-rw-r--r--drivers/staging/hv/channel.c877
-rw-r--r--drivers/staging/hv/channel_mgmt.c784
-rw-r--r--drivers/staging/hv/connection.c290
-rw-r--r--drivers/staging/hv/ext_utils.c27
-rw-r--r--drivers/staging/hv/hv.c438
-rw-r--r--drivers/staging/hv/hv_api.h905
-rw-r--r--drivers/staging/hv/hv_compat.h81
-rw-r--r--drivers/staging/hv/hv_kvp.c334
-rw-r--r--drivers/staging/hv/hv_kvp.h184
-rw-r--r--drivers/staging/hv/hv_mouse.c975
-rw-r--r--drivers/staging/hv/hv_timesource.c64
-rw-r--r--drivers/staging/hv/hv_util.c (renamed from drivers/staging/hv/hyperv_utils.c)179
-rw-r--r--drivers/staging/hv/hyperv.h953
-rw-r--r--drivers/staging/hv/hyperv_net.h (renamed from drivers/staging/hv/rndis.h)765
-rw-r--r--drivers/staging/hv/hyperv_storage.h334
-rw-r--r--drivers/staging/hv/hyperv_vmbus.h629
-rw-r--r--drivers/staging/hv/include/asm/hyperv.h193
-rw-r--r--drivers/staging/hv/include/asm/mshyperv.h16
-rw-r--r--drivers/staging/hv/include/linux/atomic.h5
-rw-r--r--drivers/staging/hv/logging.h95
-rw-r--r--drivers/staging/hv/netvsc.c1015
-rw-r--r--drivers/staging/hv/netvsc_drv.c322
-rw-r--r--drivers/staging/hv/osd.c228
-rw-r--r--drivers/staging/hv/osd.h70
-rw-r--r--drivers/staging/hv/overrides.mk4
-rw-r--r--drivers/staging/hv/ring_buffer.c526
-rw-r--r--drivers/staging/hv/rndis_filter.c831
-rw-r--r--drivers/staging/hv/storvsc.c564
-rw-r--r--drivers/staging/hv/storvsc_drv.c1008
-rw-r--r--drivers/staging/hv/tools/hv_kvp_daemon.c494
-rw-r--r--drivers/staging/hv/utils.h119
-rw-r--r--drivers/staging/hv/vmbus.h79
-rw-r--r--drivers/staging/hv/vmbus_drv.c1224
-rw-r--r--drivers/staging/hv/vstorage.h192
63 files changed, 11811 insertions, 13454 deletions
diff --git a/drivers/staging/hv/BlkVsc.c b/drivers/staging/hv/BlkVsc.c
deleted file mode 100644
index ee7c29884eb4..000000000000
--- a/drivers/staging/hv/BlkVsc.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include "osd.h"
-#include "StorVsc.c"
-
-static const char *gBlkDriverName = "blkvsc";
-
-/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
-static const struct hv_guid gBlkVscDeviceType = {
- .data = {
- 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
- 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
- }
-};
-
-static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
-{
- struct storvsc_device_info *deviceInfo;
- int ret = 0;
-
- deviceInfo = (struct storvsc_device_info *)AdditionalInfo;
-
- ret = StorVscOnDeviceAdd(Device, AdditionalInfo);
- if (ret != 0)
- return ret;
-
- /*
- * We need to use the device instance guid to set the path and target
- * id. For IDE devices, the device instance id is formatted as
- * <bus id> * - <device id> - 8899 - 000000000000.
- */
- deviceInfo->PathId = Device->deviceInstance.data[3] << 24 |
- Device->deviceInstance.data[2] << 16 |
- Device->deviceInstance.data[1] << 8 |
- Device->deviceInstance.data[0];
-
- deviceInfo->TargetId = Device->deviceInstance.data[5] << 8 |
- Device->deviceInstance.data[4];
-
- return ret;
-}
-
-int BlkVscInitialize(struct hv_driver *Driver)
-{
- struct storvsc_driver_object *storDriver;
- int ret = 0;
-
- storDriver = (struct storvsc_driver_object *)Driver;
-
- /* Make sure we are at least 2 pages since 1 page is used for control */
- /* ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); */
-
- Driver->name = gBlkDriverName;
- memcpy(&Driver->deviceType, &gBlkVscDeviceType, sizeof(struct hv_guid));
-
- storDriver->RequestExtSize = sizeof(struct storvsc_request_extension);
-
- /*
- * Divide the ring buffer data size (which is 1 page less than the ring
- * buffer size since that page is reserved for the ring buffer indices)
- * by the max request size (which is
- * VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER + struct vstor_packet + u64)
- */
- storDriver->MaxOutstandingRequestsPerChannel =
- ((storDriver->RingBufferSize - PAGE_SIZE) /
- ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET +
- sizeof(struct vstor_packet) + sizeof(u64),
- sizeof(u64)));
-
- DPRINT_INFO(BLKVSC, "max io outstd %u",
- storDriver->MaxOutstandingRequestsPerChannel);
-
- /* Setup the dispatch table */
- storDriver->Base.OnDeviceAdd = BlkVscOnDeviceAdd;
- storDriver->Base.OnDeviceRemove = StorVscOnDeviceRemove;
- storDriver->Base.OnCleanup = StorVscOnCleanup;
- storDriver->OnIORequest = StorVscOnIORequest;
-
- return ret;
-}
diff --git a/drivers/staging/hv/Channel.c b/drivers/staging/hv/Channel.c
deleted file mode 100644
index d712ba827455..000000000000
--- a/drivers/staging/hv/Channel.c
+++ /dev/null
@@ -1,1044 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include "osd.h"
-#include "logging.h"
-#include "VmbusPrivate.h"
-
-/* Internal routines */
-static int VmbusChannelCreateGpadlHeader(
- void *Kbuffer, /* must be phys and virt contiguous */
- u32 Size, /* page-size multiple */
- struct vmbus_channel_msginfo **msgInfo,
- u32 *MessageCount);
-static void DumpVmbusChannel(struct vmbus_channel *channel);
-static void VmbusChannelSetEvent(struct vmbus_channel *channel);
-
-
-#if 0
-static void DumpMonitorPage(struct hv_monitor_page *MonitorPage)
-{
- int i = 0;
- int j = 0;
-
- DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d",
- MonitorPage, MonitorPage->TriggerState);
-
- for (i = 0; i < 4; i++)
- DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i,
- MonitorPage->TriggerGroup[i].AsUINT64);
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 32; j++) {
- DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j,
- MonitorPage->Latency[i][j]);
- }
- }
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 32; j++) {
- DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j,
- MonitorPage->Parameter[i][j].ConnectionId.Asu32);
- DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j,
- MonitorPage->Parameter[i][j].FlagNumber);
- }
- }
-}
-#endif
-
-/*
- * VmbusChannelSetEvent - Trigger an event notification on the specified
- * channel.
- */
-static void VmbusChannelSetEvent(struct vmbus_channel *Channel)
-{
- struct hv_monitor_page *monitorPage;
-
- if (Channel->OfferMsg.MonitorAllocated) {
- /* Each u32 represents 32 channels */
- sync_set_bit(Channel->OfferMsg.ChildRelId & 31,
- (unsigned long *) gVmbusConnection.SendInterruptPage +
- (Channel->OfferMsg.ChildRelId >> 5));
-
- monitorPage = gVmbusConnection.MonitorPages;
- monitorPage++; /* Get the child to parent monitor page */
-
- sync_set_bit(Channel->MonitorBit,
- (unsigned long *)&monitorPage->TriggerGroup
- [Channel->MonitorGroup].Pending);
-
- } else {
- VmbusSetEvent(Channel->OfferMsg.ChildRelId);
- }
-}
-
-#if 0
-static void VmbusChannelClearEvent(struct vmbus_channel *channel)
-{
- struct hv_monitor_page *monitorPage;
-
- if (Channel->OfferMsg.MonitorAllocated) {
- /* Each u32 represents 32 channels */
- sync_clear_bit(Channel->OfferMsg.ChildRelId & 31,
- (unsigned long *)gVmbusConnection.SendInterruptPage +
- (Channel->OfferMsg.ChildRelId >> 5));
-
- monitorPage =
- (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
- monitorPage++; /* Get the child to parent monitor page */
-
- sync_clear_bit(Channel->MonitorBit,
- (unsigned long *)&monitorPage->TriggerGroup
- [Channel->MonitorGroup].Pending);
- }
-}
-
-#endif
-/*
- * VmbusChannelGetDebugInfo -Retrieve various channel debug info
- */
-void VmbusChannelGetDebugInfo(struct vmbus_channel *Channel,
- struct vmbus_channel_debug_info *DebugInfo)
-{
- struct hv_monitor_page *monitorPage;
- u8 monitorGroup = (u8)Channel->OfferMsg.MonitorId / 32;
- u8 monitorOffset = (u8)Channel->OfferMsg.MonitorId % 32;
- /* u32 monitorBit = 1 << monitorOffset; */
-
- DebugInfo->RelId = Channel->OfferMsg.ChildRelId;
- DebugInfo->State = Channel->State;
- memcpy(&DebugInfo->InterfaceType,
- &Channel->OfferMsg.Offer.InterfaceType, sizeof(struct hv_guid));
- memcpy(&DebugInfo->InterfaceInstance,
- &Channel->OfferMsg.Offer.InterfaceInstance,
- sizeof(struct hv_guid));
-
- monitorPage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
-
- DebugInfo->MonitorId = Channel->OfferMsg.MonitorId;
-
- DebugInfo->ServerMonitorPending =
- monitorPage->TriggerGroup[monitorGroup].Pending;
- DebugInfo->ServerMonitorLatency =
- monitorPage->Latency[monitorGroup][monitorOffset];
- DebugInfo->ServerMonitorConnectionId =
- monitorPage->Parameter[monitorGroup]
- [monitorOffset].ConnectionId.u.Id;
-
- monitorPage++;
-
- DebugInfo->ClientMonitorPending =
- monitorPage->TriggerGroup[monitorGroup].Pending;
- DebugInfo->ClientMonitorLatency =
- monitorPage->Latency[monitorGroup][monitorOffset];
- DebugInfo->ClientMonitorConnectionId =
- monitorPage->Parameter[monitorGroup]
- [monitorOffset].ConnectionId.u.Id;
-
- RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound);
- RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound);
-}
-
-/*
- * VmbusChannelOpen - Open the specified channel.
- */
-int VmbusChannelOpen(struct vmbus_channel *NewChannel, u32 SendRingBufferSize,
- u32 RecvRingBufferSize, void *UserData, u32 UserDataLen,
- void (*OnChannelCallback)(void *context), void *Context)
-{
- struct vmbus_channel_open_channel *openMsg;
- struct vmbus_channel_msginfo *openInfo = NULL;
- void *in, *out;
- unsigned long flags;
- int ret, err = 0;
-
- /* Aligned to page size */
- /* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */
- /* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */
-
- NewChannel->OnChannelCallback = OnChannelCallback;
- NewChannel->ChannelCallbackContext = Context;
-
- /* Allocate the ring buffer */
- out = osd_PageAlloc((SendRingBufferSize + RecvRingBufferSize)
- >> PAGE_SHIFT);
- if (!out)
- return -ENOMEM;
-
- /* ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0); */
-
- in = (void *)((unsigned long)out + SendRingBufferSize);
-
- NewChannel->RingBufferPages = out;
- NewChannel->RingBufferPageCount = (SendRingBufferSize +
- RecvRingBufferSize) >> PAGE_SHIFT;
-
- ret = RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize);
- if (ret != 0) {
- err = ret;
- goto errorout;
- }
-
- ret = RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize);
- if (ret != 0) {
- err = ret;
- goto errorout;
- }
-
-
- /* Establish the gpadl for the ring buffer */
- DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...",
- NewChannel);
-
- NewChannel->RingBufferGpadlHandle = 0;
-
- ret = VmbusChannelEstablishGpadl(NewChannel,
- NewChannel->Outbound.RingBuffer,
- SendRingBufferSize +
- RecvRingBufferSize,
- &NewChannel->RingBufferGpadlHandle);
-
- if (ret != 0) {
- err = ret;
- goto errorout;
- }
-
- DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p "
- "size %d recv ring %p size %d, downstreamoffset %d>",
- NewChannel, NewChannel->OfferMsg.ChildRelId,
- NewChannel->RingBufferGpadlHandle,
- NewChannel->Outbound.RingBuffer,
- NewChannel->Outbound.RingSize,
- NewChannel->Inbound.RingBuffer,
- NewChannel->Inbound.RingSize,
- SendRingBufferSize);
-
- /* Create and init the channel open message */
- openInfo = kmalloc(sizeof(*openInfo) +
- sizeof(struct vmbus_channel_open_channel),
- GFP_KERNEL);
- if (!openInfo) {
- err = -ENOMEM;
- goto errorout;
- }
-
- openInfo->WaitEvent = osd_WaitEventCreate();
- if (!openInfo->WaitEvent) {
- err = -ENOMEM;
- goto errorout;
- }
-
- openMsg = (struct vmbus_channel_open_channel *)openInfo->Msg;
- openMsg->Header.MessageType = ChannelMessageOpenChannel;
- openMsg->OpenId = NewChannel->OfferMsg.ChildRelId; /* FIXME */
- openMsg->ChildRelId = NewChannel->OfferMsg.ChildRelId;
- openMsg->RingBufferGpadlHandle = NewChannel->RingBufferGpadlHandle;
- openMsg->DownstreamRingBufferPageOffset = SendRingBufferSize >>
- PAGE_SHIFT;
- openMsg->ServerContextAreaGpadlHandle = 0; /* TODO */
-
- if (UserDataLen > MAX_USER_DEFINED_BYTES) {
- err = -EINVAL;
- goto errorout;
- }
-
- if (UserDataLen)
- memcpy(openMsg->UserData, UserData, UserDataLen);
-
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&openInfo->MsgListEntry,
- &gVmbusConnection.ChannelMsgList);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_DBG(VMBUS, "Sending channel open msg...");
-
- ret = VmbusPostMessage(openMsg,
- sizeof(struct vmbus_channel_open_channel));
- if (ret != 0) {
- DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
- goto Cleanup;
- }
-
- /* FIXME: Need to time-out here */
- osd_WaitEventWait(openInfo->WaitEvent);
-
- if (openInfo->Response.OpenResult.Status == 0)
- DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel);
- else
- DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!",
- NewChannel, openInfo->Response.OpenResult.Status);
-
-Cleanup:
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_del(&openInfo->MsgListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- kfree(openInfo->WaitEvent);
- kfree(openInfo);
- return 0;
-
-errorout:
- RingBufferCleanup(&NewChannel->Outbound);
- RingBufferCleanup(&NewChannel->Inbound);
- osd_PageFree(out, (SendRingBufferSize + RecvRingBufferSize)
- >> PAGE_SHIFT);
- kfree(openInfo);
- return err;
-}
-
-/*
- * DumpGpadlBody - Dump the gpadl body message to the console for
- * debugging purposes.
- */
-static void DumpGpadlBody(struct vmbus_channel_gpadl_body *Gpadl, u32 Len)
-{
- int i;
- int pfnCount;
-
- pfnCount = (Len - sizeof(struct vmbus_channel_gpadl_body)) /
- sizeof(u64);
- DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount);
-
- for (i = 0; i < pfnCount; i++)
- DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu",
- i, Gpadl->Pfn[i]);
-}
-
-/*
- * DumpGpadlHeader - Dump the gpadl header message to the console for
- * debugging purposes.
- */
-static void DumpGpadlHeader(struct vmbus_channel_gpadl_header *Gpadl)
-{
- int i, j;
- int pageCount;
-
- DPRINT_DBG(VMBUS,
- "gpadl header - relid %d, range count %d, range buflen %d",
- Gpadl->ChildRelId, Gpadl->RangeCount, Gpadl->RangeBufLen);
- for (i = 0; i < Gpadl->RangeCount; i++) {
- pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT;
- pageCount = (pageCount > 26) ? 26 : pageCount;
-
- DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d "
- "page count %d", i, Gpadl->Range[i].ByteCount,
- Gpadl->Range[i].ByteOffset, pageCount);
-
- for (j = 0; j < pageCount; j++)
- DPRINT_DBG(VMBUS, "%d) pfn %llu", j,
- Gpadl->Range[i].PfnArray[j]);
- }
-}
-
-/*
- * VmbusChannelCreateGpadlHeader - Creates a gpadl for the specified buffer
- */
-static int VmbusChannelCreateGpadlHeader(void *Kbuffer, u32 Size,
- struct vmbus_channel_msginfo **MsgInfo,
- u32 *MessageCount)
-{
- int i;
- int pageCount;
- unsigned long long pfn;
- struct vmbus_channel_gpadl_header *gpaHeader;
- struct vmbus_channel_gpadl_body *gpadlBody;
- struct vmbus_channel_msginfo *msgHeader;
- struct vmbus_channel_msginfo *msgBody = NULL;
- u32 msgSize;
-
- int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize;
-
- /* ASSERT((kbuffer & (PAGE_SIZE-1)) == 0); */
- /* ASSERT((Size & (PAGE_SIZE-1)) == 0); */
-
- pageCount = Size >> PAGE_SHIFT;
- pfn = virt_to_phys(Kbuffer) >> PAGE_SHIFT;
-
- /* do we need a gpadl body msg */
- pfnSize = MAX_SIZE_CHANNEL_MESSAGE -
- sizeof(struct vmbus_channel_gpadl_header) -
- sizeof(struct gpa_range);
- pfnCount = pfnSize / sizeof(u64);
-
- if (pageCount > pfnCount) {
- /* we need a gpadl body */
- /* fill in the header */
- msgSize = sizeof(struct vmbus_channel_msginfo) +
- sizeof(struct vmbus_channel_gpadl_header) +
- sizeof(struct gpa_range) + pfnCount * sizeof(u64);
- msgHeader = kzalloc(msgSize, GFP_KERNEL);
- if (!msgHeader)
- goto nomem;
-
- INIT_LIST_HEAD(&msgHeader->SubMsgList);
- msgHeader->MessageSize = msgSize;
-
- gpaHeader = (struct vmbus_channel_gpadl_header *)msgHeader->Msg;
- gpaHeader->RangeCount = 1;
- gpaHeader->RangeBufLen = sizeof(struct gpa_range) +
- pageCount * sizeof(u64);
- gpaHeader->Range[0].ByteOffset = 0;
- gpaHeader->Range[0].ByteCount = Size;
- for (i = 0; i < pfnCount; i++)
- gpaHeader->Range[0].PfnArray[i] = pfn+i;
- *MsgInfo = msgHeader;
- *MessageCount = 1;
-
- pfnSum = pfnCount;
- pfnLeft = pageCount - pfnCount;
-
- /* how many pfns can we fit */
- pfnSize = MAX_SIZE_CHANNEL_MESSAGE -
- sizeof(struct vmbus_channel_gpadl_body);
- pfnCount = pfnSize / sizeof(u64);
-
- /* fill in the body */
- while (pfnLeft) {
- if (pfnLeft > pfnCount)
- pfnCurr = pfnCount;
- else
- pfnCurr = pfnLeft;
-
- msgSize = sizeof(struct vmbus_channel_msginfo) +
- sizeof(struct vmbus_channel_gpadl_body) +
- pfnCurr * sizeof(u64);
- msgBody = kzalloc(msgSize, GFP_KERNEL);
- /* FIXME: we probably need to more if this fails */
- if (!msgBody)
- goto nomem;
- msgBody->MessageSize = msgSize;
- (*MessageCount)++;
- gpadlBody =
- (struct vmbus_channel_gpadl_body *)msgBody->Msg;
-
- /*
- * FIXME:
- * Gpadl is u32 and we are using a pointer which could
- * be 64-bit
- */
- /* gpadlBody->Gpadl = kbuffer; */
- for (i = 0; i < pfnCurr; i++)
- gpadlBody->Pfn[i] = pfn + pfnSum + i;
-
- /* add to msg header */
- list_add_tail(&msgBody->MsgListEntry,
- &msgHeader->SubMsgList);
- pfnSum += pfnCurr;
- pfnLeft -= pfnCurr;
- }
- } else {
- /* everything fits in a header */
- msgSize = sizeof(struct vmbus_channel_msginfo) +
- sizeof(struct vmbus_channel_gpadl_header) +
- sizeof(struct gpa_range) + pageCount * sizeof(u64);
- msgHeader = kzalloc(msgSize, GFP_KERNEL);
- if (msgHeader == NULL)
- goto nomem;
- msgHeader->MessageSize = msgSize;
-
- gpaHeader = (struct vmbus_channel_gpadl_header *)msgHeader->Msg;
- gpaHeader->RangeCount = 1;
- gpaHeader->RangeBufLen = sizeof(struct gpa_range) +
- pageCount * sizeof(u64);
- gpaHeader->Range[0].ByteOffset = 0;
- gpaHeader->Range[0].ByteCount = Size;
- for (i = 0; i < pageCount; i++)
- gpaHeader->Range[0].PfnArray[i] = pfn+i;
-
- *MsgInfo = msgHeader;
- *MessageCount = 1;
- }
-
- return 0;
-nomem:
- kfree(msgHeader);
- kfree(msgBody);
- return -ENOMEM;
-}
-
-/*
- * VmbusChannelEstablishGpadl - Estabish a GPADL for the specified buffer
- *
- * @Channel: a channel
- * @Kbuffer: from kmalloc
- * @Size: page-size multiple
- * @GpadlHandle: some funky thing
- */
-int VmbusChannelEstablishGpadl(struct vmbus_channel *Channel, void *Kbuffer,
- u32 Size, u32 *GpadlHandle)
-{
- struct vmbus_channel_gpadl_header *gpadlMsg;
- struct vmbus_channel_gpadl_body *gpadlBody;
- /* struct vmbus_channel_gpadl_created *gpadlCreated; */
- struct vmbus_channel_msginfo *msgInfo = NULL;
- struct vmbus_channel_msginfo *subMsgInfo;
- u32 msgCount;
- struct list_head *curr;
- u32 nextGpadlHandle;
- unsigned long flags;
- int ret = 0;
-
- nextGpadlHandle = atomic_read(&gVmbusConnection.NextGpadlHandle);
- atomic_inc(&gVmbusConnection.NextGpadlHandle);
-
- ret = VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount);
- if (ret)
- return ret;
-
- msgInfo->WaitEvent = osd_WaitEventCreate();
- if (!msgInfo->WaitEvent) {
- ret = -ENOMEM;
- goto Cleanup;
- }
-
- gpadlMsg = (struct vmbus_channel_gpadl_header *)msgInfo->Msg;
- gpadlMsg->Header.MessageType = ChannelMessageGpadlHeader;
- gpadlMsg->ChildRelId = Channel->OfferMsg.ChildRelId;
- gpadlMsg->Gpadl = nextGpadlHandle;
-
- DumpGpadlHeader(gpadlMsg);
-
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&msgInfo->MsgListEntry,
- &gVmbusConnection.ChannelMsgList);
-
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
- DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d",
- Kbuffer, Size, msgCount);
-
- DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd",
- msgInfo->MessageSize - sizeof(*msgInfo));
-
- ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize -
- sizeof(*msgInfo));
- if (ret != 0) {
- DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
- goto Cleanup;
- }
-
- if (msgCount > 1) {
- list_for_each(curr, &msgInfo->SubMsgList) {
-
- /* FIXME: should this use list_entry() instead ? */
- subMsgInfo = (struct vmbus_channel_msginfo *)curr;
- gpadlBody =
- (struct vmbus_channel_gpadl_body *)subMsgInfo->Msg;
-
- gpadlBody->Header.MessageType = ChannelMessageGpadlBody;
- gpadlBody->Gpadl = nextGpadlHandle;
-
- DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd",
- subMsgInfo->MessageSize -
- sizeof(*subMsgInfo));
-
- DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize -
- sizeof(*subMsgInfo));
- ret = VmbusPostMessage(gpadlBody,
- subMsgInfo->MessageSize -
- sizeof(*subMsgInfo));
- if (ret != 0)
- goto Cleanup;
-
- }
- }
- osd_WaitEventWait(msgInfo->WaitEvent);
-
- /* At this point, we received the gpadl created msg */
- DPRINT_DBG(VMBUS, "Received GPADL created "
- "(relid %d, status %d handle %x)",
- Channel->OfferMsg.ChildRelId,
- msgInfo->Response.GpadlCreated.CreationStatus,
- gpadlMsg->Gpadl);
-
- *GpadlHandle = gpadlMsg->Gpadl;
-
-Cleanup:
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_del(&msgInfo->MsgListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- kfree(msgInfo->WaitEvent);
- kfree(msgInfo);
- return ret;
-}
-
-/*
- * VmbusChannelTeardownGpadl -Teardown the specified GPADL handle
- */
-int VmbusChannelTeardownGpadl(struct vmbus_channel *Channel, u32 GpadlHandle)
-{
- struct vmbus_channel_gpadl_teardown *msg;
- struct vmbus_channel_msginfo *info;
- unsigned long flags;
- int ret;
-
- /* ASSERT(GpadlHandle != 0); */
-
- info = kmalloc(sizeof(*info) +
- sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- info->WaitEvent = osd_WaitEventCreate();
- if (!info->WaitEvent) {
- kfree(info);
- return -ENOMEM;
- }
-
- msg = (struct vmbus_channel_gpadl_teardown *)info->Msg;
-
- msg->Header.MessageType = ChannelMessageGpadlTeardown;
- msg->ChildRelId = Channel->OfferMsg.ChildRelId;
- msg->Gpadl = GpadlHandle;
-
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&info->MsgListEntry,
- &gVmbusConnection.ChannelMsgList);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- ret = VmbusPostMessage(msg,
- sizeof(struct vmbus_channel_gpadl_teardown));
- if (ret != 0) {
- /* TODO: */
- /* something... */
- }
-
- osd_WaitEventWait(info->WaitEvent);
-
- /* Received a torndown response */
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_del(&info->MsgListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- kfree(info->WaitEvent);
- kfree(info);
- return ret;
-}
-
-/*
- * VmbusChannelClose - Close the specified channel
- */
-void VmbusChannelClose(struct vmbus_channel *Channel)
-{
- struct vmbus_channel_close_channel *msg;
- struct vmbus_channel_msginfo *info;
- unsigned long flags;
- int ret;
-
- /* Stop callback and cancel the timer asap */
- Channel->OnChannelCallback = NULL;
- del_timer_sync(&Channel->poll_timer);
-
- /* Send a closing message */
- info = kmalloc(sizeof(*info) +
- sizeof(struct vmbus_channel_close_channel), GFP_KERNEL);
- /* FIXME: can't do anything other than return here because the
- * function is void */
- if (!info)
- return;
-
- /* info->waitEvent = osd_WaitEventCreate(); */
-
- msg = (struct vmbus_channel_close_channel *)info->Msg;
- msg->Header.MessageType = ChannelMessageCloseChannel;
- msg->ChildRelId = Channel->OfferMsg.ChildRelId;
-
- ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_close_channel));
- if (ret != 0) {
- /* TODO: */
- /* something... */
- }
-
- /* Tear down the gpadl for the channel's ring buffer */
- if (Channel->RingBufferGpadlHandle)
- VmbusChannelTeardownGpadl(Channel,
- Channel->RingBufferGpadlHandle);
-
- /* TODO: Send a msg to release the childRelId */
-
- /* Cleanup the ring buffers for this channel */
- RingBufferCleanup(&Channel->Outbound);
- RingBufferCleanup(&Channel->Inbound);
-
- osd_PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount);
-
- kfree(info);
-
- /*
- * If we are closing the channel during an error path in
- * opening the channel, don't free the channel since the
- * caller will free the channel
- */
-
- if (Channel->State == CHANNEL_OPEN_STATE) {
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_del(&Channel->ListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-
- FreeVmbusChannel(Channel);
- }
-}
-
-/**
- * VmbusChannelSendPacket() - Send the specified buffer on the given channel
- * @Channel: Pointer to vmbus_channel structure.
- * @Buffer: Pointer to the buffer you want to receive the data into.
- * @BufferLen: Maximum size of what the the buffer will hold
- * @RequestId: Identifier of the request
- * @vmbus_packet_type: Type of packet that is being send e.g. negotiate, time
- * packet etc.
- *
- * Sends data in @Buffer directly to hyper-v via the vmbus
- * This will send the data unparsed to hyper-v.
- *
- * Mainly used by Hyper-V drivers.
- */
-int VmbusChannelSendPacket(struct vmbus_channel *Channel, const void *Buffer,
- u32 BufferLen, u64 RequestId,
- enum vmbus_packet_type Type, u32 Flags)
-{
- struct vmpacket_descriptor desc;
- u32 packetLen = sizeof(struct vmpacket_descriptor) + BufferLen;
- u32 packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
- struct scatterlist bufferList[3];
- u64 alignedData = 0;
- int ret;
-
- DPRINT_DBG(VMBUS, "channel %p buffer %p len %d",
- Channel, Buffer, BufferLen);
-
- DumpVmbusChannel(Channel);
-
- /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
-
- /* Setup the descriptor */
- desc.Type = Type; /* VmbusPacketTypeDataInBand; */
- desc.Flags = Flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
- /* in 8-bytes granularity */
- desc.DataOffset8 = sizeof(struct vmpacket_descriptor) >> 3;
- desc.Length8 = (u16)(packetLenAligned >> 3);
- desc.TransactionId = RequestId;
-
- sg_init_table(bufferList, 3);
- sg_set_buf(&bufferList[0], &desc, sizeof(struct vmpacket_descriptor));
- sg_set_buf(&bufferList[1], Buffer, BufferLen);
- sg_set_buf(&bufferList[2], &alignedData, packetLenAligned - packetLen);
-
- ret = RingBufferWrite(&Channel->Outbound, bufferList, 3);
-
- /* TODO: We should determine if this is optional */
- if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
- VmbusChannelSetEvent(Channel);
-
- return ret;
-}
-EXPORT_SYMBOL(VmbusChannelSendPacket);
-
-/*
- * VmbusChannelSendPacketPageBuffer - Send a range of single-page buffer
- * packets using a GPADL Direct packet type.
- */
-int VmbusChannelSendPacketPageBuffer(struct vmbus_channel *Channel,
- struct hv_page_buffer PageBuffers[],
- u32 PageCount, void *Buffer, u32 BufferLen,
- u64 RequestId)
-{
- int ret;
- int i;
- struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc;
- u32 descSize;
- u32 packetLen;
- u32 packetLenAligned;
- struct scatterlist bufferList[3];
- u64 alignedData = 0;
-
- if (PageCount > MAX_PAGE_BUFFER_COUNT)
- return -EINVAL;
-
- DumpVmbusChannel(Channel);
-
- /*
- * Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the
- * largest size we support
- */
- descSize = sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER) -
- ((MAX_PAGE_BUFFER_COUNT - PageCount) *
- sizeof(struct hv_page_buffer));
- packetLen = descSize + BufferLen;
- packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
-
- /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
-
- /* Setup the descriptor */
- desc.Type = VmbusPacketTypeDataUsingGpaDirect;
- desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
- desc.DataOffset8 = descSize >> 3; /* in 8-bytes grandularity */
- desc.Length8 = (u16)(packetLenAligned >> 3);
- desc.TransactionId = RequestId;
- desc.RangeCount = PageCount;
-
- for (i = 0; i < PageCount; i++) {
- desc.Range[i].Length = PageBuffers[i].Length;
- desc.Range[i].Offset = PageBuffers[i].Offset;
- desc.Range[i].Pfn = PageBuffers[i].Pfn;
- }
-
- sg_init_table(bufferList, 3);
- sg_set_buf(&bufferList[0], &desc, descSize);
- sg_set_buf(&bufferList[1], Buffer, BufferLen);
- sg_set_buf(&bufferList[2], &alignedData, packetLenAligned - packetLen);
-
- ret = RingBufferWrite(&Channel->Outbound, bufferList, 3);
-
- /* TODO: We should determine if this is optional */
- if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
- VmbusChannelSetEvent(Channel);
-
- return ret;
-}
-
-/*
- * VmbusChannelSendPacketMultiPageBuffer - Send a multi-page buffer packet
- * using a GPADL Direct packet type.
- */
-int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel *Channel,
- struct hv_multipage_buffer *MultiPageBuffer,
- void *Buffer, u32 BufferLen, u64 RequestId)
-{
- int ret;
- struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc;
- u32 descSize;
- u32 packetLen;
- u32 packetLenAligned;
- struct scatterlist bufferList[3];
- u64 alignedData = 0;
- u32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset,
- MultiPageBuffer->Length);
-
- DumpVmbusChannel(Channel);
-
- DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u",
- MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount);
-
- if ((PfnCount < 0) || (PfnCount > MAX_MULTIPAGE_BUFFER_COUNT))
- return -EINVAL;
-
- /*
- * Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is
- * the largest size we support
- */
- descSize = sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER) -
- ((MAX_MULTIPAGE_BUFFER_COUNT - PfnCount) *
- sizeof(u64));
- packetLen = descSize + BufferLen;
- packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
-
- /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
-
- /* Setup the descriptor */
- desc.Type = VmbusPacketTypeDataUsingGpaDirect;
- desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
- desc.DataOffset8 = descSize >> 3; /* in 8-bytes grandularity */
- desc.Length8 = (u16)(packetLenAligned >> 3);
- desc.TransactionId = RequestId;
- desc.RangeCount = 1;
-
- desc.Range.Length = MultiPageBuffer->Length;
- desc.Range.Offset = MultiPageBuffer->Offset;
-
- memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray,
- PfnCount * sizeof(u64));
-
- sg_init_table(bufferList, 3);
- sg_set_buf(&bufferList[0], &desc, descSize);
- sg_set_buf(&bufferList[1], Buffer, BufferLen);
- sg_set_buf(&bufferList[2], &alignedData, packetLenAligned - packetLen);
-
- ret = RingBufferWrite(&Channel->Outbound, bufferList, 3);
-
- /* TODO: We should determine if this is optional */
- if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
- VmbusChannelSetEvent(Channel);
-
- return ret;
-}
-
-
-/**
- * VmbusChannelRecvPacket() - Retrieve the user packet on the specified channel
- * @Channel: Pointer to vmbus_channel structure.
- * @Buffer: Pointer to the buffer you want to receive the data into.
- * @BufferLen: Maximum size of what the the buffer will hold
- * @BufferActualLen: The actual size of the data after it was received
- * @RequestId: Identifier of the request
- *
- * Receives directly from the hyper-v vmbus and puts the data it received
- * into Buffer. This will receive the data unparsed from hyper-v.
- *
- * Mainly used by Hyper-V drivers.
- */
-int VmbusChannelRecvPacket(struct vmbus_channel *Channel, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen, u64 *RequestId)
-{
- struct vmpacket_descriptor desc;
- u32 packetLen;
- u32 userLen;
- int ret;
- unsigned long flags;
-
- *BufferActualLen = 0;
- *RequestId = 0;
-
- spin_lock_irqsave(&Channel->inbound_lock, flags);
-
- ret = RingBufferPeek(&Channel->Inbound, &desc,
- sizeof(struct vmpacket_descriptor));
- if (ret != 0) {
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
- return 0;
- }
-
- /* VmbusChannelClearEvent(Channel); */
-
- packetLen = desc.Length8 << 3;
- userLen = packetLen - (desc.DataOffset8 << 3);
- /* ASSERT(userLen > 0); */
-
- DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
- "flag %d tid %llx pktlen %d datalen %d> ",
- Channel, Channel->OfferMsg.ChildRelId, desc.Type,
- desc.Flags, desc.TransactionId, packetLen, userLen);
-
- *BufferActualLen = userLen;
-
- if (userLen > BufferLen) {
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d",
- BufferLen, userLen);
- return -1;
- }
-
- *RequestId = desc.TransactionId;
-
- /* Copy over the packet to the user buffer */
- ret = RingBufferRead(&Channel->Inbound, Buffer, userLen,
- (desc.DataOffset8 << 3));
-
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL(VmbusChannelRecvPacket);
-
-/*
- * VmbusChannelRecvPacketRaw - Retrieve the raw packet on the specified channel
- */
-int VmbusChannelRecvPacketRaw(struct vmbus_channel *Channel, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen,
- u64 *RequestId)
-{
- struct vmpacket_descriptor desc;
- u32 packetLen;
- u32 userLen;
- int ret;
- unsigned long flags;
-
- *BufferActualLen = 0;
- *RequestId = 0;
-
- spin_lock_irqsave(&Channel->inbound_lock, flags);
-
- ret = RingBufferPeek(&Channel->Inbound, &desc,
- sizeof(struct vmpacket_descriptor));
- if (ret != 0) {
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
- return 0;
- }
-
- /* VmbusChannelClearEvent(Channel); */
-
- packetLen = desc.Length8 << 3;
- userLen = packetLen - (desc.DataOffset8 << 3);
-
- DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
- "flag %d tid %llx pktlen %d datalen %d> ",
- Channel, Channel->OfferMsg.ChildRelId, desc.Type,
- desc.Flags, desc.TransactionId, packetLen, userLen);
-
- *BufferActualLen = packetLen;
-
- if (packetLen > BufferLen) {
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but "
- "got space for only %d bytes", packetLen, BufferLen);
- return -2;
- }
-
- *RequestId = desc.TransactionId;
-
- /* Copy over the entire packet to the user buffer */
- ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0);
-
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
- return 0;
-}
-
-/*
- * VmbusChannelOnChannelEvent - Channel event callback
- */
-void VmbusChannelOnChannelEvent(struct vmbus_channel *Channel)
-{
- DumpVmbusChannel(Channel);
- /* ASSERT(Channel->OnChannelCallback); */
-
- Channel->OnChannelCallback(Channel->ChannelCallbackContext);
-
- mod_timer(&Channel->poll_timer, jiffies + usecs_to_jiffies(100));
-}
-
-/*
- * VmbusChannelOnTimer - Timer event callback
- */
-void VmbusChannelOnTimer(unsigned long data)
-{
- struct vmbus_channel *channel = (struct vmbus_channel *)data;
-
- if (channel->OnChannelCallback)
- channel->OnChannelCallback(channel->ChannelCallbackContext);
-}
-
-/*
- * DumpVmbusChannel - Dump vmbus channel info to the console
- */
-static void DumpVmbusChannel(struct vmbus_channel *Channel)
-{
- DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId);
- DumpRingInfo(&Channel->Outbound, "Outbound ");
- DumpRingInfo(&Channel->Inbound, "Inbound ");
-}
diff --git a/drivers/staging/hv/Channel.h b/drivers/staging/hv/Channel.h
deleted file mode 100644
index 6b283edcae68..000000000000
--- a/drivers/staging/hv/Channel.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _CHANNEL_H_
-#define _CHANNEL_H_
-
-#include "ChannelMgmt.h"
-
-/* The format must be the same as struct vmdata_gpa_direct */
-struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER {
- u16 Type;
- u16 DataOffset8;
- u16 Length8;
- u16 Flags;
- u64 TransactionId;
- u32 Reserved;
- u32 RangeCount;
- struct hv_page_buffer Range[MAX_PAGE_BUFFER_COUNT];
-} __attribute__((packed));
-
-/* The format must be the same as struct vmdata_gpa_direct */
-struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER {
- u16 Type;
- u16 DataOffset8;
- u16 Length8;
- u16 Flags;
- u64 TransactionId;
- u32 Reserved;
- u32 RangeCount; /* Always 1 in this case */
- struct hv_multipage_buffer Range;
-} __attribute__((packed));
-
-
-extern int VmbusChannelOpen(struct vmbus_channel *channel,
- u32 SendRingBufferSize,
- u32 RecvRingBufferSize,
- void *UserData,
- u32 UserDataLen,
- void(*OnChannelCallback)(void *context),
- void *Context);
-
-extern void VmbusChannelClose(struct vmbus_channel *channel);
-
-extern int VmbusChannelSendPacket(struct vmbus_channel *channel,
- const void *Buffer,
- u32 BufferLen,
- u64 RequestId,
- enum vmbus_packet_type Type,
- u32 Flags);
-
-extern int VmbusChannelSendPacketPageBuffer(struct vmbus_channel *channel,
- struct hv_page_buffer PageBuffers[],
- u32 PageCount,
- void *Buffer,
- u32 BufferLen,
- u64 RequestId);
-
-extern int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel *channel,
- struct hv_multipage_buffer *mpb,
- void *Buffer,
- u32 BufferLen,
- u64 RequestId);
-
-extern int VmbusChannelEstablishGpadl(struct vmbus_channel *channel,
- void *Kbuffer,
- u32 Size,
- u32 *GpadlHandle);
-
-extern int VmbusChannelTeardownGpadl(struct vmbus_channel *channel,
- u32 GpadlHandle);
-
-extern int VmbusChannelRecvPacket(struct vmbus_channel *channel,
- void *Buffer,
- u32 BufferLen,
- u32 *BufferActualLen,
- u64 *RequestId);
-
-extern int VmbusChannelRecvPacketRaw(struct vmbus_channel *channel,
- void *Buffer,
- u32 BufferLen,
- u32 *BufferActualLen,
- u64 *RequestId);
-
-extern void VmbusChannelOnChannelEvent(struct vmbus_channel *channel);
-
-extern void VmbusChannelGetDebugInfo(struct vmbus_channel *channel,
- struct vmbus_channel_debug_info *debug);
-
-extern void VmbusChannelOnTimer(unsigned long data);
-
-#endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/hv/ChannelInterface.c b/drivers/staging/hv/ChannelInterface.c
deleted file mode 100644
index 019b064f7cb3..000000000000
--- a/drivers/staging/hv/ChannelInterface.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include "osd.h"
-#include "VmbusPrivate.h"
-
-static int IVmbusChannelOpen(struct hv_device *device, u32 SendBufferSize,
- u32 RecvRingBufferSize, void *UserData,
- u32 UserDataLen,
- void (*ChannelCallback)(void *context),
- void *Context)
-{
- return VmbusChannelOpen(device->context, SendBufferSize,
- RecvRingBufferSize, UserData, UserDataLen,
- ChannelCallback, Context);
-}
-
-static void IVmbusChannelClose(struct hv_device *device)
-{
- VmbusChannelClose(device->context);
-}
-
-static int IVmbusChannelSendPacket(struct hv_device *device, const void *Buffer,
- u32 BufferLen, u64 RequestId, u32 Type,
- u32 Flags)
-{
- return VmbusChannelSendPacket(device->context, Buffer, BufferLen,
- RequestId, Type, Flags);
-}
-
-static int IVmbusChannelSendPacketPageBuffer(struct hv_device *device,
- struct hv_page_buffer PageBuffers[],
- u32 PageCount, void *Buffer,
- u32 BufferLen, u64 RequestId)
-{
- return VmbusChannelSendPacketPageBuffer(device->context, PageBuffers,
- PageCount, Buffer, BufferLen,
- RequestId);
-}
-
-static int IVmbusChannelSendPacketMultiPageBuffer(struct hv_device *device,
- struct hv_multipage_buffer *MultiPageBuffer,
- void *Buffer, u32 BufferLen, u64 RequestId)
-{
- return VmbusChannelSendPacketMultiPageBuffer(device->context,
- MultiPageBuffer, Buffer,
- BufferLen, RequestId);
-}
-
-static int IVmbusChannelRecvPacket(struct hv_device *device, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen,
- u64 *RequestId)
-{
- return VmbusChannelRecvPacket(device->context, Buffer, BufferLen,
- BufferActualLen, RequestId);
-}
-
-static int IVmbusChannelRecvPacketRaw(struct hv_device *device, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen,
- u64 *RequestId)
-{
- return VmbusChannelRecvPacketRaw(device->context, Buffer, BufferLen,
- BufferActualLen, RequestId);
-}
-
-static int IVmbusChannelEstablishGpadl(struct hv_device *device, void *Buffer,
- u32 BufferLen, u32 *GpadlHandle)
-{
- return VmbusChannelEstablishGpadl(device->context, Buffer, BufferLen,
- GpadlHandle);
-}
-
-static int IVmbusChannelTeardownGpadl(struct hv_device *device, u32 GpadlHandle)
-{
- return VmbusChannelTeardownGpadl(device->context, GpadlHandle);
-
-}
-
-void GetChannelInterface(struct vmbus_channel_interface *iface)
-{
- iface->Open = IVmbusChannelOpen;
- iface->Close = IVmbusChannelClose;
- iface->SendPacket = IVmbusChannelSendPacket;
- iface->SendPacketPageBuffer = IVmbusChannelSendPacketPageBuffer;
- iface->SendPacketMultiPageBuffer =
- IVmbusChannelSendPacketMultiPageBuffer;
- iface->RecvPacket = IVmbusChannelRecvPacket;
- iface->RecvPacketRaw = IVmbusChannelRecvPacketRaw;
- iface->EstablishGpadl = IVmbusChannelEstablishGpadl;
- iface->TeardownGpadl = IVmbusChannelTeardownGpadl;
- iface->GetInfo = GetChannelInfo;
-}
-
-void GetChannelInfo(struct hv_device *device, struct hv_device_info *info)
-{
- struct vmbus_channel_debug_info debugInfo;
-
- if (!device->context)
- return;
-
- VmbusChannelGetDebugInfo(device->context, &debugInfo);
-
- info->ChannelId = debugInfo.RelId;
- info->ChannelState = debugInfo.State;
- memcpy(&info->ChannelType, &debugInfo.InterfaceType,
- sizeof(struct hv_guid));
- memcpy(&info->ChannelInstance, &debugInfo.InterfaceInstance,
- sizeof(struct hv_guid));
-
- info->MonitorId = debugInfo.MonitorId;
-
- info->ServerMonitorPending = debugInfo.ServerMonitorPending;
- info->ServerMonitorLatency = debugInfo.ServerMonitorLatency;
- info->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId;
-
- info->ClientMonitorPending = debugInfo.ClientMonitorPending;
- info->ClientMonitorLatency = debugInfo.ClientMonitorLatency;
- info->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId;
-
- info->Inbound.InterruptMask = debugInfo.Inbound.CurrentInterruptMask;
- info->Inbound.ReadIndex = debugInfo.Inbound.CurrentReadIndex;
- info->Inbound.WriteIndex = debugInfo.Inbound.CurrentWriteIndex;
- info->Inbound.BytesAvailToRead = debugInfo.Inbound.BytesAvailToRead;
- info->Inbound.BytesAvailToWrite = debugInfo.Inbound.BytesAvailToWrite;
-
- info->Outbound.InterruptMask = debugInfo.Outbound.CurrentInterruptMask;
- info->Outbound.ReadIndex = debugInfo.Outbound.CurrentReadIndex;
- info->Outbound.WriteIndex = debugInfo.Outbound.CurrentWriteIndex;
- info->Outbound.BytesAvailToRead = debugInfo.Outbound.BytesAvailToRead;
- info->Outbound.BytesAvailToWrite = debugInfo.Outbound.BytesAvailToWrite;
-}
diff --git a/drivers/staging/hv/ChannelInterface.h b/drivers/staging/hv/ChannelInterface.h
deleted file mode 100644
index 27b7a253b711..000000000000
--- a/drivers/staging/hv/ChannelInterface.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _CHANNEL_INTERFACE_H_
-#define _CHANNEL_INTERFACE_H_
-
-#include "VmbusApi.h"
-
-void GetChannelInterface(struct vmbus_channel_interface *ChannelInterface);
-
-void GetChannelInfo(struct hv_device *Device,
- struct hv_device_info *DeviceInfo);
-
-#endif /* _CHANNEL_INTERFACE_H_ */
diff --git a/drivers/staging/hv/ChannelMgmt.c b/drivers/staging/hv/ChannelMgmt.c
deleted file mode 100644
index 8d27f709bf3d..000000000000
--- a/drivers/staging/hv/ChannelMgmt.c
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/completion.h>
-#include "osd.h"
-#include "logging.h"
-#include "VmbusPrivate.h"
-#include "utils.h"
-
-struct vmbus_channel_message_table_entry {
- enum vmbus_channel_message_type messageType;
- void (*messageHandler)(struct vmbus_channel_message_header *msg);
-};
-
-#define MAX_MSG_TYPES 3
-#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 7
-
-static const struct hv_guid
- gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
- /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
- /* Storage - SCSI */
- {
- .data = {
- 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
- 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
- }
- },
-
- /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
- /* Network */
- {
- .data = {
- 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
- 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
- }
- },
-
- /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
- /* Input */
- {
- .data = {
- 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
- 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
- }
- },
-
- /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
- /* IDE */
- {
- .data = {
- 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
- 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
- }
- },
- /* 0E0B6031-5213-4934-818B-38D90CED39DB */
- /* Shutdown */
- {
- .data = {
- 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
- 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
- }
- },
- /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
- /* TimeSync */
- {
- .data = {
- 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
- 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
- }
- },
- /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
- /* Heartbeat */
- {
- .data = {
- 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
- 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
- }
- },
-};
-
-
-/**
- * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
- * @icmsghdrp: Pointer to msg header structure
- * @icmsg_negotiate: Pointer to negotiate message structure
- * @buf: Raw buffer channel data
- *
- * @icmsghdrp is of type &struct icmsg_hdr.
- * @negop is of type &struct icmsg_negotiate.
- * Set up and fill in default negotiate response message. This response can
- * come from both the vmbus driver and the hv_utils driver. The current api
- * will respond properly to both Windows 2008 and Windows 2008-R2 operating
- * systems.
- *
- * Mainly used by Hyper-V drivers.
- */
-void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
- struct icmsg_negotiate *negop,
- u8 *buf)
-{
- if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- icmsghdrp->icmsgsize = 0x10;
-
- negop = (struct icmsg_negotiate *)&buf[
- sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
-
- if (negop->icframe_vercnt == 2 &&
- negop->icversion_data[1].major == 3) {
- negop->icversion_data[0].major = 3;
- negop->icversion_data[0].minor = 0;
- negop->icversion_data[1].major = 3;
- negop->icversion_data[1].minor = 0;
- } else {
- negop->icversion_data[0].major = 1;
- negop->icversion_data[0].minor = 0;
- negop->icversion_data[1].major = 1;
- negop->icversion_data[1].minor = 0;
- }
-
- negop->icframe_vercnt = 1;
- negop->icmsg_vercnt = 1;
- }
-}
-EXPORT_SYMBOL(prep_negotiate_resp);
-
-/**
- * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
- * Hyper-V requests
- * @context: Pointer to argument structure.
- *
- * Set up the default handler for non device driver specific requests
- * from Hyper-V. This stub responds to the default negotiate messages
- * that come in for every non IDE/SCSI/Network request.
- * This behavior is normally overwritten in the hv_utils driver. That
- * driver handles requests like gracefull shutdown, heartbeats etc.
- *
- * Mainly used by Hyper-V drivers.
- */
-void chn_cb_negotiate(void *context)
-{
- struct vmbus_channel *channel = context;
- u8 *buf;
- u32 buflen, recvlen;
- u64 requestid;
-
- struct icmsg_hdr *icmsghdrp;
- struct icmsg_negotiate *negop = NULL;
-
- buflen = PAGE_SIZE;
- buf = kmalloc(buflen, GFP_ATOMIC);
-
- VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);
-
- if (recvlen > 0) {
- icmsghdrp = (struct icmsg_hdr *)&buf[
- sizeof(struct vmbuspipe_hdr)];
-
- prep_negotiate_resp(icmsghdrp, negop, buf);
-
- icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
- | ICMSGHDRFLAG_RESPONSE;
-
- VmbusChannelSendPacket(channel, buf,
- recvlen, requestid,
- VmbusPacketTypeDataInBand, 0);
- }
-
- kfree(buf);
-}
-EXPORT_SYMBOL(chn_cb_negotiate);
-
-/*
- * Function table used for message responses for non IDE/SCSI/Network type
- * messages. (Such as KVP/Shutdown etc)
- */
-struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
- /* 0E0B6031-5213-4934-818B-38D90CED39DB */
- /* Shutdown */
- {
- .msg_type = HV_SHUTDOWN_MSG,
- .data = {
- 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
- 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
- },
- .callback = chn_cb_negotiate,
- .log_msg = "Shutdown channel functionality initialized"
- },
-
- /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
- /* TimeSync */
- {
- .msg_type = HV_TIMESYNC_MSG,
- .data = {
- 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
- 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
- },
- .callback = chn_cb_negotiate,
- .log_msg = "Timesync channel functionality initialized"
- },
- /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
- /* Heartbeat */
- {
- .msg_type = HV_HEARTBEAT_MSG,
- .data = {
- 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
- 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
- },
- .callback = chn_cb_negotiate,
- .log_msg = "Heartbeat channel functionality initialized"
- },
-};
-EXPORT_SYMBOL(hv_cb_utils);
-
-/*
- * AllocVmbusChannel - Allocate and initialize a vmbus channel object
- */
-struct vmbus_channel *AllocVmbusChannel(void)
-{
- struct vmbus_channel *channel;
-
- channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
- if (!channel)
- return NULL;
-
- spin_lock_init(&channel->inbound_lock);
-
- init_timer(&channel->poll_timer);
- channel->poll_timer.data = (unsigned long)channel;
- channel->poll_timer.function = VmbusChannelOnTimer;
-
- channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
- if (!channel->ControlWQ) {
- kfree(channel);
- return NULL;
- }
-
- return channel;
-}
-
-/*
- * ReleaseVmbusChannel - Release the vmbus channel object itself
- */
-static inline void ReleaseVmbusChannel(void *context)
-{
- struct vmbus_channel *channel = context;
-
- DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
- destroy_workqueue(channel->ControlWQ);
- DPRINT_DBG(VMBUS, "channel released (%p)", channel);
-
- kfree(channel);
-}
-
-/*
- * FreeVmbusChannel - Release the resources used by the vmbus channel object
- */
-void FreeVmbusChannel(struct vmbus_channel *Channel)
-{
- del_timer_sync(&Channel->poll_timer);
-
- /*
- * We have to release the channel's workqueue/thread in the vmbus's
- * workqueue/thread context
- * ie we can't destroy ourselves.
- */
- osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
- Channel);
-}
-
-
-DECLARE_COMPLETION(hv_channel_ready);
-
-/*
- * Count initialized channels, and ensure all channels are ready when hv_vmbus
- * module loading completes.
- */
-static void count_hv_channel(void)
-{
- static int counter;
- unsigned long flags;
-
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- if (++counter == MAX_MSG_TYPES)
- complete(&hv_channel_ready);
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-}
-
-
-/*
- * VmbusChannelProcessOffer - Process the offer by creating a channel/device
- * associated with this offer
- */
-static void VmbusChannelProcessOffer(void *context)
-{
- struct vmbus_channel *newChannel = context;
- struct vmbus_channel *channel;
- bool fNew = true;
- int ret;
- int cnt;
- unsigned long flags;
-
- /* Make sure this is a new offer */
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
-
- list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
- if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
- &newChannel->OfferMsg.Offer.InterfaceType,
- sizeof(struct hv_guid)) &&
- !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
- &newChannel->OfferMsg.Offer.InterfaceInstance,
- sizeof(struct hv_guid))) {
- fNew = false;
- break;
- }
- }
-
- if (fNew)
- list_add_tail(&newChannel->ListEntry,
- &gVmbusConnection.ChannelList);
-
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-
- if (!fNew) {
- DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
- newChannel->OfferMsg.ChildRelId);
- FreeVmbusChannel(newChannel);
- return;
- }
-
- /*
- * Start the process of binding this offer to the driver
- * We need to set the DeviceObject field before calling
- * VmbusChildDeviceAdd()
- */
- newChannel->DeviceObject = VmbusChildDeviceCreate(
- &newChannel->OfferMsg.Offer.InterfaceType,
- &newChannel->OfferMsg.Offer.InterfaceInstance,
- newChannel);
-
- DPRINT_DBG(VMBUS, "child device object allocated - %p",
- newChannel->DeviceObject);
-
- /*
- * Add the new device to the bus. This will kick off device-driver
- * binding which eventually invokes the device driver's AddDevice()
- * method.
- */
- ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
- if (ret != 0) {
- DPRINT_ERR(VMBUS,
- "unable to add child device object (relid %d)",
- newChannel->OfferMsg.ChildRelId);
-
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_del(&newChannel->ListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-
- FreeVmbusChannel(newChannel);
- } else {
- /*
- * This state is used to indicate a successful open
- * so that when we do close the channel normally, we
- * can cleanup properly
- */
- newChannel->State = CHANNEL_OPEN_STATE;
-
- /* Open IC channels */
- for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
- if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType,
- &hv_cb_utils[cnt].data,
- sizeof(struct hv_guid)) == 0 &&
- VmbusChannelOpen(newChannel, 2 * PAGE_SIZE,
- 2 * PAGE_SIZE, NULL, 0,
- hv_cb_utils[cnt].callback,
- newChannel) == 0) {
- hv_cb_utils[cnt].channel = newChannel;
- DPRINT_INFO(VMBUS, "%s",
- hv_cb_utils[cnt].log_msg);
- count_hv_channel();
- }
- }
- }
-}
-
-/*
- * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
- */
-static void VmbusChannelProcessRescindOffer(void *context)
-{
- struct vmbus_channel *channel = context;
-
- VmbusChildDeviceRemove(channel->DeviceObject);
-}
-
-/*
- * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
- *
- * We ignore all offers except network and storage offers. For each network and
- * storage offers, we create a channel object and queue a work item to the
- * channel object to process the offer synchronously
- */
-static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_offer_channel *offer;
- struct vmbus_channel *newChannel;
- struct hv_guid *guidType;
- struct hv_guid *guidInstance;
- int i;
- int fSupported = 0;
-
- offer = (struct vmbus_channel_offer_channel *)hdr;
- for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
- if (memcmp(&offer->Offer.InterfaceType,
- &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
- fSupported = 1;
- break;
- }
- }
-
- if (!fSupported) {
- DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
- "child relid %d", offer->ChildRelId);
- return;
- }
-
- guidType = &offer->Offer.InterfaceType;
- guidInstance = &offer->Offer.InterfaceInstance;
-
- DPRINT_INFO(VMBUS, "Channel offer notification - "
- "child relid %d monitor id %d allocated %d, "
- "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x} "
- "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x}",
- offer->ChildRelId, offer->MonitorId,
- offer->MonitorAllocated,
- guidType->data[3], guidType->data[2],
- guidType->data[1], guidType->data[0],
- guidType->data[5], guidType->data[4],
- guidType->data[7], guidType->data[6],
- guidType->data[8], guidType->data[9],
- guidType->data[10], guidType->data[11],
- guidType->data[12], guidType->data[13],
- guidType->data[14], guidType->data[15],
- guidInstance->data[3], guidInstance->data[2],
- guidInstance->data[1], guidInstance->data[0],
- guidInstance->data[5], guidInstance->data[4],
- guidInstance->data[7], guidInstance->data[6],
- guidInstance->data[8], guidInstance->data[9],
- guidInstance->data[10], guidInstance->data[11],
- guidInstance->data[12], guidInstance->data[13],
- guidInstance->data[14], guidInstance->data[15]);
-
- /* Allocate the channel object and save this offer. */
- newChannel = AllocVmbusChannel();
- if (!newChannel) {
- DPRINT_ERR(VMBUS, "unable to allocate channel object");
- return;
- }
-
- DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
-
- memcpy(&newChannel->OfferMsg, offer,
- sizeof(struct vmbus_channel_offer_channel));
- newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
- newChannel->MonitorBit = (u8)offer->MonitorId % 32;
-
- /* TODO: Make sure the offer comes from our parent partition */
- osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
- newChannel);
-}
-
-/*
- * VmbusChannelOnOfferRescind - Rescind offer handler.
- *
- * We queue a work item to process this offer synchronously
- */
-static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_rescind_offer *rescind;
- struct vmbus_channel *channel;
-
- rescind = (struct vmbus_channel_rescind_offer *)hdr;
- channel = GetChannelFromRelId(rescind->ChildRelId);
- if (channel == NULL) {
- DPRINT_DBG(VMBUS, "channel not found for relId %d",
- rescind->ChildRelId);
- return;
- }
-
- osd_schedule_callback(channel->ControlWQ,
- VmbusChannelProcessRescindOffer,
- channel);
-}
-
-/*
- * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
- *
- * Nothing to do here.
- */
-static void VmbusChannelOnOffersDelivered(
- struct vmbus_channel_message_header *hdr)
-{
-}
-
-/*
- * VmbusChannelOnOpenResult - Open result handler.
- *
- * This is invoked when we received a response to our channel open request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_open_result *result;
- struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_open_channel *openMsg;
- unsigned long flags;
-
- result = (struct vmbus_channel_open_result *)hdr;
- DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
-
- /*
- * Find the open msg, copy the result and signal/unblock the wait event
- */
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
- list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType == ChannelMessageOpenChannel) {
- openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
- if (openMsg->ChildRelId == result->ChildRelId &&
- openMsg->OpenId == result->OpenId) {
- memcpy(&msgInfo->Response.OpenResult,
- result,
- sizeof(struct vmbus_channel_open_result));
- osd_WaitEventSet(msgInfo->WaitEvent);
- break;
- }
- }
- }
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-}
-
-/*
- * VmbusChannelOnGpadlCreated - GPADL created handler.
- *
- * This is invoked when we received a response to our gpadl create request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_gpadl_created *gpadlCreated;
- struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_gpadl_header *gpadlHeader;
- unsigned long flags;
-
- gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
- DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
- gpadlCreated->CreationStatus);
-
- /*
- * Find the establish msg, copy the result and signal/unblock the wait
- * event
- */
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
- list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
- gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
-
- if ((gpadlCreated->ChildRelId ==
- gpadlHeader->ChildRelId) &&
- (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
- memcpy(&msgInfo->Response.GpadlCreated,
- gpadlCreated,
- sizeof(struct vmbus_channel_gpadl_created));
- osd_WaitEventSet(msgInfo->WaitEvent);
- break;
- }
- }
- }
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-}
-
-/*
- * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
- *
- * This is invoked when we received a response to our gpadl teardown request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnGpadlTorndown(
- struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_gpadl_torndown *gpadlTorndown;
- struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_gpadl_teardown *gpadlTeardown;
- unsigned long flags;
-
- gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
-
- /*
- * Find the open msg, copy the result and signal/unblock the wait event
- */
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
- list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
- gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
-
- if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
- memcpy(&msgInfo->Response.GpadlTorndown,
- gpadlTorndown,
- sizeof(struct vmbus_channel_gpadl_torndown));
- osd_WaitEventSet(msgInfo->WaitEvent);
- break;
- }
- }
- }
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-}
-
-/*
- * VmbusChannelOnVersionResponse - Version response handler
- *
- * This is invoked when we received a response to our initiate contact request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnVersionResponse(
- struct vmbus_channel_message_header *hdr)
-{
- struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_initiate_contact *initiate;
- struct vmbus_channel_version_response *versionResponse;
- unsigned long flags;
-
- versionResponse = (struct vmbus_channel_version_response *)hdr;
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
- list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType ==
- ChannelMessageInitiateContact) {
- initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
- memcpy(&msgInfo->Response.VersionResponse,
- versionResponse,
- sizeof(struct vmbus_channel_version_response));
- osd_WaitEventSet(msgInfo->WaitEvent);
- }
- }
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-}
-
-/* Channel message dispatch table */
-static struct vmbus_channel_message_table_entry
- gChannelMessageTable[ChannelMessageCount] = {
- {ChannelMessageInvalid, NULL},
- {ChannelMessageOfferChannel, VmbusChannelOnOffer},
- {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind},
- {ChannelMessageRequestOffers, NULL},
- {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered},
- {ChannelMessageOpenChannel, NULL},
- {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult},
- {ChannelMessageCloseChannel, NULL},
- {ChannelMessageGpadlHeader, NULL},
- {ChannelMessageGpadlBody, NULL},
- {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated},
- {ChannelMessageGpadlTeardown, NULL},
- {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown},
- {ChannelMessageRelIdReleased, NULL},
- {ChannelMessageInitiateContact, NULL},
- {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse},
- {ChannelMessageUnload, NULL},
-};
-
-/*
- * VmbusOnChannelMessage - Handler for channel protocol messages.
- *
- * This is invoked in the vmbus worker thread context.
- */
-void VmbusOnChannelMessage(void *Context)
-{
- struct hv_message *msg = Context;
- struct vmbus_channel_message_header *hdr;
- int size;
-
- hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
- size = msg->Header.PayloadSize;
-
- DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
-
- if (hdr->MessageType >= ChannelMessageCount) {
- DPRINT_ERR(VMBUS,
- "Received invalid channel message type %d size %d",
- hdr->MessageType, size);
- print_hex_dump_bytes("", DUMP_PREFIX_NONE,
- (unsigned char *)msg->u.Payload, size);
- kfree(msg);
- return;
- }
-
- if (gChannelMessageTable[hdr->MessageType].messageHandler)
- gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
- else
- DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
- hdr->MessageType);
-
- /* Free the msg that was allocated in VmbusOnMsgDPC() */
- kfree(msg);
-}
-
-/*
- * VmbusChannelRequestOffers - Send a request to get all our pending offers.
- */
-int VmbusChannelRequestOffers(void)
-{
- struct vmbus_channel_message_header *msg;
- struct vmbus_channel_msginfo *msgInfo;
- int ret;
-
- msgInfo = kmalloc(sizeof(*msgInfo) +
- sizeof(struct vmbus_channel_message_header),
- GFP_KERNEL);
- if (!msgInfo)
- return -ENOMEM;
-
- msgInfo->WaitEvent = osd_WaitEventCreate();
- if (!msgInfo->WaitEvent) {
- kfree(msgInfo);
- return -ENOMEM;
- }
-
- msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- msg->MessageType = ChannelMessageRequestOffers;
-
- /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
- INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
- &msgInfo->msgListEntry);
- SpinlockRelease(gVmbusConnection.channelMsgLock);*/
-
- ret = VmbusPostMessage(msg,
- sizeof(struct vmbus_channel_message_header));
- if (ret != 0) {
- DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
-
- /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
- REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
- SpinlockRelease(gVmbusConnection.channelMsgLock);*/
-
- goto Cleanup;
- }
- /* osd_WaitEventWait(msgInfo->waitEvent); */
-
- /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
- REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
- SpinlockRelease(gVmbusConnection.channelMsgLock);*/
-
-
-Cleanup:
- if (msgInfo) {
- kfree(msgInfo->WaitEvent);
- kfree(msgInfo);
- }
-
- return ret;
-}
-
-/*
- * VmbusChannelReleaseUnattachedChannels - Release channels that are
- * unattached/unconnected ie (no drivers associated)
- */
-void VmbusChannelReleaseUnattachedChannels(void)
-{
- struct vmbus_channel *channel, *pos;
- struct vmbus_channel *start = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
-
- list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
- ListEntry) {
- if (channel == start)
- break;
-
- if (!channel->DeviceObject->Driver) {
- list_del(&channel->ListEntry);
- DPRINT_INFO(VMBUS,
- "Releasing unattached device object %p",
- channel->DeviceObject);
-
- VmbusChildDeviceRemove(channel->DeviceObject);
- FreeVmbusChannel(channel);
- } else {
- if (!start)
- start = channel;
- }
- }
-
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-}
-
-/* eof */
diff --git a/drivers/staging/hv/ChannelMgmt.h b/drivers/staging/hv/ChannelMgmt.h
deleted file mode 100644
index 6e2f84de03ee..000000000000
--- a/drivers/staging/hv/ChannelMgmt.h
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _CHANNEL_MGMT_H_
-#define _CHANNEL_MGMT_H_
-
-#include <linux/list.h>
-#include <linux/timer.h>
-#include "RingBuffer.h"
-#include "VmbusChannelInterface.h"
-#include "VmbusPacketFormat.h"
-
-/* Version 1 messages */
-enum vmbus_channel_message_type {
- ChannelMessageInvalid = 0,
- ChannelMessageOfferChannel = 1,
- ChannelMessageRescindChannelOffer = 2,
- ChannelMessageRequestOffers = 3,
- ChannelMessageAllOffersDelivered = 4,
- ChannelMessageOpenChannel = 5,
- ChannelMessageOpenChannelResult = 6,
- ChannelMessageCloseChannel = 7,
- ChannelMessageGpadlHeader = 8,
- ChannelMessageGpadlBody = 9,
- ChannelMessageGpadlCreated = 10,
- ChannelMessageGpadlTeardown = 11,
- ChannelMessageGpadlTorndown = 12,
- ChannelMessageRelIdReleased = 13,
- ChannelMessageInitiateContact = 14,
- ChannelMessageVersionResponse = 15,
- ChannelMessageUnload = 16,
-#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
- ChannelMessageViewRangeAdd = 17,
- ChannelMessageViewRangeRemove = 18,
-#endif
- ChannelMessageCount
-};
-
-struct vmbus_channel_message_header {
- enum vmbus_channel_message_type MessageType;
- u32 Padding;
-} __attribute__((packed));
-
-/* Query VMBus Version parameters */
-struct vmbus_channel_query_vmbus_version {
- struct vmbus_channel_message_header Header;
- u32 Version;
-} __attribute__((packed));
-
-/* VMBus Version Supported parameters */
-struct vmbus_channel_version_supported {
- struct vmbus_channel_message_header Header;
- bool VersionSupported;
-} __attribute__((packed));
-
-/* Offer Channel parameters */
-struct vmbus_channel_offer_channel {
- struct vmbus_channel_message_header Header;
- struct vmbus_channel_offer Offer;
- u32 ChildRelId;
- u8 MonitorId;
- bool MonitorAllocated;
-} __attribute__((packed));
-
-/* Rescind Offer parameters */
-struct vmbus_channel_rescind_offer {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
-} __attribute__((packed));
-
-/*
- * Request Offer -- no parameters, SynIC message contains the partition ID
- * Set Snoop -- no parameters, SynIC message contains the partition ID
- * Clear Snoop -- no parameters, SynIC message contains the partition ID
- * All Offers Delivered -- no parameters, SynIC message contains the partition
- * ID
- * Flush Client -- no parameters, SynIC message contains the partition ID
- */
-
-/* Open Channel parameters */
-struct vmbus_channel_open_channel {
- struct vmbus_channel_message_header Header;
-
- /* Identifies the specific VMBus channel that is being opened. */
- u32 ChildRelId;
-
- /* ID making a particular open request at a channel offer unique. */
- u32 OpenId;
-
- /* GPADL for the channel's ring buffer. */
- u32 RingBufferGpadlHandle;
-
- /* GPADL for the channel's server context save area. */
- u32 ServerContextAreaGpadlHandle;
-
- /*
- * The upstream ring buffer begins at offset zero in the memory
- * described by RingBufferGpadlHandle. The downstream ring buffer
- * follows it at this offset (in pages).
- */
- u32 DownstreamRingBufferPageOffset;
-
- /* User-specific data to be passed along to the server endpoint. */
- unsigned char UserData[MAX_USER_DEFINED_BYTES];
-} __attribute__((packed));
-
-/* Open Channel Result parameters */
-struct vmbus_channel_open_result {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
- u32 OpenId;
- u32 Status;
-} __attribute__((packed));
-
-/* Close channel parameters; */
-struct vmbus_channel_close_channel {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
-} __attribute__((packed));
-
-/* Channel Message GPADL */
-#define GPADL_TYPE_RING_BUFFER 1
-#define GPADL_TYPE_SERVER_SAVE_AREA 2
-#define GPADL_TYPE_TRANSACTION 8
-
-/*
- * The number of PFNs in a GPADL message is defined by the number of
- * pages that would be spanned by ByteCount and ByteOffset. If the
- * implied number of PFNs won't fit in this packet, there will be a
- * follow-up packet that contains more.
- */
-struct vmbus_channel_gpadl_header {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
- u32 Gpadl;
- u16 RangeBufLen;
- u16 RangeCount;
- struct gpa_range Range[0];
-} __attribute__((packed));
-
-/* This is the followup packet that contains more PFNs. */
-struct vmbus_channel_gpadl_body {
- struct vmbus_channel_message_header Header;
- u32 MessageNumber;
- u32 Gpadl;
- u64 Pfn[0];
-} __attribute__((packed));
-
-struct vmbus_channel_gpadl_created {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
- u32 Gpadl;
- u32 CreationStatus;
-} __attribute__((packed));
-
-struct vmbus_channel_gpadl_teardown {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
- u32 Gpadl;
-} __attribute__((packed));
-
-struct vmbus_channel_gpadl_torndown {
- struct vmbus_channel_message_header Header;
- u32 Gpadl;
-} __attribute__((packed));
-
-#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
-struct vmbus_channel_view_range_add {
- struct vmbus_channel_message_header Header;
- PHYSICAL_ADDRESS ViewRangeBase;
- u64 ViewRangeLength;
- u32 ChildRelId;
-} __attribute__((packed));
-
-struct vmbus_channel_view_range_remove {
- struct vmbus_channel_message_header Header;
- PHYSICAL_ADDRESS ViewRangeBase;
- u32 ChildRelId;
-} __attribute__((packed));
-#endif
-
-struct vmbus_channel_relid_released {
- struct vmbus_channel_message_header Header;
- u32 ChildRelId;
-} __attribute__((packed));
-
-struct vmbus_channel_initiate_contact {
- struct vmbus_channel_message_header Header;
- u32 VMBusVersionRequested;
- u32 Padding2;
- u64 InterruptPage;
- u64 MonitorPage1;
- u64 MonitorPage2;
-} __attribute__((packed));
-
-struct vmbus_channel_version_response {
- struct vmbus_channel_message_header Header;
- bool VersionSupported;
-} __attribute__((packed));
-
-enum vmbus_channel_state {
- CHANNEL_OFFER_STATE,
- CHANNEL_OPENING_STATE,
- CHANNEL_OPEN_STATE,
-};
-
-struct vmbus_channel {
- struct list_head ListEntry;
-
- struct hv_device *DeviceObject;
-
- struct timer_list poll_timer; /* SA-111 workaround */
-
- enum vmbus_channel_state State;
-
- struct vmbus_channel_offer_channel OfferMsg;
- /*
- * These are based on the OfferMsg.MonitorId.
- * Save it here for easy access.
- */
- u8 MonitorGroup;
- u8 MonitorBit;
-
- u32 RingBufferGpadlHandle;
-
- /* Allocated memory for ring buffer */
- void *RingBufferPages;
- u32 RingBufferPageCount;
- struct hv_ring_buffer_info Outbound; /* send to parent */
- struct hv_ring_buffer_info Inbound; /* receive from parent */
- spinlock_t inbound_lock;
- struct workqueue_struct *ControlWQ;
-
- /* Channel callback are invoked in this workqueue context */
- /* HANDLE dataWorkQueue; */
-
- void (*OnChannelCallback)(void *context);
- void *ChannelCallbackContext;
-};
-
-struct vmbus_channel_debug_info {
- u32 RelId;
- enum vmbus_channel_state State;
- struct hv_guid InterfaceType;
- struct hv_guid InterfaceInstance;
- u32 MonitorId;
- u32 ServerMonitorPending;
- u32 ServerMonitorLatency;
- u32 ServerMonitorConnectionId;
- u32 ClientMonitorPending;
- u32 ClientMonitorLatency;
- u32 ClientMonitorConnectionId;
-
- struct hv_ring_buffer_debug_info Inbound;
- struct hv_ring_buffer_debug_info Outbound;
-};
-
-/*
- * Represents each channel msg on the vmbus connection This is a
- * variable-size data structure depending on the msg type itself
- */
-struct vmbus_channel_msginfo {
- /* Bookkeeping stuff */
- struct list_head MsgListEntry;
-
- /* So far, this is only used to handle gpadl body message */
- struct list_head SubMsgList;
-
- /* Synchronize the request/response if needed */
- struct osd_waitevent *WaitEvent;
-
- union {
- struct vmbus_channel_version_supported VersionSupported;
- struct vmbus_channel_open_result OpenResult;
- struct vmbus_channel_gpadl_torndown GpadlTorndown;
- struct vmbus_channel_gpadl_created GpadlCreated;
- struct vmbus_channel_version_response VersionResponse;
- } Response;
-
- u32 MessageSize;
- /*
- * The channel message that goes out on the "wire".
- * It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
- */
- unsigned char Msg[0];
-};
-
-
-struct vmbus_channel *AllocVmbusChannel(void);
-
-void FreeVmbusChannel(struct vmbus_channel *Channel);
-
-void VmbusOnChannelMessage(void *Context);
-
-int VmbusChannelRequestOffers(void);
-
-void VmbusChannelReleaseUnattachedChannels(void);
-
-#endif /* _CHANNEL_MGMT_H_ */
diff --git a/drivers/staging/hv/Connection.c b/drivers/staging/hv/Connection.c
deleted file mode 100644
index b60b0c64b9ca..000000000000
--- a/drivers/staging/hv/Connection.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include "osd.h"
-#include "logging.h"
-#include "VmbusPrivate.h"
-
-
-struct VMBUS_CONNECTION gVmbusConnection = {
- .ConnectState = Disconnected,
- .NextGpadlHandle = ATOMIC_INIT(0xE1E10),
-};
-
-/*
- * VmbusConnect - Sends a connect request on the partition service connection
- */
-int VmbusConnect(void)
-{
- int ret = 0;
- struct vmbus_channel_msginfo *msgInfo = NULL;
- struct vmbus_channel_initiate_contact *msg;
- unsigned long flags;
-
- /* Make sure we are not connecting or connected */
- if (gVmbusConnection.ConnectState != Disconnected)
- return -1;
-
- /* Initialize the vmbus connection */
- gVmbusConnection.ConnectState = Connecting;
- gVmbusConnection.WorkQueue = create_workqueue("hv_vmbus_con");
- if (!gVmbusConnection.WorkQueue) {
- ret = -1;
- goto Cleanup;
- }
-
- INIT_LIST_HEAD(&gVmbusConnection.ChannelMsgList);
- spin_lock_init(&gVmbusConnection.channelmsg_lock);
-
- INIT_LIST_HEAD(&gVmbusConnection.ChannelList);
- spin_lock_init(&gVmbusConnection.channel_lock);
-
- /*
- * Setup the vmbus event connection for channel interrupt
- * abstraction stuff
- */
- gVmbusConnection.InterruptPage = osd_PageAlloc(1);
- if (gVmbusConnection.InterruptPage == NULL) {
- ret = -1;
- goto Cleanup;
- }
-
- gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage;
- gVmbusConnection.SendInterruptPage =
- (void *)((unsigned long)gVmbusConnection.InterruptPage +
- (PAGE_SIZE >> 1));
-
- /*
- * Setup the monitor notification facility. The 1st page for
- * parent->child and the 2nd page for child->parent
- */
- gVmbusConnection.MonitorPages = osd_PageAlloc(2);
- if (gVmbusConnection.MonitorPages == NULL) {
- ret = -1;
- goto Cleanup;
- }
-
- msgInfo = kzalloc(sizeof(*msgInfo) +
- sizeof(struct vmbus_channel_initiate_contact),
- GFP_KERNEL);
- if (msgInfo == NULL) {
- ret = -ENOMEM;
- goto Cleanup;
- }
-
- msgInfo->WaitEvent = osd_WaitEventCreate();
- if (!msgInfo->WaitEvent) {
- ret = -ENOMEM;
- goto Cleanup;
- }
-
- msg = (struct vmbus_channel_initiate_contact *)msgInfo->Msg;
-
- msg->Header.MessageType = ChannelMessageInitiateContact;
- msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER;
- msg->InterruptPage = virt_to_phys(gVmbusConnection.InterruptPage);
- msg->MonitorPage1 = virt_to_phys(gVmbusConnection.MonitorPages);
- msg->MonitorPage2 = virt_to_phys(
- (void *)((unsigned long)gVmbusConnection.MonitorPages +
- PAGE_SIZE));
-
- /*
- * Add to list before we send the request since we may
- * receive the response before returning from this routine
- */
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&msgInfo->MsgListEntry,
- &gVmbusConnection.ChannelMsgList);
-
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, "
- "monitor1 pfn %llx,, monitor2 pfn %llx",
- msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
-
- DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
- ret = VmbusPostMessage(msg,
- sizeof(struct vmbus_channel_initiate_contact));
- if (ret != 0) {
- list_del(&msgInfo->MsgListEntry);
- goto Cleanup;
- }
-
- /* Wait for the connection response */
- osd_WaitEventWait(msgInfo->WaitEvent);
-
- list_del(&msgInfo->MsgListEntry);
-
- /* Check if successful */
- if (msgInfo->Response.VersionResponse.VersionSupported) {
- DPRINT_INFO(VMBUS, "Vmbus connected!!");
- gVmbusConnection.ConnectState = Connected;
-
- } else {
- DPRINT_ERR(VMBUS, "Vmbus connection failed!!..."
- "current version (%d) not supported",
- VMBUS_REVISION_NUMBER);
- ret = -1;
- goto Cleanup;
- }
-
- kfree(msgInfo->WaitEvent);
- kfree(msgInfo);
- return 0;
-
-Cleanup:
- gVmbusConnection.ConnectState = Disconnected;
-
- if (gVmbusConnection.WorkQueue)
- destroy_workqueue(gVmbusConnection.WorkQueue);
-
- if (gVmbusConnection.InterruptPage) {
- osd_PageFree(gVmbusConnection.InterruptPage, 1);
- gVmbusConnection.InterruptPage = NULL;
- }
-
- if (gVmbusConnection.MonitorPages) {
- osd_PageFree(gVmbusConnection.MonitorPages, 2);
- gVmbusConnection.MonitorPages = NULL;
- }
-
- if (msgInfo) {
- kfree(msgInfo->WaitEvent);
- kfree(msgInfo);
- }
-
- return ret;
-}
-
-/*
- * VmbusDisconnect - Sends a disconnect request on the partition service connection
- */
-int VmbusDisconnect(void)
-{
- int ret = 0;
- struct vmbus_channel_message_header *msg;
-
- /* Make sure we are connected */
- if (gVmbusConnection.ConnectState != Connected)
- return -1;
-
- msg = kzalloc(sizeof(struct vmbus_channel_message_header), GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
-
- msg->MessageType = ChannelMessageUnload;
-
- ret = VmbusPostMessage(msg,
- sizeof(struct vmbus_channel_message_header));
- if (ret != 0)
- goto Cleanup;
-
- osd_PageFree(gVmbusConnection.InterruptPage, 1);
-
- /* TODO: iterate thru the msg list and free up */
- destroy_workqueue(gVmbusConnection.WorkQueue);
-
- gVmbusConnection.ConnectState = Disconnected;
-
- DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
-
-Cleanup:
- kfree(msg);
- return ret;
-}
-
-/*
- * GetChannelFromRelId - Get the channel object given its child relative id (ie channel id)
- */
-struct vmbus_channel *GetChannelFromRelId(u32 relId)
-{
- struct vmbus_channel *channel;
- struct vmbus_channel *foundChannel = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
- if (channel->OfferMsg.ChildRelId == relId) {
- foundChannel = channel;
- break;
- }
- }
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-
- return foundChannel;
-}
-
-/*
- * VmbusProcessChannelEvent - Process a channel event notification
- */
-static void VmbusProcessChannelEvent(void *context)
-{
- struct vmbus_channel *channel;
- u32 relId = (u32)(unsigned long)context;
-
- /* ASSERT(relId > 0); */
-
- /*
- * Find the channel based on this relid and invokes the
- * channel callback to process the event
- */
- channel = GetChannelFromRelId(relId);
-
- if (channel) {
- VmbusChannelOnChannelEvent(channel);
- /*
- * WorkQueueQueueWorkItem(channel->dataWorkQueue,
- * VmbusChannelOnChannelEvent,
- * (void*)channel);
- */
- } else {
- DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId);
- }
-}
-
-/*
- * VmbusOnEvents - Handler for events
- */
-void VmbusOnEvents(void)
-{
- int dword;
- int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
- int bit;
- int relid;
- u32 *recvInterruptPage = gVmbusConnection.RecvInterruptPage;
-
- /* Check events */
- if (recvInterruptPage) {
- for (dword = 0; dword < maxdword; dword++) {
- if (recvInterruptPage[dword]) {
- for (bit = 0; bit < 32; bit++) {
- if (sync_test_and_clear_bit(bit,
- (unsigned long *)
- &recvInterruptPage[dword])) {
- relid = (dword << 5) + bit;
- DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
-
- if (relid == 0) {
- /* special case - vmbus channel protocol msg */
- DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
- continue;
- } else {
- /* QueueWorkItem(VmbusProcessEvent, (void*)relid); */
- /* ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid); */
- VmbusProcessChannelEvent((void *)(unsigned long)relid);
- }
- }
- }
- }
- }
- }
- return;
-}
-
-/*
- * VmbusPostMessage - Send a msg on the vmbus's message connection
- */
-int VmbusPostMessage(void *buffer, size_t bufferLen)
-{
- union hv_connection_id connId;
-
- connId.Asu32 = 0;
- connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
- return HvPostMessage(connId, 1, buffer, bufferLen);
-}
-
-/*
- * VmbusSetEvent - Send an event notification to the parent
- */
-int VmbusSetEvent(u32 childRelId)
-{
- /* Each u32 represents 32 channels */
- sync_set_bit(childRelId & 31,
- (unsigned long *)gVmbusConnection.SendInterruptPage +
- (childRelId >> 5));
-
- return HvSignalEvent();
-}
diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/Hv.c
deleted file mode 100644
index d580270273bf..000000000000
--- a/drivers/staging/hv/Hv.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include "osd.h"
-#include "logging.h"
-#include "VmbusPrivate.h"
-
-/* The one and only */
-struct hv_context gHvContext = {
- .SynICInitialized = false,
- .HypercallPage = NULL,
- .SignalEventParam = NULL,
- .SignalEventBuffer = NULL,
-};
-
-/*
- * HvQueryHypervisorPresence - Query the cpuid for presense of windows hypervisor
- */
-static int HvQueryHypervisorPresence(void)
-{
- unsigned int eax;
- unsigned int ebx;
- unsigned int ecx;
- unsigned int edx;
- unsigned int op;
-
- eax = 0;
- ebx = 0;
- ecx = 0;
- edx = 0;
- op = HvCpuIdFunctionVersionAndFeatures;
- cpuid(op, &eax, &ebx, &ecx, &edx);
-
- return ecx & HV_PRESENT_BIT;
-}
-
-/*
- * HvQueryHypervisorInfo - Get version info of the windows hypervisor
- */
-static int HvQueryHypervisorInfo(void)
-{
- unsigned int eax;
- unsigned int ebx;
- unsigned int ecx;
- unsigned int edx;
- unsigned int maxLeaf;
- unsigned int op;
-
- /*
- * Its assumed that this is called after confirming that Viridian
- * is present. Query id and revision.
- */
- eax = 0;
- ebx = 0;
- ecx = 0;
- edx = 0;
- op = HvCpuIdFunctionHvVendorAndMaxFunction;
- cpuid(op, &eax, &ebx, &ecx, &edx);
-
- DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
- (ebx & 0xFF),
- ((ebx >> 8) & 0xFF),
- ((ebx >> 16) & 0xFF),
- ((ebx >> 24) & 0xFF),
- (ecx & 0xFF),
- ((ecx >> 8) & 0xFF),
- ((ecx >> 16) & 0xFF),
- ((ecx >> 24) & 0xFF),
- (edx & 0xFF),
- ((edx >> 8) & 0xFF),
- ((edx >> 16) & 0xFF),
- ((edx >> 24) & 0xFF));
-
- maxLeaf = eax;
- eax = 0;
- ebx = 0;
- ecx = 0;
- edx = 0;
- op = HvCpuIdFunctionHvInterface;
- cpuid(op, &eax, &ebx, &ecx, &edx);
-
- DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
- (eax & 0xFF),
- ((eax >> 8) & 0xFF),
- ((eax >> 16) & 0xFF),
- ((eax >> 24) & 0xFF));
-
- if (maxLeaf >= HvCpuIdFunctionMsHvVersion) {
- eax = 0;
- ebx = 0;
- ecx = 0;
- edx = 0;
- op = HvCpuIdFunctionMsHvVersion;
- cpuid(op, &eax, &ebx, &ecx, &edx);
- DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",\
- eax,
- ebx >> 16,
- ebx & 0xFFFF,
- ecx,
- edx >> 24,
- edx & 0xFFFFFF);
- }
- return maxLeaf;
-}
-
-/*
- * HvDoHypercall - Invoke the specified hypercall
- */
-static u64 HvDoHypercall(u64 Control, void *Input, void *Output)
-{
-#ifdef CONFIG_X86_64
- u64 hvStatus = 0;
- u64 inputAddress = (Input) ? virt_to_phys(Input) : 0;
- u64 outputAddress = (Output) ? virt_to_phys(Output) : 0;
- volatile void *hypercallPage = gHvContext.HypercallPage;
-
- DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p "
- "output phys %llx virt %p hypercall %p>",
- Control, inputAddress, Input,
- outputAddress, Output, hypercallPage);
-
- __asm__ __volatile__("mov %0, %%r8" : : "r" (outputAddress) : "r8");
- __asm__ __volatile__("call *%3" : "=a" (hvStatus) :
- "c" (Control), "d" (inputAddress),
- "m" (hypercallPage));
-
- DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus);
-
- return hvStatus;
-
-#else
-
- u32 controlHi = Control >> 32;
- u32 controlLo = Control & 0xFFFFFFFF;
- u32 hvStatusHi = 1;
- u32 hvStatusLo = 1;
- u64 inputAddress = (Input) ? virt_to_phys(Input) : 0;
- u32 inputAddressHi = inputAddress >> 32;
- u32 inputAddressLo = inputAddress & 0xFFFFFFFF;
- u64 outputAddress = (Output) ? virt_to_phys(Output) : 0;
- u32 outputAddressHi = outputAddress >> 32;
- u32 outputAddressLo = outputAddress & 0xFFFFFFFF;
- volatile void *hypercallPage = gHvContext.HypercallPage;
-
- DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
- Control, Input, Output);
-
- __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi),
- "=a"(hvStatusLo) : "d" (controlHi),
- "a" (controlLo), "b" (inputAddressHi),
- "c" (inputAddressLo), "D"(outputAddressHi),
- "S"(outputAddressLo), "m" (hypercallPage));
-
- DPRINT_DBG(VMBUS, "Hypercall <return %llx>",
- hvStatusLo | ((u64)hvStatusHi << 32));
-
- return hvStatusLo | ((u64)hvStatusHi << 32);
-#endif /* !x86_64 */
-}
-
-/*
- * HvInit - Main initialization routine.
- *
- * This routine must be called before any other routines in here are called
- */
-int HvInit(void)
-{
- int ret = 0;
- int maxLeaf;
- union hv_x64_msr_hypercall_contents hypercallMsr;
- void *virtAddr = NULL;
-
- memset(gHvContext.synICEventPage, 0, sizeof(void *) * MAX_NUM_CPUS);
- memset(gHvContext.synICMessagePage, 0, sizeof(void *) * MAX_NUM_CPUS);
-
- if (!HvQueryHypervisorPresence()) {
- DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
- goto Cleanup;
- }
-
- DPRINT_INFO(VMBUS,
- "Windows hypervisor detected! Retrieving more info...");
-
- maxLeaf = HvQueryHypervisorInfo();
- /* HvQueryHypervisorFeatures(maxLeaf); */
-
- /*
- * We only support running on top of Hyper-V
- */
- rdmsrl(HV_X64_MSR_GUEST_OS_ID, gHvContext.GuestId);
-
- if (gHvContext.GuestId != 0) {
- DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!",
- gHvContext.GuestId);
- goto Cleanup;
- }
-
- /* Write our OS info */
- wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
- gHvContext.GuestId = HV_LINUX_GUEST_ID;
-
- /* See if the hypercall page is already set */
- rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
-
- /*
- * Allocate the hypercall page memory
- * virtAddr = osd_PageAlloc(1);
- */
- virtAddr = osd_VirtualAllocExec(PAGE_SIZE);
-
- if (!virtAddr) {
- DPRINT_ERR(VMBUS,
- "unable to allocate hypercall page!!");
- goto Cleanup;
- }
-
- hypercallMsr.Enable = 1;
-
- hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr);
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
-
- /* Confirm that hypercall page did get setup. */
- hypercallMsr.AsUINT64 = 0;
- rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
-
- if (!hypercallMsr.Enable) {
- DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
- goto Cleanup;
- }
-
- gHvContext.HypercallPage = virtAddr;
-
- DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx",
- gHvContext.HypercallPage,
- (u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
-
- /* Setup the global signal event param for the signal event hypercall */
- gHvContext.SignalEventBuffer =
- kmalloc(sizeof(struct hv_input_signal_event_buffer),
- GFP_KERNEL);
- if (!gHvContext.SignalEventBuffer)
- goto Cleanup;
-
- gHvContext.SignalEventParam =
- (struct hv_input_signal_event *)
- (ALIGN_UP((unsigned long)gHvContext.SignalEventBuffer,
- HV_HYPERCALL_PARAM_ALIGN));
- gHvContext.SignalEventParam->ConnectionId.Asu32 = 0;
- gHvContext.SignalEventParam->ConnectionId.u.Id =
- VMBUS_EVENT_CONNECTION_ID;
- gHvContext.SignalEventParam->FlagNumber = 0;
- gHvContext.SignalEventParam->RsvdZ = 0;
-
- return ret;
-
-Cleanup:
- if (virtAddr) {
- if (hypercallMsr.Enable) {
- hypercallMsr.AsUINT64 = 0;
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
- }
-
- vfree(virtAddr);
- }
- ret = -1;
- return ret;
-}
-
-/*
- * HvCleanup - Cleanup routine.
- *
- * This routine is called normally during driver unloading or exiting.
- */
-void HvCleanup(void)
-{
- union hv_x64_msr_hypercall_contents hypercallMsr;
-
- kfree(gHvContext.SignalEventBuffer);
- gHvContext.SignalEventBuffer = NULL;
- gHvContext.SignalEventParam = NULL;
-
- if (gHvContext.HypercallPage) {
- hypercallMsr.AsUINT64 = 0;
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
- vfree(gHvContext.HypercallPage);
- gHvContext.HypercallPage = NULL;
- }
-}
-
-/*
- * HvPostMessage - Post a message using the hypervisor message IPC.
- *
- * This involves a hypercall.
- */
-u16 HvPostMessage(union hv_connection_id connectionId,
- enum hv_message_type messageType,
- void *payload, size_t payloadSize)
-{
- struct alignedInput {
- u64 alignment8;
- struct hv_input_post_message msg;
- };
-
- struct hv_input_post_message *alignedMsg;
- u16 status;
- unsigned long addr;
-
- if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
- return -1;
-
- addr = (unsigned long)kmalloc(sizeof(struct alignedInput), GFP_ATOMIC);
- if (!addr)
- return -1;
-
- alignedMsg = (struct hv_input_post_message *)
- (ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
-
- alignedMsg->ConnectionId = connectionId;
- alignedMsg->MessageType = messageType;
- alignedMsg->PayloadSize = payloadSize;
- memcpy((void *)alignedMsg->Payload, payload, payloadSize);
-
- status = HvDoHypercall(HvCallPostMessage, alignedMsg, NULL) & 0xFFFF;
-
- kfree((void *)addr);
-
- return status;
-}
-
-
-/*
- * HvSignalEvent - Signal an event on the specified connection using the hypervisor event IPC.
- *
- * This involves a hypercall.
- */
-u16 HvSignalEvent(void)
-{
- u16 status;
-
- status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam,
- NULL) & 0xFFFF;
- return status;
-}
-
-/*
- * HvSynicInit - Initialize the Synthethic Interrupt Controller.
- *
- * If it is already initialized by another entity (ie x2v shim), we need to
- * retrieve the initialized message and event pages. Otherwise, we create and
- * initialize the message and event pages.
- */
-void HvSynicInit(void *irqarg)
-{
- u64 version;
- union hv_synic_simp simp;
- union hv_synic_siefp siefp;
- union hv_synic_sint sharedSint;
- union hv_synic_scontrol sctrl;
-
- u32 irqVector = *((u32 *)(irqarg));
- int cpu = smp_processor_id();
-
- if (!gHvContext.HypercallPage)
- return;
-
- /* Check the version */
- rdmsrl(HV_X64_MSR_SVERSION, version);
-
- DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
-
- gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
-
- if (gHvContext.synICMessagePage[cpu] == NULL) {
- DPRINT_ERR(VMBUS,
- "unable to allocate SYNIC message page!!");
- goto Cleanup;
- }
-
- gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
-
- if (gHvContext.synICEventPage[cpu] == NULL) {
- DPRINT_ERR(VMBUS,
- "unable to allocate SYNIC event page!!");
- goto Cleanup;
- }
-
- /* Setup the Synic's message page */
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- simp.SimpEnabled = 1;
- simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu])
- >> PAGE_SHIFT;
-
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
-
- wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
-
- /* Setup the Synic's event page */
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- siefp.SiefpEnabled = 1;
- siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu])
- >> PAGE_SHIFT;
-
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
-
- wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
-
- /* Setup the interception SINT. */
- /* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */
- /* interceptionSint.AsUINT64); */
-
- /* Setup the shared SINT. */
- rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
-
- sharedSint.AsUINT64 = 0;
- sharedSint.Vector = irqVector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */
- sharedSint.Masked = false;
- sharedSint.AutoEoi = true;
-
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx",
- sharedSint.AsUINT64);
-
- wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
-
- /* Enable the global synic bit */
- rdmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
- sctrl.Enable = 1;
-
- wrmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
-
- gHvContext.SynICInitialized = true;
- return;
-
-Cleanup:
- if (gHvContext.synICEventPage[cpu])
- osd_PageFree(gHvContext.synICEventPage[cpu], 1);
-
- if (gHvContext.synICMessagePage[cpu])
- osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
- return;
-}
-
-/*
- * HvSynicCleanup - Cleanup routine for HvSynicInit().
- */
-void HvSynicCleanup(void *arg)
-{
- union hv_synic_sint sharedSint;
- union hv_synic_simp simp;
- union hv_synic_siefp siefp;
- int cpu = smp_processor_id();
-
- if (!gHvContext.SynICInitialized)
- return;
-
- rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
-
- sharedSint.Masked = 1;
-
- /* Need to correctly cleanup in the case of SMP!!! */
- /* Disable the interrupt */
- wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
-
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- simp.SimpEnabled = 0;
- simp.BaseSimpGpa = 0;
-
- wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
-
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- siefp.SiefpEnabled = 0;
- siefp.BaseSiefpGpa = 0;
-
- wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
-
- osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
- osd_PageFree(gHvContext.synICEventPage[cpu], 1);
-}
diff --git a/drivers/staging/hv/Hv.h b/drivers/staging/hv/Hv.h
deleted file mode 100644
index 41f5ebb86e17..000000000000
--- a/drivers/staging/hv/Hv.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef __HV_H__
-#define __HV_H__
-
-#include "hv_api.h"
-
-enum {
- VMBUS_MESSAGE_CONNECTION_ID = 1,
- VMBUS_MESSAGE_PORT_ID = 1,
- VMBUS_EVENT_CONNECTION_ID = 2,
- VMBUS_EVENT_PORT_ID = 2,
- VMBUS_MONITOR_CONNECTION_ID = 3,
- VMBUS_MONITOR_PORT_ID = 3,
- VMBUS_MESSAGE_SINT = 2,
-};
-
-/* #defines */
-
-#define HV_PRESENT_BIT 0x80000000
-
-#define HV_LINUX_GUEST_ID_LO 0x00000000
-#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
-#define HV_LINUX_GUEST_ID (((u64)HV_LINUX_GUEST_ID_HI << 32) | \
- HV_LINUX_GUEST_ID_LO)
-
-#define HV_CPU_POWER_MANAGEMENT (1 << 0)
-#define HV_RECOMMENDATIONS_MAX 4
-
-#define HV_X64_MAX 5
-#define HV_CAPS_MAX 8
-
-
-#define HV_HYPERCALL_PARAM_ALIGN sizeof(u64)
-
-
-/* Service definitions */
-
-#define HV_SERVICE_PARENT_PORT (0)
-#define HV_SERVICE_PARENT_CONNECTION (0)
-
-#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0)
-#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1)
-#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2)
-#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3)
-
-#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1)
-#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2)
-#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3)
-#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4)
-#define HV_SERVICE_MAX_MESSAGE_ID (4)
-
-#define HV_SERVICE_PROTOCOL_VERSION (0x0010)
-#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64
-
-/* #define VMBUS_REVISION_NUMBER 6 */
-
-/* Our local vmbus's port and connection id. Anything >0 is fine */
-/* #define VMBUS_PORT_ID 11 */
-
-/* 628180B8-308D-4c5e-B7DB-1BEB62E62EF4 */
-static const struct hv_guid VMBUS_SERVICE_ID = {
- .data = {
- 0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c,
- 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4
- },
-};
-
-#define MAX_NUM_CPUS 32
-
-
-struct hv_input_signal_event_buffer {
- u64 Align8;
- struct hv_input_signal_event Event;
-};
-
-struct hv_context {
- /* We only support running on top of Hyper-V
- * So at this point this really can only contain the Hyper-V ID
- */
- u64 GuestId;
-
- void *HypercallPage;
-
- bool SynICInitialized;
-
- /*
- * This is used as an input param to HvCallSignalEvent hypercall. The
- * input param is immutable in our usage and must be dynamic mem (vs
- * stack or global). */
- struct hv_input_signal_event_buffer *SignalEventBuffer;
- /* 8-bytes aligned of the buffer above */
- struct hv_input_signal_event *SignalEventParam;
-
- void *synICMessagePage[MAX_NUM_CPUS];
- void *synICEventPage[MAX_NUM_CPUS];
-};
-
-extern struct hv_context gHvContext;
-
-
-/* Hv Interface */
-
-extern int HvInit(void);
-
-extern void HvCleanup(void);
-
-extern u16 HvPostMessage(union hv_connection_id connectionId,
- enum hv_message_type messageType,
- void *payload, size_t payloadSize);
-
-extern u16 HvSignalEvent(void);
-
-extern void HvSynicInit(void *irqarg);
-
-extern void HvSynicCleanup(void *arg);
-
-#endif /* __HV_H__ */
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
index 022e6213bf67..1a67b19ed9a0 100644
--- a/drivers/staging/hv/Kconfig
+++ b/drivers/staging/hv/Kconfig
@@ -1,6 +1,6 @@
config HYPERV
tristate "Microsoft Hyper-V client drivers"
- depends on X86 && !XEN && m
+ depends on X86 && !XEN && ACPI && PCI && m
default n
help
Select this option to run Linux as a Hyper-V client operating
@@ -17,7 +17,7 @@ config HYPERV_STORAGE
config HYPERV_BLOCK
tristate "Microsoft Hyper-V virtual block driver"
- depends on BLOCK && SCSI
+ depends on BLOCK && SCSI && (LBDAF || 64BIT)
default HYPERV
help
Select this option to enable the Hyper-V virtual block driver.
@@ -31,8 +31,16 @@ config HYPERV_NET
config HYPERV_UTILS
tristate "Microsoft Hyper-V Utilities driver"
+ depends on CONNECTOR && NLS
default HYPERV
help
Select this option to enable the Hyper-V Utilities.
+config HYPERV_MOUSE
+ tristate "Microsoft Hyper-V mouse driver"
+ depends on HID
+ default HYPERV
+ help
+ Select this option to enable the Hyper-V mouse driver.
+
endif
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
index 3ded0bcc0c11..fb94c400fd6c 100644
--- a/drivers/staging/hv/Makefile
+++ b/drivers/staging/hv/Makefile
@@ -3,11 +3,14 @@ obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
obj-$(CONFIG_HYPERV_BLOCK) += hv_blkvsc.o
obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o
obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o
+obj-$(CONFIG_HYPERV_MOUSE) += hv_mouse.o
-hv_vmbus-objs := vmbus_drv.o osd.o \
- Vmbus.o Hv.o Connection.o Channel.o \
- ChannelMgmt.o ChannelInterface.o RingBuffer.o
-hv_storvsc-objs := storvsc_drv.o StorVsc.o
-hv_blkvsc-objs := blkvsc_drv.o BlkVsc.o
-hv_netvsc-objs := netvsc_drv.o NetVsc.o RndisFilter.o
-hv_utils-objs := hyperv_utils.o ext_utils.o
+EXTRA_CFLAGS += -I$(src)/include
+
+hv_vmbus-y := vmbus_drv.o \
+ hv.o connection.o channel.o \
+ channel_mgmt.o ring_buffer.o
+hv_storvsc-y := storvsc_drv.o storvsc.o
+hv_blkvsc-y := blkvsc_drv.o storvsc.o
+hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o
+hv_utils-y := hv_util.o hv_kvp.o
diff --git a/drivers/staging/hv/NetVsc.c b/drivers/staging/hv/NetVsc.c
deleted file mode 100644
index b3e3181c9d4e..000000000000
--- a/drivers/staging/hv/NetVsc.c
+++ /dev/null
@@ -1,1328 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include "osd.h"
-#include "logging.h"
-#include "NetVsc.h"
-#include "RndisFilter.h"
-
-
-/* Globals */
-static const char *gDriverName = "netvsc";
-
-/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
-static const struct hv_guid gNetVscDeviceType = {
- .data = {
- 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
- 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
- }
-};
-
-static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo);
-
-static int NetVscOnDeviceRemove(struct hv_device *Device);
-
-static void NetVscOnCleanup(struct hv_driver *Driver);
-
-static void NetVscOnChannelCallback(void *context);
-
-static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device);
-
-static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device);
-
-static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice);
-
-static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice);
-
-static int NetVscConnectToVsp(struct hv_device *Device);
-
-static void NetVscOnSendCompletion(struct hv_device *Device,
- struct vmpacket_descriptor *Packet);
-
-static int NetVscOnSend(struct hv_device *Device,
- struct hv_netvsc_packet *Packet);
-
-static void NetVscOnReceive(struct hv_device *Device,
- struct vmpacket_descriptor *Packet);
-
-static void NetVscOnReceiveCompletion(void *Context);
-
-static void NetVscSendReceiveCompletion(struct hv_device *Device,
- u64 TransactionId);
-
-
-static struct netvsc_device *AllocNetDevice(struct hv_device *Device)
-{
- struct netvsc_device *netDevice;
-
- netDevice = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL);
- if (!netDevice)
- return NULL;
-
- /* Set to 2 to allow both inbound and outbound traffic */
- atomic_cmpxchg(&netDevice->RefCount, 0, 2);
-
- netDevice->Device = Device;
- Device->Extension = netDevice;
-
- return netDevice;
-}
-
-static void FreeNetDevice(struct netvsc_device *Device)
-{
- WARN_ON(atomic_read(&Device->RefCount) == 0);
- Device->Device->Extension = NULL;
- kfree(Device);
-}
-
-
-/* Get the net device object iff exists and its refcount > 1 */
-static struct netvsc_device *GetOutboundNetDevice(struct hv_device *Device)
-{
- struct netvsc_device *netDevice;
-
- netDevice = Device->Extension;
- if (netDevice && atomic_read(&netDevice->RefCount) > 1)
- atomic_inc(&netDevice->RefCount);
- else
- netDevice = NULL;
-
- return netDevice;
-}
-
-/* Get the net device object iff exists and its refcount > 0 */
-static struct netvsc_device *GetInboundNetDevice(struct hv_device *Device)
-{
- struct netvsc_device *netDevice;
-
- netDevice = Device->Extension;
- if (netDevice && atomic_read(&netDevice->RefCount))
- atomic_inc(&netDevice->RefCount);
- else
- netDevice = NULL;
-
- return netDevice;
-}
-
-static void PutNetDevice(struct hv_device *Device)
-{
- struct netvsc_device *netDevice;
-
- netDevice = Device->Extension;
- /* ASSERT(netDevice); */
-
- atomic_dec(&netDevice->RefCount);
-}
-
-static struct netvsc_device *ReleaseOutboundNetDevice(struct hv_device *Device)
-{
- struct netvsc_device *netDevice;
-
- netDevice = Device->Extension;
- if (netDevice == NULL)
- return NULL;
-
- /* Busy wait until the ref drop to 2, then set it to 1 */
- while (atomic_cmpxchg(&netDevice->RefCount, 2, 1) != 2)
- udelay(100);
-
- return netDevice;
-}
-
-static struct netvsc_device *ReleaseInboundNetDevice(struct hv_device *Device)
-{
- struct netvsc_device *netDevice;
-
- netDevice = Device->Extension;
- if (netDevice == NULL)
- return NULL;
-
- /* Busy wait until the ref drop to 1, then set it to 0 */
- while (atomic_cmpxchg(&netDevice->RefCount, 1, 0) != 1)
- udelay(100);
-
- Device->Extension = NULL;
- return netDevice;
-}
-
-/*
- * NetVscInitialize - Main entry point
- */
-int NetVscInitialize(struct hv_driver *drv)
-{
- struct netvsc_driver *driver = (struct netvsc_driver *)drv;
-
- DPRINT_DBG(NETVSC, "sizeof(struct hv_netvsc_packet)=%zd, "
- "sizeof(struct nvsp_message)=%zd, "
- "sizeof(struct vmtransfer_page_packet_header)=%zd",
- sizeof(struct hv_netvsc_packet),
- sizeof(struct nvsp_message),
- sizeof(struct vmtransfer_page_packet_header));
-
- /* Make sure we are at least 2 pages since 1 page is used for control */
- /* ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); */
-
- drv->name = gDriverName;
- memcpy(&drv->deviceType, &gNetVscDeviceType, sizeof(struct hv_guid));
-
- /* Make sure it is set by the caller */
- /* FIXME: These probably should still be tested in some way */
- /* ASSERT(driver->OnReceiveCallback); */
- /* ASSERT(driver->OnLinkStatusChanged); */
-
- /* Setup the dispatch table */
- driver->Base.OnDeviceAdd = NetVscOnDeviceAdd;
- driver->Base.OnDeviceRemove = NetVscOnDeviceRemove;
- driver->Base.OnCleanup = NetVscOnCleanup;
-
- driver->OnSend = NetVscOnSend;
-
- RndisFilterInit(driver);
- return 0;
-}
-
-static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
-{
- int ret = 0;
- struct netvsc_device *netDevice;
- struct nvsp_message *initPacket;
-
- netDevice = GetOutboundNetDevice(Device);
- if (!netDevice) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
- "device being destroyed?");
- return -1;
- }
- /* ASSERT(netDevice->ReceiveBufferSize > 0); */
- /* page-size grandularity */
- /* ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE - 1)) == 0); */
-
- netDevice->ReceiveBuffer =
- osd_PageAlloc(netDevice->ReceiveBufferSize >> PAGE_SHIFT);
- if (!netDevice->ReceiveBuffer) {
- DPRINT_ERR(NETVSC,
- "unable to allocate receive buffer of size %d",
- netDevice->ReceiveBufferSize);
- ret = -1;
- goto Cleanup;
- }
- /* page-aligned buffer */
- /* ASSERT(((unsigned long)netDevice->ReceiveBuffer & (PAGE_SIZE - 1)) == */
- /* 0); */
-
- DPRINT_INFO(NETVSC, "Establishing receive buffer's GPADL...");
-
- /*
- * Establish the gpadl handle for this buffer on this
- * channel. Note: This call uses the vmbus connection rather
- * than the channel to establish the gpadl handle.
- */
- ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device,
- netDevice->ReceiveBuffer,
- netDevice->ReceiveBufferSize,
- &netDevice->ReceiveBufferGpadlHandle);
- if (ret != 0) {
- DPRINT_ERR(NETVSC,
- "unable to establish receive buffer's gpadl");
- goto Cleanup;
- }
-
- /* osd_WaitEventWait(ext->ChannelInitEvent); */
-
- /* Notify the NetVsp of the gpadl handle */
- DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer...");
-
- initPacket = &netDevice->ChannelInitPacket;
-
- memset(initPacket, 0, sizeof(struct nvsp_message));
-
- initPacket->Header.MessageType = NvspMessage1TypeSendReceiveBuffer;
- initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->ReceiveBufferGpadlHandle;
- initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID;
-
- /* Send the gpadl notification request */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- initPacket,
- sizeof(struct nvsp_message),
- (unsigned long)initPacket,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(NETVSC,
- "unable to send receive buffer's gpadl to netvsp");
- goto Cleanup;
- }
-
- osd_WaitEventWait(netDevice->ChannelInitEvent);
-
- /* Check the response */
- if (initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status != NvspStatusSuccess) {
- DPRINT_ERR(NETVSC, "Unable to complete receive buffer "
- "initialzation with NetVsp - status %d",
- initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status);
- ret = -1;
- goto Cleanup;
- }
-
- /* Parse the response */
- /* ASSERT(netDevice->ReceiveSectionCount == 0); */
- /* ASSERT(netDevice->ReceiveSections == NULL); */
-
- netDevice->ReceiveSectionCount = initPacket->Messages.Version1Messages.SendReceiveBufferComplete.NumSections;
-
- netDevice->ReceiveSections = kmalloc(netDevice->ReceiveSectionCount * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL);
- if (netDevice->ReceiveSections == NULL) {
- ret = -1;
- goto Cleanup;
- }
-
- memcpy(netDevice->ReceiveSections,
- initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Sections,
- netDevice->ReceiveSectionCount * sizeof(struct nvsp_1_receive_buffer_section));
-
- DPRINT_INFO(NETVSC, "Receive sections info (count %d, offset %d, "
- "endoffset %d, suballoc size %d, num suballocs %d)",
- netDevice->ReceiveSectionCount,
- netDevice->ReceiveSections[0].Offset,
- netDevice->ReceiveSections[0].EndOffset,
- netDevice->ReceiveSections[0].SubAllocationSize,
- netDevice->ReceiveSections[0].NumSubAllocations);
-
- /*
- * For 1st release, there should only be 1 section that represents the
- * entire receive buffer
- */
- if (netDevice->ReceiveSectionCount != 1 ||
- netDevice->ReceiveSections->Offset != 0) {
- ret = -1;
- goto Cleanup;
- }
-
- goto Exit;
-
-Cleanup:
- NetVscDestroyReceiveBuffer(netDevice);
-
-Exit:
- PutNetDevice(Device);
- return ret;
-}
-
-static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
-{
- int ret = 0;
- struct netvsc_device *netDevice;
- struct nvsp_message *initPacket;
-
- netDevice = GetOutboundNetDevice(Device);
- if (!netDevice) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
- "device being destroyed?");
- return -1;
- }
- if (netDevice->SendBufferSize <= 0) {
- ret = -EINVAL;
- goto Cleanup;
- }
-
- /* page-size grandularity */
- /* ASSERT((netDevice->SendBufferSize & (PAGE_SIZE - 1)) == 0); */
-
- netDevice->SendBuffer =
- osd_PageAlloc(netDevice->SendBufferSize >> PAGE_SHIFT);
- if (!netDevice->SendBuffer) {
- DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d",
- netDevice->SendBufferSize);
- ret = -1;
- goto Cleanup;
- }
- /* page-aligned buffer */
- /* ASSERT(((unsigned long)netDevice->SendBuffer & (PAGE_SIZE - 1)) == 0); */
-
- DPRINT_INFO(NETVSC, "Establishing send buffer's GPADL...");
-
- /*
- * Establish the gpadl handle for this buffer on this
- * channel. Note: This call uses the vmbus connection rather
- * than the channel to establish the gpadl handle.
- */
- ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device,
- netDevice->SendBuffer,
- netDevice->SendBufferSize,
- &netDevice->SendBufferGpadlHandle);
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl");
- goto Cleanup;
- }
-
- /* osd_WaitEventWait(ext->ChannelInitEvent); */
-
- /* Notify the NetVsp of the gpadl handle */
- DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer...");
-
- initPacket = &netDevice->ChannelInitPacket;
-
- memset(initPacket, 0, sizeof(struct nvsp_message));
-
- initPacket->Header.MessageType = NvspMessage1TypeSendSendBuffer;
- initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->SendBufferGpadlHandle;
- initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_SEND_BUFFER_ID;
-
- /* Send the gpadl notification request */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- initPacket, sizeof(struct nvsp_message),
- (unsigned long)initPacket,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(NETVSC,
- "unable to send receive buffer's gpadl to netvsp");
- goto Cleanup;
- }
-
- osd_WaitEventWait(netDevice->ChannelInitEvent);
-
- /* Check the response */
- if (initPacket->Messages.Version1Messages.SendSendBufferComplete.Status != NvspStatusSuccess) {
- DPRINT_ERR(NETVSC, "Unable to complete send buffer "
- "initialzation with NetVsp - status %d",
- initPacket->Messages.Version1Messages.SendSendBufferComplete.Status);
- ret = -1;
- goto Cleanup;
- }
-
- netDevice->SendSectionSize = initPacket->Messages.Version1Messages.SendSendBufferComplete.SectionSize;
-
- goto Exit;
-
-Cleanup:
- NetVscDestroySendBuffer(netDevice);
-
-Exit:
- PutNetDevice(Device);
- return ret;
-}
-
-static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
-{
- struct nvsp_message *revokePacket;
- int ret = 0;
-
- /*
- * If we got a section count, it means we received a
- * SendReceiveBufferComplete msg (ie sent
- * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
- * to send a revoke msg here
- */
- if (NetDevice->ReceiveSectionCount) {
- DPRINT_INFO(NETVSC,
- "Sending NvspMessage1TypeRevokeReceiveBuffer...");
-
- /* Send the revoke receive buffer */
- revokePacket = &NetDevice->RevokePacket;
- memset(revokePacket, 0, sizeof(struct nvsp_message));
-
- revokePacket->Header.MessageType = NvspMessage1TypeRevokeReceiveBuffer;
- revokePacket->Messages.Version1Messages.RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID;
-
- ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(
- NetDevice->Device,
- revokePacket,
- sizeof(struct nvsp_message),
- (unsigned long)revokePacket,
- VmbusPacketTypeDataInBand, 0);
- /*
- * If we failed here, we might as well return and
- * have a leak rather than continue and a bugchk
- */
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to send revoke receive "
- "buffer to netvsp");
- return -1;
- }
- }
-
- /* Teardown the gpadl on the vsp end */
- if (NetDevice->ReceiveBufferGpadlHandle) {
- DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL...");
-
- ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(
- NetDevice->Device,
- NetDevice->ReceiveBufferGpadlHandle);
-
- /* If we failed here, we might as well return and have a leak rather than continue and a bugchk */
- if (ret != 0) {
- DPRINT_ERR(NETVSC,
- "unable to teardown receive buffer's gpadl");
- return -1;
- }
- NetDevice->ReceiveBufferGpadlHandle = 0;
- }
-
- if (NetDevice->ReceiveBuffer) {
- DPRINT_INFO(NETVSC, "Freeing up receive buffer...");
-
- /* Free up the receive buffer */
- osd_PageFree(NetDevice->ReceiveBuffer,
- NetDevice->ReceiveBufferSize >> PAGE_SHIFT);
- NetDevice->ReceiveBuffer = NULL;
- }
-
- if (NetDevice->ReceiveSections) {
- NetDevice->ReceiveSectionCount = 0;
- kfree(NetDevice->ReceiveSections);
- NetDevice->ReceiveSections = NULL;
- }
-
- return ret;
-}
-
-static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
-{
- struct nvsp_message *revokePacket;
- int ret = 0;
-
- /*
- * If we got a section count, it means we received a
- * SendReceiveBufferComplete msg (ie sent
- * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
- * to send a revoke msg here
- */
- if (NetDevice->SendSectionSize) {
- DPRINT_INFO(NETVSC,
- "Sending NvspMessage1TypeRevokeSendBuffer...");
-
- /* Send the revoke send buffer */
- revokePacket = &NetDevice->RevokePacket;
- memset(revokePacket, 0, sizeof(struct nvsp_message));
-
- revokePacket->Header.MessageType = NvspMessage1TypeRevokeSendBuffer;
- revokePacket->Messages.Version1Messages.RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID;
-
- ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(NetDevice->Device,
- revokePacket,
- sizeof(struct nvsp_message),
- (unsigned long)revokePacket,
- VmbusPacketTypeDataInBand, 0);
- /*
- * If we failed here, we might as well return and have a leak
- * rather than continue and a bugchk
- */
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to send revoke send buffer "
- "to netvsp");
- return -1;
- }
- }
-
- /* Teardown the gpadl on the vsp end */
- if (NetDevice->SendBufferGpadlHandle) {
- DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL...");
-
- ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(NetDevice->Device, NetDevice->SendBufferGpadlHandle);
-
- /*
- * If we failed here, we might as well return and have a leak
- * rather than continue and a bugchk
- */
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to teardown send buffer's "
- "gpadl");
- return -1;
- }
- NetDevice->SendBufferGpadlHandle = 0;
- }
-
- if (NetDevice->SendBuffer) {
- DPRINT_INFO(NETVSC, "Freeing up send buffer...");
-
- /* Free up the receive buffer */
- osd_PageFree(NetDevice->SendBuffer,
- NetDevice->SendBufferSize >> PAGE_SHIFT);
- NetDevice->SendBuffer = NULL;
- }
-
- return ret;
-}
-
-
-static int NetVscConnectToVsp(struct hv_device *Device)
-{
- int ret;
- struct netvsc_device *netDevice;
- struct nvsp_message *initPacket;
- int ndisVersion;
-
- netDevice = GetOutboundNetDevice(Device);
- if (!netDevice) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
- "device being destroyed?");
- return -1;
- }
-
- initPacket = &netDevice->ChannelInitPacket;
-
- memset(initPacket, 0, sizeof(struct nvsp_message));
- initPacket->Header.MessageType = NvspMessageTypeInit;
- initPacket->Messages.InitMessages.Init.MinProtocolVersion = NVSP_MIN_PROTOCOL_VERSION;
- initPacket->Messages.InitMessages.Init.MaxProtocolVersion = NVSP_MAX_PROTOCOL_VERSION;
-
- DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit...");
-
- /* Send the init request */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- initPacket,
- sizeof(struct nvsp_message),
- (unsigned long)initPacket,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to send NvspMessageTypeInit");
- goto Cleanup;
- }
-
- osd_WaitEventWait(netDevice->ChannelInitEvent);
-
- /* Now, check the response */
- /* ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT); */
- DPRINT_INFO(NETVSC, "NvspMessageTypeInit status(%d) max mdl chain (%d)",
- initPacket->Messages.InitMessages.InitComplete.Status,
- initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength);
-
- if (initPacket->Messages.InitMessages.InitComplete.Status !=
- NvspStatusSuccess) {
- DPRINT_ERR(NETVSC,
- "unable to initialize with netvsp (status 0x%x)",
- initPacket->Messages.InitMessages.InitComplete.Status);
- ret = -1;
- goto Cleanup;
- }
-
- if (initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion != NVSP_PROTOCOL_VERSION_1) {
- DPRINT_ERR(NETVSC, "unable to initialize with netvsp "
- "(version expected 1 got %d)",
- initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion);
- ret = -1;
- goto Cleanup;
- }
- DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendNdisVersion...");
-
- /* Send the ndis version */
- memset(initPacket, 0, sizeof(struct nvsp_message));
-
- ndisVersion = 0x00050000;
-
- initPacket->Header.MessageType = NvspMessage1TypeSendNdisVersion;
- initPacket->Messages.Version1Messages.SendNdisVersion.NdisMajorVersion =
- (ndisVersion & 0xFFFF0000) >> 16;
- initPacket->Messages.Version1Messages.SendNdisVersion.NdisMinorVersion =
- ndisVersion & 0xFFFF;
-
- /* Send the init request */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- initPacket,
- sizeof(struct nvsp_message),
- (unsigned long)initPacket,
- VmbusPacketTypeDataInBand, 0);
- if (ret != 0) {
- DPRINT_ERR(NETVSC,
- "unable to send NvspMessage1TypeSendNdisVersion");
- ret = -1;
- goto Cleanup;
- }
- /*
- * BUGBUG - We have to wait for the above msg since the
- * netvsp uses KMCL which acknowledges packet (completion
- * packet) since our Vmbus always set the
- * VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag
- */
- /* osd_WaitEventWait(NetVscChannel->ChannelInitEvent); */
-
- /* Post the big receive buffer to NetVSP */
- ret = NetVscInitializeReceiveBufferWithNetVsp(Device);
- if (ret == 0)
- ret = NetVscInitializeSendBufferWithNetVsp(Device);
-
-Cleanup:
- PutNetDevice(Device);
- return ret;
-}
-
-static void NetVscDisconnectFromVsp(struct netvsc_device *NetDevice)
-{
- NetVscDestroyReceiveBuffer(NetDevice);
- NetVscDestroySendBuffer(NetDevice);
-}
-
-/*
- * NetVscOnDeviceAdd - Callback when the device belonging to this driver is added
- */
-static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
-{
- int ret = 0;
- int i;
- struct netvsc_device *netDevice;
- struct hv_netvsc_packet *packet, *pos;
- struct netvsc_driver *netDriver =
- (struct netvsc_driver *)Device->Driver;
-
- netDevice = AllocNetDevice(Device);
- if (!netDevice) {
- ret = -1;
- goto Cleanup;
- }
-
- DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", netDevice);
-
- /* Initialize the NetVSC channel extension */
- netDevice->ReceiveBufferSize = NETVSC_RECEIVE_BUFFER_SIZE;
- spin_lock_init(&netDevice->receive_packet_list_lock);
-
- netDevice->SendBufferSize = NETVSC_SEND_BUFFER_SIZE;
-
- INIT_LIST_HEAD(&netDevice->ReceivePacketList);
-
- for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
- packet = kzalloc(sizeof(struct hv_netvsc_packet) +
- (NETVSC_RECEIVE_SG_COUNT *
- sizeof(struct hv_page_buffer)), GFP_KERNEL);
- if (!packet) {
- DPRINT_DBG(NETVSC, "unable to allocate netvsc pkts "
- "for receive pool (wanted %d got %d)",
- NETVSC_RECEIVE_PACKETLIST_COUNT, i);
- break;
- }
- list_add_tail(&packet->ListEntry,
- &netDevice->ReceivePacketList);
- }
- netDevice->ChannelInitEvent = osd_WaitEventCreate();
- if (!netDevice->ChannelInitEvent) {
- ret = -ENOMEM;
- goto Cleanup;
- }
-
- /* Open the channel */
- ret = Device->Driver->VmbusChannelInterface.Open(Device,
- netDriver->RingBufferSize,
- netDriver->RingBufferSize,
- NULL, 0,
- NetVscOnChannelCallback,
- Device);
-
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to open channel: %d", ret);
- ret = -1;
- goto Cleanup;
- }
-
- /* Channel is opened */
- DPRINT_INFO(NETVSC, "*** NetVSC channel opened successfully! ***");
-
- /* Connect with the NetVsp */
- ret = NetVscConnectToVsp(Device);
- if (ret != 0) {
- DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret);
- ret = -1;
- goto Close;
- }
-
- DPRINT_INFO(NETVSC, "*** NetVSC channel handshake result - %d ***",
- ret);
-
- return ret;
-
-Close:
- /* Now, we can close the channel safely */
- Device->Driver->VmbusChannelInterface.Close(Device);
-
-Cleanup:
-
- if (netDevice) {
- kfree(netDevice->ChannelInitEvent);
-
- list_for_each_entry_safe(packet, pos,
- &netDevice->ReceivePacketList,
- ListEntry) {
- list_del(&packet->ListEntry);
- kfree(packet);
- }
-
- ReleaseOutboundNetDevice(Device);
- ReleaseInboundNetDevice(Device);
-
- FreeNetDevice(netDevice);
- }
-
- return ret;
-}
-
-/*
- * NetVscOnDeviceRemove - Callback when the root bus device is removed
- */
-static int NetVscOnDeviceRemove(struct hv_device *Device)
-{
- struct netvsc_device *netDevice;
- struct hv_netvsc_packet *netvscPacket, *pos;
-
- DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...",
- Device->Extension);
-
- /* Stop outbound traffic ie sends and receives completions */
- netDevice = ReleaseOutboundNetDevice(Device);
- if (!netDevice) {
- DPRINT_ERR(NETVSC, "No net device present!!");
- return -1;
- }
-
- /* Wait for all send completions */
- while (atomic_read(&netDevice->NumOutstandingSends)) {
- DPRINT_INFO(NETVSC, "waiting for %d requests to complete...",
- atomic_read(&netDevice->NumOutstandingSends));
- udelay(100);
- }
-
- DPRINT_INFO(NETVSC, "Disconnecting from netvsp...");
-
- NetVscDisconnectFromVsp(netDevice);
-
- DPRINT_INFO(NETVSC, "Disabling inbound traffic on net device (%p)...",
- Device->Extension);
-
- /* Stop inbound traffic ie receives and sends completions */
- netDevice = ReleaseInboundNetDevice(Device);
-
- /* At this point, no one should be accessing netDevice except in here */
- DPRINT_INFO(NETVSC, "net device (%p) safe to remove", netDevice);
-
- /* Now, we can close the channel safely */
- Device->Driver->VmbusChannelInterface.Close(Device);
-
- /* Release all resources */
- list_for_each_entry_safe(netvscPacket, pos,
- &netDevice->ReceivePacketList, ListEntry) {
- list_del(&netvscPacket->ListEntry);
- kfree(netvscPacket);
- }
-
- kfree(netDevice->ChannelInitEvent);
- FreeNetDevice(netDevice);
- return 0;
-}
-
-/*
- * NetVscOnCleanup - Perform any cleanup when the driver is removed
- */
-static void NetVscOnCleanup(struct hv_driver *drv)
-{
-}
-
-static void NetVscOnSendCompletion(struct hv_device *Device,
- struct vmpacket_descriptor *Packet)
-{
- struct netvsc_device *netDevice;
- struct nvsp_message *nvspPacket;
- struct hv_netvsc_packet *nvscPacket;
-
- netDevice = GetInboundNetDevice(Device);
- if (!netDevice) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
- "device being destroyed?");
- return;
- }
-
- nvspPacket = (struct nvsp_message *)((unsigned long)Packet + (Packet->DataOffset8 << 3));
-
- DPRINT_DBG(NETVSC, "send completion packet - type %d",
- nvspPacket->Header.MessageType);
-
- if ((nvspPacket->Header.MessageType == NvspMessageTypeInitComplete) ||
- (nvspPacket->Header.MessageType ==
- NvspMessage1TypeSendReceiveBufferComplete) ||
- (nvspPacket->Header.MessageType ==
- NvspMessage1TypeSendSendBufferComplete)) {
- /* Copy the response back */
- memcpy(&netDevice->ChannelInitPacket, nvspPacket,
- sizeof(struct nvsp_message));
- osd_WaitEventSet(netDevice->ChannelInitEvent);
- } else if (nvspPacket->Header.MessageType ==
- NvspMessage1TypeSendRNDISPacketComplete) {
- /* Get the send context */
- nvscPacket = (struct hv_netvsc_packet *)(unsigned long)Packet->TransactionId;
- /* ASSERT(nvscPacket); */
-
- /* Notify the layer above us */
- nvscPacket->Completion.Send.OnSendCompletion(nvscPacket->Completion.Send.SendCompletionContext);
-
- atomic_dec(&netDevice->NumOutstandingSends);
- } else {
- DPRINT_ERR(NETVSC, "Unknown send completion packet type - "
- "%d received!!", nvspPacket->Header.MessageType);
- }
-
- PutNetDevice(Device);
-}
-
-static int NetVscOnSend(struct hv_device *Device,
- struct hv_netvsc_packet *Packet)
-{
- struct netvsc_device *netDevice;
- int ret = 0;
-
- struct nvsp_message sendMessage;
-
- netDevice = GetOutboundNetDevice(Device);
- if (!netDevice) {
- DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
- "ignoring outbound packets", netDevice);
- return -2;
- }
-
- sendMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacket;
- if (Packet->IsDataPacket) {
- /* 0 is RMC_DATA; */
- sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 0;
- } else {
- /* 1 is RMC_CONTROL; */
- sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 1;
- }
-
- /* Not using send buffer section */
- sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionIndex = 0xFFFFFFFF;
- sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0;
-
- if (Packet->PageBufferCount) {
- ret = Device->Driver->VmbusChannelInterface.SendPacketPageBuffer(
- Device, Packet->PageBuffers,
- Packet->PageBufferCount,
- &sendMessage,
- sizeof(struct nvsp_message),
- (unsigned long)Packet);
- } else {
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- &sendMessage,
- sizeof(struct nvsp_message),
- (unsigned long)Packet,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
- }
-
- if (ret != 0)
- DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d",
- Packet, ret);
-
- atomic_inc(&netDevice->NumOutstandingSends);
- PutNetDevice(Device);
- return ret;
-}
-
-static void NetVscOnReceive(struct hv_device *Device,
- struct vmpacket_descriptor *Packet)
-{
- struct netvsc_device *netDevice;
- struct vmtransfer_page_packet_header *vmxferpagePacket;
- struct nvsp_message *nvspPacket;
- struct hv_netvsc_packet *netvscPacket = NULL;
- unsigned long start;
- unsigned long end, endVirtual;
- /* struct netvsc_driver *netvscDriver; */
- struct xferpage_packet *xferpagePacket = NULL;
- int i, j;
- int count = 0, bytesRemain = 0;
- unsigned long flags;
- LIST_HEAD(listHead);
-
- netDevice = GetInboundNetDevice(Device);
- if (!netDevice) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
- "device being destroyed?");
- return;
- }
-
- /*
- * All inbound packets other than send completion should be xfer page
- * packet
- */
- if (Packet->Type != VmbusPacketTypeDataUsingTransferPages) {
- DPRINT_ERR(NETVSC, "Unknown packet type received - %d",
- Packet->Type);
- PutNetDevice(Device);
- return;
- }
-
- nvspPacket = (struct nvsp_message *)((unsigned long)Packet +
- (Packet->DataOffset8 << 3));
-
- /* Make sure this is a valid nvsp packet */
- if (nvspPacket->Header.MessageType != NvspMessage1TypeSendRNDISPacket) {
- DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d",
- nvspPacket->Header.MessageType);
- PutNetDevice(Device);
- return;
- }
-
- DPRINT_DBG(NETVSC, "NVSP packet received - type %d",
- nvspPacket->Header.MessageType);
-
- vmxferpagePacket = (struct vmtransfer_page_packet_header *)Packet;
-
- if (vmxferpagePacket->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID) {
- DPRINT_ERR(NETVSC, "Invalid xfer page set id - "
- "expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID,
- vmxferpagePacket->TransferPageSetId);
- PutNetDevice(Device);
- return;
- }
-
- DPRINT_DBG(NETVSC, "xfer page - range count %d",
- vmxferpagePacket->RangeCount);
-
- /*
- * Grab free packets (range count + 1) to represent this xfer
- * page packet. +1 to represent the xfer page packet itself.
- * We grab it here so that we know exactly how many we can
- * fulfil
- */
- spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags);
- while (!list_empty(&netDevice->ReceivePacketList)) {
- list_move_tail(netDevice->ReceivePacketList.next, &listHead);
- if (++count == vmxferpagePacket->RangeCount + 1)
- break;
- }
- spin_unlock_irqrestore(&netDevice->receive_packet_list_lock, flags);
-
- /*
- * We need at least 2 netvsc pkts (1 to represent the xfer
- * page and at least 1 for the range) i.e. we can handled
- * some of the xfer page packet ranges...
- */
- if (count < 2) {
- DPRINT_ERR(NETVSC, "Got only %d netvsc pkt...needed %d pkts. "
- "Dropping this xfer page packet completely!",
- count, vmxferpagePacket->RangeCount + 1);
-
- /* Return it to the freelist */
- spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags);
- for (i = count; i != 0; i--) {
- list_move_tail(listHead.next,
- &netDevice->ReceivePacketList);
- }
- spin_unlock_irqrestore(&netDevice->receive_packet_list_lock,
- flags);
-
- NetVscSendReceiveCompletion(Device,
- vmxferpagePacket->d.TransactionId);
-
- PutNetDevice(Device);
- return;
- }
-
- /* Remove the 1st packet to represent the xfer page packet itself */
- xferpagePacket = (struct xferpage_packet *)listHead.next;
- list_del(&xferpagePacket->ListEntry);
-
- /* This is how much we can satisfy */
- xferpagePacket->Count = count - 1;
- /* ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= */
- /* vmxferpagePacket->RangeCount); */
-
- if (xferpagePacket->Count != vmxferpagePacket->RangeCount) {
- DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer "
- "page...got %d", vmxferpagePacket->RangeCount,
- xferpagePacket->Count);
- }
-
- /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
- for (i = 0; i < (count - 1); i++) {
- netvscPacket = (struct hv_netvsc_packet *)listHead.next;
- list_del(&netvscPacket->ListEntry);
-
- /* Initialize the netvsc packet */
- netvscPacket->XferPagePacket = xferpagePacket;
- netvscPacket->Completion.Recv.OnReceiveCompletion =
- NetVscOnReceiveCompletion;
- netvscPacket->Completion.Recv.ReceiveCompletionContext =
- netvscPacket;
- netvscPacket->Device = Device;
- /* Save this so that we can send it back */
- netvscPacket->Completion.Recv.ReceiveCompletionTid =
- vmxferpagePacket->d.TransactionId;
-
- netvscPacket->TotalDataBufferLength =
- vmxferpagePacket->Ranges[i].ByteCount;
- netvscPacket->PageBufferCount = 1;
-
- /* ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + */
- /* vmxferpagePacket->Ranges[i].ByteCount < */
- /* netDevice->ReceiveBufferSize); */
-
- netvscPacket->PageBuffers[0].Length =
- vmxferpagePacket->Ranges[i].ByteCount;
-
- start = virt_to_phys((void *)((unsigned long)netDevice->ReceiveBuffer + vmxferpagePacket->Ranges[i].ByteOffset));
-
- netvscPacket->PageBuffers[0].Pfn = start >> PAGE_SHIFT;
- endVirtual = (unsigned long)netDevice->ReceiveBuffer
- + vmxferpagePacket->Ranges[i].ByteOffset
- + vmxferpagePacket->Ranges[i].ByteCount - 1;
- end = virt_to_phys((void *)endVirtual);
-
- /* Calculate the page relative offset */
- netvscPacket->PageBuffers[0].Offset =
- vmxferpagePacket->Ranges[i].ByteOffset & (PAGE_SIZE - 1);
- if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) {
- /* Handle frame across multiple pages: */
- netvscPacket->PageBuffers[0].Length =
- (netvscPacket->PageBuffers[0].Pfn << PAGE_SHIFT)
- + PAGE_SIZE - start;
- bytesRemain = netvscPacket->TotalDataBufferLength -
- netvscPacket->PageBuffers[0].Length;
- for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) {
- netvscPacket->PageBuffers[j].Offset = 0;
- if (bytesRemain <= PAGE_SIZE) {
- netvscPacket->PageBuffers[j].Length = bytesRemain;
- bytesRemain = 0;
- } else {
- netvscPacket->PageBuffers[j].Length = PAGE_SIZE;
- bytesRemain -= PAGE_SIZE;
- }
- netvscPacket->PageBuffers[j].Pfn =
- virt_to_phys((void *)(endVirtual - bytesRemain)) >> PAGE_SHIFT;
- netvscPacket->PageBufferCount++;
- if (bytesRemain == 0)
- break;
- }
- /* ASSERT(bytesRemain == 0); */
- }
- DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => "
- "(pfn %llx, offset %u, len %u)", i,
- vmxferpagePacket->Ranges[i].ByteOffset,
- vmxferpagePacket->Ranges[i].ByteCount,
- netvscPacket->PageBuffers[0].Pfn,
- netvscPacket->PageBuffers[0].Offset,
- netvscPacket->PageBuffers[0].Length);
-
- /* Pass it to the upper layer */
- ((struct netvsc_driver *)Device->Driver)->OnReceiveCallback(Device, netvscPacket);
-
- NetVscOnReceiveCompletion(netvscPacket->Completion.Recv.ReceiveCompletionContext);
- }
-
- /* ASSERT(list_empty(&listHead)); */
-
- PutNetDevice(Device);
-}
-
-static void NetVscSendReceiveCompletion(struct hv_device *Device,
- u64 TransactionId)
-{
- struct nvsp_message recvcompMessage;
- int retries = 0;
- int ret;
-
- DPRINT_DBG(NETVSC, "Sending receive completion pkt - %llx",
- TransactionId);
-
- recvcompMessage.Header.MessageType =
- NvspMessage1TypeSendRNDISPacketComplete;
-
- /* FIXME: Pass in the status */
- recvcompMessage.Messages.Version1Messages.SendRNDISPacketComplete.Status = NvspStatusSuccess;
-
-retry_send_cmplt:
- /* Send the completion */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- &recvcompMessage,
- sizeof(struct nvsp_message),
- TransactionId,
- VmbusPacketTypeCompletion, 0);
- if (ret == 0) {
- /* success */
- /* no-op */
- } else if (ret == -1) {
- /* no more room...wait a bit and attempt to retry 3 times */
- retries++;
- DPRINT_ERR(NETVSC, "unable to send receive completion pkt "
- "(tid %llx)...retrying %d", TransactionId, retries);
-
- if (retries < 4) {
- udelay(100);
- goto retry_send_cmplt;
- } else {
- DPRINT_ERR(NETVSC, "unable to send receive completion "
- "pkt (tid %llx)...give up retrying",
- TransactionId);
- }
- } else {
- DPRINT_ERR(NETVSC, "unable to send receive completion pkt - "
- "%llx", TransactionId);
- }
-}
-
-/* Send a receive completion packet to RNDIS device (ie NetVsp) */
-static void NetVscOnReceiveCompletion(void *Context)
-{
- struct hv_netvsc_packet *packet = Context;
- struct hv_device *device = (struct hv_device *)packet->Device;
- struct netvsc_device *netDevice;
- u64 transactionId = 0;
- bool fSendReceiveComp = false;
- unsigned long flags;
-
- /* ASSERT(packet->XferPagePacket); */
-
- /*
- * Even though it seems logical to do a GetOutboundNetDevice() here to
- * send out receive completion, we are using GetInboundNetDevice()
- * since we may have disable outbound traffic already.
- */
- netDevice = GetInboundNetDevice(device);
- if (!netDevice) {
- DPRINT_ERR(NETVSC, "unable to get net device..."
- "device being destroyed?");
- return;
- }
-
- /* Overloading use of the lock. */
- spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags);
-
- /* ASSERT(packet->XferPagePacket->Count > 0); */
- packet->XferPagePacket->Count--;
-
- /*
- * Last one in the line that represent 1 xfer page packet.
- * Return the xfer page packet itself to the freelist
- */
- if (packet->XferPagePacket->Count == 0) {
- fSendReceiveComp = true;
- transactionId = packet->Completion.Recv.ReceiveCompletionTid;
- list_add_tail(&packet->XferPagePacket->ListEntry,
- &netDevice->ReceivePacketList);
-
- }
-
- /* Put the packet back */
- list_add_tail(&packet->ListEntry, &netDevice->ReceivePacketList);
- spin_unlock_irqrestore(&netDevice->receive_packet_list_lock, flags);
-
- /* Send a receive completion for the xfer page packet */
- if (fSendReceiveComp)
- NetVscSendReceiveCompletion(device, transactionId);
-
- PutNetDevice(device);
-}
-
-static void NetVscOnChannelCallback(void *Context)
-{
- int ret;
- struct hv_device *device = Context;
- struct netvsc_device *netDevice;
- u32 bytesRecvd;
- u64 requestId;
- unsigned char *packet;
- struct vmpacket_descriptor *desc;
- unsigned char *buffer;
- int bufferlen = NETVSC_PACKET_SIZE;
-
- /* ASSERT(device); */
-
- packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char),
- GFP_KERNEL);
- if (!packet)
- return;
- buffer = packet;
-
- netDevice = GetInboundNetDevice(device);
- if (!netDevice) {
- DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
- "ignoring inbound packets", netDevice);
- goto out;
- }
-
- do {
- ret = device->Driver->VmbusChannelInterface.RecvPacketRaw(
- device, buffer, bufferlen,
- &bytesRecvd, &requestId);
- if (ret == 0) {
- if (bytesRecvd > 0) {
- DPRINT_DBG(NETVSC, "receive %d bytes, tid %llx",
- bytesRecvd, requestId);
-
- desc = (struct vmpacket_descriptor *)buffer;
- switch (desc->Type) {
- case VmbusPacketTypeCompletion:
- NetVscOnSendCompletion(device, desc);
- break;
-
- case VmbusPacketTypeDataUsingTransferPages:
- NetVscOnReceive(device, desc);
- break;
-
- default:
- DPRINT_ERR(NETVSC,
- "unhandled packet type %d, "
- "tid %llx len %d\n",
- desc->Type, requestId,
- bytesRecvd);
- break;
- }
-
- /* reset */
- if (bufferlen > NETVSC_PACKET_SIZE) {
- kfree(buffer);
- buffer = packet;
- bufferlen = NETVSC_PACKET_SIZE;
- }
- } else {
- /* reset */
- if (bufferlen > NETVSC_PACKET_SIZE) {
- kfree(buffer);
- buffer = packet;
- bufferlen = NETVSC_PACKET_SIZE;
- }
-
- break;
- }
- } else if (ret == -2) {
- /* Handle large packet */
- buffer = kmalloc(bytesRecvd, GFP_ATOMIC);
- if (buffer == NULL) {
- /* Try again next time around */
- DPRINT_ERR(NETVSC,
- "unable to allocate buffer of size "
- "(%d)!!", bytesRecvd);
- break;
- }
-
- bufferlen = bytesRecvd;
- }
- } while (1);
-
- PutNetDevice(device);
-out:
- kfree(buffer);
- return;
-}
diff --git a/drivers/staging/hv/NetVsc.h b/drivers/staging/hv/NetVsc.h
deleted file mode 100644
index a6264db8388a..000000000000
--- a/drivers/staging/hv/NetVsc.h
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _NETVSC_H_
-#define _NETVSC_H_
-
-#include <linux/list.h>
-#include "VmbusPacketFormat.h"
-#include "VmbusChannelInterface.h"
-#include "NetVscApi.h"
-
-
-#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
-
-#define NVSP_PROTOCOL_VERSION_1 2
-#define NVSP_MIN_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1
-#define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1
-
-enum {
- NvspMessageTypeNone = 0,
-
- /* Init Messages */
- NvspMessageTypeInit = 1,
- NvspMessageTypeInitComplete = 2,
-
- NvspVersionMessageStart = 100,
-
- /* Version 1 Messages */
- NvspMessage1TypeSendNdisVersion = NvspVersionMessageStart,
-
- NvspMessage1TypeSendReceiveBuffer,
- NvspMessage1TypeSendReceiveBufferComplete,
- NvspMessage1TypeRevokeReceiveBuffer,
-
- NvspMessage1TypeSendSendBuffer,
- NvspMessage1TypeSendSendBufferComplete,
- NvspMessage1TypeRevokeSendBuffer,
-
- NvspMessage1TypeSendRNDISPacket,
- NvspMessage1TypeSendRNDISPacketComplete,
-
- /*
- * This should be set to the number of messages for the version with
- * the maximum number of messages.
- */
- NvspNumMessagePerVersion = 9,
-};
-
-enum {
- NvspStatusNone = 0,
- NvspStatusSuccess,
- NvspStatusFailure,
- NvspStatusProtocolVersionRangeTooNew,
- NvspStatusProtocolVersionRangeTooOld,
- NvspStatusInvalidRndisPacket,
- NvspStatusBusy,
- NvspStatusMax,
-};
-
-struct nvsp_message_header {
- u32 MessageType;
-};
-
-/* 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 MinProtocolVersion;
- u32 MaxProtocolVersion;
-} __attribute__((packed));
-
-/*
- * This message is used by the VSP to complete the initialization of the
- * channel. This message should never include anything other then versioning
- * (i.e. this message will be the same for ever).
- */
-struct nvsp_message_init_complete {
- u32 NegotiatedProtocolVersion;
- u32 MaximumMdlChainLength;
- u32 Status;
-} __attribute__((packed));
-
-union nvsp_message_init_uber {
- struct nvsp_message_init Init;
- struct nvsp_message_init_complete InitComplete;
-} __attribute__((packed));
-
-/* Version 1 Messages */
-
-/*
- * This message is used by the VSC to send the NDIS version to the VSP. The VSP
- * can use this information when handling OIDs sent by the VSC.
- */
-struct nvsp_1_message_send_ndis_version {
- u32 NdisMajorVersion;
- u32 NdisMinorVersion;
-} __attribute__((packed));
-
-/*
- * This message is used by the VSC to send a receive buffer to the VSP. The VSP
- * can then use the receive buffer to send data to the VSC.
- */
-struct nvsp_1_message_send_receive_buffer {
- u32 GpadlHandle;
- u16 Id;
-} __attribute__((packed));
-
-struct nvsp_1_receive_buffer_section {
- u32 Offset;
- u32 SubAllocationSize;
- u32 NumSubAllocations;
- u32 EndOffset;
-} __attribute__((packed));
-
-/*
- * This message is used by the VSP to acknowledge a receive buffer send by the
- * VSC. This message must be sent by the VSP before the VSP uses the receive
- * buffer.
- */
-struct nvsp_1_message_send_receive_buffer_complete {
- u32 Status;
- u32 NumSections;
-
- /*
- * The receive buffer is split into two parts, a large suballocation
- * section and a small suballocation section. These sections are then
- * suballocated by a certain size.
- */
-
- /*
- * For example, the following break up of the receive buffer has 6
- * large suballocations and 10 small suballocations.
- */
-
- /*
- * | Large Section | | Small Section |
- * ------------------------------------------------------------
- * | | | | | | | | | | | | | | | | | |
- * | |
- * LargeOffset SmallOffset
- */
-
- struct nvsp_1_receive_buffer_section Sections[1];
-} __attribute__((packed));
-
-/*
- * This message is sent by the VSC to revoke the receive buffer. After the VSP
- * completes this transaction, the vsp should never use the receive buffer
- * again.
- */
-struct nvsp_1_message_revoke_receive_buffer {
- u16 Id;
-};
-
-/*
- * This message is used by the VSC to send a send buffer to the VSP. The VSC
- * can then use the send buffer to send data to the VSP.
- */
-struct nvsp_1_message_send_send_buffer {
- u32 GpadlHandle;
- u16 Id;
-} __attribute__((packed));
-
-/*
- * This message is used by the VSP to acknowledge a send buffer sent by the
- * VSC. This message must be sent by the VSP before the VSP uses the sent
- * buffer.
- */
-struct nvsp_1_message_send_send_buffer_complete {
- u32 Status;
-
- /*
- * The VSC gets to choose the size of the send buffer and the VSP gets
- * to choose the sections size of the buffer. This was done to enable
- * dynamic reconfigurations when the cost of GPA-direct buffers
- * decreases.
- */
- u32 SectionSize;
-} __attribute__((packed));
-
-/*
- * This message is sent by the VSC to revoke the send buffer. After the VSP
- * completes this transaction, the vsp should never use the send buffer again.
- */
-struct nvsp_1_message_revoke_send_buffer {
- u16 Id;
-};
-
-/*
- * This message is used by both the VSP and the VSC to send a RNDIS message to
- * the opposite channel endpoint.
- */
-struct nvsp_1_message_send_rndis_packet {
- /*
- * This field is specified by RNIDS. They assume there's two different
- * channels of communication. However, the Network VSP only has one.
- * Therefore, the channel travels with the RNDIS packet.
- */
- u32 ChannelType;
-
- /*
- * 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 SendBufferSectionIndex;
- u32 SendBufferSectionSize;
-} __attribute__((packed));
-
-/*
- * This message is used by both the VSP and the VSC to complete a RNDIS message
- * to the opposite channel endpoint. At this point, the initiator of this
- * message cannot use any resources associated with the original RNDIS packet.
- */
-struct nvsp_1_message_send_rndis_packet_complete {
- u32 Status;
-};
-
-union nvsp_1_message_uber {
- struct nvsp_1_message_send_ndis_version SendNdisVersion;
-
- struct nvsp_1_message_send_receive_buffer SendReceiveBuffer;
- struct nvsp_1_message_send_receive_buffer_complete
- SendReceiveBufferComplete;
- struct nvsp_1_message_revoke_receive_buffer RevokeReceiveBuffer;
-
- struct nvsp_1_message_send_send_buffer SendSendBuffer;
- struct nvsp_1_message_send_send_buffer_complete SendSendBufferComplete;
- struct nvsp_1_message_revoke_send_buffer RevokeSendBuffer;
-
- struct nvsp_1_message_send_rndis_packet SendRNDISPacket;
- struct nvsp_1_message_send_rndis_packet_complete
- SendRNDISPacketComplete;
-} __attribute__((packed));
-
-union nvsp_all_messages {
- union nvsp_message_init_uber InitMessages;
- union nvsp_1_message_uber Version1Messages;
-} __attribute__((packed));
-
-/* ALL Messages */
-struct nvsp_message {
- struct nvsp_message_header Header;
- union nvsp_all_messages Messages;
-} __attribute__((packed));
-
-
-
-
-/* #define NVSC_MIN_PROTOCOL_VERSION 1 */
-/* #define NVSC_MAX_PROTOCOL_VERSION 1 */
-
-#define NETVSC_SEND_BUFFER_SIZE (64*1024) /* 64K */
-#define NETVSC_SEND_BUFFER_ID 0xface
-
-
-#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024) /* 1MB */
-
-#define NETVSC_RECEIVE_BUFFER_ID 0xcafe
-
-#define NETVSC_RECEIVE_SG_COUNT 1
-
-/* Preallocated receive packets */
-#define NETVSC_RECEIVE_PACKETLIST_COUNT 256
-
-#define NETVSC_PACKET_SIZE 2048
-
-/* Per netvsc channel-specific */
-struct netvsc_device {
- struct hv_device *Device;
-
- atomic_t RefCount;
- atomic_t NumOutstandingSends;
- /*
- * List of free preallocated hv_netvsc_packet to represent receive
- * packet
- */
- struct list_head ReceivePacketList;
- spinlock_t receive_packet_list_lock;
-
- /* Send buffer allocated by us but manages by NetVSP */
- void *SendBuffer;
- u32 SendBufferSize;
- u32 SendBufferGpadlHandle;
- u32 SendSectionSize;
-
- /* Receive buffer allocated by us but manages by NetVSP */
- void *ReceiveBuffer;
- u32 ReceiveBufferSize;
- u32 ReceiveBufferGpadlHandle;
- u32 ReceiveSectionCount;
- struct nvsp_1_receive_buffer_section *ReceiveSections;
-
- /* Used for NetVSP initialization protocol */
- struct osd_waitevent *ChannelInitEvent;
- struct nvsp_message ChannelInitPacket;
-
- struct nvsp_message RevokePacket;
- /* unsigned char HwMacAddr[HW_MACADDR_LEN]; */
-
- /* Holds rndis device info */
- void *Extension;
-};
-
-#endif /* _NETVSC_H_ */
diff --git a/drivers/staging/hv/NetVscApi.h b/drivers/staging/hv/NetVscApi.h
deleted file mode 100644
index 91a4cd9965d8..000000000000
--- a/drivers/staging/hv/NetVscApi.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _NETVSC_API_H_
-#define _NETVSC_API_H_
-
-#include "VmbusApi.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 ListEntry;
-
- /* # 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 ListEntry;
-
- struct hv_device *Device;
- bool IsDataPacket;
-
- /*
- * Valid only for receives when we break a xfer page packet
- * into multiple netvsc packets
- */
- struct xferpage_packet *XferPagePacket;
-
- union {
- struct{
- u64 ReceiveCompletionTid;
- void *ReceiveCompletionContext;
- void (*OnReceiveCompletion)(void *context);
- } Recv;
- struct{
- u64 SendCompletionTid;
- void *SendCompletionContext;
- void (*OnSendCompletion)(void *context);
- } Send;
- } Completion;
-
- /* This points to the memory after PageBuffers */
- void *Extension;
-
- u32 TotalDataBufferLength;
- /* Points to the send/receive buffer where the ethernet frame is */
- u32 PageBufferCount;
- struct hv_page_buffer PageBuffers[NETVSC_PACKET_MAXPAGE];
-};
-
-/* Represents the net vsc driver */
-struct netvsc_driver {
- /* Must be the first field */
- /* Which is a bug FIXME! */
- struct hv_driver Base;
-
- u32 RingBufferSize;
- u32 RequestExtSize;
-
- /*
- * This is set by the caller to allow us to callback when we
- * receive a packet from the "wire"
- */
- int (*OnReceiveCallback)(struct hv_device *dev,
- struct hv_netvsc_packet *packet);
- void (*OnLinkStatusChanged)(struct hv_device *dev, u32 Status);
-
- /* Specific to this driver */
- int (*OnSend)(struct hv_device *dev, struct hv_netvsc_packet *packet);
-
- void *Context;
-};
-
-struct netvsc_device_info {
- unsigned char MacAddr[6];
- bool LinkState; /* 0 - link up, 1 - link down */
-};
-
-/* Interface */
-int NetVscInitialize(struct hv_driver *drv);
-int RndisFilterOnOpen(struct hv_device *Device);
-int RndisFilterOnClose(struct hv_device *Device);
-
-#endif /* _NETVSC_API_H_ */
diff --git a/drivers/staging/hv/RingBuffer.c b/drivers/staging/hv/RingBuffer.c
deleted file mode 100644
index c4e02a55f524..000000000000
--- a/drivers/staging/hv/RingBuffer.c
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include "osd.h"
-#include "logging.h"
-#include "RingBuffer.h"
-
-
-/* #defines */
-
-
-/* Amount of space to write to */
-#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w))
-
-
-/*++
-
-Name:
- GetRingBufferAvailBytes()
-
-Description:
- Get number of bytes available to read and to write to
- for the specified ring buffer
-
---*/
-static inline void
-GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, u32 *read, u32 *write)
-{
- u32 read_loc, write_loc;
-
- /* Capture the read/write indices before they changed */
- read_loc = rbi->RingBuffer->ReadIndex;
- write_loc = rbi->RingBuffer->WriteIndex;
-
- *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize);
- *read = rbi->RingDataSize - *write;
-}
-
-/*++
-
-Name:
- GetNextWriteLocation()
-
-Description:
- Get the next write location for the specified ring buffer
-
---*/
-static inline u32
-GetNextWriteLocation(struct hv_ring_buffer_info *RingInfo)
-{
- u32 next = RingInfo->RingBuffer->WriteIndex;
-
- /* ASSERT(next < RingInfo->RingDataSize); */
-
- return next;
-}
-
-/*++
-
-Name:
- SetNextWriteLocation()
-
-Description:
- Set the next write location for the specified ring buffer
-
---*/
-static inline void
-SetNextWriteLocation(struct hv_ring_buffer_info *RingInfo,
- u32 NextWriteLocation)
-{
- RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
-}
-
-/*++
-
-Name:
- GetNextReadLocation()
-
-Description:
- Get the next read location for the specified ring buffer
-
---*/
-static inline u32
-GetNextReadLocation(struct hv_ring_buffer_info *RingInfo)
-{
- u32 next = RingInfo->RingBuffer->ReadIndex;
-
- /* ASSERT(next < RingInfo->RingDataSize); */
-
- return next;
-}
-
-/*++
-
-Name:
- GetNextReadLocationWithOffset()
-
-Description:
- Get the next read location + offset for the specified ring buffer.
- This allows the caller to skip
-
---*/
-static inline u32
-GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset)
-{
- u32 next = RingInfo->RingBuffer->ReadIndex;
-
- /* ASSERT(next < RingInfo->RingDataSize); */
- next += Offset;
- next %= RingInfo->RingDataSize;
-
- return next;
-}
-
-/*++
-
-Name:
- SetNextReadLocation()
-
-Description:
- Set the next read location for the specified ring buffer
-
---*/
-static inline void
-SetNextReadLocation(struct hv_ring_buffer_info *RingInfo, u32 NextReadLocation)
-{
- RingInfo->RingBuffer->ReadIndex = NextReadLocation;
-}
-
-
-/*++
-
-Name:
- GetRingBuffer()
-
-Description:
- Get the start of the ring buffer
-
---*/
-static inline void *
-GetRingBuffer(struct hv_ring_buffer_info *RingInfo)
-{
- return (void *)RingInfo->RingBuffer->Buffer;
-}
-
-
-/*++
-
-Name:
- GetRingBufferSize()
-
-Description:
- Get the size of the ring buffer
-
---*/
-static inline u32
-GetRingBufferSize(struct hv_ring_buffer_info *RingInfo)
-{
- return RingInfo->RingDataSize;
-}
-
-/*++
-
-Name:
- GetRingBufferIndices()
-
-Description:
- Get the read and write indices as u64 of the specified ring buffer
-
---*/
-static inline u64
-GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo)
-{
- return (u64)RingInfo->RingBuffer->WriteIndex << 32;
-}
-
-
-/*++
-
-Name:
- DumpRingInfo()
-
-Description:
- Dump out to console the ring buffer info
-
---*/
-void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix)
-{
- u32 bytesAvailToWrite;
- u32 bytesAvailToRead;
-
- GetRingBufferAvailBytes(RingInfo,
- &bytesAvailToRead,
- &bytesAvailToWrite);
-
- DPRINT(VMBUS,
- DEBUG_RING_LVL,
- "%s <<ringinfo %p buffer %p avail write %u "
- "avail read %u read idx %u write idx %u>>",
- Prefix,
- RingInfo,
- RingInfo->RingBuffer->Buffer,
- bytesAvailToWrite,
- bytesAvailToRead,
- RingInfo->RingBuffer->ReadIndex,
- RingInfo->RingBuffer->WriteIndex);
-}
-
-
-/* Internal routines */
-
-static u32
-CopyToRingBuffer(
- struct hv_ring_buffer_info *RingInfo,
- u32 StartWriteOffset,
- void *Src,
- u32 SrcLen);
-
-static u32
-CopyFromRingBuffer(
- struct hv_ring_buffer_info *RingInfo,
- void *Dest,
- u32 DestLen,
- u32 StartReadOffset);
-
-
-
-/*++
-
-Name:
- RingBufferGetDebugInfo()
-
-Description:
- Get various debug metrics for the specified ring buffer
-
---*/
-void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
- struct hv_ring_buffer_debug_info *debug_info)
-{
- u32 bytesAvailToWrite;
- u32 bytesAvailToRead;
-
- if (RingInfo->RingBuffer) {
- GetRingBufferAvailBytes(RingInfo,
- &bytesAvailToRead,
- &bytesAvailToWrite);
-
- debug_info->BytesAvailToRead = bytesAvailToRead;
- debug_info->BytesAvailToWrite = bytesAvailToWrite;
- debug_info->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
- debug_info->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
- debug_info->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
- }
-}
-
-
-/*++
-
-Name:
- GetRingBufferInterruptMask()
-
-Description:
- Get the interrupt mask for the specified ring buffer
-
---*/
-u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi)
-{
- return rbi->RingBuffer->InterruptMask;
-}
-
-/*++
-
-Name:
- RingBufferInit()
-
-Description:
- Initialize the ring buffer
-
---*/
-int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 BufferLen)
-{
- if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
- return -EINVAL;
-
- memset(RingInfo, 0, sizeof(struct hv_ring_buffer_info));
-
- RingInfo->RingBuffer = (struct hv_ring_buffer *)Buffer;
- RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
-
- RingInfo->RingSize = BufferLen;
- RingInfo->RingDataSize = BufferLen - sizeof(struct hv_ring_buffer);
-
- spin_lock_init(&RingInfo->ring_lock);
-
- return 0;
-}
-
-/*++
-
-Name:
- RingBufferCleanup()
-
-Description:
- Cleanup the ring buffer
-
---*/
-void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo)
-{
-}
-
-/*++
-
-Name:
- RingBufferWrite()
-
-Description:
- Write to the ring buffer
-
---*/
-int RingBufferWrite(struct hv_ring_buffer_info *OutRingInfo,
- struct scatterlist *sglist, u32 sgcount)
-{
- int i = 0;
- u32 byteAvailToWrite;
- u32 byteAvailToRead;
- u32 totalBytesToWrite = 0;
-
- struct scatterlist *sg;
- volatile u32 nextWriteLocation;
- u64 prevIndices = 0;
- unsigned long flags;
-
- for_each_sg(sglist, sg, sgcount, i)
- {
- totalBytesToWrite += sg->length;
- }
-
- totalBytesToWrite += sizeof(u64);
-
- spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
-
- GetRingBufferAvailBytes(OutRingInfo,
- &byteAvailToRead,
- &byteAvailToWrite);
-
- DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
-
- /* DumpRingInfo(OutRingInfo, "BEFORE "); */
-
- /* If there is only room for the packet, assume it is full. */
- /* Otherwise, the next time around, we think the ring buffer */
- /* is empty since the read index == write index */
- if (byteAvailToWrite <= totalBytesToWrite) {
- DPRINT_DBG(VMBUS,
- "No more space left on outbound ring buffer "
- "(needed %u, avail %u)",
- totalBytesToWrite,
- byteAvailToWrite);
-
- spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
- return -1;
- }
-
- /* Write to the ring buffer */
- nextWriteLocation = GetNextWriteLocation(OutRingInfo);
-
- for_each_sg(sglist, sg, sgcount, i)
- {
- nextWriteLocation = CopyToRingBuffer(OutRingInfo,
- nextWriteLocation,
- sg_virt(sg),
- sg->length);
- }
-
- /* Set previous packet start */
- prevIndices = GetRingBufferIndices(OutRingInfo);
-
- nextWriteLocation = CopyToRingBuffer(OutRingInfo,
- nextWriteLocation,
- &prevIndices,
- sizeof(u64));
-
- /* Make sure we flush all writes before updating the writeIndex */
- mb();
-
- /* Now, update the write location */
- SetNextWriteLocation(OutRingInfo, nextWriteLocation);
-
- /* DumpRingInfo(OutRingInfo, "AFTER "); */
-
- spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
- return 0;
-}
-
-
-/*++
-
-Name:
- RingBufferPeek()
-
-Description:
- Read without advancing the read index
-
---*/
-int RingBufferPeek(struct hv_ring_buffer_info *InRingInfo, void *Buffer, u32 BufferLen)
-{
- u32 bytesAvailToWrite;
- u32 bytesAvailToRead;
- u32 nextReadLocation = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&InRingInfo->ring_lock, flags);
-
- GetRingBufferAvailBytes(InRingInfo,
- &bytesAvailToRead,
- &bytesAvailToWrite);
-
- /* Make sure there is something to read */
- if (bytesAvailToRead < BufferLen) {
- /* DPRINT_DBG(VMBUS,
- "got callback but not enough to read "
- "<avail to read %d read size %d>!!",
- bytesAvailToRead,
- BufferLen); */
-
- spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
-
- return -1;
- }
-
- /* Convert to byte offset */
- nextReadLocation = GetNextReadLocation(InRingInfo);
-
- nextReadLocation = CopyFromRingBuffer(InRingInfo,
- Buffer,
- BufferLen,
- nextReadLocation);
-
- spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
-
- return 0;
-}
-
-
-/*++
-
-Name:
- RingBufferRead()
-
-Description:
- Read and advance the read index
-
---*/
-int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer,
- u32 BufferLen, u32 Offset)
-{
- u32 bytesAvailToWrite;
- u32 bytesAvailToRead;
- u32 nextReadLocation = 0;
- u64 prevIndices = 0;
- unsigned long flags;
-
- if (BufferLen <= 0)
- return -EINVAL;
-
- spin_lock_irqsave(&InRingInfo->ring_lock, flags);
-
- GetRingBufferAvailBytes(InRingInfo,
- &bytesAvailToRead,
- &bytesAvailToWrite);
-
- DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
-
- /* DumpRingInfo(InRingInfo, "BEFORE "); */
-
- /* Make sure there is something to read */
- if (bytesAvailToRead < BufferLen) {
- DPRINT_DBG(VMBUS,
- "got callback but not enough to read "
- "<avail to read %d read size %d>!!",
- bytesAvailToRead,
- BufferLen);
-
- spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
-
- return -1;
- }
-
- nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
-
- nextReadLocation = CopyFromRingBuffer(InRingInfo,
- Buffer,
- BufferLen,
- nextReadLocation);
-
- nextReadLocation = CopyFromRingBuffer(InRingInfo,
- &prevIndices,
- sizeof(u64),
- nextReadLocation);
-
- /* Make sure all reads are done before we update the read index since */
- /* the writer may start writing to the read area once the read index */
- /*is updated */
- mb();
-
- /* Update the read index */
- SetNextReadLocation(InRingInfo, nextReadLocation);
-
- /* DumpRingInfo(InRingInfo, "AFTER "); */
-
- spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
-
- return 0;
-}
-
-
-/*++
-
-Name:
- CopyToRingBuffer()
-
-Description:
- Helper routine to copy from source to ring buffer.
- Assume there is enough room. Handles wrap-around in dest case only!!
-
---*/
-static u32
-CopyToRingBuffer(
- struct hv_ring_buffer_info *RingInfo,
- u32 StartWriteOffset,
- void *Src,
- u32 SrcLen)
-{
- void *ringBuffer = GetRingBuffer(RingInfo);
- u32 ringBufferSize = GetRingBufferSize(RingInfo);
- u32 fragLen;
-
- /* wrap-around detected! */
- if (SrcLen > ringBufferSize - StartWriteOffset) {
- DPRINT_DBG(VMBUS, "wrap-around detected!");
-
- fragLen = ringBufferSize - StartWriteOffset;
- memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
- memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
- } else
- memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
-
- StartWriteOffset += SrcLen;
- StartWriteOffset %= ringBufferSize;
-
- return StartWriteOffset;
-}
-
-
-/*++
-
-Name:
- CopyFromRingBuffer()
-
-Description:
- Helper routine to copy to source from ring buffer.
- Assume there is enough room. Handles wrap-around in src case only!!
-
---*/
-static u32
-CopyFromRingBuffer(
- struct hv_ring_buffer_info *RingInfo,
- void *Dest,
- u32 DestLen,
- u32 StartReadOffset)
-{
- void *ringBuffer = GetRingBuffer(RingInfo);
- u32 ringBufferSize = GetRingBufferSize(RingInfo);
-
- u32 fragLen;
-
- /* wrap-around detected at the src */
- if (DestLen > ringBufferSize - StartReadOffset) {
- DPRINT_DBG(VMBUS, "src wrap-around detected!");
-
- fragLen = ringBufferSize - StartReadOffset;
-
- memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
- memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
- } else
-
- memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
-
-
- StartReadOffset += DestLen;
- StartReadOffset %= ringBufferSize;
-
- return StartReadOffset;
-}
-
-
-/* eof */
diff --git a/drivers/staging/hv/RingBuffer.h b/drivers/staging/hv/RingBuffer.h
deleted file mode 100644
index a7f1717c6a56..000000000000
--- a/drivers/staging/hv/RingBuffer.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _RING_BUFFER_H_
-#define _RING_BUFFER_H_
-
-#include <linux/scatterlist.h>
-
-struct hv_ring_buffer {
- /* Offset in bytes from the start of ring data below */
- volatile u32 WriteIndex;
-
- /* Offset in bytes from the start of ring data below */
- volatile u32 ReadIndex;
-
- volatile u32 InterruptMask;
-
- /* Pad it to PAGE_SIZE so that data starts on page boundary */
- u8 Reserved[4084];
-
- /* NOTE:
- * The InterruptMask field is used only for channels but since our
- * vmbus connection also uses this data structure and its data starts
- * here, we commented out this field.
- */
- /* volatile u32 InterruptMask; */
-
- /*
- * Ring data starts here + RingDataStartOffset
- * !!! DO NOT place any fields below this !!!
- */
- u8 Buffer[0];
-} __attribute__((packed));
-
-struct hv_ring_buffer_info {
- struct hv_ring_buffer *RingBuffer;
- u32 RingSize; /* Include the shared header */
- spinlock_t ring_lock;
-
- u32 RingDataSize; /* < ringSize */
- u32 RingDataStartOffset;
-};
-
-struct hv_ring_buffer_debug_info {
- u32 CurrentInterruptMask;
- u32 CurrentReadIndex;
- u32 CurrentWriteIndex;
- u32 BytesAvailToRead;
- u32 BytesAvailToWrite;
-};
-
-
-
-/* Interface */
-
-
-int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer,
- u32 BufferLen);
-
-void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo);
-
-int RingBufferWrite(struct hv_ring_buffer_info *RingInfo,
- struct scatterlist *sglist,
- u32 sgcount);
-
-int RingBufferPeek(struct hv_ring_buffer_info *RingInfo, void *Buffer,
- u32 BufferLen);
-
-int RingBufferRead(struct hv_ring_buffer_info *RingInfo,
- void *Buffer,
- u32 BufferLen,
- u32 Offset);
-
-u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *RingInfo);
-
-void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix);
-
-void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
- struct hv_ring_buffer_debug_info *debug_info);
-
-#endif /* _RING_BUFFER_H_ */
diff --git a/drivers/staging/hv/RndisFilter.c b/drivers/staging/hv/RndisFilter.c
deleted file mode 100644
index 159b2304b4b9..000000000000
--- a/drivers/staging/hv/RndisFilter.c
+++ /dev/null
@@ -1,918 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#include <linux/kernel.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/if_ether.h>
-
-#include "osd.h"
-#include "logging.h"
-#include "NetVscApi.h"
-#include "RndisFilter.h"
-
-/* Data types */
-struct rndis_filter_driver_object {
- /* The original driver */
- struct netvsc_driver InnerDriver;
-};
-
-enum rndis_device_state {
- RNDIS_DEV_UNINITIALIZED = 0,
- RNDIS_DEV_INITIALIZING,
- RNDIS_DEV_INITIALIZED,
- RNDIS_DEV_DATAINITIALIZED,
-};
-
-struct rndis_device {
- struct netvsc_device *NetDevice;
-
- enum rndis_device_state State;
- u32 LinkStatus;
- atomic_t NewRequestId;
-
- spinlock_t request_lock;
- struct list_head RequestList;
-
- unsigned char HwMacAddr[ETH_ALEN];
-};
-
-struct rndis_request {
- struct list_head ListEntry;
- struct osd_waitevent *WaitEvent;
-
- /*
- * FIXME: We assumed a fixed size response here. If we do ever need to
- * handle a bigger response, we can either define a max response
- * message or add a response buffer variable above this field
- */
- struct rndis_message ResponseMessage;
-
- /* Simplify allocation by having a netvsc packet inline */
- struct hv_netvsc_packet Packet;
- struct hv_page_buffer Buffer;
- /* FIXME: We assumed a fixed size request here. */
- struct rndis_message RequestMessage;
-};
-
-
-struct rndis_filter_packet {
- void *CompletionContext;
- void (*OnCompletion)(void *context);
- struct rndis_message Message;
-};
-
-
-static int RndisFilterOnDeviceAdd(struct hv_device *Device,
- void *AdditionalInfo);
-
-static int RndisFilterOnDeviceRemove(struct hv_device *Device);
-
-static void RndisFilterOnCleanup(struct hv_driver *Driver);
-
-static int RndisFilterOnSend(struct hv_device *Device,
- struct hv_netvsc_packet *Packet);
-
-static void RndisFilterOnSendCompletion(void *Context);
-
-static void RndisFilterOnSendRequestCompletion(void *Context);
-
-
-/* The one and only */
-static struct rndis_filter_driver_object gRndisFilter;
-
-static struct rndis_device *GetRndisDevice(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->RequestList);
-
- device->State = RNDIS_DEV_UNINITIALIZED;
-
- return device;
-}
-
-static struct rndis_request *GetRndisRequest(struct rndis_device *Device,
- u32 MessageType,
- u32 MessageLength)
-{
- struct rndis_request *request;
- struct rndis_message *rndisMessage;
- struct rndis_set_request *set;
- unsigned long flags;
-
- request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL);
- if (!request)
- return NULL;
-
- request->WaitEvent = osd_WaitEventCreate();
- if (!request->WaitEvent) {
- kfree(request);
- return NULL;
- }
-
- rndisMessage = &request->RequestMessage;
- rndisMessage->NdisMessageType = MessageType;
- rndisMessage->MessageLength = MessageLength;
-
- /*
- * 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 = &rndisMessage->Message.SetRequest;
- set->RequestId = atomic_inc_return(&Device->NewRequestId);
-
- /* Add to the request list */
- spin_lock_irqsave(&Device->request_lock, flags);
- list_add_tail(&request->ListEntry, &Device->RequestList);
- spin_unlock_irqrestore(&Device->request_lock, flags);
-
- return request;
-}
-
-static void PutRndisRequest(struct rndis_device *Device,
- struct rndis_request *Request)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&Device->request_lock, flags);
- list_del(&Request->ListEntry);
- spin_unlock_irqrestore(&Device->request_lock, flags);
-
- kfree(Request->WaitEvent);
- kfree(Request);
-}
-
-static void DumpRndisMessage(struct rndis_message *RndisMessage)
-{
- switch (RndisMessage->NdisMessageType) {
- case REMOTE_NDIS_PACKET_MSG:
- DPRINT_DBG(NETVSC, "REMOTE_NDIS_PACKET_MSG (len %u, "
- "data offset %u data len %u, # oob %u, "
- "oob offset %u, oob len %u, pkt offset %u, "
- "pkt len %u",
- RndisMessage->MessageLength,
- RndisMessage->Message.Packet.DataOffset,
- RndisMessage->Message.Packet.DataLength,
- RndisMessage->Message.Packet.NumOOBDataElements,
- RndisMessage->Message.Packet.OOBDataOffset,
- RndisMessage->Message.Packet.OOBDataLength,
- RndisMessage->Message.Packet.PerPacketInfoOffset,
- RndisMessage->Message.Packet.PerPacketInfoLength);
- break;
-
- case REMOTE_NDIS_INITIALIZE_CMPLT:
- DPRINT_DBG(NETVSC, "REMOTE_NDIS_INITIALIZE_CMPLT "
- "(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
- "device flags %d, max xfer size 0x%x, max pkts %u, "
- "pkt aligned %u)",
- RndisMessage->MessageLength,
- RndisMessage->Message.InitializeComplete.RequestId,
- RndisMessage->Message.InitializeComplete.Status,
- RndisMessage->Message.InitializeComplete.MajorVersion,
- RndisMessage->Message.InitializeComplete.MinorVersion,
- RndisMessage->Message.InitializeComplete.DeviceFlags,
- RndisMessage->Message.InitializeComplete.MaxTransferSize,
- RndisMessage->Message.InitializeComplete.MaxPacketsPerMessage,
- RndisMessage->Message.InitializeComplete.PacketAlignmentFactor);
- break;
-
- case REMOTE_NDIS_QUERY_CMPLT:
- DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT "
- "(len %u, id 0x%x, status 0x%x, buf len %u, "
- "buf offset %u)",
- RndisMessage->MessageLength,
- RndisMessage->Message.QueryComplete.RequestId,
- RndisMessage->Message.QueryComplete.Status,
- RndisMessage->Message.QueryComplete.InformationBufferLength,
- RndisMessage->Message.QueryComplete.InformationBufferOffset);
- break;
-
- case REMOTE_NDIS_SET_CMPLT:
- DPRINT_DBG(NETVSC,
- "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)",
- RndisMessage->MessageLength,
- RndisMessage->Message.SetComplete.RequestId,
- RndisMessage->Message.SetComplete.Status);
- break;
-
- case REMOTE_NDIS_INDICATE_STATUS_MSG:
- DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG "
- "(len %u, status 0x%x, buf len %u, buf offset %u)",
- RndisMessage->MessageLength,
- RndisMessage->Message.IndicateStatus.Status,
- RndisMessage->Message.IndicateStatus.StatusBufferLength,
- RndisMessage->Message.IndicateStatus.StatusBufferOffset);
- break;
-
- default:
- DPRINT_DBG(NETVSC, "0x%x (len %u)",
- RndisMessage->NdisMessageType,
- RndisMessage->MessageLength);
- break;
- }
-}
-
-static int RndisFilterSendRequest(struct rndis_device *Device,
- struct rndis_request *Request)
-{
- int ret;
- struct hv_netvsc_packet *packet;
-
- /* Setup the packet to send it */
- packet = &Request->Packet;
-
- packet->IsDataPacket = false;
- packet->TotalDataBufferLength = Request->RequestMessage.MessageLength;
- packet->PageBufferCount = 1;
-
- packet->PageBuffers[0].Pfn = virt_to_phys(&Request->RequestMessage) >>
- PAGE_SHIFT;
- packet->PageBuffers[0].Length = Request->RequestMessage.MessageLength;
- packet->PageBuffers[0].Offset =
- (unsigned long)&Request->RequestMessage & (PAGE_SIZE - 1);
-
- packet->Completion.Send.SendCompletionContext = Request;/* packet; */
- packet->Completion.Send.OnSendCompletion =
- RndisFilterOnSendRequestCompletion;
- packet->Completion.Send.SendCompletionTid = (unsigned long)Device;
-
- ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet);
- return ret;
-}
-
-static void RndisFilterReceiveResponse(struct rndis_device *Device,
- struct rndis_message *Response)
-{
- struct rndis_request *request = NULL;
- bool found = false;
- unsigned long flags;
-
- spin_lock_irqsave(&Device->request_lock, flags);
- list_for_each_entry(request, &Device->RequestList, ListEntry) {
- /*
- * All request/response message contains RequestId as the 1st
- * field
- */
- if (request->RequestMessage.Message.InitializeRequest.RequestId
- == Response->Message.InitializeComplete.RequestId) {
- DPRINT_DBG(NETVSC, "found rndis request for "
- "this response (id 0x%x req type 0x%x res "
- "type 0x%x)",
- request->RequestMessage.Message.InitializeRequest.RequestId,
- request->RequestMessage.NdisMessageType,
- Response->NdisMessageType);
-
- found = true;
- break;
- }
- }
- spin_unlock_irqrestore(&Device->request_lock, flags);
-
- if (found) {
- if (Response->MessageLength <= sizeof(struct rndis_message)) {
- memcpy(&request->ResponseMessage, Response,
- Response->MessageLength);
- } else {
- DPRINT_ERR(NETVSC, "rndis response buffer overflow "
- "detected (size %u max %zu)",
- Response->MessageLength,
- sizeof(struct rndis_filter_packet));
-
- if (Response->NdisMessageType ==
- REMOTE_NDIS_RESET_CMPLT) {
- /* does not have a request id field */
- request->ResponseMessage.Message.ResetComplete.Status = STATUS_BUFFER_OVERFLOW;
- } else {
- request->ResponseMessage.Message.InitializeComplete.Status = STATUS_BUFFER_OVERFLOW;
- }
- }
-
- osd_WaitEventSet(request->WaitEvent);
- } else {
- DPRINT_ERR(NETVSC, "no rndis request found for this response "
- "(id 0x%x res type 0x%x)",
- Response->Message.InitializeComplete.RequestId,
- Response->NdisMessageType);
- }
-}
-
-static void RndisFilterReceiveIndicateStatus(struct rndis_device *Device,
- struct rndis_message *Response)
-{
- struct rndis_indicate_status *indicate =
- &Response->Message.IndicateStatus;
-
- if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) {
- gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 1);
- } else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT) {
- gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 0);
- } else {
- /*
- * TODO:
- */
- }
-}
-
-static void RndisFilterReceiveData(struct rndis_device *Device,
- struct rndis_message *Message,
- struct hv_netvsc_packet *Packet)
-{
- struct rndis_packet *rndisPacket;
- u32 dataOffset;
-
- /* empty ethernet frame ?? */
- /* ASSERT(Packet->PageBuffers[0].Length > */
- /* RNDIS_MESSAGE_SIZE(struct rndis_packet)); */
-
- rndisPacket = &Message->Message.Packet;
-
- /*
- * 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 */
- dataOffset = RNDIS_HEADER_SIZE + rndisPacket->DataOffset;
-
- Packet->TotalDataBufferLength -= dataOffset;
- Packet->PageBuffers[0].Offset += dataOffset;
- Packet->PageBuffers[0].Length -= dataOffset;
-
- Packet->IsDataPacket = true;
-
- gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device,
- Packet);
-}
-
-static int RndisFilterOnReceive(struct hv_device *Device,
- struct hv_netvsc_packet *Packet)
-{
- struct netvsc_device *netDevice = Device->Extension;
- struct rndis_device *rndisDevice;
- struct rndis_message rndisMessage;
- struct rndis_message *rndisHeader;
-
- if (!netDevice)
- return -EINVAL;
-
- /* Make sure the rndis device state is initialized */
- if (!netDevice->Extension) {
- DPRINT_ERR(NETVSC, "got rndis message but no rndis device..."
- "dropping this message!");
- return -1;
- }
-
- rndisDevice = (struct rndis_device *)netDevice->Extension;
- if (rndisDevice->State == RNDIS_DEV_UNINITIALIZED) {
- DPRINT_ERR(NETVSC, "got rndis message but rndis device "
- "uninitialized...dropping this message!");
- return -1;
- }
-
- rndisHeader = (struct rndis_message *)kmap_atomic(
- pfn_to_page(Packet->PageBuffers[0].Pfn), KM_IRQ0);
-
- rndisHeader = (void *)((unsigned long)rndisHeader +
- Packet->PageBuffers[0].Offset);
-
- /* Make sure we got a valid rndis message */
- /*
- * FIXME: There seems to be a bug in set completion msg where its
- * MessageLength is 16 bytes but the ByteCount field in the xfer page
- * range shows 52 bytes
- * */
-#if 0
- if (Packet->TotalDataBufferLength != rndisHeader->MessageLength) {
- kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset,
- KM_IRQ0);
-
- DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u "
- "bytes got %u)...dropping this message!",
- rndisHeader->MessageLength,
- Packet->TotalDataBufferLength);
- return -1;
- }
-#endif
-
- if ((rndisHeader->NdisMessageType != REMOTE_NDIS_PACKET_MSG) &&
- (rndisHeader->MessageLength > sizeof(struct rndis_message))) {
- DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow "
- "detected (got %u, max %zu)...marking it an error!",
- rndisHeader->MessageLength,
- sizeof(struct rndis_message));
- }
-
- memcpy(&rndisMessage, rndisHeader,
- (rndisHeader->MessageLength > sizeof(struct rndis_message)) ?
- sizeof(struct rndis_message) :
- rndisHeader->MessageLength);
-
- kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, KM_IRQ0);
-
- DumpRndisMessage(&rndisMessage);
-
- switch (rndisMessage.NdisMessageType) {
- case REMOTE_NDIS_PACKET_MSG:
- /* data msg */
- RndisFilterReceiveData(rndisDevice, &rndisMessage, Packet);
- break;
-
- case REMOTE_NDIS_INITIALIZE_CMPLT:
- case REMOTE_NDIS_QUERY_CMPLT:
- case REMOTE_NDIS_SET_CMPLT:
- /* case REMOTE_NDIS_RESET_CMPLT: */
- /* case REMOTE_NDIS_KEEPALIVE_CMPLT: */
- /* completion msgs */
- RndisFilterReceiveResponse(rndisDevice, &rndisMessage);
- break;
-
- case REMOTE_NDIS_INDICATE_STATUS_MSG:
- /* notification msgs */
- RndisFilterReceiveIndicateStatus(rndisDevice, &rndisMessage);
- break;
- default:
- DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)",
- rndisMessage.NdisMessageType,
- rndisMessage.MessageLength);
- break;
- }
-
- return 0;
-}
-
-static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid,
- void *Result, u32 *ResultSize)
-{
- struct rndis_request *request;
- u32 inresultSize = *ResultSize;
- struct rndis_query_request *query;
- struct rndis_query_complete *queryComplete;
- int ret = 0;
-
- if (!Result)
- return -EINVAL;
-
- *ResultSize = 0;
- request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG,
- RNDIS_MESSAGE_SIZE(struct rndis_query_request));
- if (!request) {
- ret = -1;
- goto Cleanup;
- }
-
- /* Setup the rndis query */
- query = &request->RequestMessage.Message.QueryRequest;
- query->Oid = Oid;
- query->InformationBufferOffset = sizeof(struct rndis_query_request);
- query->InformationBufferLength = 0;
- query->DeviceVcHandle = 0;
-
- ret = RndisFilterSendRequest(Device, request);
- if (ret != 0)
- goto Cleanup;
-
- osd_WaitEventWait(request->WaitEvent);
-
- /* Copy the response back */
- queryComplete = &request->ResponseMessage.Message.QueryComplete;
-
- if (queryComplete->InformationBufferLength > inresultSize) {
- ret = -1;
- goto Cleanup;
- }
-
- memcpy(Result,
- (void *)((unsigned long)queryComplete +
- queryComplete->InformationBufferOffset),
- queryComplete->InformationBufferLength);
-
- *ResultSize = queryComplete->InformationBufferLength;
-
-Cleanup:
- if (request)
- PutRndisRequest(Device, request);
-
- return ret;
-}
-
-static int RndisFilterQueryDeviceMac(struct rndis_device *Device)
-{
- u32 size = ETH_ALEN;
-
- return RndisFilterQueryDevice(Device,
- RNDIS_OID_802_3_PERMANENT_ADDRESS,
- Device->HwMacAddr, &size);
-}
-
-static int RndisFilterQueryDeviceLinkStatus(struct rndis_device *Device)
-{
- u32 size = sizeof(u32);
-
- return RndisFilterQueryDevice(Device,
- RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
- &Device->LinkStatus, &size);
-}
-
-static int RndisFilterSetPacketFilter(struct rndis_device *Device,
- u32 NewFilter)
-{
- struct rndis_request *request;
- struct rndis_set_request *set;
- struct rndis_set_complete *setComplete;
- u32 status;
- int ret;
-
- /* ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= */
- /* sizeof(struct rndis_message)); */
-
- request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG,
- RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
- sizeof(u32));
- if (!request) {
- ret = -1;
- goto Cleanup;
- }
-
- /* Setup the rndis set */
- set = &request->RequestMessage.Message.SetRequest;
- set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
- set->InformationBufferLength = sizeof(u32);
- set->InformationBufferOffset = sizeof(struct rndis_set_request);
-
- memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
- &NewFilter, sizeof(u32));
-
- ret = RndisFilterSendRequest(Device, request);
- if (ret != 0)
- goto Cleanup;
-
- ret = osd_WaitEventWaitEx(request->WaitEvent, 2000/*2sec*/);
- if (!ret) {
- ret = -1;
- DPRINT_ERR(NETVSC, "timeout before we got a set response...");
- /*
- * We cant deallocate the request since we may still receive a
- * send completion for it.
- */
- goto Exit;
- } else {
- if (ret > 0)
- ret = 0;
- setComplete = &request->ResponseMessage.Message.SetComplete;
- status = setComplete->Status;
- }
-
-Cleanup:
- if (request)
- PutRndisRequest(Device, request);
-Exit:
- return ret;
-}
-
-int RndisFilterInit(struct netvsc_driver *Driver)
-{
- DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd",
- sizeof(struct rndis_filter_packet));
-
- Driver->RequestExtSize = sizeof(struct rndis_filter_packet);
-
- /* Driver->Context = rndisDriver; */
-
- memset(&gRndisFilter, 0, sizeof(struct rndis_filter_driver_object));
-
- /*rndisDriver->Driver = Driver;
-
- ASSERT(Driver->OnLinkStatusChanged);
- rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/
-
- /* Save the original dispatch handlers before we override it */
- gRndisFilter.InnerDriver.Base.OnDeviceAdd = Driver->Base.OnDeviceAdd;
- gRndisFilter.InnerDriver.Base.OnDeviceRemove =
- Driver->Base.OnDeviceRemove;
- gRndisFilter.InnerDriver.Base.OnCleanup = Driver->Base.OnCleanup;
-
- /* ASSERT(Driver->OnSend); */
- /* ASSERT(Driver->OnReceiveCallback); */
- gRndisFilter.InnerDriver.OnSend = Driver->OnSend;
- gRndisFilter.InnerDriver.OnReceiveCallback = Driver->OnReceiveCallback;
- gRndisFilter.InnerDriver.OnLinkStatusChanged =
- Driver->OnLinkStatusChanged;
-
- /* Override */
- Driver->Base.OnDeviceAdd = RndisFilterOnDeviceAdd;
- Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove;
- Driver->Base.OnCleanup = RndisFilterOnCleanup;
- Driver->OnSend = RndisFilterOnSend;
- /* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */
- Driver->OnReceiveCallback = RndisFilterOnReceive;
-
- return 0;
-}
-
-static int RndisFilterInitDevice(struct rndis_device *Device)
-{
- struct rndis_request *request;
- struct rndis_initialize_request *init;
- struct rndis_initialize_complete *initComplete;
- u32 status;
- int ret;
-
- request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG,
- RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
- if (!request) {
- ret = -1;
- goto Cleanup;
- }
-
- /* Setup the rndis set */
- init = &request->RequestMessage.Message.InitializeRequest;
- init->MajorVersion = RNDIS_MAJOR_VERSION;
- init->MinorVersion = RNDIS_MINOR_VERSION;
- /* FIXME: Use 1536 - rounded ethernet frame size */
- init->MaxTransferSize = 2048;
-
- Device->State = RNDIS_DEV_INITIALIZING;
-
- ret = RndisFilterSendRequest(Device, request);
- if (ret != 0) {
- Device->State = RNDIS_DEV_UNINITIALIZED;
- goto Cleanup;
- }
-
- osd_WaitEventWait(request->WaitEvent);
-
- initComplete = &request->ResponseMessage.Message.InitializeComplete;
- status = initComplete->Status;
- if (status == RNDIS_STATUS_SUCCESS) {
- Device->State = RNDIS_DEV_INITIALIZED;
- ret = 0;
- } else {
- Device->State = RNDIS_DEV_UNINITIALIZED;
- ret = -1;
- }
-
-Cleanup:
- if (request)
- PutRndisRequest(Device, request);
-
- return ret;
-}
-
-static void RndisFilterHaltDevice(struct rndis_device *Device)
-{
- struct rndis_request *request;
- struct rndis_halt_request *halt;
-
- /* Attempt to do a rndis device halt */
- request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG,
- RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
- if (!request)
- goto Cleanup;
-
- /* Setup the rndis set */
- halt = &request->RequestMessage.Message.HaltRequest;
- halt->RequestId = atomic_inc_return(&Device->NewRequestId);
-
- /* Ignore return since this msg is optional. */
- RndisFilterSendRequest(Device, request);
-
- Device->State = RNDIS_DEV_UNINITIALIZED;
-
-Cleanup:
- if (request)
- PutRndisRequest(Device, request);
- return;
-}
-
-static int RndisFilterOpenDevice(struct rndis_device *Device)
-{
- int ret;
-
- if (Device->State != RNDIS_DEV_INITIALIZED)
- return 0;
-
- ret = RndisFilterSetPacketFilter(Device,
- NDIS_PACKET_TYPE_BROADCAST |
- NDIS_PACKET_TYPE_ALL_MULTICAST |
- NDIS_PACKET_TYPE_DIRECTED);
- if (ret == 0)
- Device->State = RNDIS_DEV_DATAINITIALIZED;
-
- return ret;
-}
-
-static int RndisFilterCloseDevice(struct rndis_device *Device)
-{
- int ret;
-
- if (Device->State != RNDIS_DEV_DATAINITIALIZED)
- return 0;
-
- ret = RndisFilterSetPacketFilter(Device, 0);
- if (ret == 0)
- Device->State = RNDIS_DEV_INITIALIZED;
-
- return ret;
-}
-
-static int RndisFilterOnDeviceAdd(struct hv_device *Device,
- void *AdditionalInfo)
-{
- int ret;
- struct netvsc_device *netDevice;
- struct rndis_device *rndisDevice;
- struct netvsc_device_info *deviceInfo = AdditionalInfo;
-
- rndisDevice = GetRndisDevice();
- if (!rndisDevice)
- return -1;
-
- DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice);
-
- /*
- * Let the inner driver handle this first to create the netvsc channel
- * NOTE! Once the channel is created, we may get a receive callback
- * (RndisFilterOnReceive()) before this call is completed
- */
- ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo);
- if (ret != 0) {
- kfree(rndisDevice);
- return ret;
- }
-
-
- /* Initialize the rndis device */
- netDevice = Device->Extension;
- /* ASSERT(netDevice); */
- /* ASSERT(netDevice->Device); */
-
- netDevice->Extension = rndisDevice;
- rndisDevice->NetDevice = netDevice;
-
- /* Send the rndis initialization message */
- ret = RndisFilterInitDevice(rndisDevice);
- if (ret != 0) {
- /*
- * TODO: If rndis init failed, we will need to shut down the
- * channel
- */
- }
-
- /* Get the mac address */
- ret = RndisFilterQueryDeviceMac(rndisDevice);
- if (ret != 0) {
- /*
- * TODO: shutdown rndis device and the channel
- */
- }
-
- DPRINT_INFO(NETVSC, "Device 0x%p mac addr %pM",
- rndisDevice, rndisDevice->HwMacAddr);
-
- memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, ETH_ALEN);
-
- RndisFilterQueryDeviceLinkStatus(rndisDevice);
-
- deviceInfo->LinkState = rndisDevice->LinkStatus;
- DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice,
- ((deviceInfo->LinkState) ? ("down") : ("up")));
-
- return ret;
-}
-
-static int RndisFilterOnDeviceRemove(struct hv_device *Device)
-{
- struct netvsc_device *netDevice = Device->Extension;
- struct rndis_device *rndisDevice = netDevice->Extension;
-
- /* Halt and release the rndis device */
- RndisFilterHaltDevice(rndisDevice);
-
- kfree(rndisDevice);
- netDevice->Extension = NULL;
-
- /* Pass control to inner driver to remove the device */
- gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device);
-
- return 0;
-}
-
-static void RndisFilterOnCleanup(struct hv_driver *Driver)
-{
-}
-
-int RndisFilterOnOpen(struct hv_device *Device)
-{
- struct netvsc_device *netDevice = Device->Extension;
-
- if (!netDevice)
- return -EINVAL;
-
- return RndisFilterOpenDevice(netDevice->Extension);
-}
-
-int RndisFilterOnClose(struct hv_device *Device)
-{
- struct netvsc_device *netDevice = Device->Extension;
-
- if (!netDevice)
- return -EINVAL;
-
- return RndisFilterCloseDevice(netDevice->Extension);
-}
-
-static int RndisFilterOnSend(struct hv_device *Device,
- struct hv_netvsc_packet *Packet)
-{
- 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 *)Packet->Extension;
- /* ASSERT(filterPacket); */
-
- memset(filterPacket, 0, sizeof(struct rndis_filter_packet));
-
- rndisMessage = &filterPacket->Message;
- rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet);
-
- rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG;
- rndisMessage->MessageLength = Packet->TotalDataBufferLength +
- rndisMessageSize;
-
- rndisPacket = &rndisMessage->Message.Packet;
- rndisPacket->DataOffset = sizeof(struct rndis_packet);
- rndisPacket->DataLength = Packet->TotalDataBufferLength;
-
- Packet->IsDataPacket = true;
- Packet->PageBuffers[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT;
- Packet->PageBuffers[0].Offset =
- (unsigned long)rndisMessage & (PAGE_SIZE-1);
- Packet->PageBuffers[0].Length = rndisMessageSize;
-
- /* Save the packet send completion and context */
- filterPacket->OnCompletion = Packet->Completion.Send.OnSendCompletion;
- filterPacket->CompletionContext =
- Packet->Completion.Send.SendCompletionContext;
-
- /* Use ours */
- Packet->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion;
- Packet->Completion.Send.SendCompletionContext = filterPacket;
-
- ret = gRndisFilter.InnerDriver.OnSend(Device, Packet);
- if (ret != 0) {
- /*
- * Reset the completion to originals to allow retries from
- * above
- */
- Packet->Completion.Send.OnSendCompletion =
- filterPacket->OnCompletion;
- Packet->Completion.Send.SendCompletionContext =
- filterPacket->CompletionContext;
- }
-
- return ret;
-}
-
-static void RndisFilterOnSendCompletion(void *Context)
-{
- struct rndis_filter_packet *filterPacket = Context;
-
- /* Pass it back to the original handler */
- filterPacket->OnCompletion(filterPacket->CompletionContext);
-}
-
-
-static void RndisFilterOnSendRequestCompletion(void *Context)
-{
- /* Noop */
-}
diff --git a/drivers/staging/hv/RndisFilter.h b/drivers/staging/hv/RndisFilter.h
deleted file mode 100644
index fa7dd79ddebf..000000000000
--- a/drivers/staging/hv/RndisFilter.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _RNDISFILTER_H_
-#define _RNDISFILTER_H_
-
-#define __struct_bcount(x)
-
-#include "NetVsc.h"
-
-#include "rndis.h"
-
-#define RNDIS_HEADER_SIZE (sizeof(struct rndis_message) - \
- sizeof(union rndis_message_container))
-
-#define NDIS_PACKET_TYPE_DIRECTED 0x00000001
-#define NDIS_PACKET_TYPE_MULTICAST 0x00000002
-#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004
-#define NDIS_PACKET_TYPE_BROADCAST 0x00000008
-#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010
-#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020
-#define NDIS_PACKET_TYPE_SMT 0x00000040
-#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080
-#define NDIS_PACKET_TYPE_GROUP 0x00000100
-#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200
-#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400
-#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800
-
-
-/* Interface */
-
-extern int RndisFilterInit(struct netvsc_driver *driver);
-
-#endif /* _RNDISFILTER_H_ */
diff --git a/drivers/staging/hv/StorVsc.c b/drivers/staging/hv/StorVsc.c
deleted file mode 100644
index 57bd3154eb3d..000000000000
--- a/drivers/staging/hv/StorVsc.c
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include "osd.h"
-#include "logging.h"
-#include "StorVscApi.h"
-#include "VmbusPacketFormat.h"
-#include "vstorage.h"
-
-
-struct storvsc_request_extension {
- /* LIST_ENTRY ListEntry; */
-
- struct hv_storvsc_request *Request;
- struct hv_device *Device;
-
- /* Synchronize the request/response if needed */
- struct osd_waitevent *WaitEvent;
-
- struct vstor_packet VStorPacket;
-};
-
-/* A storvsc device is a device object that contains a vmbus channel */
-struct storvsc_device {
- struct hv_device *Device;
-
- /* 0 indicates the device is being destroyed */
- atomic_t RefCount;
-
- int reset;
- spinlock_t lock;
- atomic_t NumOutstandingRequests;
-
- /*
- * 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 PortNumber;
- unsigned char PathId;
- unsigned char TargetId;
-
- /* LIST_ENTRY OutstandingRequestList; */
- /* HANDLE OutstandingRequestLock; */
-
- /* Used for vsc/vsp channel reset process */
- struct storvsc_request_extension InitRequest;
- struct storvsc_request_extension ResetRequest;
-};
-
-
-static const char *gDriverName = "storvsc";
-
-/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
-static const struct hv_guid gStorVscDeviceType = {
- .data = {
- 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
- 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
- }
-};
-
-
-static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device)
-{
- struct storvsc_device *storDevice;
-
- storDevice = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
- if (!storDevice)
- return NULL;
-
- /* Set to 2 to allow both inbound and outbound traffics */
- /* (ie GetStorDevice() and MustGetStorDevice()) to proceed. */
- atomic_cmpxchg(&storDevice->RefCount, 0, 2);
-
- storDevice->Device = Device;
- storDevice->reset = 0;
- spin_lock_init(&storDevice->lock);
-
- Device->Extension = storDevice;
-
- return storDevice;
-}
-
-static inline void FreeStorDevice(struct storvsc_device *Device)
-{
- /* ASSERT(atomic_read(&Device->RefCount) == 0); */
- /*kfree(Device->lock);*/
- kfree(Device);
-}
-
-/* Get the stordevice object iff exists and its refcount > 1 */
-static inline struct storvsc_device *GetStorDevice(struct hv_device *Device)
-{
- struct storvsc_device *storDevice;
- unsigned long flags;
-
- storDevice = (struct storvsc_device *)Device->Extension;
-
- spin_lock_irqsave(&storDevice->lock, flags);
-
- if (storDevice->reset == 1) {
- spin_unlock_irqrestore(&storDevice->lock, flags);
- return NULL;
- }
-
- if (storDevice && atomic_read(&storDevice->RefCount) > 1)
- atomic_inc(&storDevice->RefCount);
- else
- storDevice = NULL;
-
- spin_unlock_irqrestore(&storDevice->lock, flags);
-
- return storDevice;
-}
-
-/* Get the stordevice object iff exists and its refcount > 0 */
-static inline struct storvsc_device *MustGetStorDevice(struct hv_device *Device)
-{
- struct storvsc_device *storDevice;
- unsigned long flags;
-
- storDevice = (struct storvsc_device *)Device->Extension;
-
- spin_lock_irqsave(&storDevice->lock, flags);
-
- if (storDevice && atomic_read(&storDevice->RefCount))
- atomic_inc(&storDevice->RefCount);
- else
- storDevice = NULL;
-
- spin_unlock_irqrestore(&storDevice->lock, flags);
-
- return storDevice;
-}
-
-static inline void PutStorDevice(struct hv_device *Device)
-{
- struct storvsc_device *storDevice;
-
- storDevice = (struct storvsc_device *)Device->Extension;
- /* ASSERT(storDevice); */
-
- atomic_dec(&storDevice->RefCount);
- /* ASSERT(atomic_read(&storDevice->RefCount)); */
-}
-
-/* Drop ref count to 1 to effectively disable GetStorDevice() */
-static inline struct storvsc_device *ReleaseStorDevice(struct hv_device *Device)
-{
- struct storvsc_device *storDevice;
-
- storDevice = (struct storvsc_device *)Device->Extension;
- /* ASSERT(storDevice); */
-
- /* Busy wait until the ref drop to 2, then set it to 1 */
- while (atomic_cmpxchg(&storDevice->RefCount, 2, 1) != 2)
- udelay(100);
-
- return storDevice;
-}
-
-/* Drop ref count to 0. No one can use StorDevice object. */
-static inline struct storvsc_device *FinalReleaseStorDevice(
- struct hv_device *Device)
-{
- struct storvsc_device *storDevice;
-
- storDevice = (struct storvsc_device *)Device->Extension;
- /* ASSERT(storDevice); */
-
- /* Busy wait until the ref drop to 1, then set it to 0 */
- while (atomic_cmpxchg(&storDevice->RefCount, 1, 0) != 1)
- udelay(100);
-
- Device->Extension = NULL;
- return storDevice;
-}
-
-static int StorVscChannelInit(struct hv_device *Device)
-{
- struct storvsc_device *storDevice;
- struct storvsc_request_extension *request;
- struct vstor_packet *vstorPacket;
- int ret;
-
- storDevice = GetStorDevice(Device);
- if (!storDevice) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
- return -1;
- }
-
- request = &storDevice->InitRequest;
- vstorPacket = &request->VStorPacket;
-
- /*
- * Now, initiate the vsc/vsp initialization protocol on the open
- * channel
- */
- memset(request, 0, sizeof(struct storvsc_request_extension));
- request->WaitEvent = osd_WaitEventCreate();
- if (!request->WaitEvent) {
- ret = -ENOMEM;
- goto nomem;
- }
-
- vstorPacket->Operation = VStorOperationBeginInitialization;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
-
- /*SpinlockAcquire(gDriverExt.packetListLock);
- INSERT_TAIL_LIST(&gDriverExt.packetList, &packet->listEntry.entry);
- SpinlockRelease(gDriverExt.packetListLock);*/
-
- DPRINT_INFO(STORVSC, "BEGIN_INITIALIZATION_OPERATION...");
-
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(STORVSC,
- "unable to send BEGIN_INITIALIZATION_OPERATION");
- goto Cleanup;
- }
-
- osd_WaitEventWait(request->WaitEvent);
-
- if (vstorPacket->Operation != VStorOperationCompleteIo ||
- vstorPacket->Status != 0) {
- DPRINT_ERR(STORVSC, "BEGIN_INITIALIZATION_OPERATION failed "
- "(op %d status 0x%x)",
- vstorPacket->Operation, vstorPacket->Status);
- goto Cleanup;
- }
-
- DPRINT_INFO(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION...");
-
- /* reuse the packet for version range supported */
- memset(vstorPacket, 0, sizeof(struct vstor_packet));
- vstorPacket->Operation = VStorOperationQueryProtocolVersion;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
-
- vstorPacket->Version.MajorMinor = VMSTOR_PROTOCOL_VERSION_CURRENT;
- FILL_VMSTOR_REVISION(vstorPacket->Version.Revision);
-
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(STORVSC,
- "unable to send BEGIN_INITIALIZATION_OPERATION");
- goto Cleanup;
- }
-
- osd_WaitEventWait(request->WaitEvent);
-
- /* TODO: Check returned version */
- if (vstorPacket->Operation != VStorOperationCompleteIo ||
- vstorPacket->Status != 0) {
- DPRINT_ERR(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION failed "
- "(op %d status 0x%x)",
- vstorPacket->Operation, vstorPacket->Status);
- goto Cleanup;
- }
-
- /* Query channel properties */
- DPRINT_INFO(STORVSC, "QUERY_PROPERTIES_OPERATION...");
-
- memset(vstorPacket, 0, sizeof(struct vstor_packet));
- vstorPacket->Operation = VStorOperationQueryProperties;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
- vstorPacket->StorageChannelProperties.PortNumber =
- storDevice->PortNumber;
-
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
- if (ret != 0) {
- DPRINT_ERR(STORVSC,
- "unable to send QUERY_PROPERTIES_OPERATION");
- goto Cleanup;
- }
-
- osd_WaitEventWait(request->WaitEvent);
-
- /* TODO: Check returned version */
- if (vstorPacket->Operation != VStorOperationCompleteIo ||
- vstorPacket->Status != 0) {
- DPRINT_ERR(STORVSC, "QUERY_PROPERTIES_OPERATION failed "
- "(op %d status 0x%x)",
- vstorPacket->Operation, vstorPacket->Status);
- goto Cleanup;
- }
-
- storDevice->PathId = vstorPacket->StorageChannelProperties.PathId;
- storDevice->TargetId = vstorPacket->StorageChannelProperties.TargetId;
-
- DPRINT_DBG(STORVSC, "channel flag 0x%x, max xfer len 0x%x",
- vstorPacket->StorageChannelProperties.Flags,
- vstorPacket->StorageChannelProperties.MaxTransferBytes);
-
- DPRINT_INFO(STORVSC, "END_INITIALIZATION_OPERATION...");
-
- memset(vstorPacket, 0, sizeof(struct vstor_packet));
- vstorPacket->Operation = VStorOperationEndInitialization;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
-
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
- if (ret != 0) {
- DPRINT_ERR(STORVSC,
- "unable to send END_INITIALIZATION_OPERATION");
- goto Cleanup;
- }
-
- osd_WaitEventWait(request->WaitEvent);
-
- if (vstorPacket->Operation != VStorOperationCompleteIo ||
- vstorPacket->Status != 0) {
- DPRINT_ERR(STORVSC, "END_INITIALIZATION_OPERATION failed "
- "(op %d status 0x%x)",
- vstorPacket->Operation, vstorPacket->Status);
- goto Cleanup;
- }
-
- DPRINT_INFO(STORVSC, "**** storage channel up and running!! ****");
-
-Cleanup:
- kfree(request->WaitEvent);
- request->WaitEvent = NULL;
-nomem:
- PutStorDevice(Device);
- return ret;
-}
-
-static void StorVscOnIOCompletion(struct hv_device *Device,
- struct vstor_packet *VStorPacket,
- struct storvsc_request_extension *RequestExt)
-{
- struct hv_storvsc_request *request;
- struct storvsc_device *storDevice;
-
- storDevice = MustGetStorDevice(Device);
- if (!storDevice) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
- return;
- }
-
- DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION - request extension %p "
- "completed bytes xfer %u", RequestExt,
- VStorPacket->VmSrb.DataTransferLength);
-
- /* ASSERT(RequestExt != NULL); */
- /* ASSERT(RequestExt->Request != NULL); */
-
- request = RequestExt->Request;
-
- /* ASSERT(request->OnIOCompletion != NULL); */
-
- /* Copy over the status...etc */
- request->Status = VStorPacket->VmSrb.ScsiStatus;
-
- if (request->Status != 0 || VStorPacket->VmSrb.SrbStatus != 1) {
- DPRINT_WARN(STORVSC,
- "cmd 0x%x scsi status 0x%x srb status 0x%x\n",
- request->Cdb[0], VStorPacket->VmSrb.ScsiStatus,
- VStorPacket->VmSrb.SrbStatus);
- }
-
- if ((request->Status & 0xFF) == 0x02) {
- /* CHECK_CONDITION */
- if (VStorPacket->VmSrb.SrbStatus & 0x80) {
- /* autosense data available */
- DPRINT_WARN(STORVSC, "storvsc pkt %p autosense data "
- "valid - len %d\n", RequestExt,
- VStorPacket->VmSrb.SenseInfoLength);
-
- /* ASSERT(VStorPacket->VmSrb.SenseInfoLength <= */
- /* request->SenseBufferSize); */
- memcpy(request->SenseBuffer,
- VStorPacket->VmSrb.SenseData,
- VStorPacket->VmSrb.SenseInfoLength);
-
- request->SenseBufferSize =
- VStorPacket->VmSrb.SenseInfoLength;
- }
- }
-
- /* TODO: */
- request->BytesXfer = VStorPacket->VmSrb.DataTransferLength;
-
- request->OnIOCompletion(request);
-
- atomic_dec(&storDevice->NumOutstandingRequests);
-
- PutStorDevice(Device);
-}
-
-static void StorVscOnReceive(struct hv_device *Device,
- struct vstor_packet *VStorPacket,
- struct storvsc_request_extension *RequestExt)
-{
- switch (VStorPacket->Operation) {
- case VStorOperationCompleteIo:
- DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION");
- StorVscOnIOCompletion(Device, VStorPacket, RequestExt);
- break;
- case VStorOperationRemoveDevice:
- DPRINT_INFO(STORVSC, "REMOVE_DEVICE_OPERATION");
- /* TODO: */
- break;
-
- default:
- DPRINT_INFO(STORVSC, "Unknown operation received - %d",
- VStorPacket->Operation);
- break;
- }
-}
-
-static void StorVscOnChannelCallback(void *context)
-{
- struct hv_device *device = (struct hv_device *)context;
- struct storvsc_device *storDevice;
- u32 bytesRecvd;
- u64 requestId;
- unsigned char packet[ALIGN_UP(sizeof(struct vstor_packet), 8)];
- struct storvsc_request_extension *request;
- int ret;
-
- /* ASSERT(device); */
-
- storDevice = MustGetStorDevice(device);
- if (!storDevice) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
- return;
- }
-
- do {
- ret = device->Driver->VmbusChannelInterface.RecvPacket(device,
- packet,
- ALIGN_UP(sizeof(struct vstor_packet), 8),
- &bytesRecvd, &requestId);
- if (ret == 0 && bytesRecvd > 0) {
- DPRINT_DBG(STORVSC, "receive %d bytes - tid %llx",
- bytesRecvd, requestId);
-
- /* ASSERT(bytesRecvd == sizeof(struct vstor_packet)); */
-
- request = (struct storvsc_request_extension *)
- (unsigned long)requestId;
- /* ASSERT(request);c */
-
- /* if (vstorPacket.Flags & SYNTHETIC_FLAG) */
- if ((request == &storDevice->InitRequest) ||
- (request == &storDevice->ResetRequest)) {
- /* DPRINT_INFO(STORVSC,
- * "reset completion - operation "
- * "%u status %u",
- * vstorPacket.Operation,
- * vstorPacket.Status); */
-
- memcpy(&request->VStorPacket, packet,
- sizeof(struct vstor_packet));
-
- osd_WaitEventSet(request->WaitEvent);
- } else {
- StorVscOnReceive(device,
- (struct vstor_packet *)packet,
- request);
- }
- } else {
- /* DPRINT_DBG(STORVSC, "nothing else to read..."); */
- break;
- }
- } while (1);
-
- PutStorDevice(device);
- return;
-}
-
-static int StorVscConnectToVsp(struct hv_device *Device)
-{
- struct vmstorage_channel_properties props;
- struct storvsc_driver_object *storDriver;
- int ret;
-
- storDriver = (struct storvsc_driver_object *)Device->Driver;
- memset(&props, 0, sizeof(struct vmstorage_channel_properties));
-
- /* Open the channel */
- ret = Device->Driver->VmbusChannelInterface.Open(Device,
- storDriver->RingBufferSize,
- storDriver->RingBufferSize,
- (void *)&props,
- sizeof(struct vmstorage_channel_properties),
- StorVscOnChannelCallback,
- Device);
-
- DPRINT_DBG(STORVSC, "storage props: path id %d, tgt id %d, max xfer %d",
- props.PathId, props.TargetId, props.MaxTransferBytes);
-
- if (ret != 0) {
- DPRINT_ERR(STORVSC, "unable to open channel: %d", ret);
- return -1;
- }
-
- ret = StorVscChannelInit(Device);
-
- return ret;
-}
-
-/*
- * StorVscOnDeviceAdd - Callback when the device belonging to this driver is added
- */
-static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
-{
- struct storvsc_device *storDevice;
- /* struct vmstorage_channel_properties *props; */
- struct storvsc_device_info *deviceInfo;
- int ret = 0;
-
- deviceInfo = (struct storvsc_device_info *)AdditionalInfo;
- storDevice = AllocStorDevice(Device);
- if (!storDevice) {
- ret = -1;
- goto Cleanup;
- }
-
- /* Save the channel properties to our storvsc channel */
- /* props = (struct vmstorage_channel_properties *)
- * channel->offerMsg.Offer.u.Standard.UserDefined; */
-
- /* FIXME: */
- /*
- * If we support more than 1 scsi channel, we need to set the
- * port number here to the scsi channel but how do we get the
- * scsi channel prior to the bus scan
- */
-
- /* storChannel->PortNumber = 0;
- storChannel->PathId = props->PathId;
- storChannel->TargetId = props->TargetId; */
-
- storDevice->PortNumber = deviceInfo->PortNumber;
- /* Send it back up */
- ret = StorVscConnectToVsp(Device);
-
- /* deviceInfo->PortNumber = storDevice->PortNumber; */
- deviceInfo->PathId = storDevice->PathId;
- deviceInfo->TargetId = storDevice->TargetId;
-
- DPRINT_DBG(STORVSC, "assigned port %u, path %u target %u\n",
- storDevice->PortNumber, storDevice->PathId,
- storDevice->TargetId);
-
-Cleanup:
- return ret;
-}
-
-/*
- * StorVscOnDeviceRemove - Callback when the our device is being removed
- */
-static int StorVscOnDeviceRemove(struct hv_device *Device)
-{
- struct storvsc_device *storDevice;
-
- DPRINT_INFO(STORVSC, "disabling storage device (%p)...",
- Device->Extension);
-
- storDevice = ReleaseStorDevice(Device);
-
- /*
- * At this point, all outbound traffic should be disable. We
- * only allow inbound traffic (responses) to proceed so that
- * outstanding requests can be completed.
- */
- while (atomic_read(&storDevice->NumOutstandingRequests)) {
- DPRINT_INFO(STORVSC, "waiting for %d requests to complete...",
- atomic_read(&storDevice->NumOutstandingRequests));
- udelay(100);
- }
-
- DPRINT_INFO(STORVSC, "removing storage device (%p)...",
- Device->Extension);
-
- storDevice = FinalReleaseStorDevice(Device);
-
- DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", storDevice);
-
- /* Close the channel */
- Device->Driver->VmbusChannelInterface.Close(Device);
-
- FreeStorDevice(storDevice);
- return 0;
-}
-
-int StorVscOnHostReset(struct hv_device *Device)
-{
- struct storvsc_device *storDevice;
- struct storvsc_request_extension *request;
- struct vstor_packet *vstorPacket;
- unsigned long flags;
- int ret;
-
- DPRINT_INFO(STORVSC, "resetting host adapter...");
-
- storDevice = GetStorDevice(Device);
- if (!storDevice) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
- return -1;
- }
-
- spin_lock_irqsave(&storDevice->lock, flags);
- storDevice->reset = 1;
- spin_unlock_irqrestore(&storDevice->lock, flags);
-
- /*
- * Wait for traffic in transit to complete
- */
- while (atomic_read(&storDevice->NumOutstandingRequests))
- udelay(1000);
-
- request = &storDevice->ResetRequest;
- vstorPacket = &request->VStorPacket;
-
- request->WaitEvent = osd_WaitEventCreate();
- if (!request->WaitEvent) {
- ret = -ENOMEM;
- goto Cleanup;
- }
-
- vstorPacket->Operation = VStorOperationResetBus;
- vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
- vstorPacket->VmSrb.PathId = storDevice->PathId;
-
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)&storDevice->ResetRequest,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
- DPRINT_ERR(STORVSC, "Unable to send reset packet %p ret %d",
- vstorPacket, ret);
- goto Cleanup;
- }
-
- /* FIXME: Add a timeout */
- osd_WaitEventWait(request->WaitEvent);
-
- kfree(request->WaitEvent);
- DPRINT_INFO(STORVSC, "host adapter reset completed");
-
- /*
- * At this point, all outstanding requests in the adapter
- * should have been flushed out and return to us
- */
-
-Cleanup:
- PutStorDevice(Device);
- return ret;
-}
-
-/*
- * StorVscOnIORequest - Callback to initiate an I/O request
- */
-static int StorVscOnIORequest(struct hv_device *Device,
- struct hv_storvsc_request *Request)
-{
- struct storvsc_device *storDevice;
- struct storvsc_request_extension *requestExtension;
- struct vstor_packet *vstorPacket;
- int ret = 0;
-
- requestExtension =
- (struct storvsc_request_extension *)Request->Extension;
- vstorPacket = &requestExtension->VStorPacket;
- storDevice = GetStorDevice(Device);
-
- DPRINT_DBG(STORVSC, "enter - Device %p, DeviceExt %p, Request %p, "
- "Extension %p", Device, storDevice, Request,
- requestExtension);
-
- DPRINT_DBG(STORVSC, "req %p len %d bus %d, target %d, lun %d cdblen %d",
- Request, Request->DataBuffer.Length, Request->Bus,
- Request->TargetId, Request->LunId, Request->CdbLen);
-
- if (!storDevice) {
- DPRINT_ERR(STORVSC, "unable to get stor device..."
- "device being destroyed?");
- return -2;
- }
-
- /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, Request->Cdb,
- * Request->CdbLen); */
-
- requestExtension->Request = Request;
- requestExtension->Device = Device;
-
- memset(vstorPacket, 0 , sizeof(struct vstor_packet));
-
- vstorPacket->Flags |= REQUEST_COMPLETION_FLAG;
-
- vstorPacket->VmSrb.Length = sizeof(struct vmscsi_request);
-
- vstorPacket->VmSrb.PortNumber = Request->Host;
- vstorPacket->VmSrb.PathId = Request->Bus;
- vstorPacket->VmSrb.TargetId = Request->TargetId;
- vstorPacket->VmSrb.Lun = Request->LunId;
-
- vstorPacket->VmSrb.SenseInfoLength = SENSE_BUFFER_SIZE;
-
- /* Copy over the scsi command descriptor block */
- vstorPacket->VmSrb.CdbLength = Request->CdbLen;
- memcpy(&vstorPacket->VmSrb.Cdb, Request->Cdb, Request->CdbLen);
-
- vstorPacket->VmSrb.DataIn = Request->Type;
- vstorPacket->VmSrb.DataTransferLength = Request->DataBuffer.Length;
-
- vstorPacket->Operation = VStorOperationExecuteSRB;
-
- DPRINT_DBG(STORVSC, "srb - len %d port %d, path %d, target %d, "
- "lun %d senselen %d cdblen %d",
- vstorPacket->VmSrb.Length,
- vstorPacket->VmSrb.PortNumber,
- vstorPacket->VmSrb.PathId,
- vstorPacket->VmSrb.TargetId,
- vstorPacket->VmSrb.Lun,
- vstorPacket->VmSrb.SenseInfoLength,
- vstorPacket->VmSrb.CdbLength);
-
- if (requestExtension->Request->DataBuffer.Length) {
- ret = Device->Driver->VmbusChannelInterface.
- SendPacketMultiPageBuffer(Device,
- &requestExtension->Request->DataBuffer,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)requestExtension);
- } else {
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)requestExtension,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- }
-
- if (ret != 0) {
- DPRINT_DBG(STORVSC, "Unable to send packet %p ret %d",
- vstorPacket, ret);
- }
-
- atomic_inc(&storDevice->NumOutstandingRequests);
-
- PutStorDevice(Device);
- return ret;
-}
-
-/*
- * StorVscOnCleanup - Perform any cleanup when the driver is removed
- */
-static void StorVscOnCleanup(struct hv_driver *Driver)
-{
-}
-
-/*
- * StorVscInitialize - Main entry point
- */
-int StorVscInitialize(struct hv_driver *Driver)
-{
- struct storvsc_driver_object *storDriver;
-
- storDriver = (struct storvsc_driver_object *)Driver;
-
- DPRINT_DBG(STORVSC, "sizeof(STORVSC_REQUEST)=%zd "
- "sizeof(struct storvsc_request_extension)=%zd "
- "sizeof(struct vstor_packet)=%zd, "
- "sizeof(struct vmscsi_request)=%zd",
- sizeof(struct hv_storvsc_request),
- sizeof(struct storvsc_request_extension),
- sizeof(struct vstor_packet),
- sizeof(struct vmscsi_request));
-
- /* Make sure we are at least 2 pages since 1 page is used for control */
- /* ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); */
-
- Driver->name = gDriverName;
- memcpy(&Driver->deviceType, &gStorVscDeviceType,
- sizeof(struct hv_guid));
-
- storDriver->RequestExtSize = sizeof(struct storvsc_request_extension);
-
- /*
- * Divide the ring buffer data size (which is 1 page less
- * than the ring buffer size since that page is reserved for
- * the ring buffer indices) by the max request size (which is
- * VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER + struct vstor_packet + u64)
- */
- storDriver->MaxOutstandingRequestsPerChannel =
- ((storDriver->RingBufferSize - PAGE_SIZE) /
- ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET +
- sizeof(struct vstor_packet) + sizeof(u64),
- sizeof(u64)));
-
- DPRINT_INFO(STORVSC, "max io %u, currently %u\n",
- storDriver->MaxOutstandingRequestsPerChannel,
- STORVSC_MAX_IO_REQUESTS);
-
- /* Setup the dispatch table */
- storDriver->Base.OnDeviceAdd = StorVscOnDeviceAdd;
- storDriver->Base.OnDeviceRemove = StorVscOnDeviceRemove;
- storDriver->Base.OnCleanup = StorVscOnCleanup;
-
- storDriver->OnIORequest = StorVscOnIORequest;
-
- return 0;
-}
diff --git a/drivers/staging/hv/StorVscApi.h b/drivers/staging/hv/StorVscApi.h
deleted file mode 100644
index aad90bdc0448..000000000000
--- a/drivers/staging/hv/StorVscApi.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _STORVSC_API_H_
-#define _STORVSC_API_H_
-
-#include "VmbusApi.h"
-
-/* Defines */
-#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
-#define BLKVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
-
-#define STORVSC_MAX_IO_REQUESTS 128
-
-/*
- * In Hyper-V, each port/path/target maps to 1 scsi host adapter. In
- * reality, the path/target is not used (ie always set to 0) so our
- * scsi host adapter essentially has 1 bus with 1 target that contains
- * up to 256 luns.
- */
-#define STORVSC_MAX_LUNS_PER_TARGET 64
-#define STORVSC_MAX_TARGETS 1
-#define STORVSC_MAX_CHANNELS 1
-
-struct hv_storvsc_request;
-
-/* Matches Windows-end */
-enum storvsc_request_type{
- WRITE_TYPE,
- READ_TYPE,
- UNKNOWN_TYPE,
-};
-
-struct hv_storvsc_request {
- enum storvsc_request_type Type;
- u32 Host;
- u32 Bus;
- u32 TargetId;
- u32 LunId;
- u8 *Cdb;
- u32 CdbLen;
- u32 Status;
- u32 BytesXfer;
-
- unsigned char *SenseBuffer;
- u32 SenseBufferSize;
-
- void *Context;
-
- void (*OnIOCompletion)(struct hv_storvsc_request *Request);
-
- /* This points to the memory after DataBuffer */
- void *Extension;
-
- struct hv_multipage_buffer DataBuffer;
-};
-
-/* Represents the block vsc driver */
-struct storvsc_driver_object {
- /* Must be the first field */
- /* Which is a bug FIXME! */
- struct hv_driver Base;
-
- /* Set by caller (in bytes) */
- u32 RingBufferSize;
-
- /* Allocate this much private extension for each I/O request */
- u32 RequestExtSize;
-
- /* Maximum # of requests in flight per channel/device */
- u32 MaxOutstandingRequestsPerChannel;
-
- /* Specific to this driver */
- int (*OnIORequest)(struct hv_device *Device,
- struct hv_storvsc_request *Request);
-};
-
-struct storvsc_device_info {
- unsigned int PortNumber;
- unsigned char PathId;
- unsigned char TargetId;
-};
-
-/* Interface */
-int StorVscInitialize(struct hv_driver *driver);
-int StorVscOnHostReset(struct hv_device *Device);
-int BlkVscInitialize(struct hv_driver *driver);
-
-#endif /* _STORVSC_API_H_ */
diff --git a/drivers/staging/hv/TODO b/drivers/staging/hv/TODO
index dbfbde937a66..582fd4ab3f1e 100644
--- a/drivers/staging/hv/TODO
+++ b/drivers/staging/hv/TODO
@@ -1,15 +1,10 @@
TODO:
- fix remaining checkpatch warnings and errors
- - use of /** when it is not a kerneldoc header
- - remove RingBuffer.c to us in-kernel ringbuffer functions instead.
- audit the vmbus to verify it is working properly with the
driver model
- - convert vmbus driver interface function pointer tables
- to constant, a.k.a vmbus_ops
- see if the vmbus can be merged with the other virtual busses
in the kernel
- audit the network driver
- - use existing net_device_stats struct in network device
- checking for carrier inside open is wrong, network device API
confusion??
- audit the block driver
diff --git a/drivers/staging/hv/VersionInfo.h b/drivers/staging/hv/VersionInfo.h
deleted file mode 100644
index 35178f2c7967..000000000000
--- a/drivers/staging/hv/VersionInfo.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-#ifndef __HV_VERSION_INFO
-#define __HV_VERSION_INFO
-
-/*
- * We use the same version numbering for all Hyper-V modules.
- *
- * Definition of versioning is as follows;
- *
- * Major Number Changes for these scenarios;
- * 1. When a new version of Windows Hyper-V
- * is released.
- * 2. A Major change has occurred in the
- * Linux IC's.
- * (For example the merge for the first time
- * into the kernel) Every time the Major Number
- * changes, the Revision number is reset to 0.
- * Minor Number Changes when new functionality is added
- * to the Linux IC's that is not a bug fix.
- *
- * 3.1 - Added completed hv_utils driver. Shutdown/Heartbeat/Timesync
- */
-#define HV_DRV_VERSION "3.1"
-
-
-#endif
diff --git a/drivers/staging/hv/Vmbus.c b/drivers/staging/hv/Vmbus.c
deleted file mode 100644
index a9b031c4dd53..000000000000
--- a/drivers/staging/hv/Vmbus.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include "osd.h"
-#include "logging.h"
-#include "VersionInfo.h"
-#include "VmbusPrivate.h"
-
-static const char *gDriverName = "vmbus";
-
-/*
- * Windows vmbus does not defined this.
- * We defined this to be consistent with other devices
- */
-/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */
-static const struct hv_guid gVmbusDeviceType = {
- .data = {
- 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d,
- 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85
- }
-};
-
-/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */
-static const struct hv_guid gVmbusDeviceId = {
- .data = {
- 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40,
- 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5
- }
-};
-
-static struct hv_driver *gDriver; /* vmbus driver object */
-static struct hv_device *gDevice; /* vmbus root device */
-
-/*
- * VmbusGetChannelOffers - Retrieve the channel offers from the parent partition
- */
-static void VmbusGetChannelOffers(void)
-{
- VmbusChannelRequestOffers();
-}
-
-/*
- * VmbusGetChannelInterface - Get the channel interface
- */
-static void VmbusGetChannelInterface(struct vmbus_channel_interface *Interface)
-{
- GetChannelInterface(Interface);
-}
-
-/*
- * VmbusGetChannelInfo - Get the device info for the specified device object
- */
-static void VmbusGetChannelInfo(struct hv_device *DeviceObject,
- struct hv_device_info *DeviceInfo)
-{
- GetChannelInfo(DeviceObject, DeviceInfo);
-}
-
-/*
- * VmbusCreateChildDevice - Creates the child device on the bus that represents the channel offer
- */
-struct hv_device *VmbusChildDeviceCreate(struct hv_guid *DeviceType,
- struct hv_guid *DeviceInstance,
- void *Context)
-{
- struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
-
- return vmbusDriver->OnChildDeviceCreate(DeviceType, DeviceInstance,
- Context);
-}
-
-/*
- * VmbusChildDeviceAdd - Registers the child device with the vmbus
- */
-int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
-{
- struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
-
- return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
-}
-
-/*
- * VmbusChildDeviceRemove Unregisters the child device from the vmbus
- */
-void VmbusChildDeviceRemove(struct hv_device *ChildDevice)
-{
- struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
-
- vmbusDriver->OnChildDeviceRemove(ChildDevice);
-}
-
-/*
- * VmbusOnDeviceAdd - Callback when the root bus device is added
- */
-static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
-{
- u32 *irqvector = AdditionalInfo;
- int ret;
-
- gDevice = dev;
-
- memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
- memcpy(&gDevice->deviceInstance, &gVmbusDeviceId,
- sizeof(struct hv_guid));
-
- /* strcpy(dev->name, "vmbus"); */
- /* SynIC setup... */
- on_each_cpu(HvSynicInit, (void *)irqvector, 1);
-
- /* Connect to VMBus in the root partition */
- ret = VmbusConnect();
-
- /* VmbusSendEvent(device->localPortId+1); */
- return ret;
-}
-
-/*
- * VmbusOnDeviceRemove - Callback when the root bus device is removed
- */
-static int VmbusOnDeviceRemove(struct hv_device *dev)
-{
- int ret = 0;
-
- VmbusChannelReleaseUnattachedChannels();
- VmbusDisconnect();
- on_each_cpu(HvSynicCleanup, NULL, 1);
- return ret;
-}
-
-/*
- * VmbusOnCleanup - Perform any cleanup when the driver is removed
- */
-static void VmbusOnCleanup(struct hv_driver *drv)
-{
- /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */
-
- HvCleanup();
-}
-
-/*
- * VmbusOnMsgDPC - DPC routine to handle messages from the hypervisior
- */
-static void VmbusOnMsgDPC(struct hv_driver *drv)
-{
- int cpu = smp_processor_id();
- void *page_addr = gHvContext.synICMessagePage[cpu];
- struct hv_message *msg = (struct hv_message *)page_addr +
- VMBUS_MESSAGE_SINT;
- struct hv_message *copied;
-
- while (1) {
- if (msg->Header.MessageType == HvMessageTypeNone) {
- /* no msg */
- break;
- } else {
- copied = kmemdup(msg, sizeof(*copied), GFP_ATOMIC);
- if (copied == NULL)
- continue;
-
- osd_schedule_callback(gVmbusConnection.WorkQueue,
- VmbusOnChannelMessage,
- (void *)copied);
- }
-
- msg->Header.MessageType = HvMessageTypeNone;
-
- /*
- * Make sure the write to MessageType (ie set to
- * HvMessageTypeNone) happens before we read the
- * MessagePending and EOMing. Otherwise, the EOMing
- * will not deliver any more messages since there is
- * no empty slot
- */
- mb();
-
- if (msg->Header.MessageFlags.MessagePending) {
- /*
- * This will cause message queue rescan to
- * possibly deliver another msg from the
- * hypervisor
- */
- wrmsrl(HV_X64_MSR_EOM, 0);
- }
- }
-}
-
-/*
- * VmbusOnEventDPC - DPC routine to handle events from the hypervisior
- */
-static void VmbusOnEventDPC(struct hv_driver *drv)
-{
- /* TODO: Process any events */
- VmbusOnEvents();
-}
-
-/*
- * VmbusOnISR - ISR routine
- */
-static int VmbusOnISR(struct hv_driver *drv)
-{
- int ret = 0;
- int cpu = smp_processor_id();
- void *page_addr;
- struct hv_message *msg;
- union hv_synic_event_flags *event;
-
- page_addr = gHvContext.synICMessagePage[cpu];
- msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
-
- /* Check if there are actual msgs to be process */
- if (msg->Header.MessageType != HvMessageTypeNone) {
- DPRINT_DBG(VMBUS, "received msg type %d size %d",
- msg->Header.MessageType,
- msg->Header.PayloadSize);
- ret |= 0x1;
- }
-
- /* TODO: Check if there are events to be process */
- page_addr = gHvContext.synICEventPage[cpu];
- event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
-
- /* Since we are a child, we only need to check bit 0 */
- if (sync_test_and_clear_bit(0, (unsigned long *) &event->Flags32[0])) {
- DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
- ret |= 0x2;
- }
-
- return ret;
-}
-
-/*
- * VmbusInitialize - Main entry point
- */
-int VmbusInitialize(struct hv_driver *drv)
-{
- struct vmbus_driver *driver = (struct vmbus_driver *)drv;
- int ret;
-
- DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++",
- HV_DRV_VERSION);
- DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++",
- VMBUS_REVISION_NUMBER);
- DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++",
- VMBUS_MESSAGE_SINT);
- DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%zd, "
- "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
- sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER),
- sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
-
- drv->name = gDriverName;
- memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
-
- /* Setup dispatch table */
- driver->Base.OnDeviceAdd = VmbusOnDeviceAdd;
- driver->Base.OnDeviceRemove = VmbusOnDeviceRemove;
- driver->Base.OnCleanup = VmbusOnCleanup;
- driver->OnIsr = VmbusOnISR;
- driver->OnMsgDpc = VmbusOnMsgDPC;
- driver->OnEventDpc = VmbusOnEventDPC;
- driver->GetChannelOffers = VmbusGetChannelOffers;
- driver->GetChannelInterface = VmbusGetChannelInterface;
- driver->GetChannelInfo = VmbusGetChannelInfo;
-
- /* Hypervisor initialization...setup hypercall page..etc */
- ret = HvInit();
- if (ret != 0)
- DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x",
- ret);
- gDriver = drv;
-
- return ret;
-}
diff --git a/drivers/staging/hv/VmbusApi.h b/drivers/staging/hv/VmbusApi.h
deleted file mode 100644
index 4275be3292ce..000000000000
--- a/drivers/staging/hv/VmbusApi.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _VMBUS_API_H_
-#define _VMBUS_API_H_
-
-#define MAX_PAGE_BUFFER_COUNT 16
-#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
-
-#pragma pack(push, 1)
-
-/* Single-page buffer */
-struct hv_page_buffer {
- u32 Length;
- u32 Offset;
- u64 Pfn;
-};
-
-/* Multiple-page buffer */
-struct hv_multipage_buffer {
- /* Length and Offset determines the # of pfns in the array */
- u32 Length;
- u32 Offset;
- u64 PfnArray[MAX_MULTIPAGE_BUFFER_COUNT];
-};
-
-/* 0x18 includes the proprietary packet header */
-#define MAX_PAGE_BUFFER_PACKET (0x18 + \
- (sizeof(struct hv_page_buffer) * \
- MAX_PAGE_BUFFER_COUNT))
-#define MAX_MULTIPAGE_BUFFER_PACKET (0x18 + \
- sizeof(struct hv_multipage_buffer))
-
-
-#pragma pack(pop)
-
-struct hv_driver;
-struct hv_device;
-
-struct hv_dev_port_info {
- u32 InterruptMask;
- u32 ReadIndex;
- u32 WriteIndex;
- u32 BytesAvailToRead;
- u32 BytesAvailToWrite;
-};
-
-struct hv_device_info {
- u32 ChannelId;
- u32 ChannelState;
- struct hv_guid ChannelType;
- struct hv_guid ChannelInstance;
-
- u32 MonitorId;
- u32 ServerMonitorPending;
- u32 ServerMonitorLatency;
- u32 ServerMonitorConnectionId;
- u32 ClientMonitorPending;
- u32 ClientMonitorLatency;
- u32 ClientMonitorConnectionId;
-
- struct hv_dev_port_info Inbound;
- struct hv_dev_port_info Outbound;
-};
-
-/**
- * struct vmbus_channel_interface - Contains member functions for vmbus channel
- * @Open: Open the channel
- * @Close: Close the channel
- * @SendPacket: Send a packet over the channel
- * @SendPacketPageBuffer: Send a single page buffer over the channel
- * @SendPacketMultiPageBuffer: Send a multiple page buffers
- * @RecvPacket: Receive packet
- * @RecvPacketRaw: Receive Raw packet
- * @EstablishGpadl: Set up GPADL for ringbuffer
- * @TeardownGpadl: Teardown GPADL for ringbuffer
- * @GetInfo: Get info about the channel
- *
- * This structure contains function pointer to control vmbus channel
- * behavior. None of these functions is externally callable, but they
- * are used for normal vmbus channel internal behavior.
- * Only used by Hyper-V drivers.
- */
-struct vmbus_channel_interface {
- int (*Open)(struct hv_device *Device, u32 SendBufferSize,
- u32 RecvRingBufferSize, void *UserData, u32 UserDataLen,
- void (*ChannelCallback)(void *context),
- void *Context);
- void (*Close)(struct hv_device *device);
- int (*SendPacket)(struct hv_device *Device, const void *Buffer,
- u32 BufferLen, u64 RequestId, u32 Type, u32 Flags);
- int (*SendPacketPageBuffer)(struct hv_device *dev,
- struct hv_page_buffer PageBuffers[],
- u32 PageCount, void *Buffer, u32 BufferLen,
- u64 RequestId);
- int (*SendPacketMultiPageBuffer)(struct hv_device *device,
- struct hv_multipage_buffer *mpb,
- void *Buffer,
- u32 BufferLen,
- u64 RequestId);
- int (*RecvPacket)(struct hv_device *dev, void *buf, u32 buflen,
- u32 *BufferActualLen, u64 *RequestId);
- int (*RecvPacketRaw)(struct hv_device *dev, void *buf, u32 buflen,
- u32 *BufferActualLen, u64 *RequestId);
- int (*EstablishGpadl)(struct hv_device *dev, void *buf, u32 buflen,
- u32 *GpadlHandle);
- int (*TeardownGpadl)(struct hv_device *device, u32 GpadlHandle);
- void (*GetInfo)(struct hv_device *dev, struct hv_device_info *devinfo);
-};
-
-/* Base driver object */
-struct hv_driver {
- const char *name;
-
- /* the device type supported by this driver */
- struct hv_guid deviceType;
-
- int (*OnDeviceAdd)(struct hv_device *device, void *data);
- int (*OnDeviceRemove)(struct hv_device *device);
- void (*OnCleanup)(struct hv_driver *driver);
-
- struct vmbus_channel_interface VmbusChannelInterface;
-};
-
-/* Base device object */
-struct hv_device {
- /* the driver for this device */
- struct hv_driver *Driver;
-
- char name[64];
-
- /* the device type id of this device */
- struct hv_guid deviceType;
-
- /* the device instance id of this device */
- struct hv_guid deviceInstance;
-
- void *context;
-
- /* Device extension; */
- void *Extension;
-};
-
-/* Vmbus driver object */
-struct vmbus_driver {
- /* !! Must be the 1st field !! */
- /* FIXME if ^, then someone is doing somthing stupid */
- struct hv_driver Base;
-
- /* Set by the caller */
- struct hv_device * (*OnChildDeviceCreate)(struct hv_guid *DeviceType,
- struct hv_guid *DeviceInstance,
- void *Context);
- void (*OnChildDeviceDestroy)(struct hv_device *device);
- int (*OnChildDeviceAdd)(struct hv_device *RootDevice,
- struct hv_device *ChildDevice);
- void (*OnChildDeviceRemove)(struct hv_device *device);
-
- /* Set by the callee */
- int (*OnIsr)(struct hv_driver *driver);
- void (*OnMsgDpc)(struct hv_driver *driver);
- void (*OnEventDpc)(struct hv_driver *driver);
- void (*GetChannelOffers)(void);
-
- void (*GetChannelInterface)(struct vmbus_channel_interface *i);
- void (*GetChannelInfo)(struct hv_device *dev,
- struct hv_device_info *devinfo);
-};
-
-int VmbusInitialize(struct hv_driver *drv);
-
-#endif /* _VMBUS_API_H_ */
diff --git a/drivers/staging/hv/VmbusChannelInterface.h b/drivers/staging/hv/VmbusChannelInterface.h
deleted file mode 100644
index 26742823748d..000000000000
--- a/drivers/staging/hv/VmbusChannelInterface.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-#ifndef __VMBUSCHANNELINTERFACE_H
-#define __VMBUSCHANNELINTERFACE_H
-
-/*
- * A revision number of vmbus that is used for ensuring both ends on a
- * partition are using compatible versions.
- */
-#define VMBUS_REVISION_NUMBER 13
-
-/* Make maximum size of pipe payload of 16K */
-#define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)
-
-/* Define PipeMode values. */
-#define VMBUS_PIPE_TYPE_BYTE 0x00000000
-#define VMBUS_PIPE_TYPE_MESSAGE 0x00000004
-
-/* The size of the user defined data buffer for non-pipe offers. */
-#define MAX_USER_DEFINED_BYTES 120
-
-/* The size of the user defined data buffer for pipe offers. */
-#define MAX_PIPE_USER_DEFINED_BYTES 116
-
-/*
- * At the center of the Channel Management library is the Channel Offer. This
- * struct contains the fundamental information about an offer.
- */
-struct vmbus_channel_offer {
- struct hv_guid InterfaceType;
- struct hv_guid InterfaceInstance;
- u64 InterruptLatencyIn100nsUnits;
- u32 InterfaceRevision;
- u32 ServerContextAreaSize; /* in bytes */
- u16 ChannelFlags;
- u16 MmioMegabytes; /* in bytes * 1024 * 1024 */
-
- union {
- /* Non-pipes: The user has MAX_USER_DEFINED_BYTES bytes. */
- struct {
- unsigned char UserDefined[MAX_USER_DEFINED_BYTES];
- } Standard;
-
- /*
- * Pipes:
- * The following sructure is an integrated pipe protocol, which
- * is implemented on top of standard user-defined data. Pipe
- * clients have MAX_PIPE_USER_DEFINED_BYTES left for their own
- * use.
- */
- struct {
- u32 PipeMode;
- unsigned char UserDefined[MAX_PIPE_USER_DEFINED_BYTES];
- } Pipe;
- } u;
- u32 Padding;
-} __attribute__((packed));
-
-/* Server Flags */
-#define VMBUS_CHANNEL_ENUMERATE_DEVICE_INTERFACE 1
-#define VMBUS_CHANNEL_SERVER_SUPPORTS_TRANSFER_PAGES 2
-#define VMBUS_CHANNEL_SERVER_SUPPORTS_GPADLS 4
-#define VMBUS_CHANNEL_NAMED_PIPE_MODE 0x10
-#define VMBUS_CHANNEL_LOOPBACK_OFFER 0x100
-#define VMBUS_CHANNEL_PARENT_OFFER 0x200
-#define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION 0x400
-
-#endif
diff --git a/drivers/staging/hv/VmbusPacketFormat.h b/drivers/staging/hv/VmbusPacketFormat.h
deleted file mode 100644
index f9f6b4bf6fb1..000000000000
--- a/drivers/staging/hv/VmbusPacketFormat.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-#ifndef _VMBUSPACKETFORMAT_H_
-#define _VMBUSPACKETFORMAT_H_
-
-struct vmpacket_descriptor {
- u16 Type;
- u16 DataOffset8;
- u16 Length8;
- u16 Flags;
- u64 TransactionId;
-} __attribute__((packed));
-
-struct vmpacket_header {
- u32 PreviousPacketStartOffset;
- struct vmpacket_descriptor Descriptor;
-} __attribute__((packed));
-
-struct vmtransfer_page_range {
- u32 ByteCount;
- u32 ByteOffset;
-} __attribute__((packed));
-
-struct vmtransfer_page_packet_header {
- struct vmpacket_descriptor d;
- u16 TransferPageSetId;
- bool SenderOwnsSet;
- u8 Reserved;
- u32 RangeCount;
- struct vmtransfer_page_range Ranges[1];
-} __attribute__((packed));
-
-struct vmgpadl_packet_header {
- struct vmpacket_descriptor d;
- u32 Gpadl;
- u32 Reserved;
-} __attribute__((packed));
-
-struct vmadd_remove_transfer_page_set {
- struct vmpacket_descriptor d;
- u32 Gpadl;
- u16 TransferPageSetId;
- u16 Reserved;
-} __attribute__((packed));
-
-/*
- * This structure defines a range in guest physical space that can be made to
- * look virtually contiguous.
- */
-struct gpa_range {
- u32 ByteCount;
- u32 ByteOffset;
- u64 PfnArray[0];
-};
-
-/*
- * This is the format for an Establish Gpadl packet, which contains a handle by
- * which this GPADL will be known and a set of GPA ranges associated with it.
- * This can be converted to a MDL by the guest OS. If there are multiple GPA
- * ranges, then the resulting MDL will be "chained," representing multiple VA
- * ranges.
- */
-struct vmestablish_gpadl {
- struct vmpacket_descriptor d;
- u32 Gpadl;
- u32 RangeCount;
- struct gpa_range Range[1];
-} __attribute__((packed));
-
-/*
- * This is the format for a Teardown Gpadl packet, which indicates that the
- * GPADL handle in the Establish Gpadl packet will never be referenced again.
- */
-struct vmteardown_gpadl {
- struct vmpacket_descriptor d;
- u32 Gpadl;
- u32 Reserved; /* for alignment to a 8-byte boundary */
-} __attribute__((packed));
-
-/*
- * This is the format for a GPA-Direct packet, which contains a set of GPA
- * ranges, in addition to commands and/or data.
- */
-struct vmdata_gpa_direct {
- struct vmpacket_descriptor d;
- u32 Reserved;
- u32 RangeCount;
- struct gpa_range Range[1];
-} __attribute__((packed));
-
-/* This is the format for a Additional Data Packet. */
-struct vmadditional_data {
- struct vmpacket_descriptor d;
- u64 TotalBytes;
- u32 ByteOffset;
- u32 ByteCount;
- unsigned char Data[1];
-} __attribute__((packed));
-
-union vmpacket_largest_possible_header {
- struct vmpacket_descriptor SimpleHeader;
- struct vmtransfer_page_packet_header TransferPageHeader;
- struct vmgpadl_packet_header GpadlHeader;
- struct vmadd_remove_transfer_page_set AddRemoveTransferPageHeader;
- struct vmestablish_gpadl EstablishGpadlHeader;
- struct vmteardown_gpadl TeardownGpadlHeader;
- struct vmdata_gpa_direct DataGpaDirectHeader;
-};
-
-#define VMPACKET_DATA_START_ADDRESS(__packet) \
- (void *)(((unsigned char *)__packet) + \
- ((struct vmpacket_descriptor)__packet)->DataOffset8 * 8)
-
-#define VMPACKET_DATA_LENGTH(__packet) \
- ((((struct vmpacket_descriptor)__packet)->Length8 - \
- ((struct vmpacket_descriptor)__packet)->DataOffset8) * 8)
-
-#define VMPACKET_TRANSFER_MODE(__packet) \
- (((struct IMPACT)__packet)->Type)
-
-enum vmbus_packet_type {
- VmbusPacketTypeInvalid = 0x0,
- VmbusPacketTypeSynch = 0x1,
- VmbusPacketTypeAddTransferPageSet = 0x2,
- VmbusPacketTypeRemoveTransferPageSet = 0x3,
- VmbusPacketTypeEstablishGpadl = 0x4,
- VmbusPacketTypeTearDownGpadl = 0x5,
- VmbusPacketTypeDataInBand = 0x6,
- VmbusPacketTypeDataUsingTransferPages = 0x7,
- VmbusPacketTypeDataUsingGpadl = 0x8,
- VmbusPacketTypeDataUsingGpaDirect = 0x9,
- VmbusPacketTypeCancelRequest = 0xa,
- VmbusPacketTypeCompletion = 0xb,
- VmbusPacketTypeDataUsingAdditionalPackets = 0xc,
- VmbusPacketTypeAdditionalData = 0xd
-};
-
-#define VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED 1
-
-#endif
diff --git a/drivers/staging/hv/VmbusPrivate.h b/drivers/staging/hv/VmbusPrivate.h
deleted file mode 100644
index 5a37ccec92e8..000000000000
--- a/drivers/staging/hv/VmbusPrivate.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _VMBUS_PRIVATE_H_
-#define _VMBUS_PRIVATE_H_
-
-#include "Hv.h"
-#include "VmbusApi.h"
-#include "Channel.h"
-#include "ChannelMgmt.h"
-#include "ChannelInterface.h"
-#include "RingBuffer.h"
-#include <linux/list.h>
-#include <asm/sync_bitops.h>
-
-
-/*
- * Maximum channels is determined by the size of the interrupt page
- * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt
- * and the other is receive endpoint interrupt
- */
-#define MAX_NUM_CHANNELS ((PAGE_SIZE >> 1) << 3) /* 16348 channels */
-
-/* The value here must be in multiple of 32 */
-/* TODO: Need to make this configurable */
-#define MAX_NUM_CHANNELS_SUPPORTED 256
-
-
-enum VMBUS_CONNECT_STATE {
- Disconnected,
- Connecting,
- Connected,
- Disconnecting
-};
-
-#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT
-
-struct VMBUS_CONNECTION {
- enum VMBUS_CONNECT_STATE ConnectState;
-
- atomic_t NextGpadlHandle;
-
- /*
- * Represents channel interrupts. Each bit position represents a
- * channel. When a channel sends an interrupt via VMBUS, it finds its
- * bit in the sendInterruptPage, set it and calls Hv to generate a port
- * event. The other end receives the port event and parse the
- * recvInterruptPage to see which bit is set
- */
- void *InterruptPage;
- void *SendInterruptPage;
- void *RecvInterruptPage;
-
- /*
- * 2 pages - 1st page for parent->child notification and 2nd
- * is child->parent notification
- */
- void *MonitorPages;
- struct list_head ChannelMsgList;
- spinlock_t channelmsg_lock;
-
- /* List of channels */
- struct list_head ChannelList;
- spinlock_t channel_lock;
-
- struct workqueue_struct *WorkQueue;
-};
-
-
-struct VMBUS_MSGINFO {
- /* Bookkeeping stuff */
- struct list_head MsgListEntry;
-
- /* Synchronize the request/response if needed */
- struct osd_waitevent *WaitEvent;
-
- /* The message itself */
- unsigned char Msg[0];
-};
-
-
-extern struct VMBUS_CONNECTION gVmbusConnection;
-
-/* General vmbus interface */
-
-struct hv_device *VmbusChildDeviceCreate(struct hv_guid *deviceType,
- struct hv_guid *deviceInstance,
- void *context);
-
-int VmbusChildDeviceAdd(struct hv_device *Device);
-
-void VmbusChildDeviceRemove(struct hv_device *Device);
-
-/* static void */
-/* VmbusChildDeviceDestroy( */
-/* struct hv_device *); */
-
-struct vmbus_channel *GetChannelFromRelId(u32 relId);
-
-
-/* Connection interface */
-
-int VmbusConnect(void);
-
-int VmbusDisconnect(void);
-
-int VmbusPostMessage(void *buffer, size_t bufSize);
-
-int VmbusSetEvent(u32 childRelId);
-
-void VmbusOnEvents(void);
-
-
-#endif /* _VMBUS_PRIVATE_H_ */
diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c
index ddc553cb2e3f..3612574ca520 100644
--- a/drivers/staging/hv/blkvsc_drv.c
+++ b/drivers/staging/hv/blkvsc_drv.c
@@ -17,6 +17,7 @@
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
*/
#include <linux/init.h>
#include <linux/module.h>
@@ -30,11 +31,9 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dbg.h>
-#include "osd.h"
-#include "logging.h"
-#include "VersionInfo.h"
-#include "vmbus.h"
-#include "StorVscApi.h"
+
+#include "hyperv.h"
+#include "hyperv_storage.h"
#define BLKVSC_MINORS 64
@@ -45,6 +44,12 @@ enum blkvsc_device_type {
DVD_TYPE,
};
+enum blkvsc_op_type {
+ DO_INQUIRY,
+ DO_CAPACITY,
+ DO_FLUSH,
+};
+
/*
* This request ties the struct request and struct
* blkvsc_request/hv_storvsc_request together A struct request may be
@@ -71,9 +76,6 @@ struct blkvsc_request {
/* The group this request is part of. Maybe null */
struct blkvsc_request_group *group;
- wait_queue_head_t wevent;
- int cond;
-
int write;
sector_t sector_start;
unsigned long sector_count;
@@ -83,18 +85,12 @@ struct blkvsc_request {
unsigned char cmnd[MAX_COMMAND_SIZE];
struct hv_storvsc_request request;
- /*
- * !!!DO NOT ADD ANYTHING BELOW HERE!!! Otherwise, memory can overlap,
- * because - The extension buffer falls right here and is pointed to by
- * request.Extension;
- * Which sounds like a horrible idea, who designed this?
- */
};
/* Per device structure */
struct block_device_context {
/* point back to our device context */
- struct vm_device *device_ctx;
+ struct hv_device *device_ctx;
struct kmem_cache *request_pool;
spinlock_t lock;
struct gendisk *gd;
@@ -105,7 +101,6 @@ struct block_device_context {
unsigned int device_id_len;
int num_outstanding_reqs;
int shutting_down;
- int media_not_present;
unsigned int sector_size;
sector_t capacity;
unsigned int port;
@@ -114,524 +109,314 @@ struct block_device_context {
int users;
};
-/* Per driver */
-struct blkvsc_driver_context {
- /* !! These must be the first 2 fields !! */
- /* FIXME this is a bug! */
- struct driver_context drv_ctx;
- struct storvsc_driver_object drv_obj;
-};
+static const char *drv_name = "blkvsc";
-/* Static decl */
-static int blkvsc_probe(struct device *dev);
-static int blkvsc_remove(struct device *device);
-static void blkvsc_shutdown(struct device *device);
+/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
+static const struct hv_guid dev_type = {
+ .data = {
+ 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
+ 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
+ }
+};
-static int blkvsc_open(struct block_device *bdev, fmode_t mode);
-static int blkvsc_release(struct gendisk *disk, fmode_t mode);
-static int blkvsc_media_changed(struct gendisk *gd);
-static int blkvsc_revalidate_disk(struct gendisk *gd);
-static int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg);
-static int blkvsc_ioctl(struct block_device *bd, fmode_t mode,
- unsigned cmd, unsigned long argument);
-static void blkvsc_request(struct request_queue *queue);
+/*
+ * There is a circular dependency involving blkvsc_request_completion()
+ * and blkvsc_do_request().
+ */
static void blkvsc_request_completion(struct hv_storvsc_request *request);
-static int blkvsc_do_request(struct block_device_context *blkdev,
- struct request *req);
-static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req,
- void (*request_completion)(struct hv_storvsc_request *));
-static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req);
-static void blkvsc_cmd_completion(struct hv_storvsc_request *request);
-static int blkvsc_do_inquiry(struct block_device_context *blkdev);
-static int blkvsc_do_read_capacity(struct block_device_context *blkdev);
-static int blkvsc_do_read_capacity16(struct block_device_context *blkdev);
-static int blkvsc_do_flush(struct block_device_context *blkdev);
-static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev);
-static int blkvsc_do_pending_reqs(struct block_device_context *blkdev);
static int blkvsc_ringbuffer_size = BLKVSC_RING_BUFFER_SIZE;
+
module_param(blkvsc_ringbuffer_size, int, S_IRUGO);
MODULE_PARM_DESC(ring_size, "Ring buffer size (in bytes)");
-/* The one and only one */
-static struct blkvsc_driver_context g_blkvsc_drv;
-
-static const struct block_device_operations block_ops = {
- .owner = THIS_MODULE,
- .open = blkvsc_open,
- .release = blkvsc_release,
- .media_changed = blkvsc_media_changed,
- .revalidate_disk = blkvsc_revalidate_disk,
- .getgeo = blkvsc_getgeo,
- .ioctl = blkvsc_ioctl,
-};
-
/*
- * blkvsc_drv_init - BlkVsc driver initialization.
+ * There is a circular dependency involving blkvsc_probe()
+ * and block_ops.
*/
-static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
-{
- struct storvsc_driver_object *storvsc_drv_obj = &g_blkvsc_drv.drv_obj;
- struct driver_context *drv_ctx = &g_blkvsc_drv.drv_ctx;
- int ret;
+static int blkvsc_probe(struct hv_device *dev);
- vmbus_get_interface(&storvsc_drv_obj->Base.VmbusChannelInterface);
+static int blkvsc_device_add(struct hv_device *device,
+ void *additional_info)
+{
+ struct storvsc_device_info *device_info;
+ int ret = 0;
- storvsc_drv_obj->RingBufferSize = blkvsc_ringbuffer_size;
+ device_info = (struct storvsc_device_info *)additional_info;
- /* Callback to client driver to complete the initialization */
- drv_init(&storvsc_drv_obj->Base);
+ device_info->ring_buffer_size = blkvsc_ringbuffer_size;
- drv_ctx->driver.name = storvsc_drv_obj->Base.name;
- memcpy(&drv_ctx->class_id, &storvsc_drv_obj->Base.deviceType,
- sizeof(struct hv_guid));
+ ret = storvsc_dev_add(device, additional_info);
+ if (ret != 0)
+ return ret;
- drv_ctx->probe = blkvsc_probe;
- drv_ctx->remove = blkvsc_remove;
- drv_ctx->shutdown = blkvsc_shutdown;
+ /*
+ * We need to use the device instance guid to set the path and target
+ * id. For IDE devices, the device instance id is formatted as
+ * <bus id> * - <device id> - 8899 - 000000000000.
+ */
+ device_info->path_id = device->dev_instance.data[3] << 24 |
+ device->dev_instance.data[2] << 16 |
+ device->dev_instance.data[1] << 8 |
+ device->dev_instance.data[0];
- /* The driver belongs to vmbus */
- ret = vmbus_child_driver_register(drv_ctx);
+ device_info->target_id = device->dev_instance.data[5] << 8 |
+ device->dev_instance.data[4];
return ret;
}
-static int blkvsc_drv_exit_cb(struct device *dev, void *data)
-{
- struct device **curr = (struct device **)data;
- *curr = dev;
- return 1; /* stop iterating */
-}
-
-static void blkvsc_drv_exit(void)
+static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req,
+ void (*request_completion)(struct hv_storvsc_request *))
{
- struct storvsc_driver_object *storvsc_drv_obj = &g_blkvsc_drv.drv_obj;
- struct driver_context *drv_ctx = &g_blkvsc_drv.drv_ctx;
- struct device *current_dev;
+ struct block_device_context *blkdev = blkvsc_req->dev;
+ struct hv_storvsc_request *storvsc_req;
+ struct vmscsi_request *vm_srb;
int ret;
- while (1) {
- current_dev = NULL;
-
- /* Get the device */
- ret = driver_for_each_device(&drv_ctx->driver, NULL,
- (void *) &current_dev,
- blkvsc_drv_exit_cb);
-
- if (ret)
- DPRINT_WARN(BLKVSC_DRV,
- "driver_for_each_device returned %d", ret);
-
- if (current_dev == NULL)
- break;
+ storvsc_req = &blkvsc_req->request;
+ vm_srb = &storvsc_req->vstor_packet.vm_srb;
- /* Initiate removal from the top-down */
- device_unregister(current_dev);
- }
+ vm_srb->data_in = blkvsc_req->write ? WRITE_TYPE : READ_TYPE;
- if (storvsc_drv_obj->Base.OnCleanup)
- storvsc_drv_obj->Base.OnCleanup(&storvsc_drv_obj->Base);
+ storvsc_req->on_io_completion = request_completion;
+ storvsc_req->context = blkvsc_req;
- vmbus_child_driver_unregister(drv_ctx);
+ vm_srb->port_number = blkdev->port;
+ vm_srb->path_id = blkdev->path;
+ vm_srb->target_id = blkdev->target;
+ vm_srb->lun = 0; /* this is not really used at all */
- return;
-}
+ vm_srb->cdb_length = blkvsc_req->cmd_len;
-/*
- * blkvsc_probe - Add a new device for this driver
- */
-static int blkvsc_probe(struct device *device)
-{
- struct driver_context *driver_ctx =
- driver_to_driver_context(device->driver);
- struct blkvsc_driver_context *blkvsc_drv_ctx =
- (struct blkvsc_driver_context *)driver_ctx;
- struct storvsc_driver_object *storvsc_drv_obj =
- &blkvsc_drv_ctx->drv_obj;
- struct vm_device *device_ctx = device_to_vm_device(device);
- struct hv_device *device_obj = &device_ctx->device_obj;
-
- struct block_device_context *blkdev = NULL;
- struct storvsc_device_info device_info;
- int major = 0;
- int devnum = 0;
- int ret = 0;
- static int ide0_registered;
- static int ide1_registered;
+ memcpy(vm_srb->cdb, blkvsc_req->cmnd, vm_srb->cdb_length);
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_probe - enter");
+ storvsc_req->sense_buffer = blkvsc_req->sense_buffer;
- if (!storvsc_drv_obj->Base.OnDeviceAdd) {
- DPRINT_ERR(BLKVSC_DRV, "OnDeviceAdd() not set");
- ret = -1;
- goto Cleanup;
- }
+ ret = storvsc_do_io(blkdev->device_ctx,
+ &blkvsc_req->request);
+ if (ret == 0)
+ blkdev->num_outstanding_reqs++;
- blkdev = kzalloc(sizeof(struct block_device_context), GFP_KERNEL);
- if (!blkdev) {
- ret = -ENOMEM;
- goto Cleanup;
- }
+ return ret;
+}
- INIT_LIST_HEAD(&blkdev->pending_list);
- /* Initialize what we can here */
- spin_lock_init(&blkdev->lock);
+static int blkvsc_open(struct block_device *bdev, fmode_t mode)
+{
+ struct block_device_context *blkdev = bdev->bd_disk->private_data;
+ unsigned long flags;
- /* ASSERT(sizeof(struct blkvsc_request_group) <= */
- /* sizeof(struct blkvsc_request)); */
+ spin_lock_irqsave(&blkdev->lock, flags);
- blkdev->request_pool = kmem_cache_create(dev_name(&device_ctx->device),
- sizeof(struct blkvsc_request) +
- storvsc_drv_obj->RequestExtSize, 0,
- SLAB_HWCACHE_ALIGN, NULL);
- if (!blkdev->request_pool) {
- ret = -ENOMEM;
- goto Cleanup;
- }
+ blkdev->users++;
+ spin_unlock_irqrestore(&blkdev->lock, flags);
- /* Call to the vsc driver to add the device */
- ret = storvsc_drv_obj->Base.OnDeviceAdd(device_obj, &device_info);
- if (ret != 0) {
- DPRINT_ERR(BLKVSC_DRV, "unable to add blkvsc device");
- goto Cleanup;
- }
+ return 0;
+}
- blkdev->device_ctx = device_ctx;
- /* this identified the device 0 or 1 */
- blkdev->target = device_info.TargetId;
- /* this identified the ide ctrl 0 or 1 */
- blkdev->path = device_info.PathId;
-
- dev_set_drvdata(device, blkdev);
-
- /* Calculate the major and device num */
- if (blkdev->path == 0) {
- major = IDE0_MAJOR;
- devnum = blkdev->path + blkdev->target; /* 0 or 1 */
-
- if (!ide0_registered) {
- ret = register_blkdev(major, "ide");
- if (ret != 0) {
- DPRINT_ERR(BLKVSC_DRV,
- "register_blkdev() failed! ret %d",
- ret);
- goto Remove;
- }
- ide0_registered = 1;
- }
- } else if (blkdev->path == 1) {
- major = IDE1_MAJOR;
- devnum = blkdev->path + blkdev->target + 1; /* 2 or 3 */
-
- if (!ide1_registered) {
- ret = register_blkdev(major, "ide");
- if (ret != 0) {
- DPRINT_ERR(BLKVSC_DRV,
- "register_blkdev() failed! ret %d",
- ret);
- goto Remove;
- }
-
- ide1_registered = 1;
- }
- } else {
- DPRINT_ERR(BLKVSC_DRV, "invalid pathid");
- ret = -1;
- goto Cleanup;
- }
+static int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg)
+{
+ sector_t nsect = get_capacity(bd->bd_disk);
+ sector_t cylinders = nsect;
- DPRINT_INFO(BLKVSC_DRV, "blkvsc registered for major %d!!", major);
+ /*
+ * We are making up these values; let us keep it simple.
+ */
+ hg->heads = 0xff;
+ hg->sectors = 0x3f;
+ sector_div(cylinders, hg->heads * hg->sectors);
+ hg->cylinders = cylinders;
+ if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect)
+ hg->cylinders = 0xffff;
+ return 0;
- blkdev->gd = alloc_disk(BLKVSC_MINORS);
- if (!blkdev->gd) {
- DPRINT_ERR(BLKVSC_DRV, "register_blkdev() failed! ret %d", ret);
- ret = -1;
- goto Cleanup;
- }
+}
- blkdev->gd->queue = blk_init_queue(blkvsc_request, &blkdev->lock);
- blk_queue_max_segment_size(blkdev->gd->queue, PAGE_SIZE);
- blk_queue_max_segments(blkdev->gd->queue, MAX_MULTIPAGE_BUFFER_COUNT);
- blk_queue_segment_boundary(blkdev->gd->queue, PAGE_SIZE-1);
- blk_queue_bounce_limit(blkdev->gd->queue, BLK_BOUNCE_ANY);
- blk_queue_dma_alignment(blkdev->gd->queue, 511);
+static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req)
+{
- blkdev->gd->major = major;
- if (devnum == 1 || devnum == 3)
- blkdev->gd->first_minor = BLKVSC_MINORS;
- else
- blkdev->gd->first_minor = 0;
- blkdev->gd->fops = &block_ops;
- blkdev->gd->private_data = blkdev;
- blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device);
- sprintf(blkdev->gd->disk_name, "hd%c", 'a' + devnum);
+ blkvsc_req->cmd_len = 16;
- blkvsc_do_inquiry(blkdev);
- if (blkdev->device_type == DVD_TYPE) {
- set_disk_ro(blkdev->gd, 1);
- blkdev->gd->flags |= GENHD_FL_REMOVABLE;
- blkvsc_do_read_capacity(blkdev);
+ if (rq_data_dir(blkvsc_req->req)) {
+ blkvsc_req->write = 1;
+ blkvsc_req->cmnd[0] = WRITE_16;
} else {
- blkvsc_do_read_capacity16(blkdev);
+ blkvsc_req->write = 0;
+ blkvsc_req->cmnd[0] = READ_16;
}
- set_capacity(blkdev->gd, blkdev->capacity * (blkdev->sector_size/512));
- blk_queue_logical_block_size(blkdev->gd->queue, blkdev->sector_size);
- /* go! */
- add_disk(blkdev->gd);
+ blkvsc_req->cmnd[1] |=
+ (blkvsc_req->req->cmd_flags & REQ_FUA) ? 0x8 : 0;
- DPRINT_INFO(BLKVSC_DRV, "%s added!! capacity %lu sector_size %d",
- blkdev->gd->disk_name, (unsigned long)blkdev->capacity,
- blkdev->sector_size);
+ *(unsigned long long *)&blkvsc_req->cmnd[2] =
+ cpu_to_be64(blkvsc_req->sector_start);
+ *(unsigned int *)&blkvsc_req->cmnd[10] =
+ cpu_to_be32(blkvsc_req->sector_count);
+}
- return ret;
-Remove:
- storvsc_drv_obj->Base.OnDeviceRemove(device_obj);
+static int blkvsc_ioctl(struct block_device *bd, fmode_t mode,
+ unsigned cmd, unsigned long arg)
+{
+ struct block_device_context *blkdev = bd->bd_disk->private_data;
+ int ret = 0;
-Cleanup:
- if (blkdev) {
- if (blkdev->request_pool) {
- kmem_cache_destroy(blkdev->request_pool);
- blkdev->request_pool = NULL;
- }
- kfree(blkdev);
- blkdev = NULL;
+ switch (cmd) {
+ case HDIO_GET_IDENTITY:
+ if (copy_to_user((void __user *)arg, blkdev->device_id,
+ blkdev->device_id_len))
+ ret = -EFAULT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
return ret;
}
-static void blkvsc_shutdown(struct device *device)
+static void blkvsc_cmd_completion(struct hv_storvsc_request *request)
{
- struct block_device_context *blkdev = dev_get_drvdata(device);
+ struct blkvsc_request *blkvsc_req =
+ (struct blkvsc_request *)request->context;
+ struct block_device_context *blkdev =
+ (struct block_device_context *)blkvsc_req->dev;
+ struct scsi_sense_hdr sense_hdr;
+ struct vmscsi_request *vm_srb;
unsigned long flags;
- if (!blkdev)
- return;
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_shutdown - users %d disk %s\n",
- blkdev->users, blkdev->gd->disk_name);
+ vm_srb = &blkvsc_req->request.vstor_packet.vm_srb;
spin_lock_irqsave(&blkdev->lock, flags);
-
- blkdev->shutting_down = 1;
-
- blk_stop_queue(blkdev->gd->queue);
-
+ blkdev->num_outstanding_reqs--;
spin_unlock_irqrestore(&blkdev->lock, flags);
- while (blkdev->num_outstanding_reqs) {
- DPRINT_INFO(STORVSC, "waiting for %d requests to complete...",
- blkdev->num_outstanding_reqs);
- udelay(100);
- }
-
- blkvsc_do_flush(blkdev);
-
- spin_lock_irqsave(&blkdev->lock, flags);
-
- blkvsc_cancel_pending_reqs(blkdev);
+ if (vm_srb->scsi_status)
+ if (scsi_normalize_sense(blkvsc_req->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+ scsi_print_sense_hdr("blkvsc", &sense_hdr);
- spin_unlock_irqrestore(&blkdev->lock, flags);
+ complete(&blkvsc_req->request.wait_event);
}
-static int blkvsc_do_flush(struct block_device_context *blkdev)
-{
- struct blkvsc_request *blkvsc_req;
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_flush()\n");
-
- if (blkdev->device_type != HARDDISK_TYPE)
- return 0;
-
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL);
- if (!blkvsc_req)
- return -ENOMEM;
-
- memset(blkvsc_req, 0, sizeof(struct blkvsc_request));
- init_waitqueue_head(&blkvsc_req->wevent);
- blkvsc_req->dev = blkdev;
- blkvsc_req->req = NULL;
- blkvsc_req->write = 0;
-
- blkvsc_req->request.DataBuffer.PfnArray[0] = 0;
- blkvsc_req->request.DataBuffer.Offset = 0;
- blkvsc_req->request.DataBuffer.Length = 0;
-
- blkvsc_req->cmnd[0] = SYNCHRONIZE_CACHE;
- blkvsc_req->cmd_len = 10;
-
- /*
- * Set this here since the completion routine may be invoked and
- * completed before we return
- */
- blkvsc_req->cond = 0;
- blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
-
- wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
-
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
-
- return 0;
-}
-
-/* Do a scsi INQUIRY cmd here to get the device type (ie disk or dvd) */
-static int blkvsc_do_inquiry(struct block_device_context *blkdev)
+static int blkvsc_do_operation(struct block_device_context *blkdev,
+ enum blkvsc_op_type op)
{
struct blkvsc_request *blkvsc_req;
struct page *page_buf;
unsigned char *buf;
unsigned char device_type;
+ struct scsi_sense_hdr sense_hdr;
+ struct vmscsi_request *vm_srb;
+ unsigned long flags;
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_inquiry()\n");
+ int ret = 0;
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL);
+ blkvsc_req = kmem_cache_zalloc(blkdev->request_pool, GFP_KERNEL);
if (!blkvsc_req)
return -ENOMEM;
- memset(blkvsc_req, 0, sizeof(struct blkvsc_request));
page_buf = alloc_page(GFP_KERNEL);
if (!page_buf) {
kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
return -ENOMEM;
}
- init_waitqueue_head(&blkvsc_req->wevent);
+ vm_srb = &blkvsc_req->request.vstor_packet.vm_srb;
+ init_completion(&blkvsc_req->request.wait_event);
blkvsc_req->dev = blkdev;
blkvsc_req->req = NULL;
blkvsc_req->write = 0;
- blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf);
- blkvsc_req->request.DataBuffer.Offset = 0;
- blkvsc_req->request.DataBuffer.Length = 64;
-
- blkvsc_req->cmnd[0] = INQUIRY;
- blkvsc_req->cmnd[1] = 0x1; /* Get product data */
- blkvsc_req->cmnd[2] = 0x83; /* mode page 83 */
- blkvsc_req->cmnd[4] = 64;
- blkvsc_req->cmd_len = 6;
-
- /*
- * Set this here since the completion routine may be invoked and
- * completed before we return
- */
- blkvsc_req->cond = 0;
-
- blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
-
- DPRINT_DBG(BLKVSC_DRV, "waiting %p to complete - cond %d\n",
- blkvsc_req, blkvsc_req->cond);
-
- wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
+ blkvsc_req->request.data_buffer.pfn_array[0] =
+ page_to_pfn(page_buf);
+ blkvsc_req->request.data_buffer.offset = 0;
+
+ switch (op) {
+ case DO_INQUIRY:
+ blkvsc_req->cmnd[0] = INQUIRY;
+ blkvsc_req->cmnd[1] = 0x1; /* Get product data */
+ blkvsc_req->cmnd[2] = 0x83; /* mode page 83 */
+ blkvsc_req->cmnd[4] = 64;
+ blkvsc_req->cmd_len = 6;
+ blkvsc_req->request.data_buffer.len = 64;
+ break;
- buf = kmap(page_buf);
+ case DO_CAPACITY:
+ blkdev->sector_size = 0;
+ blkdev->capacity = 0;
- /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, 64); */
- /* be to le */
- device_type = buf[0] & 0x1F;
+ blkvsc_req->cmnd[0] = READ_CAPACITY;
+ blkvsc_req->cmd_len = 16;
+ blkvsc_req->request.data_buffer.len = 8;
+ break;
- if (device_type == 0x0) {
- blkdev->device_type = HARDDISK_TYPE;
- } else if (device_type == 0x5) {
- blkdev->device_type = DVD_TYPE;
- } else {
- /* TODO: this is currently unsupported device type */
- blkdev->device_type = UNKNOWN_DEV_TYPE;
+ case DO_FLUSH:
+ blkvsc_req->cmnd[0] = SYNCHRONIZE_CACHE;
+ blkvsc_req->cmd_len = 10;
+ blkvsc_req->request.data_buffer.pfn_array[0] = 0;
+ blkvsc_req->request.data_buffer.len = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto cleanup;
}
- DPRINT_DBG(BLKVSC_DRV, "device type %d\n", device_type);
-
- blkdev->device_id_len = buf[7];
- if (blkdev->device_id_len > 64)
- blkdev->device_id_len = 64;
-
- memcpy(blkdev->device_id, &buf[8], blkdev->device_id_len);
- /* printk_hex_dump_bytes("", DUMP_PREFIX_NONE, blkdev->device_id,
- * blkdev->device_id_len); */
-
- kunmap(page_buf);
-
- __free_page(page_buf);
-
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
-
- return 0;
-}
-
-/* Do a scsi READ_CAPACITY cmd here to get the size of the disk */
-static int blkvsc_do_read_capacity(struct block_device_context *blkdev)
-{
- struct blkvsc_request *blkvsc_req;
- struct page *page_buf;
- unsigned char *buf;
- struct scsi_sense_hdr sense_hdr;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_read_capacity()\n");
+ spin_lock_irqsave(&blkdev->lock, flags);
+ blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
+ spin_unlock_irqrestore(&blkdev->lock, flags);
- blkdev->sector_size = 0;
- blkdev->capacity = 0;
- blkdev->media_not_present = 0; /* assume a disk is present */
+ wait_for_completion_interruptible(&blkvsc_req->request.wait_event);
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL);
- if (!blkvsc_req)
- return -ENOMEM;
+ /* check error */
+ if (vm_srb->scsi_status) {
+ scsi_normalize_sense(blkvsc_req->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr);
- memset(blkvsc_req, 0, sizeof(struct blkvsc_request));
- page_buf = alloc_page(GFP_KERNEL);
- if (!page_buf) {
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
- return -ENOMEM;
+ return 0;
}
- init_waitqueue_head(&blkvsc_req->wevent);
- blkvsc_req->dev = blkdev;
- blkvsc_req->req = NULL;
- blkvsc_req->write = 0;
+ buf = kmap(page_buf);
- blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf);
- blkvsc_req->request.DataBuffer.Offset = 0;
- blkvsc_req->request.DataBuffer.Length = 8;
+ switch (op) {
+ case DO_INQUIRY:
+ device_type = buf[0] & 0x1F;
- blkvsc_req->cmnd[0] = READ_CAPACITY;
- blkvsc_req->cmd_len = 16;
+ if (device_type == 0x0)
+ blkdev->device_type = HARDDISK_TYPE;
+ else
+ blkdev->device_type = UNKNOWN_DEV_TYPE;
- /*
- * Set this here since the completion routine may be invoked
- * and completed before we return
- */
- blkvsc_req->cond = 0;
+ blkdev->device_id_len = buf[7];
+ if (blkdev->device_id_len > 64)
+ blkdev->device_id_len = 64;
- blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
-
- DPRINT_DBG(BLKVSC_DRV, "waiting %p to complete - cond %d\n",
- blkvsc_req, blkvsc_req->cond);
+ memcpy(blkdev->device_id, &buf[8], blkdev->device_id_len);
+ break;
- wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
+ case DO_CAPACITY:
+ /* be to le */
+ blkdev->capacity =
+ ((buf[0] << 24) | (buf[1] << 16) |
+ (buf[2] << 8) | buf[3]) + 1;
- /* check error */
- if (blkvsc_req->request.Status) {
- scsi_normalize_sense(blkvsc_req->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr);
+ blkdev->sector_size =
+ (buf[4] << 24) | (buf[5] << 16) |
+ (buf[6] << 8) | buf[7];
+ break;
+ default:
+ break;
- if (sense_hdr.asc == 0x3A) {
- /* Medium not present */
- blkdev->media_not_present = 1;
- }
- return 0;
}
- buf = kmap(page_buf);
- /* be to le */
- blkdev->capacity = ((buf[0] << 24) | (buf[1] << 16) |
- (buf[2] << 8) | buf[3]) + 1;
- blkdev->sector_size = (buf[4] << 24) | (buf[5] << 16) |
- (buf[6] << 8) | buf[7];
+cleanup:
kunmap(page_buf);
@@ -639,122 +424,86 @@ static int blkvsc_do_read_capacity(struct block_device_context *blkdev)
kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
- return 0;
+ return ret;
}
-static int blkvsc_do_read_capacity16(struct block_device_context *blkdev)
-{
- struct blkvsc_request *blkvsc_req;
- struct page *page_buf;
- unsigned char *buf;
- struct scsi_sense_hdr sense_hdr;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_read_capacity16()\n");
-
- blkdev->sector_size = 0;
- blkdev->capacity = 0;
- blkdev->media_not_present = 0; /* assume a disk is present */
-
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL);
- if (!blkvsc_req)
- return -ENOMEM;
- memset(blkvsc_req, 0, sizeof(struct blkvsc_request));
- page_buf = alloc_page(GFP_KERNEL);
- if (!page_buf) {
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
- return -ENOMEM;
- }
+static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev)
+{
+ struct blkvsc_request *pend_req, *tmp;
+ struct blkvsc_request *comp_req, *tmp2;
+ struct vmscsi_request *vm_srb;
- init_waitqueue_head(&blkvsc_req->wevent);
- blkvsc_req->dev = blkdev;
- blkvsc_req->req = NULL;
- blkvsc_req->write = 0;
+ int ret = 0;
- blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf);
- blkvsc_req->request.DataBuffer.Offset = 0;
- blkvsc_req->request.DataBuffer.Length = 12;
- blkvsc_req->cmnd[0] = 0x9E; /* READ_CAPACITY16; */
- blkvsc_req->cmd_len = 16;
+ /* Flush the pending list first */
+ list_for_each_entry_safe(pend_req, tmp, &blkdev->pending_list,
+ pend_entry) {
+ /*
+ * The pend_req could be part of a partially completed
+ * request. If so, complete those req first until we
+ * hit the pend_req
+ */
+ list_for_each_entry_safe(comp_req, tmp2,
+ &pend_req->group->blkvsc_req_list,
+ req_entry) {
- /*
- * Set this here since the completion routine may be invoked
- * and completed before we return
- */
- blkvsc_req->cond = 0;
+ if (comp_req == pend_req)
+ break;
- blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion);
+ list_del(&comp_req->req_entry);
- DPRINT_DBG(BLKVSC_DRV, "waiting %p to complete - cond %d\n",
- blkvsc_req, blkvsc_req->cond);
+ if (comp_req->req) {
+ vm_srb =
+ &comp_req->request.vstor_packet.
+ vm_srb;
+ ret = __blk_end_request(comp_req->req,
+ (!vm_srb->scsi_status ? 0 : -EIO),
+ comp_req->sector_count *
+ blkdev->sector_size);
- wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond);
+ /* FIXME: shouldn't this do more than return? */
+ if (ret)
+ goto out;
+ }
- /* check error */
- if (blkvsc_req->request.Status) {
- scsi_normalize_sense(blkvsc_req->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr);
- if (sense_hdr.asc == 0x3A) {
- /* Medium not present */
- blkdev->media_not_present = 1;
+ kmem_cache_free(blkdev->request_pool, comp_req);
}
- return 0;
- }
- buf = kmap(page_buf);
-
- /* be to le */
- blkdev->capacity = be64_to_cpu(*(unsigned long long *) &buf[0]) + 1;
- blkdev->sector_size = be32_to_cpu(*(unsigned int *)&buf[8]);
-#if 0
- blkdev->capacity = ((buf[0] << 24) | (buf[1] << 16) |
- (buf[2] << 8) | buf[3]) + 1;
- blkdev->sector_size = (buf[4] << 24) | (buf[5] << 16) |
- (buf[6] << 8) | buf[7];
-#endif
+ list_del(&pend_req->pend_entry);
- kunmap(page_buf);
+ list_del(&pend_req->req_entry);
- __free_page(page_buf);
+ if (comp_req->req) {
+ if (!__blk_end_request(pend_req->req, -EIO,
+ pend_req->sector_count *
+ blkdev->sector_size)) {
+ /*
+ * All the sectors have been xferred ie the
+ * request is done
+ */
+ kmem_cache_free(blkdev->request_pool,
+ pend_req->group);
+ }
+ }
- kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
+ kmem_cache_free(blkdev->request_pool, pend_req);
+ }
- return 0;
+out:
+ return ret;
}
+
/*
* blkvsc_remove() - Callback when our device is removed
*/
-static int blkvsc_remove(struct device *device)
+static int blkvsc_remove(struct hv_device *dev)
{
- struct driver_context *driver_ctx =
- driver_to_driver_context(device->driver);
- struct blkvsc_driver_context *blkvsc_drv_ctx =
- (struct blkvsc_driver_context *)driver_ctx;
- struct storvsc_driver_object *storvsc_drv_obj =
- &blkvsc_drv_ctx->drv_obj;
- struct vm_device *device_ctx = device_to_vm_device(device);
- struct hv_device *device_obj = &device_ctx->device_obj;
- struct block_device_context *blkdev = dev_get_drvdata(device);
+ struct block_device_context *blkdev = dev_get_drvdata(&dev->device);
unsigned long flags;
- int ret;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_remove()\n");
- if (!storvsc_drv_obj->Base.OnDeviceRemove)
- return -1;
-
- /*
- * Call to the vsc driver to let it know that the device is being
- * removed
- */
- ret = storvsc_drv_obj->Base.OnDeviceRemove(device_obj);
- if (ret != 0) {
- /* TODO: */
- DPRINT_ERR(BLKVSC_DRV,
- "unable to remove blkvsc device (ret %d)", ret);
- }
/* Get to a known state */
spin_lock_irqsave(&blkdev->lock, flags);
@@ -763,148 +512,80 @@ static int blkvsc_remove(struct device *device)
blk_stop_queue(blkdev->gd->queue);
- spin_unlock_irqrestore(&blkdev->lock, flags);
-
- while (blkdev->num_outstanding_reqs) {
- DPRINT_INFO(STORVSC, "waiting for %d requests to complete...",
- blkdev->num_outstanding_reqs);
- udelay(100);
- }
-
- blkvsc_do_flush(blkdev);
-
- spin_lock_irqsave(&blkdev->lock, flags);
-
blkvsc_cancel_pending_reqs(blkdev);
spin_unlock_irqrestore(&blkdev->lock, flags);
- blk_cleanup_queue(blkdev->gd->queue);
+ blkvsc_do_operation(blkdev, DO_FLUSH);
- del_gendisk(blkdev->gd);
+ if (blkdev->users == 0) {
+ del_gendisk(blkdev->gd);
+ put_disk(blkdev->gd);
+ blk_cleanup_queue(blkdev->gd->queue);
- kmem_cache_destroy(blkdev->request_pool);
+ storvsc_dev_remove(blkdev->device_ctx);
- kfree(blkdev);
+ kmem_cache_destroy(blkdev->request_pool);
+ kfree(blkdev);
+ }
- return ret;
+ return 0;
}
-static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req)
+static void blkvsc_shutdown(struct hv_device *dev)
{
- /* ASSERT(blkvsc_req->req); */
- /* ASSERT(blkvsc_req->sector_count <= (MAX_MULTIPAGE_BUFFER_COUNT*8)); */
+ struct block_device_context *blkdev = dev_get_drvdata(&dev->device);
+ unsigned long flags;
- blkvsc_req->cmd_len = 16;
+ if (!blkdev)
+ return;
- if (blkvsc_req->sector_start > 0xffffffff) {
- if (rq_data_dir(blkvsc_req->req)) {
- blkvsc_req->write = 1;
- blkvsc_req->cmnd[0] = WRITE_16;
- } else {
- blkvsc_req->write = 0;
- blkvsc_req->cmnd[0] = READ_16;
- }
+ spin_lock_irqsave(&blkdev->lock, flags);
- blkvsc_req->cmnd[1] |=
- (blkvsc_req->req->cmd_flags & REQ_FUA) ? 0x8 : 0;
-
- *(unsigned long long *)&blkvsc_req->cmnd[2] =
- cpu_to_be64(blkvsc_req->sector_start);
- *(unsigned int *)&blkvsc_req->cmnd[10] =
- cpu_to_be32(blkvsc_req->sector_count);
- } else if ((blkvsc_req->sector_count > 0xff) ||
- (blkvsc_req->sector_start > 0x1fffff)) {
- if (rq_data_dir(blkvsc_req->req)) {
- blkvsc_req->write = 1;
- blkvsc_req->cmnd[0] = WRITE_10;
- } else {
- blkvsc_req->write = 0;
- blkvsc_req->cmnd[0] = READ_10;
- }
+ blkdev->shutting_down = 1;
- blkvsc_req->cmnd[1] |=
- (blkvsc_req->req->cmd_flags & REQ_FUA) ? 0x8 : 0;
+ blk_stop_queue(blkdev->gd->queue);
- *(unsigned int *)&blkvsc_req->cmnd[2] =
- cpu_to_be32(blkvsc_req->sector_start);
- *(unsigned short *)&blkvsc_req->cmnd[7] =
- cpu_to_be16(blkvsc_req->sector_count);
- } else {
- if (rq_data_dir(blkvsc_req->req)) {
- blkvsc_req->write = 1;
- blkvsc_req->cmnd[0] = WRITE_6;
- } else {
- blkvsc_req->write = 0;
- blkvsc_req->cmnd[0] = READ_6;
- }
+ blkvsc_cancel_pending_reqs(blkdev);
- *(unsigned int *)&blkvsc_req->cmnd[1] =
- cpu_to_be32(blkvsc_req->sector_start) >> 8;
- blkvsc_req->cmnd[1] &= 0x1f;
- blkvsc_req->cmnd[4] = (unsigned char)blkvsc_req->sector_count;
- }
-}
+ spin_unlock_irqrestore(&blkdev->lock, flags);
-static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req,
- void (*request_completion)(struct hv_storvsc_request *))
-{
- struct block_device_context *blkdev = blkvsc_req->dev;
- struct vm_device *device_ctx = blkdev->device_ctx;
- struct driver_context *driver_ctx =
- driver_to_driver_context(device_ctx->device.driver);
- struct blkvsc_driver_context *blkvsc_drv_ctx =
- (struct blkvsc_driver_context *)driver_ctx;
- struct storvsc_driver_object *storvsc_drv_obj =
- &blkvsc_drv_ctx->drv_obj;
- struct hv_storvsc_request *storvsc_req;
- int ret;
+ blkvsc_do_operation(blkdev, DO_FLUSH);
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_submit_request() - "
- "req %p type %s start_sector %lu count %ld offset %d "
- "len %d\n", blkvsc_req,
- (blkvsc_req->write) ? "WRITE" : "READ",
- (unsigned long) blkvsc_req->sector_start,
- blkvsc_req->sector_count,
- blkvsc_req->request.DataBuffer.Offset,
- blkvsc_req->request.DataBuffer.Length);
-#if 0
- for (i = 0; i < (blkvsc_req->request.DataBuffer.Length >> 12); i++) {
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_submit_request() - "
- "req %p pfn[%d] %llx\n",
- blkvsc_req, i,
- blkvsc_req->request.DataBuffer.PfnArray[i]);
- }
-#endif
+ /*
+ * Now wait for all outgoing I/O to be drained.
+ */
+ storvsc_wait_to_drain((struct storvsc_device *)dev->ext);
- storvsc_req = &blkvsc_req->request;
- storvsc_req->Extension = (void *)((unsigned long)blkvsc_req +
- sizeof(struct blkvsc_request));
+}
- storvsc_req->Type = blkvsc_req->write ? WRITE_TYPE : READ_TYPE;
+static int blkvsc_release(struct gendisk *disk, fmode_t mode)
+{
+ struct block_device_context *blkdev = disk->private_data;
+ unsigned long flags;
- storvsc_req->OnIOCompletion = request_completion;
- storvsc_req->Context = blkvsc_req;
+ spin_lock_irqsave(&blkdev->lock, flags);
- storvsc_req->Host = blkdev->port;
- storvsc_req->Bus = blkdev->path;
- storvsc_req->TargetId = blkdev->target;
- storvsc_req->LunId = 0; /* this is not really used at all */
+ if ((--blkdev->users == 0) && (blkdev->shutting_down)) {
+ blk_stop_queue(blkdev->gd->queue);
+ spin_unlock_irqrestore(&blkdev->lock, flags);
- storvsc_req->CdbLen = blkvsc_req->cmd_len;
- storvsc_req->Cdb = blkvsc_req->cmnd;
+ blkvsc_do_operation(blkdev, DO_FLUSH);
+ del_gendisk(blkdev->gd);
+ put_disk(blkdev->gd);
+ blk_cleanup_queue(blkdev->gd->queue);
- storvsc_req->SenseBuffer = blkvsc_req->sense_buffer;
- storvsc_req->SenseBufferSize = SCSI_SENSE_BUFFERSIZE;
+ storvsc_dev_remove(blkdev->device_ctx);
- ret = storvsc_drv_obj->OnIORequest(&blkdev->device_ctx->device_obj,
- &blkvsc_req->request);
- if (ret == 0)
- blkdev->num_outstanding_reqs++;
+ kmem_cache_destroy(blkdev->request_pool);
+ kfree(blkdev);
+ } else
+ spin_unlock_irqrestore(&blkdev->lock, flags);
- return ret;
+ return 0;
}
+
/*
* We break the request into 1 or more blkvsc_requests and submit
* them. If we cant submit them all, we put them on the
@@ -926,11 +607,8 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
int pending = 0;
struct blkvsc_request_group *group = NULL;
- DPRINT_DBG(BLKVSC_DRV, "blkdev %p req %p sect %lu\n", blkdev, req,
- (unsigned long)blk_rq_pos(req));
-
/* Create a group to tie req to list of blkvsc_reqs */
- group = kmem_cache_alloc(blkdev->request_pool, GFP_ATOMIC);
+ group = kmem_cache_zalloc(blkdev->request_pool, GFP_ATOMIC);
if (!group)
return -ENOMEM;
@@ -946,11 +624,6 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
* Map this bio into an existing or new storvsc request
*/
bio_for_each_segment(bvec, bio, seg_idx) {
- DPRINT_DBG(BLKVSC_DRV, "bio_for_each_segment() "
- "- req %p bio %p bvec %p seg_idx %d "
- "databuf_idx %d\n", req, bio, bvec,
- seg_idx, databuf_idx);
-
/* Get a new storvsc request */
/* 1st-time */
if ((!blkvsc_req) ||
@@ -962,10 +635,15 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
(prev_bvec->bv_len != PAGE_SIZE))) {
/* submit the prev one */
if (blkvsc_req) {
- blkvsc_req->sector_start = start_sector;
- sector_div(blkvsc_req->sector_start, (blkdev->sector_size >> 9));
-
- blkvsc_req->sector_count = num_sectors / (blkdev->sector_size >> 9);
+ blkvsc_req->sector_start =
+ start_sector;
+ sector_div(
+ blkvsc_req->sector_start,
+ (blkdev->sector_size >> 9));
+
+ blkvsc_req->sector_count =
+ num_sectors /
+ (blkdev->sector_size >> 9);
blkvsc_init_rw(blkvsc_req);
}
@@ -973,18 +651,24 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
* Create new blkvsc_req to represent
* the current bvec
*/
- blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_ATOMIC);
+ blkvsc_req =
+ kmem_cache_zalloc(
+ blkdev->request_pool, GFP_ATOMIC);
if (!blkvsc_req) {
/* free up everything */
list_for_each_entry_safe(
blkvsc_req, tmp,
&group->blkvsc_req_list,
req_entry) {
- list_del(&blkvsc_req->req_entry);
- kmem_cache_free(blkdev->request_pool, blkvsc_req);
+ list_del(
+ &blkvsc_req->req_entry);
+ kmem_cache_free(
+ blkdev->request_pool,
+ blkvsc_req);
}
- kmem_cache_free(blkdev->request_pool, group);
+ kmem_cache_free(
+ blkdev->request_pool, group);
return -ENOMEM;
}
@@ -993,23 +677,32 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
blkvsc_req->dev = blkdev;
blkvsc_req->req = req;
- blkvsc_req->request.DataBuffer.Offset = bvec->bv_offset;
- blkvsc_req->request.DataBuffer.Length = 0;
+ blkvsc_req->request.
+ data_buffer.offset
+ = bvec->bv_offset;
+ blkvsc_req->request.
+ data_buffer.len = 0;
/* Add to the group */
blkvsc_req->group = group;
blkvsc_req->group->outstanding++;
list_add_tail(&blkvsc_req->req_entry,
- &blkvsc_req->group->blkvsc_req_list);
+ &blkvsc_req->group->blkvsc_req_list);
start_sector += num_sectors;
num_sectors = 0;
databuf_idx = 0;
}
- /* Add the curr bvec/segment to the curr blkvsc_req */
- blkvsc_req->request.DataBuffer.PfnArray[databuf_idx] = page_to_pfn(bvec->bv_page);
- blkvsc_req->request.DataBuffer.Length += bvec->bv_len;
+ /*
+ * Add the curr bvec/segment to the curr
+ * blkvsc_req
+ */
+ blkvsc_req->request.data_buffer.
+ pfn_array[databuf_idx]
+ = page_to_pfn(bvec->bv_page);
+ blkvsc_req->request.data_buffer.len
+ += bvec->bv_len;
prev_bvec = bvec;
@@ -1023,10 +716,6 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
/* Handle the last one */
if (blkvsc_req) {
- DPRINT_DBG(BLKVSC_DRV, "blkdev %p req %p group %p count %d\n",
- blkdev, req, blkvsc_req->group,
- blkvsc_req->group->outstanding);
-
blkvsc_req->sector_start = start_sector;
sector_div(blkvsc_req->sector_start,
(blkdev->sector_size >> 9));
@@ -1039,13 +728,6 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
list_for_each_entry(blkvsc_req, &group->blkvsc_req_list, req_entry) {
if (pending) {
- DPRINT_DBG(BLKVSC_DRV, "adding blkvsc_req to "
- "pending_list - blkvsc_req %p start_sect %lu"
- " sect_count %ld (%lu %ld)\n", blkvsc_req,
- (unsigned long)blkvsc_req->sector_start,
- blkvsc_req->sector_count,
- (unsigned long)start_sector,
- (unsigned long)num_sectors);
list_add_tail(&blkvsc_req->pend_entry,
&blkdev->pending_list);
@@ -1058,186 +740,12 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
&blkdev->pending_list);
}
- DPRINT_DBG(BLKVSC_DRV, "submitted blkvsc_req %p "
- "start_sect %lu sect_count %ld (%lu %ld) "
- "ret %d\n", blkvsc_req,
- (unsigned long)blkvsc_req->sector_start,
- blkvsc_req->sector_count,
- (unsigned long)start_sector,
- num_sectors, ret);
}
}
return pending;
}
-static void blkvsc_cmd_completion(struct hv_storvsc_request *request)
-{
- struct blkvsc_request *blkvsc_req =
- (struct blkvsc_request *)request->Context;
- struct block_device_context *blkdev =
- (struct block_device_context *)blkvsc_req->dev;
- struct scsi_sense_hdr sense_hdr;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_cmd_completion() - req %p\n",
- blkvsc_req);
-
- blkdev->num_outstanding_reqs--;
-
- if (blkvsc_req->request.Status)
- if (scsi_normalize_sense(blkvsc_req->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr))
- scsi_print_sense_hdr("blkvsc", &sense_hdr);
-
- blkvsc_req->cond = 1;
- wake_up_interruptible(&blkvsc_req->wevent);
-}
-
-static void blkvsc_request_completion(struct hv_storvsc_request *request)
-{
- struct blkvsc_request *blkvsc_req =
- (struct blkvsc_request *)request->Context;
- struct block_device_context *blkdev =
- (struct block_device_context *)blkvsc_req->dev;
- unsigned long flags;
- struct blkvsc_request *comp_req, *tmp;
-
- /* ASSERT(blkvsc_req->group); */
-
- DPRINT_DBG(BLKVSC_DRV, "blkdev %p blkvsc_req %p group %p type %s "
- "sect_start %lu sect_count %ld len %d group outstd %d "
- "total outstd %d\n",
- blkdev, blkvsc_req, blkvsc_req->group,
- (blkvsc_req->write) ? "WRITE" : "READ",
- (unsigned long)blkvsc_req->sector_start,
- blkvsc_req->sector_count,
- blkvsc_req->request.DataBuffer.Length,
- blkvsc_req->group->outstanding,
- blkdev->num_outstanding_reqs);
-
- spin_lock_irqsave(&blkdev->lock, flags);
-
- blkdev->num_outstanding_reqs--;
- blkvsc_req->group->outstanding--;
-
- /*
- * Only start processing when all the blkvsc_reqs are
- * completed. This guarantees no out-of-order blkvsc_req
- * completion when calling end_that_request_first()
- */
- if (blkvsc_req->group->outstanding == 0) {
- list_for_each_entry_safe(comp_req, tmp,
- &blkvsc_req->group->blkvsc_req_list,
- req_entry) {
- DPRINT_DBG(BLKVSC_DRV, "completing blkvsc_req %p "
- "sect_start %lu sect_count %ld\n",
- comp_req,
- (unsigned long)comp_req->sector_start,
- comp_req->sector_count);
-
- list_del(&comp_req->req_entry);
-
- if (!__blk_end_request(comp_req->req,
- (!comp_req->request.Status ? 0 : -EIO),
- comp_req->sector_count * blkdev->sector_size)) {
- /*
- * All the sectors have been xferred ie the
- * request is done
- */
- DPRINT_DBG(BLKVSC_DRV, "req %p COMPLETED\n",
- comp_req->req);
- kmem_cache_free(blkdev->request_pool,
- comp_req->group);
- }
-
- kmem_cache_free(blkdev->request_pool, comp_req);
- }
-
- if (!blkdev->shutting_down) {
- blkvsc_do_pending_reqs(blkdev);
- blk_start_queue(blkdev->gd->queue);
- blkvsc_request(blkdev->gd->queue);
- }
- }
-
- spin_unlock_irqrestore(&blkdev->lock, flags);
-}
-
-static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev)
-{
- struct blkvsc_request *pend_req, *tmp;
- struct blkvsc_request *comp_req, *tmp2;
-
- int ret = 0;
-
- DPRINT_DBG(BLKVSC_DRV, "blkvsc_cancel_pending_reqs()");
-
- /* Flush the pending list first */
- list_for_each_entry_safe(pend_req, tmp, &blkdev->pending_list,
- pend_entry) {
- /*
- * The pend_req could be part of a partially completed
- * request. If so, complete those req first until we
- * hit the pend_req
- */
- list_for_each_entry_safe(comp_req, tmp2,
- &pend_req->group->blkvsc_req_list,
- req_entry) {
- DPRINT_DBG(BLKVSC_DRV, "completing blkvsc_req %p "
- "sect_start %lu sect_count %ld\n",
- comp_req,
- (unsigned long) comp_req->sector_start,
- comp_req->sector_count);
-
- if (comp_req == pend_req)
- break;
-
- list_del(&comp_req->req_entry);
-
- if (comp_req->req) {
- ret = __blk_end_request(comp_req->req,
- (!comp_req->request.Status ? 0 : -EIO),
- comp_req->sector_count *
- blkdev->sector_size);
-
- /* FIXME: shouldn't this do more than return? */
- if (ret)
- goto out;
- }
-
- kmem_cache_free(blkdev->request_pool, comp_req);
- }
-
- DPRINT_DBG(BLKVSC_DRV, "cancelling pending request - %p\n",
- pend_req);
-
- list_del(&pend_req->pend_entry);
-
- list_del(&pend_req->req_entry);
-
- if (comp_req->req) {
- if (!__blk_end_request(pend_req->req, -EIO,
- pend_req->sector_count *
- blkdev->sector_size)) {
- /*
- * All the sectors have been xferred ie the
- * request is done
- */
- DPRINT_DBG(BLKVSC_DRV,
- "blkvsc_cancel_pending_reqs() - "
- "req %p COMPLETED\n", pend_req->req);
- kmem_cache_free(blkdev->request_pool,
- pend_req->group);
- }
- }
-
- kmem_cache_free(blkdev->request_pool, pend_req);
- }
-
-out:
- return ret;
-}
-
static int blkvsc_do_pending_reqs(struct block_device_context *blkdev)
{
struct blkvsc_request *pend_req, *tmp;
@@ -1246,8 +754,6 @@ static int blkvsc_do_pending_reqs(struct block_device_context *blkdev)
/* Flush the pending list first */
list_for_each_entry_safe(pend_req, tmp, &blkdev->pending_list,
pend_entry) {
- DPRINT_DBG(BLKVSC_DRV, "working off pending_list - %p\n",
- pend_req);
ret = blkvsc_submit_request(pend_req,
blkvsc_request_completion);
@@ -1260,19 +766,17 @@ static int blkvsc_do_pending_reqs(struct block_device_context *blkdev)
return ret;
}
+
static void blkvsc_request(struct request_queue *queue)
{
struct block_device_context *blkdev = NULL;
struct request *req;
int ret = 0;
- DPRINT_DBG(BLKVSC_DRV, "- enter\n");
while ((req = blk_peek_request(queue)) != NULL) {
- DPRINT_DBG(BLKVSC_DRV, "- req %p\n", req);
blkdev = req->rq_disk->private_data;
- if (blkdev->shutting_down || req->cmd_type != REQ_TYPE_FS ||
- blkdev->media_not_present) {
+ if (blkdev->shutting_down || req->cmd_type != REQ_TYPE_FS) {
__blk_end_request_cur(req, 0);
continue;
}
@@ -1280,8 +784,6 @@ static void blkvsc_request(struct request_queue *queue)
ret = blkvsc_do_pending_reqs(blkdev);
if (ret != 0) {
- DPRINT_DBG(BLKVSC_DRV,
- "- stop queue - pending_list not empty\n");
blk_stop_queue(queue);
break;
}
@@ -1290,11 +792,9 @@ static void blkvsc_request(struct request_queue *queue)
ret = blkvsc_do_request(blkdev, req);
if (ret > 0) {
- DPRINT_DBG(BLKVSC_DRV, "- stop queue - no room\n");
blk_stop_queue(queue);
break;
} else if (ret < 0) {
- DPRINT_DBG(BLKVSC_DRV, "- stop queue - no mem\n");
blk_requeue_request(queue, req);
blk_stop_queue(queue);
break;
@@ -1302,186 +802,216 @@ static void blkvsc_request(struct request_queue *queue)
}
}
-static int blkvsc_open(struct block_device *bdev, fmode_t mode)
-{
- struct block_device_context *blkdev = bdev->bd_disk->private_data;
-
- DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users,
- blkdev->gd->disk_name);
-
- spin_lock(&blkdev->lock);
- if (!blkdev->users && blkdev->device_type == DVD_TYPE) {
- spin_unlock(&blkdev->lock);
- check_disk_change(bdev);
- spin_lock(&blkdev->lock);
- }
- blkdev->users++;
+/* The one and only one */
+static struct hv_driver blkvsc_drv = {
+ .probe = blkvsc_probe,
+ .remove = blkvsc_remove,
+ .shutdown = blkvsc_shutdown,
+};
- spin_unlock(&blkdev->lock);
- return 0;
-}
+static const struct block_device_operations block_ops = {
+ .owner = THIS_MODULE,
+ .open = blkvsc_open,
+ .release = blkvsc_release,
+ .getgeo = blkvsc_getgeo,
+ .ioctl = blkvsc_ioctl,
+};
-static int blkvsc_release(struct gendisk *disk, fmode_t mode)
+/*
+ * blkvsc_drv_init - BlkVsc driver initialization.
+ */
+static int blkvsc_drv_init(void)
{
- struct block_device_context *blkdev = disk->private_data;
+ struct hv_driver *drv = &blkvsc_drv;
+ int ret;
- DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users,
- blkdev->gd->disk_name);
+ BUILD_BUG_ON(sizeof(sector_t) != 8);
- spin_lock(&blkdev->lock);
- if (blkdev->users == 1) {
- spin_unlock(&blkdev->lock);
- blkvsc_do_flush(blkdev);
- spin_lock(&blkdev->lock);
- }
+ memcpy(&drv->dev_type, &dev_type, sizeof(struct hv_guid));
+ drv->driver.name = drv_name;
- blkdev->users--;
+ /* The driver belongs to vmbus */
+ ret = vmbus_child_driver_register(&drv->driver);
- spin_unlock(&blkdev->lock);
- return 0;
+ return ret;
}
-static int blkvsc_media_changed(struct gendisk *gd)
+
+static void blkvsc_drv_exit(void)
{
- DPRINT_DBG(BLKVSC_DRV, "- enter\n");
- return 1;
+
+ vmbus_child_driver_unregister(&blkvsc_drv.driver);
}
-static int blkvsc_revalidate_disk(struct gendisk *gd)
+/*
+ * blkvsc_probe - Add a new device for this driver
+ */
+static int blkvsc_probe(struct hv_device *dev)
{
- struct block_device_context *blkdev = gd->private_data;
-
- DPRINT_DBG(BLKVSC_DRV, "- enter\n");
+ struct block_device_context *blkdev = NULL;
+ struct storvsc_device_info device_info;
+ struct storvsc_major_info major_info;
+ int ret = 0;
- if (blkdev->device_type == DVD_TYPE) {
- blkvsc_do_read_capacity(blkdev);
- set_capacity(blkdev->gd, blkdev->capacity *
- (blkdev->sector_size/512));
- blk_queue_logical_block_size(gd->queue, blkdev->sector_size);
+ blkdev = kzalloc(sizeof(struct block_device_context), GFP_KERNEL);
+ if (!blkdev) {
+ ret = -ENOMEM;
+ goto cleanup;
}
- return 0;
-}
-static int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg)
-{
- sector_t total_sectors = get_capacity(bd->bd_disk);
- sector_t cylinder_times_heads = 0;
- sector_t temp = 0;
+ INIT_LIST_HEAD(&blkdev->pending_list);
- int sectors_per_track = 0;
- int heads = 0;
- int cylinders = 0;
- int rem = 0;
+ /* Initialize what we can here */
+ spin_lock_init(&blkdev->lock);
- if (total_sectors > (65535 * 16 * 255))
- total_sectors = (65535 * 16 * 255);
- if (total_sectors >= (65535 * 16 * 63)) {
- sectors_per_track = 255;
- heads = 16;
+ blkdev->request_pool = kmem_cache_create(dev_name(&dev->device),
+ sizeof(struct blkvsc_request), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!blkdev->request_pool) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
- cylinder_times_heads = total_sectors;
- /* sector_div stores the quotient in cylinder_times_heads */
- rem = sector_div(cylinder_times_heads, sectors_per_track);
- } else {
- sectors_per_track = 17;
- cylinder_times_heads = total_sectors;
- /* sector_div stores the quotient in cylinder_times_heads */
- rem = sector_div(cylinder_times_heads, sectors_per_track);
+ ret = blkvsc_device_add(dev, &device_info);
+ if (ret != 0)
+ goto cleanup;
- temp = cylinder_times_heads + 1023;
- /* sector_div stores the quotient in temp */
- rem = sector_div(temp, 1024);
+ blkdev->device_ctx = dev;
+ /* this identified the device 0 or 1 */
+ blkdev->target = device_info.target_id;
+ /* this identified the ide ctrl 0 or 1 */
+ blkdev->path = device_info.path_id;
- heads = temp;
+ dev_set_drvdata(&dev->device, blkdev);
- if (heads < 4)
- heads = 4;
+ ret = storvsc_get_major_info(&device_info, &major_info);
+ if (ret)
+ goto cleanup;
- if (cylinder_times_heads >= (heads * 1024) || (heads > 16)) {
- sectors_per_track = 31;
- heads = 16;
+ if (major_info.do_register) {
+ ret = register_blkdev(major_info.major, major_info.devname);
- cylinder_times_heads = total_sectors;
- /*
- * sector_div stores the quotient in
- * cylinder_times_heads
- */
- rem = sector_div(cylinder_times_heads,
- sectors_per_track);
+ if (ret != 0) {
+ DPRINT_ERR(BLKVSC_DRV,
+ "register_blkdev() failed! ret %d", ret);
+ goto remove;
}
+ }
- if (cylinder_times_heads >= (heads * 1024)) {
- sectors_per_track = 63;
- heads = 16;
+ DPRINT_INFO(BLKVSC_DRV, "blkvsc registered for major %d!!",
+ major_info.major);
- cylinder_times_heads = total_sectors;
- /*
- * sector_div stores the quotient in
- * cylinder_times_heads
- */
- rem = sector_div(cylinder_times_heads,
- sectors_per_track);
- }
+ blkdev->gd = alloc_disk(BLKVSC_MINORS);
+ if (!blkdev->gd) {
+ ret = -1;
+ goto cleanup;
}
- temp = cylinder_times_heads;
- /* sector_div stores the quotient in temp */
- rem = sector_div(temp, heads);
- cylinders = temp;
+ blkdev->gd->queue = blk_init_queue(blkvsc_request, &blkdev->lock);
- hg->heads = heads;
- hg->sectors = sectors_per_track;
- hg->cylinders = cylinders;
+ blk_queue_max_segment_size(blkdev->gd->queue, PAGE_SIZE);
+ blk_queue_max_segments(blkdev->gd->queue, MAX_MULTIPAGE_BUFFER_COUNT);
+ blk_queue_segment_boundary(blkdev->gd->queue, PAGE_SIZE-1);
+ blk_queue_bounce_limit(blkdev->gd->queue, BLK_BOUNCE_ANY);
+ blk_queue_dma_alignment(blkdev->gd->queue, 511);
- DPRINT_INFO(BLKVSC_DRV, "CHS (%d, %d, %d)", cylinders, heads,
- sectors_per_track);
+ blkdev->gd->major = major_info.major;
+ if (major_info.index == 1 || major_info.index == 3)
+ blkdev->gd->first_minor = BLKVSC_MINORS;
+ else
+ blkdev->gd->first_minor = 0;
+ blkdev->gd->fops = &block_ops;
+ blkdev->gd->private_data = blkdev;
+ blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device);
+ sprintf(blkdev->gd->disk_name, "hd%c", 'a' + major_info.index);
- return 0;
-}
+ blkvsc_do_operation(blkdev, DO_INQUIRY);
+ blkvsc_do_operation(blkdev, DO_CAPACITY);
-static int blkvsc_ioctl(struct block_device *bd, fmode_t mode,
- unsigned cmd, unsigned long argument)
-{
-/* struct block_device_context *blkdev = bd->bd_disk->private_data; */
- int ret;
+ set_capacity(blkdev->gd, blkdev->capacity * (blkdev->sector_size/512));
+ blk_queue_logical_block_size(blkdev->gd->queue, blkdev->sector_size);
+ /* go! */
+ add_disk(blkdev->gd);
- switch (cmd) {
- /*
- * TODO: I think there is certain format for HDIO_GET_IDENTITY rather
- * than just a GUID. Commented it out for now.
- */
-#if 0
- case HDIO_GET_IDENTITY:
- DPRINT_INFO(BLKVSC_DRV, "HDIO_GET_IDENTITY\n");
- if (copy_to_user((void __user *)arg, blkdev->device_id,
- blkdev->device_id_len))
- ret = -EFAULT;
- break;
-#endif
- default:
- ret = -EINVAL;
- break;
+ DPRINT_INFO(BLKVSC_DRV, "%s added!! capacity %lu sector_size %d",
+ blkdev->gd->disk_name, (unsigned long)blkdev->capacity,
+ blkdev->sector_size);
+
+ return ret;
+
+remove:
+ storvsc_dev_remove(dev);
+
+cleanup:
+ if (blkdev) {
+ if (blkdev->request_pool) {
+ kmem_cache_destroy(blkdev->request_pool);
+ blkdev->request_pool = NULL;
+ }
+ kfree(blkdev);
+ blkdev = NULL;
}
return ret;
}
-static int __init blkvsc_init(void)
+static void blkvsc_request_completion(struct hv_storvsc_request *request)
{
- int ret;
+ struct blkvsc_request *blkvsc_req =
+ (struct blkvsc_request *)request->context;
+ struct block_device_context *blkdev =
+ (struct block_device_context *)blkvsc_req->dev;
+ unsigned long flags;
+ struct blkvsc_request *comp_req, *tmp;
+ struct vmscsi_request *vm_srb;
- BUILD_BUG_ON(sizeof(sector_t) != 8);
- DPRINT_INFO(BLKVSC_DRV, "Blkvsc initializing....");
+ spin_lock_irqsave(&blkdev->lock, flags);
- ret = blkvsc_drv_init(BlkVscInitialize);
+ blkdev->num_outstanding_reqs--;
+ blkvsc_req->group->outstanding--;
- return ret;
+ /*
+ * Only start processing when all the blkvsc_reqs are
+ * completed. This guarantees no out-of-order blkvsc_req
+ * completion when calling end_that_request_first()
+ */
+ if (blkvsc_req->group->outstanding == 0) {
+ list_for_each_entry_safe(comp_req, tmp,
+ &blkvsc_req->group->blkvsc_req_list,
+ req_entry) {
+
+ list_del(&comp_req->req_entry);
+
+ vm_srb =
+ &comp_req->request.vstor_packet.vm_srb;
+ if (!__blk_end_request(comp_req->req,
+ (!vm_srb->scsi_status ? 0 : -EIO),
+ comp_req->sector_count * blkdev->sector_size)) {
+ /*
+ * All the sectors have been xferred ie the
+ * request is done
+ */
+ kmem_cache_free(blkdev->request_pool,
+ comp_req->group);
+ }
+
+ kmem_cache_free(blkdev->request_pool, comp_req);
+ }
+
+ if (!blkdev->shutting_down) {
+ blkvsc_do_pending_reqs(blkdev);
+ blk_start_queue(blkdev->gd->queue);
+ blkvsc_request(blkdev->gd->queue);
+ }
+ }
+
+ spin_unlock_irqrestore(&blkdev->lock, flags);
}
static void __exit blkvsc_exit(void)
@@ -1492,5 +1022,5 @@ static void __exit blkvsc_exit(void)
MODULE_LICENSE("GPL");
MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V virtual block driver");
-module_init(blkvsc_init);
+module_init(blkvsc_drv_init);
module_exit(blkvsc_exit);
diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c
new file mode 100644
index 000000000000..cffca7c9143d
--- /dev/null
+++ b/drivers/staging/hv/channel.c
@@ -0,0 +1,877 @@
+/*
+ * 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/slab.h>
+#include <linux/module.h>
+
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
+
+#define NUM_PAGES_SPANNED(addr, len) \
+((PAGE_ALIGN(addr + len) >> PAGE_SHIFT) - (addr >> PAGE_SHIFT))
+
+/* Internal routines */
+static int create_gpadl_header(
+ void *kbuffer, /* must be phys and virt contiguous */
+ u32 size, /* page-size multiple */
+ struct vmbus_channel_msginfo **msginfo,
+ u32 *messagecount);
+static void vmbus_setevent(struct vmbus_channel *channel);
+
+/*
+ * vmbus_setevent- Trigger an event notification on the specified
+ * channel.
+ */
+static void vmbus_setevent(struct vmbus_channel *channel)
+{
+ struct hv_monitor_page *monitorpage;
+
+ if (channel->offermsg.monitor_allocated) {
+ /* Each u32 represents 32 channels */
+ sync_set_bit(channel->offermsg.child_relid & 31,
+ (unsigned long *) vmbus_connection.send_int_page +
+ (channel->offermsg.child_relid >> 5));
+
+ monitorpage = vmbus_connection.monitor_pages;
+ monitorpage++; /* Get the child to parent monitor page */
+
+ sync_set_bit(channel->monitor_bit,
+ (unsigned long *)&monitorpage->trigger_group
+ [channel->monitor_grp].pending);
+
+ } else {
+ vmbus_set_event(channel->offermsg.child_relid);
+ }
+}
+
+/*
+ * vmbus_get_debug_info -Retrieve various channel debug info
+ */
+void vmbus_get_debug_info(struct vmbus_channel *channel,
+ struct vmbus_channel_debug_info *debuginfo)
+{
+ struct hv_monitor_page *monitorpage;
+ u8 monitor_group = (u8)channel->offermsg.monitorid / 32;
+ u8 monitor_offset = (u8)channel->offermsg.monitorid % 32;
+ /* u32 monitorBit = 1 << monitorOffset; */
+
+ debuginfo->relid = channel->offermsg.child_relid;
+ debuginfo->state = channel->state;
+ memcpy(&debuginfo->interfacetype,
+ &channel->offermsg.offer.if_type, sizeof(struct hv_guid));
+ memcpy(&debuginfo->interface_instance,
+ &channel->offermsg.offer.if_instance,
+ sizeof(struct hv_guid));
+
+ monitorpage = (struct hv_monitor_page *)vmbus_connection.monitor_pages;
+
+ debuginfo->monitorid = channel->offermsg.monitorid;
+
+ debuginfo->servermonitor_pending =
+ monitorpage->trigger_group[monitor_group].pending;
+ debuginfo->servermonitor_latency =
+ monitorpage->latency[monitor_group][monitor_offset];
+ debuginfo->servermonitor_connectionid =
+ monitorpage->parameter[monitor_group]
+ [monitor_offset].connectionid.u.id;
+
+ monitorpage++;
+
+ debuginfo->clientmonitor_pending =
+ monitorpage->trigger_group[monitor_group].pending;
+ debuginfo->clientmonitor_latency =
+ monitorpage->latency[monitor_group][monitor_offset];
+ debuginfo->clientmonitor_connectionid =
+ monitorpage->parameter[monitor_group]
+ [monitor_offset].connectionid.u.id;
+
+ hv_ringbuffer_get_debuginfo(&channel->inbound, &debuginfo->inbound);
+ hv_ringbuffer_get_debuginfo(&channel->outbound, &debuginfo->outbound);
+}
+
+/*
+ * vmbus_open - Open the specified channel.
+ */
+int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
+ u32 recv_ringbuffer_size, void *userdata, u32 userdatalen,
+ void (*onchannelcallback)(void *context), void *context)
+{
+ struct vmbus_channel_open_channel *openMsg;
+ struct vmbus_channel_msginfo *openInfo = NULL;
+ void *in, *out;
+ unsigned long flags;
+ int ret, t, err = 0;
+
+ newchannel->onchannel_callback = onchannelcallback;
+ newchannel->channel_callback_context = context;
+
+ /* Allocate the ring buffer */
+ out = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
+ get_order(send_ringbuffer_size + recv_ringbuffer_size));
+
+ if (!out)
+ return -ENOMEM;
+
+
+ in = (void *)((unsigned long)out + send_ringbuffer_size);
+
+ newchannel->ringbuffer_pages = out;
+ newchannel->ringbuffer_pagecount = (send_ringbuffer_size +
+ recv_ringbuffer_size) >> PAGE_SHIFT;
+
+ ret = hv_ringbuffer_init(
+ &newchannel->outbound, out, send_ringbuffer_size);
+
+ if (ret != 0) {
+ err = ret;
+ goto errorout;
+ }
+
+ ret = hv_ringbuffer_init(
+ &newchannel->inbound, in, recv_ringbuffer_size);
+ if (ret != 0) {
+ err = ret;
+ goto errorout;
+ }
+
+
+ /* Establish the gpadl for the ring buffer */
+ newchannel->ringbuffer_gpadlhandle = 0;
+
+ ret = vmbus_establish_gpadl(newchannel,
+ newchannel->outbound.ring_buffer,
+ send_ringbuffer_size +
+ recv_ringbuffer_size,
+ &newchannel->ringbuffer_gpadlhandle);
+
+ if (ret != 0) {
+ err = ret;
+ goto errorout;
+ }
+
+ /* Create and init the channel open message */
+ openInfo = kmalloc(sizeof(*openInfo) +
+ sizeof(struct vmbus_channel_open_channel),
+ GFP_KERNEL);
+ if (!openInfo) {
+ err = -ENOMEM;
+ goto errorout;
+ }
+
+ init_completion(&openInfo->waitevent);
+
+ openMsg = (struct vmbus_channel_open_channel *)openInfo->msg;
+ openMsg->header.msgtype = CHANNELMSG_OPENCHANNEL;
+ openMsg->openid = newchannel->offermsg.child_relid;
+ openMsg->child_relid = newchannel->offermsg.child_relid;
+ openMsg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle;
+ openMsg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >>
+ PAGE_SHIFT;
+ openMsg->server_contextarea_gpadlhandle = 0;
+
+ if (userdatalen > MAX_USER_DEFINED_BYTES) {
+ err = -EINVAL;
+ goto errorout;
+ }
+
+ if (userdatalen)
+ memcpy(openMsg->userdata, userdata, userdatalen);
+
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_add_tail(&openInfo->msglistentry,
+ &vmbus_connection.chn_msg_list);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+
+ ret = vmbus_post_msg(openMsg,
+ sizeof(struct vmbus_channel_open_channel));
+
+ if (ret != 0)
+ goto cleanup;
+
+ t = wait_for_completion_timeout(&openInfo->waitevent, HZ);
+ if (t == 0) {
+ err = -ETIMEDOUT;
+ goto errorout;
+ }
+
+
+ if (openInfo->response.open_result.status)
+ err = openInfo->response.open_result.status;
+
+cleanup:
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_del(&openInfo->msglistentry);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+
+ kfree(openInfo);
+ return err;
+
+errorout:
+ hv_ringbuffer_cleanup(&newchannel->outbound);
+ hv_ringbuffer_cleanup(&newchannel->inbound);
+ free_pages((unsigned long)out,
+ get_order(send_ringbuffer_size + recv_ringbuffer_size));
+ kfree(openInfo);
+ return err;
+}
+EXPORT_SYMBOL_GPL(vmbus_open);
+
+/*
+ * dump_gpadl_body - Dump the gpadl body message to the console for
+ * debugging purposes.
+ */
+static void dump_gpadl_body(struct vmbus_channel_gpadl_body *gpadl, u32 len)
+{
+ int i;
+ int pfncount;
+
+ pfncount = (len - sizeof(struct vmbus_channel_gpadl_body)) /
+ sizeof(u64);
+
+ DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", len, pfncount);
+
+ for (i = 0; i < pfncount; i++)
+ DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu",
+ i, gpadl->pfn[i]);
+}
+
+/*
+ * dump_gpadl_header - Dump the gpadl header message to the console for
+ * debugging purposes.
+ */
+static void dump_gpadl_header(struct vmbus_channel_gpadl_header *gpadl)
+{
+ int i, j;
+ int pagecount;
+
+ DPRINT_DBG(VMBUS,
+ "gpadl header - relid %d, range count %d, range buflen %d",
+ gpadl->child_relid, gpadl->rangecount, gpadl->range_buflen);
+ for (i = 0; i < gpadl->rangecount; i++) {
+ pagecount = gpadl->range[i].byte_count >> PAGE_SHIFT;
+ pagecount = (pagecount > 26) ? 26 : pagecount;
+
+ DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d "
+ "page count %d", i, gpadl->range[i].byte_count,
+ gpadl->range[i].byte_offset, pagecount);
+
+ for (j = 0; j < pagecount; j++)
+ DPRINT_DBG(VMBUS, "%d) pfn %llu", j,
+ gpadl->range[i].pfn_array[j]);
+ }
+}
+
+/*
+ * create_gpadl_header - Creates a gpadl for the specified buffer
+ */
+static int create_gpadl_header(void *kbuffer, u32 size,
+ struct vmbus_channel_msginfo **msginfo,
+ u32 *messagecount)
+{
+ int i;
+ int pagecount;
+ unsigned long long pfn;
+ struct vmbus_channel_gpadl_header *gpadl_header;
+ struct vmbus_channel_gpadl_body *gpadl_body;
+ struct vmbus_channel_msginfo *msgheader;
+ struct vmbus_channel_msginfo *msgbody = NULL;
+ u32 msgsize;
+
+ int pfnsum, pfncount, pfnleft, pfncurr, pfnsize;
+
+ pagecount = size >> PAGE_SHIFT;
+ pfn = virt_to_phys(kbuffer) >> PAGE_SHIFT;
+
+ /* do we need a gpadl body msg */
+ pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
+ sizeof(struct vmbus_channel_gpadl_header) -
+ sizeof(struct gpa_range);
+ pfncount = pfnsize / sizeof(u64);
+
+ if (pagecount > pfncount) {
+ /* we need a gpadl body */
+ /* fill in the header */
+ msgsize = sizeof(struct vmbus_channel_msginfo) +
+ sizeof(struct vmbus_channel_gpadl_header) +
+ sizeof(struct gpa_range) + pfncount * sizeof(u64);
+ msgheader = kzalloc(msgsize, GFP_KERNEL);
+ if (!msgheader)
+ goto nomem;
+
+ INIT_LIST_HEAD(&msgheader->submsglist);
+ msgheader->msgsize = msgsize;
+
+ gpadl_header = (struct vmbus_channel_gpadl_header *)
+ msgheader->msg;
+ gpadl_header->rangecount = 1;
+ gpadl_header->range_buflen = sizeof(struct gpa_range) +
+ pagecount * sizeof(u64);
+ gpadl_header->range[0].byte_offset = 0;
+ gpadl_header->range[0].byte_count = size;
+ for (i = 0; i < pfncount; i++)
+ gpadl_header->range[0].pfn_array[i] = pfn+i;
+ *msginfo = msgheader;
+ *messagecount = 1;
+
+ pfnsum = pfncount;
+ pfnleft = pagecount - pfncount;
+
+ /* how many pfns can we fit */
+ pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
+ sizeof(struct vmbus_channel_gpadl_body);
+ pfncount = pfnsize / sizeof(u64);
+
+ /* fill in the body */
+ while (pfnleft) {
+ if (pfnleft > pfncount)
+ pfncurr = pfncount;
+ else
+ pfncurr = pfnleft;
+
+ msgsize = sizeof(struct vmbus_channel_msginfo) +
+ sizeof(struct vmbus_channel_gpadl_body) +
+ pfncurr * sizeof(u64);
+ msgbody = kzalloc(msgsize, GFP_KERNEL);
+
+ if (!msgbody) {
+ struct vmbus_channel_msginfo *pos = NULL;
+ struct vmbus_channel_msginfo *tmp = NULL;
+ /*
+ * Free up all the allocated messages.
+ */
+ list_for_each_entry_safe(pos, tmp,
+ &msgheader->submsglist,
+ msglistentry) {
+
+ list_del(&pos->msglistentry);
+ kfree(pos);
+ }
+
+ goto nomem;
+ }
+
+ msgbody->msgsize = msgsize;
+ (*messagecount)++;
+ gpadl_body =
+ (struct vmbus_channel_gpadl_body *)msgbody->msg;
+
+ /*
+ * Gpadl is u32 and we are using a pointer which could
+ * be 64-bit
+ * This is governed by the guest/host protocol and
+ * so the hypervisor gurantees that this is ok.
+ */
+ for (i = 0; i < pfncurr; i++)
+ gpadl_body->pfn[i] = pfn + pfnsum + i;
+
+ /* add to msg header */
+ list_add_tail(&msgbody->msglistentry,
+ &msgheader->submsglist);
+ pfnsum += pfncurr;
+ pfnleft -= pfncurr;
+ }
+ } else {
+ /* everything fits in a header */
+ msgsize = sizeof(struct vmbus_channel_msginfo) +
+ sizeof(struct vmbus_channel_gpadl_header) +
+ sizeof(struct gpa_range) + pagecount * sizeof(u64);
+ msgheader = kzalloc(msgsize, GFP_KERNEL);
+ if (msgheader == NULL)
+ goto nomem;
+ msgheader->msgsize = msgsize;
+
+ gpadl_header = (struct vmbus_channel_gpadl_header *)
+ msgheader->msg;
+ gpadl_header->rangecount = 1;
+ gpadl_header->range_buflen = sizeof(struct gpa_range) +
+ pagecount * sizeof(u64);
+ gpadl_header->range[0].byte_offset = 0;
+ gpadl_header->range[0].byte_count = size;
+ for (i = 0; i < pagecount; i++)
+ gpadl_header->range[0].pfn_array[i] = pfn+i;
+
+ *msginfo = msgheader;
+ *messagecount = 1;
+ }
+
+ return 0;
+nomem:
+ kfree(msgheader);
+ kfree(msgbody);
+ return -ENOMEM;
+}
+
+/*
+ * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer
+ *
+ * @channel: a channel
+ * @kbuffer: from kmalloc
+ * @size: page-size multiple
+ * @gpadl_handle: some funky thing
+ */
+int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
+ u32 size, u32 *gpadl_handle)
+{
+ struct vmbus_channel_gpadl_header *gpadlmsg;
+ struct vmbus_channel_gpadl_body *gpadl_body;
+ /* struct vmbus_channel_gpadl_created *gpadlCreated; */
+ struct vmbus_channel_msginfo *msginfo = NULL;
+ struct vmbus_channel_msginfo *submsginfo;
+ u32 msgcount;
+ struct list_head *curr;
+ u32 next_gpadl_handle;
+ unsigned long flags;
+ int ret = 0;
+ int t;
+
+ next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
+ atomic_inc(&vmbus_connection.next_gpadl_handle);
+
+ ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
+ if (ret)
+ return ret;
+
+ init_completion(&msginfo->waitevent);
+
+ gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg;
+ gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER;
+ gpadlmsg->child_relid = channel->offermsg.child_relid;
+ gpadlmsg->gpadl = next_gpadl_handle;
+
+ dump_gpadl_header(gpadlmsg);
+
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_add_tail(&msginfo->msglistentry,
+ &vmbus_connection.chn_msg_list);
+
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+
+ ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize -
+ sizeof(*msginfo));
+ if (ret != 0)
+ goto cleanup;
+
+ if (msgcount > 1) {
+ list_for_each(curr, &msginfo->submsglist) {
+
+ submsginfo = (struct vmbus_channel_msginfo *)curr;
+ gpadl_body =
+ (struct vmbus_channel_gpadl_body *)submsginfo->msg;
+
+ gpadl_body->header.msgtype =
+ CHANNELMSG_GPADL_BODY;
+ gpadl_body->gpadl = next_gpadl_handle;
+
+ dump_gpadl_body(gpadl_body, submsginfo->msgsize -
+ sizeof(*submsginfo));
+ ret = vmbus_post_msg(gpadl_body,
+ submsginfo->msgsize -
+ sizeof(*submsginfo));
+ if (ret != 0)
+ goto cleanup;
+
+ }
+ }
+ t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
+ BUG_ON(t == 0);
+
+
+ /* At this point, we received the gpadl created msg */
+ *gpadl_handle = gpadlmsg->gpadl;
+
+cleanup:
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_del(&msginfo->msglistentry);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+
+ kfree(msginfo);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_establish_gpadl);
+
+/*
+ * vmbus_teardown_gpadl -Teardown the specified GPADL handle
+ */
+int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
+{
+ struct vmbus_channel_gpadl_teardown *msg;
+ struct vmbus_channel_msginfo *info;
+ unsigned long flags;
+ int ret, t;
+
+ /* ASSERT(gpadl_handle != 0); */
+
+ info = kmalloc(sizeof(*info) +
+ sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ init_completion(&info->waitevent);
+
+ msg = (struct vmbus_channel_gpadl_teardown *)info->msg;
+
+ msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN;
+ msg->child_relid = channel->offermsg.child_relid;
+ msg->gpadl = gpadl_handle;
+
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_add_tail(&info->msglistentry,
+ &vmbus_connection.chn_msg_list);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+ ret = vmbus_post_msg(msg,
+ sizeof(struct vmbus_channel_gpadl_teardown));
+
+ BUG_ON(ret != 0);
+ t = wait_for_completion_timeout(&info->waitevent, 5*HZ);
+ BUG_ON(t == 0);
+
+ /* Received a torndown response */
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_del(&info->msglistentry);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+
+ kfree(info);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
+
+/*
+ * vmbus_close - Close the specified channel
+ */
+void vmbus_close(struct vmbus_channel *channel)
+{
+ struct vmbus_channel_close_channel *msg;
+ int ret;
+
+ /* Stop callback and cancel the timer asap */
+ channel->onchannel_callback = NULL;
+
+ /* Send a closing message */
+
+ msg = &channel->close_msg.msg;
+
+ msg->header.msgtype = CHANNELMSG_CLOSECHANNEL;
+ msg->child_relid = channel->offermsg.child_relid;
+
+ ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel));
+
+ BUG_ON(ret != 0);
+ /* Tear down the gpadl for the channel's ring buffer */
+ if (channel->ringbuffer_gpadlhandle)
+ vmbus_teardown_gpadl(channel,
+ channel->ringbuffer_gpadlhandle);
+
+ /* Cleanup the ring buffers for this channel */
+ hv_ringbuffer_cleanup(&channel->outbound);
+ hv_ringbuffer_cleanup(&channel->inbound);
+
+ free_pages((unsigned long)channel->ringbuffer_pages,
+ get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
+
+
+}
+EXPORT_SYMBOL_GPL(vmbus_close);
+
+/**
+ * vmbus_sendpacket() - Send the specified buffer on the given channel
+ * @channel: Pointer to vmbus_channel structure.
+ * @buffer: Pointer to the buffer you want to receive the data into.
+ * @bufferlen: Maximum size of what the the buffer will hold
+ * @requestid: Identifier of the request
+ * @type: Type of packet that is being send e.g. negotiate, time
+ * packet etc.
+ *
+ * Sends data in @buffer directly to hyper-v via the vmbus
+ * This will send the data unparsed to hyper-v.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
+ u32 bufferlen, u64 requestid,
+ enum vmbus_packet_type type, u32 flags)
+{
+ struct vmpacket_descriptor desc;
+ u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
+ u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
+ struct scatterlist bufferlist[3];
+ u64 aligned_data = 0;
+ int ret;
+
+
+ /* Setup the descriptor */
+ desc.type = type; /* VmbusPacketTypeDataInBand; */
+ desc.flags = flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
+ /* in 8-bytes granularity */
+ desc.offset8 = sizeof(struct vmpacket_descriptor) >> 3;
+ desc.len8 = (u16)(packetlen_aligned >> 3);
+ desc.trans_id = requestid;
+
+ sg_init_table(bufferlist, 3);
+ sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
+ sg_set_buf(&bufferlist[1], buffer, bufferlen);
+ sg_set_buf(&bufferlist[2], &aligned_data,
+ packetlen_aligned - packetlen);
+
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
+
+ if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
+ vmbus_setevent(channel);
+
+ return ret;
+}
+EXPORT_SYMBOL(vmbus_sendpacket);
+
+/*
+ * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer
+ * packets using a GPADL Direct packet type.
+ */
+int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
+ struct hv_page_buffer pagebuffers[],
+ u32 pagecount, void *buffer, u32 bufferlen,
+ u64 requestid)
+{
+ int ret;
+ int i;
+ struct vmbus_channel_packet_page_buffer desc;
+ u32 descsize;
+ u32 packetlen;
+ u32 packetlen_aligned;
+ struct scatterlist bufferlist[3];
+ u64 aligned_data = 0;
+
+ if (pagecount > MAX_PAGE_BUFFER_COUNT)
+ return -EINVAL;
+
+
+ /*
+ * Adjust the size down since vmbus_channel_packet_page_buffer is the
+ * largest size we support
+ */
+ descsize = sizeof(struct vmbus_channel_packet_page_buffer) -
+ ((MAX_PAGE_BUFFER_COUNT - pagecount) *
+ sizeof(struct hv_page_buffer));
+ packetlen = descsize + bufferlen;
+ packetlen_aligned = ALIGN(packetlen, sizeof(u64));
+
+ /* Setup the descriptor */
+ desc.type = VM_PKT_DATA_USING_GPA_DIRECT;
+ desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
+ desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
+ desc.length8 = (u16)(packetlen_aligned >> 3);
+ desc.transactionid = requestid;
+ desc.rangecount = pagecount;
+
+ for (i = 0; i < pagecount; i++) {
+ desc.range[i].len = pagebuffers[i].len;
+ desc.range[i].offset = pagebuffers[i].offset;
+ desc.range[i].pfn = pagebuffers[i].pfn;
+ }
+
+ sg_init_table(bufferlist, 3);
+ sg_set_buf(&bufferlist[0], &desc, descsize);
+ sg_set_buf(&bufferlist[1], buffer, bufferlen);
+ sg_set_buf(&bufferlist[2], &aligned_data,
+ packetlen_aligned - packetlen);
+
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
+
+ if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
+ vmbus_setevent(channel);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer);
+
+/*
+ * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
+ * using a GPADL Direct packet type.
+ */
+int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
+ struct hv_multipage_buffer *multi_pagebuffer,
+ void *buffer, u32 bufferlen, u64 requestid)
+{
+ int ret;
+ struct vmbus_channel_packet_multipage_buffer desc;
+ u32 descsize;
+ u32 packetlen;
+ u32 packetlen_aligned;
+ struct scatterlist bufferlist[3];
+ u64 aligned_data = 0;
+ u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
+ multi_pagebuffer->len);
+
+
+ if ((pfncount < 0) || (pfncount > MAX_MULTIPAGE_BUFFER_COUNT))
+ return -EINVAL;
+
+ /*
+ * Adjust the size down since vmbus_channel_packet_multipage_buffer is
+ * the largest size we support
+ */
+ descsize = sizeof(struct vmbus_channel_packet_multipage_buffer) -
+ ((MAX_MULTIPAGE_BUFFER_COUNT - pfncount) *
+ sizeof(u64));
+ packetlen = descsize + bufferlen;
+ packetlen_aligned = ALIGN(packetlen, sizeof(u64));
+
+
+ /* Setup the descriptor */
+ desc.type = VM_PKT_DATA_USING_GPA_DIRECT;
+ desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
+ desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
+ desc.length8 = (u16)(packetlen_aligned >> 3);
+ desc.transactionid = requestid;
+ desc.rangecount = 1;
+
+ desc.range.len = multi_pagebuffer->len;
+ desc.range.offset = multi_pagebuffer->offset;
+
+ memcpy(desc.range.pfn_array, multi_pagebuffer->pfn_array,
+ pfncount * sizeof(u64));
+
+ sg_init_table(bufferlist, 3);
+ sg_set_buf(&bufferlist[0], &desc, descsize);
+ sg_set_buf(&bufferlist[1], buffer, bufferlen);
+ sg_set_buf(&bufferlist[2], &aligned_data,
+ packetlen_aligned - packetlen);
+
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
+
+ if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
+ vmbus_setevent(channel);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
+
+/**
+ * vmbus_recvpacket() - Retrieve the user packet on the specified channel
+ * @channel: Pointer to vmbus_channel structure.
+ * @buffer: Pointer to the buffer you want to receive the data into.
+ * @bufferlen: Maximum size of what the the buffer will hold
+ * @buffer_actual_len: The actual size of the data after it was received
+ * @requestid: Identifier of the request
+ *
+ * Receives directly from the hyper-v vmbus and puts the data it received
+ * into Buffer. This will receive the data unparsed from hyper-v.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
+ u32 bufferlen, u32 *buffer_actual_len, u64 *requestid)
+{
+ struct vmpacket_descriptor desc;
+ u32 packetlen;
+ u32 userlen;
+ int ret;
+ unsigned long flags;
+
+ *buffer_actual_len = 0;
+ *requestid = 0;
+
+ spin_lock_irqsave(&channel->inbound_lock, flags);
+
+ ret = hv_ringbuffer_peek(&channel->inbound, &desc,
+ sizeof(struct vmpacket_descriptor));
+ if (ret != 0) {
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+ return 0;
+ }
+
+ packetlen = desc.len8 << 3;
+ userlen = packetlen - (desc.offset8 << 3);
+
+ *buffer_actual_len = userlen;
+
+ if (userlen > bufferlen) {
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+
+ pr_err("Buffer too small - got %d needs %d\n",
+ bufferlen, userlen);
+ return -ETOOSMALL;
+ }
+
+ *requestid = desc.trans_id;
+
+ /* Copy over the packet to the user buffer */
+ ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen,
+ (desc.offset8 << 3));
+
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(vmbus_recvpacket);
+
+/*
+ * vmbus_recvpacket_raw - Retrieve the raw packet on the specified channel
+ */
+int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
+ u32 bufferlen, u32 *buffer_actual_len,
+ u64 *requestid)
+{
+ struct vmpacket_descriptor desc;
+ u32 packetlen;
+ u32 userlen;
+ int ret;
+ unsigned long flags;
+
+ *buffer_actual_len = 0;
+ *requestid = 0;
+
+ spin_lock_irqsave(&channel->inbound_lock, flags);
+
+ ret = hv_ringbuffer_peek(&channel->inbound, &desc,
+ sizeof(struct vmpacket_descriptor));
+ if (ret != 0) {
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+ return 0;
+ }
+
+
+ packetlen = desc.len8 << 3;
+ userlen = packetlen - (desc.offset8 << 3);
+
+ *buffer_actual_len = packetlen;
+
+ if (packetlen > bufferlen) {
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+
+ pr_err("Buffer too small - needed %d bytes but "
+ "got space for only %d bytes\n",
+ packetlen, bufferlen);
+ return -2;
+ }
+
+ *requestid = desc.trans_id;
+
+ /* Copy over the entire packet to the user buffer */
+ ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0);
+
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
new file mode 100644
index 000000000000..bf011f3fb851
--- /dev/null
+++ b/drivers/staging/hv/channel_mgmt.c
@@ -0,0 +1,784 @@
+/*
+ * 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/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
+
+struct vmbus_channel_message_table_entry {
+ enum vmbus_channel_message_type message_type;
+ void (*message_handler)(struct vmbus_channel_message_header *msg);
+};
+
+#define MAX_MSG_TYPES 4
+#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 8
+
+static const struct hv_guid
+ supported_device_classes[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
+ /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
+ /* Storage - SCSI */
+ {
+ .data = {
+ 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
+ 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
+ }
+ },
+
+ /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
+ /* Network */
+ {
+ .data = {
+ 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
+ 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
+ }
+ },
+
+ /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
+ /* Input */
+ {
+ .data = {
+ 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
+ 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
+ }
+ },
+
+ /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
+ /* IDE */
+ {
+ .data = {
+ 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
+ 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
+ }
+ },
+ /* 0E0B6031-5213-4934-818B-38D90CED39DB */
+ /* Shutdown */
+ {
+ .data = {
+ 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
+ 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
+ }
+ },
+ /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
+ /* TimeSync */
+ {
+ .data = {
+ 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
+ 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
+ }
+ },
+ /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
+ /* Heartbeat */
+ {
+ .data = {
+ 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
+ 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
+ }
+ },
+ /* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
+ /* KVP */
+ {
+ .data = {
+ 0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
+ 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6
+ }
+ },
+
+};
+
+
+/**
+ * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
+ * @icmsghdrp: Pointer to msg header structure
+ * @icmsg_negotiate: Pointer to negotiate message structure
+ * @buf: Raw buffer channel data
+ *
+ * @icmsghdrp is of type &struct icmsg_hdr.
+ * @negop is of type &struct icmsg_negotiate.
+ * Set up and fill in default negotiate response message. This response can
+ * come from both the vmbus driver and the hv_utils driver. The current api
+ * will respond properly to both Windows 2008 and Windows 2008-R2 operating
+ * systems.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
+ struct icmsg_negotiate *negop,
+ u8 *buf)
+{
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ icmsghdrp->icmsgsize = 0x10;
+
+ negop = (struct icmsg_negotiate *)&buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ if (negop->icframe_vercnt == 2 &&
+ negop->icversion_data[1].major == 3) {
+ negop->icversion_data[0].major = 3;
+ negop->icversion_data[0].minor = 0;
+ negop->icversion_data[1].major = 3;
+ negop->icversion_data[1].minor = 0;
+ } else {
+ negop->icversion_data[0].major = 1;
+ negop->icversion_data[0].minor = 0;
+ negop->icversion_data[1].major = 1;
+ negop->icversion_data[1].minor = 0;
+ }
+
+ negop->icframe_vercnt = 1;
+ negop->icmsg_vercnt = 1;
+ }
+}
+EXPORT_SYMBOL(prep_negotiate_resp);
+
+/**
+ * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
+ * Hyper-V requests
+ * @context: Pointer to argument structure.
+ *
+ * Set up the default handler for non device driver specific requests
+ * from Hyper-V. This stub responds to the default negotiate messages
+ * that come in for every non IDE/SCSI/Network request.
+ * This behavior is normally overwritten in the hv_utils driver. That
+ * driver handles requests like graceful shutdown, heartbeats etc.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+void chn_cb_negotiate(void *context)
+{
+ struct vmbus_channel *channel = context;
+ u8 *buf;
+ u32 buflen, recvlen;
+ u64 requestid;
+
+ struct icmsg_hdr *icmsghdrp;
+ struct icmsg_negotiate *negop = NULL;
+
+ if (channel->util_index >= 0) {
+ /*
+ * This is a properly initialized util channel.
+ * Route this callback appropriately and setup state
+ * so that we don't need to reroute again.
+ */
+ if (hv_cb_utils[channel->util_index].callback != NULL) {
+ /*
+ * The util driver has established a handler for
+ * this service; do the magic.
+ */
+ channel->onchannel_callback =
+ hv_cb_utils[channel->util_index].callback;
+ (hv_cb_utils[channel->util_index].callback)(channel);
+ return;
+ }
+ }
+
+ buflen = PAGE_SIZE;
+ buf = kmalloc(buflen, GFP_ATOMIC);
+
+ vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
+
+ if (recvlen > 0) {
+ icmsghdrp = (struct icmsg_hdr *)&buf[
+ sizeof(struct vmbuspipe_hdr)];
+
+ prep_negotiate_resp(icmsghdrp, negop, buf);
+
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+ | ICMSGHDRFLAG_RESPONSE;
+
+ vmbus_sendpacket(channel, buf,
+ recvlen, requestid,
+ VM_PKT_DATA_INBAND, 0);
+ }
+
+ kfree(buf);
+}
+EXPORT_SYMBOL(chn_cb_negotiate);
+
+/*
+ * Function table used for message responses for non IDE/SCSI/Network type
+ * messages. (Such as KVP/Shutdown etc)
+ */
+struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
+ /* 0E0B6031-5213-4934-818B-38D90CED39DB */
+ /* Shutdown */
+ {
+ .msg_type = HV_SHUTDOWN_MSG,
+ .data = {
+ 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
+ 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
+ },
+ .log_msg = "Shutdown channel functionality initialized"
+ },
+
+ /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
+ /* TimeSync */
+ {
+ .msg_type = HV_TIMESYNC_MSG,
+ .data = {
+ 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
+ 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
+ },
+ .log_msg = "Timesync channel functionality initialized"
+ },
+ /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
+ /* Heartbeat */
+ {
+ .msg_type = HV_HEARTBEAT_MSG,
+ .data = {
+ 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
+ 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
+ },
+ .log_msg = "Heartbeat channel functionality initialized"
+ },
+ /* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
+ /* KVP */
+ {
+ .data = {
+ 0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
+ 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6
+ },
+ .log_msg = "KVP channel functionality initialized"
+ },
+};
+EXPORT_SYMBOL(hv_cb_utils);
+
+/*
+ * alloc_channel - Allocate and initialize a vmbus channel object
+ */
+static struct vmbus_channel *alloc_channel(void)
+{
+ struct vmbus_channel *channel;
+
+ channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
+ if (!channel)
+ return NULL;
+
+ spin_lock_init(&channel->inbound_lock);
+
+ channel->controlwq = create_workqueue("hv_vmbus_ctl");
+ if (!channel->controlwq) {
+ kfree(channel);
+ return NULL;
+ }
+
+ return channel;
+}
+
+/*
+ * release_hannel - Release the vmbus channel object itself
+ */
+static void release_channel(struct work_struct *work)
+{
+ struct vmbus_channel *channel = container_of(work,
+ struct vmbus_channel,
+ work);
+
+ destroy_workqueue(channel->controlwq);
+
+ kfree(channel);
+}
+
+/*
+ * free_channel - Release the resources used by the vmbus channel object
+ */
+void free_channel(struct vmbus_channel *channel)
+{
+
+ /*
+ * We have to release the channel's workqueue/thread in the vmbus's
+ * workqueue/thread context
+ * ie we can't destroy ourselves.
+ */
+ INIT_WORK(&channel->work, release_channel);
+ queue_work(vmbus_connection.work_queue, &channel->work);
+}
+
+
+
+/*
+ * vmbus_process_rescind_offer -
+ * Rescind the offer by initiating a device removal
+ */
+static void vmbus_process_rescind_offer(struct work_struct *work)
+{
+ struct vmbus_channel *channel = container_of(work,
+ struct vmbus_channel,
+ work);
+
+ vmbus_child_device_unregister(channel->device_obj);
+}
+
+/*
+ * vmbus_process_offer - Process the offer by creating a channel/device
+ * associated with this offer
+ */
+static void vmbus_process_offer(struct work_struct *work)
+{
+ struct vmbus_channel *newchannel = container_of(work,
+ struct vmbus_channel,
+ work);
+ struct vmbus_channel *channel;
+ bool fnew = true;
+ int ret;
+ int cnt;
+ unsigned long flags;
+
+ /* The next possible work is rescind handling */
+ INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
+
+ /* Make sure this is a new offer */
+ spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+
+ list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
+ if (!memcmp(&channel->offermsg.offer.if_type,
+ &newchannel->offermsg.offer.if_type,
+ sizeof(struct hv_guid)) &&
+ !memcmp(&channel->offermsg.offer.if_instance,
+ &newchannel->offermsg.offer.if_instance,
+ sizeof(struct hv_guid))) {
+ fnew = false;
+ break;
+ }
+ }
+
+ if (fnew)
+ list_add_tail(&newchannel->listentry,
+ &vmbus_connection.chn_list);
+
+ spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+
+ if (!fnew) {
+ free_channel(newchannel);
+ return;
+ }
+
+ /*
+ * Start the process of binding this offer to the driver
+ * We need to set the DeviceObject field before calling
+ * vmbus_child_dev_add()
+ */
+ newchannel->device_obj = vmbus_child_device_create(
+ &newchannel->offermsg.offer.if_type,
+ &newchannel->offermsg.offer.if_instance,
+ newchannel);
+
+ /*
+ * Add the new device to the bus. This will kick off device-driver
+ * binding which eventually invokes the device driver's AddDevice()
+ * method.
+ */
+ ret = vmbus_child_device_register(newchannel->device_obj);
+ if (ret != 0) {
+ pr_err("unable to add child device object (relid %d)\n",
+ newchannel->offermsg.child_relid);
+
+ spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ list_del(&newchannel->listentry);
+ spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+
+ free_channel(newchannel);
+ } else {
+ /*
+ * This state is used to indicate a successful open
+ * so that when we do close the channel normally, we
+ * can cleanup properly
+ */
+ newchannel->state = CHANNEL_OPEN_STATE;
+ newchannel->util_index = -1; /* Invalid index */
+
+ /* Open IC channels */
+ for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
+ if (memcmp(&newchannel->offermsg.offer.if_type,
+ &hv_cb_utils[cnt].data,
+ sizeof(struct hv_guid)) == 0 &&
+ vmbus_open(newchannel, 2 * PAGE_SIZE,
+ 2 * PAGE_SIZE, NULL, 0,
+ chn_cb_negotiate,
+ newchannel) == 0) {
+ hv_cb_utils[cnt].channel = newchannel;
+ newchannel->util_index = cnt;
+
+ pr_info("%s\n", hv_cb_utils[cnt].log_msg);
+
+ }
+ }
+ }
+}
+
+/*
+ * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
+ *
+ * We ignore all offers except network and storage offers. For each network and
+ * storage offers, we create a channel object and queue a work item to the
+ * channel object to process the offer synchronously
+ */
+static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_offer_channel *offer;
+ struct vmbus_channel *newchannel;
+ struct hv_guid *guidtype;
+ struct hv_guid *guidinstance;
+ int i;
+ int fsupported = 0;
+
+ offer = (struct vmbus_channel_offer_channel *)hdr;
+ for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
+ if (memcmp(&offer->offer.if_type,
+ &supported_device_classes[i],
+ sizeof(struct hv_guid)) == 0) {
+ fsupported = 1;
+ break;
+ }
+ }
+
+ if (!fsupported)
+ return;
+
+ guidtype = &offer->offer.if_type;
+ guidinstance = &offer->offer.if_instance;
+
+ /* Allocate the channel object and save this offer. */
+ newchannel = alloc_channel();
+ if (!newchannel) {
+ pr_err("Unable to allocate channel object\n");
+ return;
+ }
+
+ memcpy(&newchannel->offermsg, offer,
+ sizeof(struct vmbus_channel_offer_channel));
+ newchannel->monitor_grp = (u8)offer->monitorid / 32;
+ newchannel->monitor_bit = (u8)offer->monitorid % 32;
+
+ INIT_WORK(&newchannel->work, vmbus_process_offer);
+ queue_work(newchannel->controlwq, &newchannel->work);
+}
+
+/*
+ * vmbus_onoffer_rescind - Rescind offer handler.
+ *
+ * We queue a work item to process this offer synchronously
+ */
+static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_rescind_offer *rescind;
+ struct vmbus_channel *channel;
+
+ rescind = (struct vmbus_channel_rescind_offer *)hdr;
+ channel = relid2channel(rescind->child_relid);
+
+ if (channel == NULL)
+ /* Just return here, no channel found */
+ return;
+
+ /* work is initialized for vmbus_process_rescind_offer() from
+ * vmbus_process_offer() where the channel got created */
+ queue_work(channel->controlwq, &channel->work);
+}
+
+/*
+ * vmbus_onoffers_delivered -
+ * This is invoked when all offers have been delivered.
+ *
+ * Nothing to do here.
+ */
+static void vmbus_onoffers_delivered(
+ struct vmbus_channel_message_header *hdr)
+{
+}
+
+/*
+ * vmbus_onopen_result - Open result handler.
+ *
+ * This is invoked when we received a response to our channel open request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_open_result *result;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_open_channel *openmsg;
+ unsigned long flags;
+
+ result = (struct vmbus_channel_open_result *)hdr;
+
+ /*
+ * Find the open msg, copy the result and signal/unblock the wait event
+ */
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+
+ list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
+ msglistentry) {
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->msg;
+
+ if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
+ openmsg =
+ (struct vmbus_channel_open_channel *)msginfo->msg;
+ if (openmsg->child_relid == result->child_relid &&
+ openmsg->openid == result->openid) {
+ memcpy(&msginfo->response.open_result,
+ result,
+ sizeof(
+ struct vmbus_channel_open_result));
+ complete(&msginfo->waitevent);
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+}
+
+/*
+ * vmbus_ongpadl_created - GPADL created handler.
+ *
+ * This is invoked when we received a response to our gpadl create request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_gpadl_created *gpadlcreated;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_gpadl_header *gpadlheader;
+ unsigned long flags;
+
+ gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
+
+ /*
+ * Find the establish msg, copy the result and signal/unblock the wait
+ * event
+ */
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+
+ list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
+ msglistentry) {
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->msg;
+
+ if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
+ gpadlheader =
+ (struct vmbus_channel_gpadl_header *)requestheader;
+
+ if ((gpadlcreated->child_relid ==
+ gpadlheader->child_relid) &&
+ (gpadlcreated->gpadl == gpadlheader->gpadl)) {
+ memcpy(&msginfo->response.gpadl_created,
+ gpadlcreated,
+ sizeof(
+ struct vmbus_channel_gpadl_created));
+ complete(&msginfo->waitevent);
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+}
+
+/*
+ * vmbus_ongpadl_torndown - GPADL torndown handler.
+ *
+ * This is invoked when we received a response to our gpadl teardown request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void vmbus_ongpadl_torndown(
+ struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_gpadl_torndown *gpadl_torndown;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_gpadl_teardown *gpadl_teardown;
+ unsigned long flags;
+
+ gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
+
+ /*
+ * Find the open msg, copy the result and signal/unblock the wait event
+ */
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+
+ list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
+ msglistentry) {
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->msg;
+
+ if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
+ gpadl_teardown =
+ (struct vmbus_channel_gpadl_teardown *)requestheader;
+
+ if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
+ memcpy(&msginfo->response.gpadl_torndown,
+ gpadl_torndown,
+ sizeof(
+ struct vmbus_channel_gpadl_torndown));
+ complete(&msginfo->waitevent);
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+}
+
+/*
+ * vmbus_onversion_response - Version response handler
+ *
+ * This is invoked when we received a response to our initiate contact request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void vmbus_onversion_response(
+ struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_initiate_contact *initiate;
+ struct vmbus_channel_version_response *version_response;
+ unsigned long flags;
+
+ version_response = (struct vmbus_channel_version_response *)hdr;
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+
+ list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
+ msglistentry) {
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->msg;
+
+ if (requestheader->msgtype ==
+ CHANNELMSG_INITIATE_CONTACT) {
+ initiate =
+ (struct vmbus_channel_initiate_contact *)requestheader;
+ memcpy(&msginfo->response.version_response,
+ version_response,
+ sizeof(struct vmbus_channel_version_response));
+ complete(&msginfo->waitevent);
+ }
+ }
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+}
+
+/* Channel message dispatch table */
+static struct vmbus_channel_message_table_entry
+ channel_message_table[CHANNELMSG_COUNT] = {
+ {CHANNELMSG_INVALID, NULL},
+ {CHANNELMSG_OFFERCHANNEL, vmbus_onoffer},
+ {CHANNELMSG_RESCIND_CHANNELOFFER, vmbus_onoffer_rescind},
+ {CHANNELMSG_REQUESTOFFERS, NULL},
+ {CHANNELMSG_ALLOFFERS_DELIVERED, vmbus_onoffers_delivered},
+ {CHANNELMSG_OPENCHANNEL, NULL},
+ {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result},
+ {CHANNELMSG_CLOSECHANNEL, NULL},
+ {CHANNELMSG_GPADL_HEADER, NULL},
+ {CHANNELMSG_GPADL_BODY, NULL},
+ {CHANNELMSG_GPADL_CREATED, vmbus_ongpadl_created},
+ {CHANNELMSG_GPADL_TEARDOWN, NULL},
+ {CHANNELMSG_GPADL_TORNDOWN, vmbus_ongpadl_torndown},
+ {CHANNELMSG_RELID_RELEASED, NULL},
+ {CHANNELMSG_INITIATE_CONTACT, NULL},
+ {CHANNELMSG_VERSION_RESPONSE, vmbus_onversion_response},
+ {CHANNELMSG_UNLOAD, NULL},
+};
+
+/*
+ * vmbus_onmessage - Handler for channel protocol messages.
+ *
+ * This is invoked in the vmbus worker thread context.
+ */
+void vmbus_onmessage(void *context)
+{
+ struct hv_message *msg = context;
+ struct vmbus_channel_message_header *hdr;
+ int size;
+
+ hdr = (struct vmbus_channel_message_header *)msg->u.payload;
+ size = msg->header.payload_size;
+
+ if (hdr->msgtype >= CHANNELMSG_COUNT) {
+ pr_err("Received invalid channel message type %d size %d\n",
+ hdr->msgtype, size);
+ print_hex_dump_bytes("", DUMP_PREFIX_NONE,
+ (unsigned char *)msg->u.payload, size);
+ return;
+ }
+
+ if (channel_message_table[hdr->msgtype].message_handler)
+ channel_message_table[hdr->msgtype].message_handler(hdr);
+ else
+ pr_err("Unhandled channel message type %d\n", hdr->msgtype);
+}
+
+/*
+ * vmbus_request_offers - Send a request to get all our pending offers.
+ */
+int vmbus_request_offers(void)
+{
+ struct vmbus_channel_message_header *msg;
+ struct vmbus_channel_msginfo *msginfo;
+ int ret, t;
+
+ msginfo = kmalloc(sizeof(*msginfo) +
+ sizeof(struct vmbus_channel_message_header),
+ GFP_KERNEL);
+ if (!msginfo)
+ return -ENOMEM;
+
+ init_completion(&msginfo->waitevent);
+
+ msg = (struct vmbus_channel_message_header *)msginfo->msg;
+
+ msg->msgtype = CHANNELMSG_REQUESTOFFERS;
+
+
+ ret = vmbus_post_msg(msg,
+ sizeof(struct vmbus_channel_message_header));
+ if (ret != 0) {
+ pr_err("Unable to request offers - %d\n", ret);
+
+ goto cleanup;
+ }
+
+ t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
+ if (t == 0) {
+ ret = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+
+
+cleanup:
+ kfree(msginfo);
+
+ return ret;
+}
+
+/* eof */
diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c
new file mode 100644
index 000000000000..7e15392fac9e
--- /dev/null
+++ b/drivers/staging/hv/connection.c
@@ -0,0 +1,290 @@
+/*
+ *
+ * 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/slab.h>
+#include <linux/vmalloc.h>
+
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
+
+
+struct vmbus_connection vmbus_connection = {
+ .conn_state = DISCONNECTED,
+ .next_gpadl_handle = ATOMIC_INIT(0xE1E10),
+};
+
+/*
+ * vmbus_connect - Sends a connect request on the partition service connection
+ */
+int vmbus_connect(void)
+{
+ int ret = 0;
+ int t;
+ struct vmbus_channel_msginfo *msginfo = NULL;
+ struct vmbus_channel_initiate_contact *msg;
+ unsigned long flags;
+
+ /* Make sure we are not connecting or connected */
+ if (vmbus_connection.conn_state != DISCONNECTED)
+ return -EISCONN;
+
+ /* Initialize the vmbus connection */
+ vmbus_connection.conn_state = CONNECTING;
+ vmbus_connection.work_queue = create_workqueue("hv_vmbus_con");
+ if (!vmbus_connection.work_queue) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ INIT_LIST_HEAD(&vmbus_connection.chn_msg_list);
+ spin_lock_init(&vmbus_connection.channelmsg_lock);
+
+ INIT_LIST_HEAD(&vmbus_connection.chn_list);
+ spin_lock_init(&vmbus_connection.channel_lock);
+
+ /*
+ * Setup the vmbus event connection for channel interrupt
+ * abstraction stuff
+ */
+ vmbus_connection.int_page =
+ (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, 0);
+ if (vmbus_connection.int_page == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ vmbus_connection.recv_int_page = vmbus_connection.int_page;
+ vmbus_connection.send_int_page =
+ (void *)((unsigned long)vmbus_connection.int_page +
+ (PAGE_SIZE >> 1));
+
+ /*
+ * Setup the monitor notification facility. The 1st page for
+ * parent->child and the 2nd page for child->parent
+ */
+ vmbus_connection.monitor_pages =
+ (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 1);
+ if (vmbus_connection.monitor_pages == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ msginfo = kzalloc(sizeof(*msginfo) +
+ sizeof(struct vmbus_channel_initiate_contact),
+ GFP_KERNEL);
+ if (msginfo == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ init_completion(&msginfo->waitevent);
+
+ msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;
+
+ msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
+ msg->vmbus_version_requested = VMBUS_REVISION_NUMBER;
+ msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
+ msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages);
+ msg->monitor_page2 = virt_to_phys(
+ (void *)((unsigned long)vmbus_connection.monitor_pages +
+ PAGE_SIZE));
+
+ /*
+ * Add to list before we send the request since we may
+ * receive the response before returning from this routine
+ */
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_add_tail(&msginfo->msglistentry,
+ &vmbus_connection.chn_msg_list);
+
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+
+ ret = vmbus_post_msg(msg,
+ sizeof(struct vmbus_channel_initiate_contact));
+ if (ret != 0) {
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_del(&msginfo->msglistentry);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
+ flags);
+ goto cleanup;
+ }
+
+ /* Wait for the connection response */
+ t = wait_for_completion_timeout(&msginfo->waitevent, HZ);
+ if (t == 0) {
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
+ flags);
+ list_del(&msginfo->msglistentry);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
+ flags);
+ ret = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_del(&msginfo->msglistentry);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+
+ /* Check if successful */
+ if (msginfo->response.version_response.version_supported) {
+ vmbus_connection.conn_state = CONNECTED;
+ } else {
+ pr_err("Unable to connect, "
+ "Version %d not supported by Hyper-V\n",
+ VMBUS_REVISION_NUMBER);
+ ret = -ECONNREFUSED;
+ goto cleanup;
+ }
+
+ kfree(msginfo);
+ return 0;
+
+cleanup:
+ vmbus_connection.conn_state = DISCONNECTED;
+
+ if (vmbus_connection.work_queue)
+ destroy_workqueue(vmbus_connection.work_queue);
+
+ if (vmbus_connection.int_page) {
+ free_pages((unsigned long)vmbus_connection.int_page, 0);
+ vmbus_connection.int_page = NULL;
+ }
+
+ if (vmbus_connection.monitor_pages) {
+ free_pages((unsigned long)vmbus_connection.monitor_pages, 1);
+ vmbus_connection.monitor_pages = NULL;
+ }
+
+ kfree(msginfo);
+
+ return ret;
+}
+
+
+/*
+ * relid2channel - Get the channel object given its
+ * child relative id (ie channel id)
+ */
+struct vmbus_channel *relid2channel(u32 relid)
+{
+ struct vmbus_channel *channel;
+ struct vmbus_channel *found_channel = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
+ if (channel->offermsg.child_relid == relid) {
+ found_channel = channel;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+
+ return found_channel;
+}
+
+/*
+ * process_chn_event - Process a channel event notification
+ */
+static void process_chn_event(u32 relid)
+{
+ struct vmbus_channel *channel;
+
+ /* ASSERT(relId > 0); */
+
+ /*
+ * Find the channel based on this relid and invokes the
+ * channel callback to process the event
+ */
+ channel = relid2channel(relid);
+
+ if (channel) {
+ channel->onchannel_callback(channel->channel_callback_context);
+ } else {
+ pr_err("channel not found for relid - %u\n", relid);
+ }
+}
+
+/*
+ * vmbus_on_event - Handler for events
+ */
+void vmbus_on_event(unsigned long data)
+{
+ u32 dword;
+ u32 maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
+ int bit;
+ u32 relid;
+ u32 *recv_int_page = vmbus_connection.recv_int_page;
+
+ /* Check events */
+ if (!recv_int_page)
+ return;
+ for (dword = 0; dword < maxdword; dword++) {
+ if (!recv_int_page[dword])
+ continue;
+ for (bit = 0; bit < 32; bit++) {
+ if (sync_test_and_clear_bit(bit, (unsigned long *)&recv_int_page[dword])) {
+ relid = (dword << 5) + bit;
+
+ if (relid == 0) {
+ /*
+ * Special case - vmbus
+ * channel protocol msg
+ */
+ continue;
+ }
+ process_chn_event(relid);
+ }
+ }
+ }
+}
+
+/*
+ * vmbus_post_msg - Send a msg on the vmbus's message connection
+ */
+int vmbus_post_msg(void *buffer, size_t buflen)
+{
+ union hv_connection_id conn_id;
+
+ conn_id.asu32 = 0;
+ conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID;
+ return hv_post_message(conn_id, 1, buffer, buflen);
+}
+
+/*
+ * vmbus_set_event - Send an event notification to the parent
+ */
+int vmbus_set_event(u32 child_relid)
+{
+ /* Each u32 represents 32 channels */
+ sync_set_bit(child_relid & 31,
+ (unsigned long *)vmbus_connection.send_int_page +
+ (child_relid >> 5));
+
+ return hv_signal_event();
+}
diff --git a/drivers/staging/hv/ext_utils.c b/drivers/staging/hv/ext_utils.c
deleted file mode 100644
index a44cd1b93e06..000000000000
--- a/drivers/staging/hv/ext_utils.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2010, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#include <linux/reboot.h>
-#include "utils.h"
-
-void shutdown_linux_system()
-{
- orderly_poweroff(false);
-}
diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c
new file mode 100644
index 000000000000..824f81679ae8
--- /dev/null
+++ b/drivers/staging/hv/hv.c
@@ -0,0 +1,438 @@
+/*
+ * 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/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "hyperv.h"
+#include "hyperv_vmbus.h"
+
+/* The one and only */
+struct hv_context hv_context = {
+ .synic_initialized = false,
+ .hypercall_page = NULL,
+ .signal_event_param = NULL,
+ .signal_event_buffer = NULL,
+};
+
+/*
+ * query_hypervisor_presence
+ * - Query the cpuid for presence of windows hypervisor
+ */
+static int query_hypervisor_presence(void)
+{
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+ unsigned int op;
+
+ eax = 0;
+ ebx = 0;
+ ecx = 0;
+ edx = 0;
+ op = HVCPUID_VERSION_FEATURES;
+ cpuid(op, &eax, &ebx, &ecx, &edx);
+
+ return ecx & HV_PRESENT_BIT;
+}
+
+/*
+ * query_hypervisor_info - Get version info of the windows hypervisor
+ */
+static int query_hypervisor_info(void)
+{
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+ unsigned int max_leaf;
+ unsigned int op;
+
+ /*
+ * Its assumed that this is called after confirming that Viridian
+ * is present. Query id and revision.
+ */
+ eax = 0;
+ ebx = 0;
+ ecx = 0;
+ edx = 0;
+ op = HVCPUID_VENDOR_MAXFUNCTION;
+ cpuid(op, &eax, &ebx, &ecx, &edx);
+
+ max_leaf = eax;
+
+ if (max_leaf >= HVCPUID_VERSION) {
+ eax = 0;
+ ebx = 0;
+ ecx = 0;
+ edx = 0;
+ op = HVCPUID_VERSION;
+ cpuid(op, &eax, &ebx, &ecx, &edx);
+ pr_info("Hyper-V Host OS Build:%d-%d.%d-%d-%d.%d\n",
+ eax,
+ ebx >> 16,
+ ebx & 0xFFFF,
+ ecx,
+ edx >> 24,
+ edx & 0xFFFFFF);
+ }
+ return max_leaf;
+}
+
+/*
+ * do_hypercall- Invoke the specified hypercall
+ */
+static u64 do_hypercall(u64 control, void *input, void *output)
+{
+#ifdef CONFIG_X86_64
+ u64 hv_status = 0;
+ u64 input_address = (input) ? virt_to_phys(input) : 0;
+ u64 output_address = (output) ? virt_to_phys(output) : 0;
+ volatile void *hypercall_page = hv_context.hypercall_page;
+
+ __asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
+ __asm__ __volatile__("call *%3" : "=a" (hv_status) :
+ "c" (control), "d" (input_address),
+ "m" (hypercall_page));
+
+ return hv_status;
+
+#else
+
+ u32 control_hi = control >> 32;
+ u32 control_lo = control & 0xFFFFFFFF;
+ u32 hv_status_hi = 1;
+ u32 hv_status_lo = 1;
+ u64 input_address = (input) ? virt_to_phys(input) : 0;
+ u32 input_address_hi = input_address >> 32;
+ u32 input_address_lo = input_address & 0xFFFFFFFF;
+ u64 output_address = (output) ? virt_to_phys(output) : 0;
+ u32 output_address_hi = output_address >> 32;
+ u32 output_address_lo = output_address & 0xFFFFFFFF;
+ volatile void *hypercall_page = hv_context.hypercall_page;
+
+ __asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
+ "=a"(hv_status_lo) : "d" (control_hi),
+ "a" (control_lo), "b" (input_address_hi),
+ "c" (input_address_lo), "D"(output_address_hi),
+ "S"(output_address_lo), "m" (hypercall_page));
+
+ return hv_status_lo | ((u64)hv_status_hi << 32);
+#endif /* !x86_64 */
+}
+
+/*
+ * hv_init - Main initialization routine.
+ *
+ * This routine must be called before any other routines in here are called
+ */
+int hv_init(void)
+{
+ int ret = 0;
+ int max_leaf;
+ union hv_x64_msr_hypercall_contents hypercall_msr;
+ void *virtaddr = NULL;
+
+ memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS);
+ memset(hv_context.synic_message_page, 0,
+ sizeof(void *) * MAX_NUM_CPUS);
+
+ if (!query_hypervisor_presence())
+ goto cleanup;
+
+ max_leaf = query_hypervisor_info();
+ /* HvQueryHypervisorFeatures(maxLeaf); */
+
+ /*
+ * We only support running on top of Hyper-V
+ */
+ rdmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
+
+ if (hv_context.guestid != 0)
+ goto cleanup;
+
+ /* Write our OS info */
+ wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
+ hv_context.guestid = HV_LINUX_GUEST_ID;
+
+ /* See if the hypercall page is already set */
+ rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+
+ /*
+ * Allocate the hypercall page memory
+ * virtaddr = osd_page_alloc(1);
+ */
+ virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
+
+ if (!virtaddr)
+ goto cleanup;
+
+ hypercall_msr.enable = 1;
+
+ hypercall_msr.guest_physical_address = vmalloc_to_pfn(virtaddr);
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+
+ /* Confirm that hypercall page did get setup. */
+ hypercall_msr.as_uint64 = 0;
+ rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+
+ if (!hypercall_msr.enable)
+ goto cleanup;
+
+ hv_context.hypercall_page = virtaddr;
+
+ /* Setup the global signal event param for the signal event hypercall */
+ hv_context.signal_event_buffer =
+ kmalloc(sizeof(struct hv_input_signal_event_buffer),
+ GFP_KERNEL);
+ if (!hv_context.signal_event_buffer)
+ goto cleanup;
+
+ hv_context.signal_event_param =
+ (struct hv_input_signal_event *)
+ (ALIGN((unsigned long)
+ hv_context.signal_event_buffer,
+ HV_HYPERCALL_PARAM_ALIGN));
+ hv_context.signal_event_param->connectionid.asu32 = 0;
+ hv_context.signal_event_param->connectionid.u.id =
+ VMBUS_EVENT_CONNECTION_ID;
+ hv_context.signal_event_param->flag_number = 0;
+ hv_context.signal_event_param->rsvdz = 0;
+
+ return ret;
+
+cleanup:
+ if (virtaddr) {
+ if (hypercall_msr.enable) {
+ hypercall_msr.as_uint64 = 0;
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+ }
+
+ vfree(virtaddr);
+ }
+ ret = -1;
+ return ret;
+}
+
+/*
+ * hv_cleanup - Cleanup routine.
+ *
+ * This routine is called normally during driver unloading or exiting.
+ */
+void hv_cleanup(void)
+{
+ union hv_x64_msr_hypercall_contents hypercall_msr;
+
+ kfree(hv_context.signal_event_buffer);
+ hv_context.signal_event_buffer = NULL;
+ hv_context.signal_event_param = NULL;
+
+ if (hv_context.hypercall_page) {
+ hypercall_msr.as_uint64 = 0;
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+ vfree(hv_context.hypercall_page);
+ hv_context.hypercall_page = NULL;
+ }
+}
+
+/*
+ * hv_post_message - Post a message using the hypervisor message IPC.
+ *
+ * This involves a hypercall.
+ */
+u16 hv_post_message(union hv_connection_id connection_id,
+ enum hv_message_type message_type,
+ void *payload, size_t payload_size)
+{
+ struct aligned_input {
+ u64 alignment8;
+ struct hv_input_post_message msg;
+ };
+
+ struct hv_input_post_message *aligned_msg;
+ u16 status;
+ unsigned long addr;
+
+ if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
+ return -EMSGSIZE;
+
+ addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC);
+ if (!addr)
+ return -ENOMEM;
+
+ aligned_msg = (struct hv_input_post_message *)
+ (ALIGN(addr, HV_HYPERCALL_PARAM_ALIGN));
+
+ aligned_msg->connectionid = connection_id;
+ aligned_msg->message_type = message_type;
+ aligned_msg->payload_size = payload_size;
+ memcpy((void *)aligned_msg->payload, payload, payload_size);
+
+ status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
+ & 0xFFFF;
+
+ kfree((void *)addr);
+
+ return status;
+}
+
+
+/*
+ * hv_signal_event -
+ * Signal an event on the specified connection using the hypervisor event IPC.
+ *
+ * This involves a hypercall.
+ */
+u16 hv_signal_event(void)
+{
+ u16 status;
+
+ status = do_hypercall(HVCALL_SIGNAL_EVENT,
+ hv_context.signal_event_param,
+ NULL) & 0xFFFF;
+ return status;
+}
+
+/*
+ * hv_synic_init - Initialize the Synthethic Interrupt Controller.
+ *
+ * If it is already initialized by another entity (ie x2v shim), we need to
+ * retrieve the initialized message and event pages. Otherwise, we create and
+ * initialize the message and event pages.
+ */
+void hv_synic_init(void *irqarg)
+{
+ u64 version;
+ union hv_synic_simp simp;
+ union hv_synic_siefp siefp;
+ union hv_synic_sint shared_sint;
+ union hv_synic_scontrol sctrl;
+
+ u32 irq_vector = *((u32 *)(irqarg));
+ int cpu = smp_processor_id();
+
+ if (!hv_context.hypercall_page)
+ return;
+
+ /* Check the version */
+ rdmsrl(HV_X64_MSR_SVERSION, version);
+
+ hv_context.synic_message_page[cpu] =
+ (void *)get_zeroed_page(GFP_ATOMIC);
+
+ if (hv_context.synic_message_page[cpu] == NULL) {
+ pr_err("Unable to allocate SYNIC message page\n");
+ goto cleanup;
+ }
+
+ hv_context.synic_event_page[cpu] =
+ (void *)get_zeroed_page(GFP_ATOMIC);
+
+ if (hv_context.synic_event_page[cpu] == NULL) {
+ pr_err("Unable to allocate SYNIC event page\n");
+ goto cleanup;
+ }
+
+ /* Setup the Synic's message page */
+ rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+ simp.simp_enabled = 1;
+ simp.base_simp_gpa = virt_to_phys(hv_context.synic_message_page[cpu])
+ >> PAGE_SHIFT;
+
+ wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+
+ /* Setup the Synic's event page */
+ rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+ siefp.siefp_enabled = 1;
+ siefp.base_siefp_gpa = virt_to_phys(hv_context.synic_event_page[cpu])
+ >> PAGE_SHIFT;
+
+ wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+
+ /* Setup the shared SINT. */
+ rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
+
+ shared_sint.as_uint64 = 0;
+ shared_sint.vector = irq_vector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */
+ shared_sint.masked = false;
+ shared_sint.auto_eoi = true;
+
+ wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
+
+ /* Enable the global synic bit */
+ rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
+ sctrl.enable = 1;
+
+ wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
+
+ hv_context.synic_initialized = true;
+ return;
+
+cleanup:
+ if (hv_context.synic_event_page[cpu])
+ free_page((unsigned long)hv_context.synic_event_page[cpu]);
+
+ if (hv_context.synic_message_page[cpu])
+ free_page((unsigned long)hv_context.synic_message_page[cpu]);
+ return;
+}
+
+/*
+ * hv_synic_cleanup - Cleanup routine for hv_synic_init().
+ */
+void hv_synic_cleanup(void *arg)
+{
+ union hv_synic_sint shared_sint;
+ union hv_synic_simp simp;
+ union hv_synic_siefp siefp;
+ int cpu = smp_processor_id();
+
+ if (!hv_context.synic_initialized)
+ return;
+
+ rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
+
+ shared_sint.masked = 1;
+
+ /* Need to correctly cleanup in the case of SMP!!! */
+ /* Disable the interrupt */
+ wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
+
+ rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+ simp.simp_enabled = 0;
+ simp.base_simp_gpa = 0;
+
+ wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
+
+ rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+ siefp.siefp_enabled = 0;
+ siefp.base_siefp_gpa = 0;
+
+ wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
+
+ free_page((unsigned long)hv_context.synic_message_page[cpu]);
+ free_page((unsigned long)hv_context.synic_event_page[cpu]);
+}
diff --git a/drivers/staging/hv/hv_api.h b/drivers/staging/hv/hv_api.h
deleted file mode 100644
index 9eb818ee07ba..000000000000
--- a/drivers/staging/hv/hv_api.h
+++ /dev/null
@@ -1,905 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#ifndef __HV_API_H
-#define __HV_API_H
-
-
-/* Status codes for hypervisor operations. */
-
-/*
- * HV_STATUS_SUCCESS
- * The specified hypercall succeeded
- */
-#define HV_STATUS_SUCCESS ((u16)0x0000)
-
-/*
- * HV_STATUS_INVALID_HYPERCALL_CODE
- * The hypervisor does not support the operation because the specified
- * hypercall code is not supported.
- */
-#define HV_STATUS_INVALID_HYPERCALL_CODE ((u16)0x0002)
-
-/*
- * HV_STATUS_INVALID_HYPERCALL_INPUT
- * The hypervisor does not support the operation because the encoding for the
- * hypercall input register is not supported.
- */
-#define HV_STATUS_INVALID_HYPERCALL_INPUT ((u16)0x0003)
-
-/*
- * HV_STATUS_INVALID_ALIGNMENT
- * The hypervisor could not perform the operation beacuse a parameter has an
- * invalid alignment.
- */
-#define HV_STATUS_INVALID_ALIGNMENT ((u16)0x0004)
-
-/*
- * HV_STATUS_INVALID_PARAMETER
- * The hypervisor could not perform the operation beacuse an invalid parameter
- * was specified.
- */
-#define HV_STATUS_INVALID_PARAMETER ((u16)0x0005)
-
-/*
- * HV_STATUS_ACCESS_DENIED
- * Access to the specified object was denied.
- */
-#define HV_STATUS_ACCESS_DENIED ((u16)0x0006)
-
-/*
- * HV_STATUS_INVALID_PARTITION_STATE
- * The hypervisor could not perform the operation because the partition is
- * entering or in an invalid state.
- */
-#define HV_STATUS_INVALID_PARTITION_STATE ((u16)0x0007)
-
-/*
- * HV_STATUS_OPERATION_DENIED
- * The operation is not allowed in the current state.
- */
-#define HV_STATUS_OPERATION_DENIED ((u16)0x0008)
-
-/*
- * HV_STATUS_UNKNOWN_PROPERTY
- * The hypervisor does not recognize the specified partition property.
- */
-#define HV_STATUS_UNKNOWN_PROPERTY ((u16)0x0009)
-
-/*
- * HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE
- * The specified value of a partition property is out of range or violates an
- * invariant.
- */
-#define HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE ((u16)0x000A)
-
-/*
- * HV_STATUS_INSUFFICIENT_MEMORY
- * There is not enough memory in the hypervisor pool to complete the operation.
- */
-#define HV_STATUS_INSUFFICIENT_MEMORY ((u16)0x000B)
-
-/*
- * HV_STATUS_PARTITION_TOO_DEEP
- * The maximum partition depth has been exceeded for the partition hierarchy.
- */
-#define HV_STATUS_PARTITION_TOO_DEEP ((u16)0x000C)
-
-/*
- * HV_STATUS_INVALID_PARTITION_ID
- * A partition with the specified partition Id does not exist.
- */
-#define HV_STATUS_INVALID_PARTITION_ID ((u16)0x000D)
-
-/*
- * HV_STATUS_INVALID_VP_INDEX
- * The hypervisor could not perform the operation because the specified VP
- * index is invalid.
- */
-#define HV_STATUS_INVALID_VP_INDEX ((u16)0x000E)
-
-/*
- * HV_STATUS_NOT_FOUND
- * The iteration is complete; no addition items in the iteration could be
- * found.
- */
-#define HV_STATUS_NOT_FOUND ((u16)0x0010)
-
-/*
- * HV_STATUS_INVALID_PORT_ID
- * The hypervisor could not perform the operation because the specified port
- * identifier is invalid.
- */
-#define HV_STATUS_INVALID_PORT_ID ((u16)0x0011)
-
-/*
- * HV_STATUS_INVALID_CONNECTION_ID
- * The hypervisor could not perform the operation because the specified
- * connection identifier is invalid.
- */
-#define HV_STATUS_INVALID_CONNECTION_ID ((u16)0x0012)
-
-/*
- * HV_STATUS_INSUFFICIENT_BUFFERS
- * You did not supply enough message buffers to send a message.
- */
-#define HV_STATUS_INSUFFICIENT_BUFFERS ((u16)0x0013)
-
-/*
- * HV_STATUS_NOT_ACKNOWLEDGED
- * The previous virtual interrupt has not been acknowledged.
- */
-#define HV_STATUS_NOT_ACKNOWLEDGED ((u16)0x0014)
-
-/*
- * HV_STATUS_INVALID_VP_STATE
- * A virtual processor is not in the correct state for the performance of the
- * indicated operation.
- */
-#define HV_STATUS_INVALID_VP_STATE ((u16)0x0015)
-
-/*
- * HV_STATUS_ACKNOWLEDGED
- * The previous virtual interrupt has already been acknowledged.
- */
-#define HV_STATUS_ACKNOWLEDGED ((u16)0x0016)
-
-/*
- * HV_STATUS_INVALID_SAVE_RESTORE_STATE
- * The indicated partition is not in a valid state for saving or restoring.
- */
-#define HV_STATUS_INVALID_SAVE_RESTORE_STATE ((u16)0x0017)
-
-/*
- * HV_STATUS_INVALID_SYNIC_STATE
- * The hypervisor could not complete the operation because a required feature
- * of the synthetic interrupt controller (SynIC) was disabled.
- */
-#define HV_STATUS_INVALID_SYNIC_STATE ((u16)0x0018)
-
-/*
- * HV_STATUS_OBJECT_IN_USE
- * The hypervisor could not perform the operation because the object or value
- * was either already in use or being used for a purpose that would not permit
- * completing the operation.
- */
-#define HV_STATUS_OBJECT_IN_USE ((u16)0x0019)
-
-/*
- * HV_STATUS_INVALID_PROXIMITY_DOMAIN_INFO
- * The proximity domain information is invalid.
- */
-#define HV_STATUS_INVALID_PROXIMITY_DOMAIN_INFO ((u16)0x001A)
-
-/*
- * HV_STATUS_NO_DATA
- * An attempt to retrieve debugging data failed because none was available.
- */
-#define HV_STATUS_NO_DATA ((u16)0x001B)
-
-/*
- * HV_STATUS_INACTIVE
- * The physical connection being used for debuggging has not recorded any
- * receive activity since the last operation.
- */
-#define HV_STATUS_INACTIVE ((u16)0x001C)
-
-/*
- * HV_STATUS_NO_RESOURCES
- * There are not enough resources to complete the operation.
- */
-#define HV_STATUS_NO_RESOURCES ((u16)0x001D)
-
-/*
- * HV_STATUS_FEATURE_UNAVAILABLE
- * A hypervisor feature is not available to the user.
- */
-#define HV_STATUS_FEATURE_UNAVAILABLE ((u16)0x001E)
-
-/*
- * HV_STATUS_UNSUCCESSFUL
- * {Operation Failed} The requested operation was unsuccessful.
- */
-#define HV_STATUS_UNSUCCESSFUL ((u16)0x1001)
-
-/*
- * HV_STATUS_INSUFFICIENT_BUFFER
- * The specified buffer was too small to contain all of the requested data.
- */
-#define HV_STATUS_INSUFFICIENT_BUFFER ((u16)0x1002)
-
-/*
- * HV_STATUS_GPA_NOT_PRESENT
- * The guest physical address is not currently associated with a system
- * physical address.
- */
-#define HV_STATUS_GPA_NOT_PRESENT ((u16)0x1003)
-
-/*
- * HV_STATUS_GUEST_PAGE_FAULT
- * The operation would have resulted in a page fault in the guest.
- */
-#define HV_STATUS_GUEST_PAGE_FAULT ((u16)0x1004)
-
-/*
- * HV_STATUS_RUNDOWN_DISABLED
- * The operation cannot proceed as the rundown object was marked disabled.
- */
-#define HV_STATUS_RUNDOWN_DISABLED ((u16)0x1005)
-
-/*
- * HV_STATUS_KEY_ALREADY_EXISTS
- * The entry cannot be added as another entry with the same key already exists.
- */
-#define HV_STATUS_KEY_ALREADY_EXISTS ((u16)0x1006)
-
-/*
- * HV_STATUS_GPA_INTERCEPT
- * The operation resulted an intercept on a region of guest physical memory.
- */
-#define HV_STATUS_GPA_INTERCEPT ((u16)0x1007)
-
-/*
- * HV_STATUS_GUEST_GENERAL_PROTECTION_FAULT
- * The operation would have resulted in a general protection fault in the
- * guest.
- */
-#define HV_STATUS_GUEST_GENERAL_PROTECTION_FAULT ((u16)0x1008)
-
-/*
- * HV_STATUS_GUEST_STACK_FAULT
- * The operation would have resulted in a stack fault in the guest.
- */
-#define HV_STATUS_GUEST_STACK_FAULT ((u16)0x1009)
-
-/*
- * HV_STATUS_GUEST_INVALID_OPCODE_FAULT
- * The operation would have resulted in an invalid opcode fault in the guest.
- */
-#define HV_STATUS_GUEST_INVALID_OPCODE_FAULT ((u16)0x100A)
-
-/*
- * HV_STATUS_FINALIZE_INCOMPLETE
- * The partition is not completely finalized.
- */
-#define HV_STATUS_FINALIZE_INCOMPLETE ((u16)0x100B)
-
-/*
- * HV_STATUS_GUEST_MACHINE_CHECK_ABORT
- * The operation would have resulted in an machine check abort in the guest.
- */
-#define HV_STATUS_GUEST_MACHINE_CHECK_ABORT ((u16)0x100C)
-
-/*
- * HV_STATUS_ILLEGAL_OVERLAY_ACCESS
- * An illegal access was attempted to an overlay page.
- */
-#define HV_STATUS_ILLEGAL_OVERLAY_ACCESS ((u16)0x100D)
-
-/*
- * HV_STATUS_INSUFFICIENT_SYSTEM_VA
- * There is not enough system VA space available to satisfy the request,
- */
-#define HV_STATUS_INSUFFICIENT_SYSTEM_VA ((u16)0x100E)
-
-/*
- * HV_STATUS_VIRTUAL_ADDRESS_NOT_MAPPED
- * The passed virtual address was not mapped in the hypervisor address space.
- */
-#define HV_STATUS_VIRTUAL_ADDRESS_NOT_MAPPED ((u16)0x100F)
-
-/*
- * HV_STATUS_NOT_IMPLEMENTED
- * The requested operation is not implemented in this version of the
- * hypervisor.
- */
-#define HV_STATUS_NOT_IMPLEMENTED ((u16)0x1010)
-
-/*
- * HV_STATUS_VMX_INSTRUCTION_FAILED
- * The requested VMX instruction failed to complete successfully.
- */
-#define HV_STATUS_VMX_INSTRUCTION_FAILED ((u16)0x1011)
-
-/*
- * HV_STATUS_VMX_INSTRUCTION_FAILED_WITH_STATUS
- * The requested VMX instruction failed to complete successfully indicating
- * status.
- */
-#define HV_STATUS_VMX_INSTRUCTION_FAILED_WITH_STATUS ((u16)0x1012)
-
-/*
- * HV_STATUS_MSR_ACCESS_FAILED
- * The requested access to the model specific register failed.
- */
-#define HV_STATUS_MSR_ACCESS_FAILED ((u16)0x1013)
-
-/*
- * HV_STATUS_CR_ACCESS_FAILED
- * The requested access to the control register failed.
- */
-#define HV_STATUS_CR_ACCESS_FAILED ((u16)0x1014)
-
-/*
- * HV_STATUS_TIMEOUT
- * The specified timeout expired before the operation completed.
- */
-#define HV_STATUS_TIMEOUT ((u16)0x1016)
-
-/*
- * HV_STATUS_MSR_INTERCEPT
- * The requested access to the model specific register generated an intercept.
- */
-#define HV_STATUS_MSR_INTERCEPT ((u16)0x1017)
-
-/*
- * HV_STATUS_CPUID_INTERCEPT
- * The CPUID instruction generated an intercept.
- */
-#define HV_STATUS_CPUID_INTERCEPT ((u16)0x1018)
-
-/*
- * HV_STATUS_REPEAT_INSTRUCTION
- * The current instruction should be repeated and the instruction pointer not
- * advanced.
- */
-#define HV_STATUS_REPEAT_INSTRUCTION ((u16)0x1019)
-
-/*
- * HV_STATUS_PAGE_PROTECTION_VIOLATION
- * The current instruction should be repeated and the instruction pointer not
- * advanced.
- */
-#define HV_STATUS_PAGE_PROTECTION_VIOLATION ((u16)0x101A)
-
-/*
- * HV_STATUS_PAGE_TABLE_INVALID
- * The current instruction should be repeated and the instruction pointer not
- * advanced.
- */
-#define HV_STATUS_PAGE_TABLE_INVALID ((u16)0x101B)
-
-/*
- * HV_STATUS_PAGE_NOT_PRESENT
- * The current instruction should be repeated and the instruction pointer not
- * advanced.
- */
-#define HV_STATUS_PAGE_NOT_PRESENT ((u16)0x101C)
-
-/*
- * HV_STATUS_IO_INTERCEPT
- * The requested access to the I/O port generated an intercept.
- */
-#define HV_STATUS_IO_INTERCEPT ((u16)0x101D)
-
-/*
- * HV_STATUS_NOTHING_TO_DO
- * There is nothing to do.
- */
-#define HV_STATUS_NOTHING_TO_DO ((u16)0x101E)
-
-/*
- * HV_STATUS_THREAD_TERMINATING
- * The requested thread is terminating.
- */
-#define HV_STATUS_THREAD_TERMINATING ((u16)0x101F)
-
-/*
- * HV_STATUS_SECTION_ALREADY_CONSTRUCTED
- * The specified section was already constructed.
- */
-#define HV_STATUS_SECTION_ALREADY_CONSTRUCTED ((u16)0x1020)
-
-/* HV_STATUS_SECTION_NOT_ALREADY_CONSTRUCTED
- * The specified section was not already constructed.
- */
-#define HV_STATUS_SECTION_NOT_ALREADY_CONSTRUCTED ((u16)0x1021)
-
-/*
- * HV_STATUS_PAGE_ALREADY_COMMITTED
- * The specified virtual address was already backed by physical memory.
- */
-#define HV_STATUS_PAGE_ALREADY_COMMITTED ((u16)0x1022)
-
-/*
- * HV_STATUS_PAGE_NOT_ALREADY_COMMITTED
- * The specified virtual address was not already backed by physical memory.
- */
-#define HV_STATUS_PAGE_NOT_ALREADY_COMMITTED ((u16)0x1023)
-
-/*
- * HV_STATUS_COMMITTED_PAGES_REMAIN
- * Committed pages remain in the section.
- */
-#define HV_STATUS_COMMITTED_PAGES_REMAIN ((u16)0x1024)
-
-/*
- * HV_STATUS_NO_REMAINING_COMMITTED_PAGES
- * No additional committed pages beyond the specified page exist in the
- * section.
- */
-#define HV_STATUS_NO_REMAINING_COMMITTED_PAGES ((u16)0x1025)
-
-/*
- * HV_STATUS_INSUFFICIENT_COMPARTMENT_VA
- * The VA space of the compartment is exhausted.
- */
-#define HV_STATUS_INSUFFICIENT_COMPARTMENT_VA ((u16)0x1026)
-
-/*
- * HV_STATUS_DEREF_SPA_LIST_FULL
- * The SPA dereference list is full, and there are additional entries to be
- * added to it.
- */
-#define HV_STATUS_DEREF_SPA_LIST_FULL ((u16)0x1027)
-
-/*
- * HV_STATUS_GPA_OUT_OF_RANGE
- * The supplied GPA is out of range.
- */
-#define HV_STATUS_GPA_OUT_OF_RANGE ((u16)0x1027)
-
-/*
- * HV_STATUS_NONVOLATILE_XMM_STALE
- * The XMM register that was being accessed is stale.
- */
-#define HV_STATUS_NONVOLATILE_XMM_STALE ((u16)0x1028)
-
-/* HV_STATUS_UNSUPPORTED_PROCESSOR
- * The hypervisor does not support the processors in this system.
- */
-#define HV_STATUS_UNSUPPORTED_PROCESSOR ((u16)0x1029)
-
-/*
- * HV_STATUS_INSUFFICIENT_CROM_SPACE
- * Insufficient space existed for copying over the CROM contents.
- */
-#define HV_STATUS_INSUFFICIENT_CROM_SPACE ((u16)0x2000)
-
-/*
- * HV_STATUS_BAD_CROM_FORMAT
- * The contents of the CROM failed validation attempts.
- */
-#define HV_STATUS_BAD_CROM_FORMAT ((u16)0x2001)
-
-/*
- * HV_STATUS_UNSUPPORTED_CROM_FORMAT
- * The contents of the CROM contain contents the parser doesn't support.
- */
-#define HV_STATUS_UNSUPPORTED_CROM_FORMAT ((u16)0x2002)
-
-/*
- * HV_STATUS_UNSUPPORTED_CONTROLLER
- * The register format of the OHCI controller specified for debugging is not
- * supported.
- */
-#define HV_STATUS_UNSUPPORTED_CONTROLLER ((u16)0x2003)
-
-/*
- * HV_STATUS_CROM_TOO_LARGE
- * The CROM contents were to large to copy over.
- */
-#define HV_STATUS_CROM_TOO_LARGE ((u16)0x2004)
-
-/*
- * HV_STATUS_CONTROLLER_IN_USE
- * The OHCI controller specified for debugging cannot be used as it is already
- * in use.
- */
-#define HV_STATUS_CONTROLLER_IN_USE ((u16)0x2005)
-
-
-/*
- * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
- * is set by CPUID(HvCpuIdFunctionVersionAndFeatures).
- */
-enum hv_cpuid_function {
- HvCpuIdFunctionVersionAndFeatures = 0x00000001,
- HvCpuIdFunctionHvVendorAndMaxFunction = 0x40000000,
- HvCpuIdFunctionHvInterface = 0x40000001,
-
- /*
- * The remaining functions depend on the value of
- * HvCpuIdFunctionInterface
- */
- HvCpuIdFunctionMsHvVersion = 0x40000002,
- HvCpuIdFunctionMsHvFeatures = 0x40000003,
- HvCpuIdFunctionMsHvEnlightenmentInformation = 0x40000004,
- HvCpuIdFunctionMsHvImplementationLimits = 0x40000005,
-};
-
-/* Define the virtual APIC registers */
-#define HV_X64_MSR_EOI (0x40000070)
-#define HV_X64_MSR_ICR (0x40000071)
-#define HV_X64_MSR_TPR (0x40000072)
-#define HV_X64_MSR_APIC_ASSIST_PAGE (0x40000073)
-
-/* Define version of the synthetic interrupt controller. */
-#define HV_SYNIC_VERSION (1)
-
-/* Define synthetic interrupt controller model specific registers. */
-#define HV_X64_MSR_SCONTROL (0x40000080)
-#define HV_X64_MSR_SVERSION (0x40000081)
-#define HV_X64_MSR_SIEFP (0x40000082)
-#define HV_X64_MSR_SIMP (0x40000083)
-#define HV_X64_MSR_EOM (0x40000084)
-#define HV_X64_MSR_SINT0 (0x40000090)
-#define HV_X64_MSR_SINT1 (0x40000091)
-#define HV_X64_MSR_SINT2 (0x40000092)
-#define HV_X64_MSR_SINT3 (0x40000093)
-#define HV_X64_MSR_SINT4 (0x40000094)
-#define HV_X64_MSR_SINT5 (0x40000095)
-#define HV_X64_MSR_SINT6 (0x40000096)
-#define HV_X64_MSR_SINT7 (0x40000097)
-#define HV_X64_MSR_SINT8 (0x40000098)
-#define HV_X64_MSR_SINT9 (0x40000099)
-#define HV_X64_MSR_SINT10 (0x4000009A)
-#define HV_X64_MSR_SINT11 (0x4000009B)
-#define HV_X64_MSR_SINT12 (0x4000009C)
-#define HV_X64_MSR_SINT13 (0x4000009D)
-#define HV_X64_MSR_SINT14 (0x4000009E)
-#define HV_X64_MSR_SINT15 (0x4000009F)
-
-/* Define the expected SynIC version. */
-#define HV_SYNIC_VERSION_1 (0x1)
-
-/* Define synthetic interrupt controller message constants. */
-#define HV_MESSAGE_SIZE (256)
-#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240)
-#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
-#define HV_ANY_VP (0xFFFFFFFF)
-
-/* Define synthetic interrupt controller flag constants. */
-#define HV_EVENT_FLAGS_COUNT (256 * 8)
-#define HV_EVENT_FLAGS_BYTE_COUNT (256)
-#define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32))
-
-/* Define hypervisor message types. */
-enum hv_message_type {
- HvMessageTypeNone = 0x00000000,
-
- /* Memory access messages. */
- HvMessageTypeUnmappedGpa = 0x80000000,
- HvMessageTypeGpaIntercept = 0x80000001,
-
- /* Timer notification messages. */
- HvMessageTimerExpired = 0x80000010,
-
- /* Error messages. */
- HvMessageTypeInvalidVpRegisterValue = 0x80000020,
- HvMessageTypeUnrecoverableException = 0x80000021,
- HvMessageTypeUnsupportedFeature = 0x80000022,
-
- /* Trace buffer complete messages. */
- HvMessageTypeEventLogBufferComplete = 0x80000040,
-
- /* Platform-specific processor intercept messages. */
- HvMessageTypeX64IoPortIntercept = 0x80010000,
- HvMessageTypeX64MsrIntercept = 0x80010001,
- HvMessageTypeX64CpuidIntercept = 0x80010002,
- HvMessageTypeX64ExceptionIntercept = 0x80010003,
- HvMessageTypeX64ApicEoi = 0x80010004,
- HvMessageTypeX64LegacyFpError = 0x80010005
-};
-
-/* Define the number of synthetic interrupt sources. */
-#define HV_SYNIC_SINT_COUNT (16)
-#define HV_SYNIC_STIMER_COUNT (4)
-
-/* Define invalid partition identifier. */
-#define HV_PARTITION_ID_INVALID ((u64)0x0)
-
-/* Define connection identifier type. */
-union hv_connection_id {
- u32 Asu32;
- struct {
- u32 Id:24;
- u32 Reserved:8;
- } u;
-};
-
-/* Define port identifier type. */
-union hv_port_id {
- u32 Asu32;
- struct {
- u32 Id:24;
- u32 Reserved:8;
- } u ;
-};
-
-/* Define port type. */
-enum hv_port_type {
- HvPortTypeMessage = 1,
- HvPortTypeEvent = 2,
- HvPortTypeMonitor = 3
-};
-
-/* Define port information structure. */
-struct hv_port_info {
- enum hv_port_type PortType;
- u32 Padding;
- union {
- struct {
- u32 TargetSint;
- u32 TargetVp;
- u64 RsvdZ;
- } MessagePortInfo;
- struct {
- u32 TargetSint;
- u32 TargetVp;
- u16 BaseFlagNumber;
- u16 FlagCount;
- u32 RsvdZ;
- } EventPortInfo;
- struct {
- u64 MonitorAddress;
- u64 RsvdZ;
- } MonitorPortInfo;
- };
-};
-
-struct hv_connection_info {
- enum hv_port_type PortType;
- u32 Padding;
- union {
- struct {
- u64 RsvdZ;
- } MessageConnectionInfo;
- struct {
- u64 RsvdZ;
- } EventConnectionInfo;
- struct {
- u64 MonitorAddress;
- } MonitorConnectionInfo;
- };
-};
-
-/* Define synthetic interrupt controller message flags. */
-union hv_message_flags {
- u8 Asu8;
- struct {
- u8 MessagePending:1;
- u8 Reserved:7;
- };
-};
-
-/* Define synthetic interrupt controller message header. */
-struct hv_message_header {
- enum hv_message_type MessageType;
- u8 PayloadSize;
- union hv_message_flags MessageFlags;
- u8 Reserved[2];
- union {
- u64 Sender;
- union hv_port_id Port;
- };
-};
-
-/* Define timer message payload structure. */
-struct hv_timer_message_payload {
- u32 TimerIndex;
- u32 Reserved;
- u64 ExpirationTime; /* When the timer expired */
- u64 DeliveryTime; /* When the message was delivered */
-};
-
-/* Define synthetic interrupt controller message format. */
-struct hv_message {
- struct hv_message_header Header;
- union {
- u64 Payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
- } u ;
-};
-
-/* Define the number of message buffers associated with each port. */
-#define HV_PORT_MESSAGE_BUFFER_COUNT (16)
-
-/* Define the synthetic interrupt message page layout. */
-struct hv_message_page {
- struct hv_message SintMessage[HV_SYNIC_SINT_COUNT];
-};
-
-/* Define the synthetic interrupt controller event flags format. */
-union hv_synic_event_flags {
- u8 Flags8[HV_EVENT_FLAGS_BYTE_COUNT];
- u32 Flags32[HV_EVENT_FLAGS_DWORD_COUNT];
-};
-
-/* Define the synthetic interrupt flags page layout. */
-struct hv_synic_event_flags_page {
- union hv_synic_event_flags SintEventFlags[HV_SYNIC_SINT_COUNT];
-};
-
-/* Define SynIC control register. */
-union hv_synic_scontrol {
- u64 AsUINT64;
- struct {
- u64 Enable:1;
- u64 Reserved:63;
- };
-};
-
-/* Define synthetic interrupt source. */
-union hv_synic_sint {
- u64 AsUINT64;
- struct {
- u64 Vector:8;
- u64 Reserved1:8;
- u64 Masked:1;
- u64 AutoEoi:1;
- u64 Reserved2:46;
- };
-};
-
-/* Define the format of the SIMP register */
-union hv_synic_simp {
- u64 AsUINT64;
- struct {
- u64 SimpEnabled:1;
- u64 Preserved:11;
- u64 BaseSimpGpa:52;
- };
-};
-
-/* Define the format of the SIEFP register */
-union hv_synic_siefp {
- u64 AsUINT64;
- struct {
- u64 SiefpEnabled:1;
- u64 Preserved:11;
- u64 BaseSiefpGpa:52;
- };
-};
-
-/* Definitions for the monitored notification facility */
-union hv_monitor_trigger_group {
- u64 AsUINT64;
- struct {
- u32 Pending;
- u32 Armed;
- };
-};
-
-struct hv_monitor_parameter {
- union hv_connection_id ConnectionId;
- u16 FlagNumber;
- u16 RsvdZ;
-};
-
-union hv_monitor_trigger_state {
- u32 Asu32;
-
- struct {
- u32 GroupEnable:4;
- u32 RsvdZ:28;
- };
-};
-
-/* struct hv_monitor_page Layout */
-/* ------------------------------------------------------ */
-/* | 0 | TriggerState (4 bytes) | Rsvd1 (4 bytes) | */
-/* | 8 | TriggerGroup[0] | */
-/* | 10 | TriggerGroup[1] | */
-/* | 18 | TriggerGroup[2] | */
-/* | 20 | TriggerGroup[3] | */
-/* | 28 | Rsvd2[0] | */
-/* | 30 | Rsvd2[1] | */
-/* | 38 | Rsvd2[2] | */
-/* | 40 | NextCheckTime[0][0] | NextCheckTime[0][1] | */
-/* | ... | */
-/* | 240 | Latency[0][0..3] | */
-/* | 340 | Rsvz3[0] | */
-/* | 440 | Parameter[0][0] | */
-/* | 448 | Parameter[0][1] | */
-/* | ... | */
-/* | 840 | Rsvd4[0] | */
-/* ------------------------------------------------------ */
-struct hv_monitor_page {
- union hv_monitor_trigger_state TriggerState;
- u32 RsvdZ1;
-
- union hv_monitor_trigger_group TriggerGroup[4];
- u64 RsvdZ2[3];
-
- s32 NextCheckTime[4][32];
-
- u16 Latency[4][32];
- u64 RsvdZ3[32];
-
- struct hv_monitor_parameter Parameter[4][32];
-
- u8 RsvdZ4[1984];
-};
-
-/* Declare the various hypercall operations. */
-enum hv_call_code {
- HvCallPostMessage = 0x005c,
- HvCallSignalEvent = 0x005d,
-};
-
-/* Definition of the HvPostMessage hypercall input structure. */
-struct hv_input_post_message {
- union hv_connection_id ConnectionId;
- u32 Reserved;
- enum hv_message_type MessageType;
- u32 PayloadSize;
- u64 Payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
-};
-
-/* Definition of the HvSignalEvent hypercall input structure. */
-struct hv_input_signal_event {
- union hv_connection_id ConnectionId;
- u16 FlagNumber;
- u16 RsvdZ;
-};
-
-/*
- * Versioning definitions used for guests reporting themselves to the
- * hypervisor, and visa versa.
- */
-
-/* Version info reported by guest OS's */
-enum hv_guest_os_vendor {
- HvGuestOsVendorMicrosoft = 0x0001
-};
-
-enum hv_guest_os_microsoft_ids {
- HvGuestOsMicrosoftUndefined = 0x00,
- HvGuestOsMicrosoftMSDOS = 0x01,
- HvGuestOsMicrosoftWindows3x = 0x02,
- HvGuestOsMicrosoftWindows9x = 0x03,
- HvGuestOsMicrosoftWindowsNT = 0x04,
- HvGuestOsMicrosoftWindowsCE = 0x05
-};
-
-/*
- * Declare the MSR used to identify the guest OS.
- */
-#define HV_X64_MSR_GUEST_OS_ID 0x40000000
-
-union hv_x64_msr_guest_os_id_contents {
- u64 AsUINT64;
- struct {
- u64 BuildNumber:16;
- u64 ServiceVersion:8; /* Service Pack, etc. */
- u64 MinorVersion:8;
- u64 MajorVersion:8;
- u64 OsId:8; /* enum hv_guest_os_microsoft_ids (if Vendor=MS) */
- u64 VendorId:16; /* enum hv_guest_os_vendor */
- };
-};
-
-/*
- * Declare the MSR used to setup pages used to communicate with the hypervisor.
- */
-#define HV_X64_MSR_HYPERCALL 0x40000001
-
-union hv_x64_msr_hypercall_contents {
- u64 AsUINT64;
- struct {
- u64 Enable:1;
- u64 Reserved:11;
- u64 GuestPhysicalAddress:52;
- };
-};
-
-#endif
diff --git a/drivers/staging/hv/hv_compat.h b/drivers/staging/hv/hv_compat.h
new file mode 100644
index 000000000000..16724bacb732
--- /dev/null
+++ b/drivers/staging/hv/hv_compat.h
@@ -0,0 +1,81 @@
+
+#ifndef _HV_COMPAT_H
+#define _HV_COMPAT_H
+
+#include <linux/rcupdate.h>
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <net/arp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+
+#define CN_KVP_IDX 0x9
+
+#ifndef pr_warn
+#define pr_warn(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
+#endif
+
+
+#define DEF_SCSI_QCMD(func_name) \
+ int func_name(struct scsi_cmnd *cmd, \
+ void (*done)(struct scsi_cmnd *)) \
+ { \
+ int rc; \
+ rc = func_name##_lck(cmd, done); \
+ return rc; \
+ }
+
+#define blk_queue_max_segments(a, b)
+
+#ifndef netdev_err
+static inline void netdev_err(struct net_device *net, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+#endif
+
+#ifndef netdev_dbg
+#if defined(DEBUG)
+#define netdev_dbg(dev, fmt, ...) netdev_err(dev, fmt, ...)
+#else
+#define netdev_dbg(__dev, format, args...) \
+({ \
+ if (0) \
+ netdev_err(__dev, format, ##args); \
+ 0; \
+})
+
+#endif
+#endif
+
+
+#if defined(RHEL_RELEASE_VERSION) && (RHEL_RELEASE_CODE == 1536) && \
+LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
+static inline void netif_notify_peers(struct net_device *net)
+{
+ struct in_device *idev;
+
+ rcu_read_lock();
+ if (((idev = __in_dev_get_rcu(net)) != NULL) &&
+ idev->ifa_list != NULL) {
+ arp_send(ARPOP_REQUEST, ETH_P_ARP,
+ idev->ifa_list->ifa_address, net,
+ idev->ifa_list->ifa_address, NULL,
+ net->dev_addr, NULL);
+ }
+ rcu_read_unlock();
+}
+
+#endif
+#endif
diff --git a/drivers/staging/hv/hv_kvp.c b/drivers/staging/hv/hv_kvp.c
new file mode 100644
index 000000000000..13b0ecf7d5d6
--- /dev/null
+++ b/drivers/staging/hv/hv_kvp.c
@@ -0,0 +1,334 @@
+/*
+ * An implementation of key value pair (KVP) functionality for Linux.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/net.h>
+#include <linux/nls.h>
+#include <linux/connector.h>
+#include <linux/workqueue.h>
+
+#include "hyperv.h"
+#include "hv_kvp.h"
+
+
+
+/*
+ * Global state maintained for transaction that is being processed.
+ * Note that only one transaction can be active at any point in time.
+ *
+ * This state is set when we receive a request from the host; we
+ * cleanup this state when the transaction is completed - when we respond
+ * to the host with the key value.
+ */
+
+static struct {
+ bool active; /* transaction status - active or not */
+ int recv_len; /* number of bytes received. */
+ struct vmbus_channel *recv_channel; /* chn we got the request */
+ u64 recv_req_id; /* request ID. */
+} kvp_transaction;
+
+static int kvp_send_key(int index);
+
+static void kvp_respond_to_host(char *key, char *value, int error);
+static void kvp_work_func(struct work_struct *dummy);
+static void kvp_register(void);
+
+static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
+
+static struct cb_id kvp_id = { CN_KVP_IDX, CN_KVP_VAL };
+static const char kvp_name[] = "kvp_kernel_module";
+static int timeout_fired;
+static u8 *recv_buffer;
+/*
+ * Register the kernel component with the user-level daemon.
+ * As part of this registration, pass the LIC version number.
+ */
+
+static void
+kvp_register(void)
+{
+
+ struct cn_msg *msg;
+
+ msg = kzalloc(sizeof(*msg) + strlen(HV_DRV_VERSION) + 1 , GFP_ATOMIC);
+
+ if (msg) {
+ msg->id.idx = CN_KVP_IDX;
+ msg->id.val = CN_KVP_VAL;
+ msg->seq = KVP_REGISTER;
+ strcpy(msg->data, HV_DRV_VERSION);
+ msg->len = strlen(HV_DRV_VERSION) + 1;
+ cn_netlink_send(msg, 0, GFP_ATOMIC);
+ kfree(msg);
+ }
+}
+static void
+kvp_work_func(struct work_struct *dummy)
+{
+ /*
+ * If the timer fires, the user-mode component has not responded;
+ * process the pending transaction.
+ */
+ kvp_respond_to_host("Unknown key", "Guest timed out", timeout_fired);
+ timeout_fired = 1;
+}
+
+/*
+ * Callback when data is received from user mode.
+ */
+
+static void
+kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
+{
+ struct hv_ku_msg *message;
+
+ message = (struct hv_ku_msg *)msg->data;
+ if (msg->seq == KVP_REGISTER) {
+ pr_info("KVP: user-mode registering done.\n");
+ kvp_register();
+ }
+
+ if (msg->seq == KVP_USER_SET) {
+ /*
+ * Complete the transaction by forwarding the key value
+ * to the host. But first, cancel the timeout.
+ */
+ if (cancel_delayed_work_sync(&kvp_work))
+ kvp_respond_to_host(message->kvp_key,
+ message->kvp_value,
+ !strlen(message->kvp_key));
+ }
+}
+
+static int
+kvp_send_key(int index)
+{
+ struct cn_msg *msg;
+
+ msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
+
+ if (msg) {
+ msg->id.idx = CN_KVP_IDX;
+ msg->id.val = CN_KVP_VAL;
+ msg->seq = KVP_KERNEL_GET;
+ ((struct hv_ku_msg *)msg->data)->kvp_index = index;
+ msg->len = sizeof(struct hv_ku_msg);
+ cn_netlink_send(msg, 0, GFP_ATOMIC);
+ kfree(msg);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Send a response back to the host.
+ */
+
+static void
+kvp_respond_to_host(char *key, char *value, int error)
+{
+ struct hv_kvp_msg *kvp_msg;
+ struct hv_kvp_msg_enumerate *kvp_data;
+ char *key_name;
+ struct icmsg_hdr *icmsghdrp;
+ int keylen, valuelen;
+ u32 buf_len;
+ struct vmbus_channel *channel;
+ u64 req_id;
+
+ /*
+ * If a transaction is not active; log and return.
+ */
+
+ if (!kvp_transaction.active) {
+ /*
+ * This is a spurious call!
+ */
+ pr_warn("KVP: Transaction not active\n");
+ return;
+ }
+ /*
+ * Copy the global state for completing the transaction. Note that
+ * only one transaction can be active at a time.
+ */
+
+ buf_len = kvp_transaction.recv_len;
+ channel = kvp_transaction.recv_channel;
+ req_id = kvp_transaction.recv_req_id;
+
+ icmsghdrp = (struct icmsg_hdr *)
+ &recv_buffer[sizeof(struct vmbuspipe_hdr)];
+ kvp_msg = (struct hv_kvp_msg *)
+ &recv_buffer[sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+ kvp_data = &kvp_msg->kvp_data;
+ key_name = key;
+
+ /*
+ * If the error parameter is set, terminate the host's enumeration.
+ */
+ if (error) {
+ /*
+ * We don't support this index or the we have timedout;
+ * terminate the host-side iteration by returning an error.
+ */
+ icmsghdrp->status = HV_E_FAIL;
+ goto response_done;
+ }
+
+ /*
+ * The windows host expects the key/value pair to be encoded
+ * in utf16.
+ */
+ keylen = utf8s_to_utf16s(key_name, strlen(key_name),
+ (wchar_t *)kvp_data->data.key);
+ kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */
+ valuelen = utf8s_to_utf16s(value, strlen(value),
+ (wchar_t *)kvp_data->data.value);
+ kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */
+
+ kvp_data->data.value_type = REG_SZ; /* all our values are strings */
+ icmsghdrp->status = HV_S_OK;
+
+response_done:
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
+
+ vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
+ VM_PKT_DATA_INBAND, 0);
+
+ kvp_transaction.active = false;
+}
+
+/*
+ * This callback is invoked when we get a KVP message from the host.
+ * The host ensures that only one KVP transaction can be active at a time.
+ * KVP implementation in Linux needs to forward the key to a user-mde
+ * component to retrive the corresponding value. Consequently, we cannot
+ * respond to the host in the conext of this callback. Since the host
+ * guarantees that at most only one transaction can be active at a time,
+ * we stash away the transaction state in a set of global variables.
+ */
+
+void hv_kvp_onchannelcallback(void *context)
+{
+ struct vmbus_channel *channel = context;
+ u32 recvlen;
+ u64 requestid;
+
+ struct hv_kvp_msg *kvp_msg;
+ struct hv_kvp_msg_enumerate *kvp_data;
+
+ struct icmsg_hdr *icmsghdrp;
+ struct icmsg_negotiate *negop = NULL;
+
+
+ if (kvp_transaction.active)
+ return;
+
+
+ vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
+
+ if (recvlen > 0) {
+ icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ prep_negotiate_resp(icmsghdrp, negop, recv_buffer);
+ } else {
+ kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ kvp_data = &kvp_msg->kvp_data;
+
+ /*
+ * We only support the "get" operation on
+ * "KVP_POOL_AUTO" pool.
+ */
+
+ if ((kvp_msg->kvp_hdr.pool != KVP_POOL_AUTO) ||
+ (kvp_msg->kvp_hdr.operation !=
+ KVP_OP_ENUMERATE)) {
+ icmsghdrp->status = HV_E_FAIL;
+ goto callback_done;
+ }
+
+ /*
+ * Stash away this global state for completing the
+ * transaction; note transactions are serialized.
+ */
+ kvp_transaction.recv_len = recvlen;
+ kvp_transaction.recv_channel = channel;
+ kvp_transaction.recv_req_id = requestid;
+ kvp_transaction.active = true;
+
+ /*
+ * Get the information from the
+ * user-mode component.
+ * component. This transaction will be
+ * completed when we get the value from
+ * the user-mode component.
+ * Set a timeout to deal with
+ * user-mode not responding.
+ */
+ kvp_send_key(kvp_data->index);
+ schedule_delayed_work(&kvp_work, 100);
+
+ return;
+
+ }
+
+callback_done:
+
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+ | ICMSGHDRFLAG_RESPONSE;
+
+ vmbus_sendpacket(channel, recv_buffer,
+ recvlen, requestid,
+ VM_PKT_DATA_INBAND, 0);
+ }
+
+}
+
+int
+hv_kvp_init(void)
+{
+ int err;
+
+ err = cn_add_callback(&kvp_id, kvp_name, kvp_cn_callback);
+ if (err)
+ return err;
+ recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!recv_buffer)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void hv_kvp_deinit(void)
+{
+ cn_del_callback(&kvp_id);
+ cancel_delayed_work_sync(&kvp_work);
+ kfree(recv_buffer);
+}
diff --git a/drivers/staging/hv/hv_kvp.h b/drivers/staging/hv/hv_kvp.h
new file mode 100644
index 000000000000..8c402f357d37
--- /dev/null
+++ b/drivers/staging/hv/hv_kvp.h
@@ -0,0 +1,184 @@
+/*
+ * An implementation of HyperV key value pair (KVP) functionality for Linux.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef _KVP_H
+#define _KVP_H_
+
+/*
+ * Maximum value size - used for both key names and value data, and includes
+ * any applicable NULL terminators.
+ *
+ * Note: This limit is somewhat arbitrary, but falls easily within what is
+ * supported for all native guests (back to Win 2000) and what is reasonable
+ * for the IC KVP exchange functionality. Note that Windows Me/98/95 are
+ * limited to 255 character key names.
+ *
+ * MSDN recommends not storing data values larger than 2048 bytes in the
+ * registry.
+ *
+ * Note: This value is used in defining the KVP exchange message - this value
+ * cannot be modified without affecting the message size and compatibility.
+ */
+
+/*
+ * bytes, including any null terminators
+ */
+#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048)
+
+
+/*
+ * Maximum key size - the registry limit for the length of an entry name
+ * is 256 characters, including the null terminator
+ */
+
+#define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512)
+
+/*
+ * In Linux, we implement the KVP functionality in two components:
+ * 1) The kernel component which is packaged as part of the hv_utils driver
+ * is responsible for communicating with the host and responsible for
+ * implementing the host/guest protocol. 2) A user level daemon that is
+ * responsible for data gathering.
+ *
+ * Host/Guest Protocol: The host iterates over an index and expects the guest
+ * to assign a key name to the index and also return the value corresponding to
+ * the key. The host will have atmost one KVP transaction outstanding at any
+ * given point in time. The host side iteration stops when the guest returns
+ * an error. Microsoft has specified the following mapping of key names to
+ * host specified index:
+ *
+ * Index Key Name
+ * 0 FullyQualifiedDomainName
+ * 1 IntegrationServicesVersion
+ * 2 NetworkAddressIPv4
+ * 3 NetworkAddressIPv6
+ * 4 OSBuildNumber
+ * 5 OSName
+ * 6 OSMajorVersion
+ * 7 OSMinorVersion
+ * 8 OSVersion
+ * 9 ProcessorArchitecture
+ *
+ * The Windows host expects the Key Name and Key Value to be encoded in utf16.
+ *
+ * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
+ * data gathering functionality in a user mode daemon. The user level daemon
+ * is also responsible for binding the key name to the index as well. The
+ * kernel and user-level daemon communicate using a connector channel.
+ *
+ * The user mode component first registers with the
+ * the kernel component. Subsequently, the kernel component requests, data
+ * for the specified keys. In response to this message the user mode component
+ * fills in the value corresponding to the specified key. We overload the
+ * sequence field in the cn_msg header to define our KVP message types.
+ *
+ *
+ * The kernel component simply acts as a conduit for communication between the
+ * Windows host and the user-level daemon. The kernel component passes up the
+ * index received from the Host to the user-level daemon. If the index is
+ * valid (supported), the corresponding key as well as its
+ * value (both are strings) is returned. If the index is invalid
+ * (not supported), a NULL key string is returned.
+ */
+
+/*
+ *
+ * The following definitions are shared with the user-mode component; do not
+ * change any of this without making the corresponding changes in
+ * the KVP user-mode component.
+ */
+
+#define CN_KVP_VAL 0x1 /* This supports queries from the kernel */
+#define CN_KVP_USER_VAL 0x2 /* This supports queries from the user */
+
+enum hv_ku_op {
+ KVP_REGISTER = 0, /* Register the user mode component */
+ KVP_KERNEL_GET, /* Kernel is requesting the value */
+ KVP_KERNEL_SET, /* Kernel is providing the value */
+ KVP_USER_GET, /* User is requesting the value */
+ KVP_USER_SET /* User is providing the value */
+};
+
+struct hv_ku_msg {
+ __u32 kvp_index; /* Key index */
+ __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
+ __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
+};
+
+
+
+
+#ifdef __KERNEL__
+
+/*
+ * Registry value types.
+ */
+
+#define REG_SZ 1
+
+enum hv_kvp_exchg_op {
+ KVP_OP_GET = 0,
+ KVP_OP_SET,
+ KVP_OP_DELETE,
+ KVP_OP_ENUMERATE,
+ KVP_OP_COUNT /* Number of operations, must be last. */
+};
+
+enum hv_kvp_exchg_pool {
+ KVP_POOL_EXTERNAL = 0,
+ KVP_POOL_GUEST,
+ KVP_POOL_AUTO,
+ KVP_POOL_AUTO_EXTERNAL,
+ KVP_POOL_AUTO_INTERNAL,
+ KVP_POOL_COUNT /* Number of pools, must be last. */
+};
+
+struct hv_kvp_hdr {
+ u8 operation;
+ u8 pool;
+};
+
+struct hv_kvp_exchg_msg_value {
+ u32 value_type;
+ u32 key_size;
+ u32 value_size;
+ u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+};
+
+struct hv_kvp_msg_enumerate {
+ u32 index;
+ struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg {
+ struct hv_kvp_hdr kvp_hdr;
+ struct hv_kvp_msg_enumerate kvp_data;
+};
+
+int hv_kvp_init(void);
+void hv_kvp_deinit(void);
+void hv_kvp_onchannelcallback(void *);
+
+#endif /* __KERNEL__ */
+#endif /* _KVP_H */
+
diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c
new file mode 100644
index 000000000000..b191810b898d
--- /dev/null
+++ b/drivers/staging/hv/hv_mouse.c
@@ -0,0 +1,975 @@
+/*
+ * 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/pci.h>
+#include <linux/dmi.h>
+#include <linux/delay.h>
+
+#include "hyperv.h"
+
+
+/*
+ * Data types
+ */
+struct hv_input_dev_info {
+ unsigned short vendor;
+ unsigned short product;
+ unsigned short version;
+ char name[128];
+};
+
+/* 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 {
+ SynthHidProtocolRequest,
+ SynthHidProtocolResponse,
+ SynthHidInitialDeviceInfo,
+ SynthHidInitialDeviceInfoAck,
+ SynthHidInputReport,
+ SynthHidMax
+};
+
+/*
+ * 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 {
+ PipeMessageInvalid = 0,
+ PipeMessageData,
+ PipeMessageMaximum
+};
+
+
+struct pipe_prt_msg {
+ enum pipe_prot_msg_type type;
+ u32 size;
+ char data[1];
+};
+
+/*
+ * Data types
+ */
+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;
+ /* 0 indicates the device is being destroyed */
+ atomic_t ref_count;
+ int num_outstanding_req;
+ unsigned char init_complete;
+ struct mousevsc_prt_msg protocol_req;
+ struct mousevsc_prt_msg protocol_resp;
+ /* Synchronize the request/response if needed */
+ wait_queue_head_t protocol_wait_event;
+ wait_queue_head_t dev_info_wait_event;
+ int protocol_wait_condition;
+ int device_wait_condition;
+ 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;
+};
+
+
+static const char *driver_name = "mousevsc";
+
+/* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
+static const struct hv_guid mouse_guid = {
+ .data = {0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
+ 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A}
+};
+
+static void deviceinfo_callback(struct hv_device *dev, struct hv_input_dev_info *info);
+static void inputreport_callback(struct hv_device *dev, void *packet, u32 len);
+static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len);
+
+static struct mousevsc_dev *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;
+
+ /*
+ * Set to 2 to allow both inbound and outbound traffics
+ * (ie get_input_device() and must_get_input_device()) to proceed.
+ */
+ atomic_cmpxchg(&input_dev->ref_count, 0, 2);
+
+ input_dev->device = device;
+ device->ext = input_dev;
+
+ return input_dev;
+}
+
+static void free_input_device(struct mousevsc_dev *device)
+{
+ WARN_ON(atomic_read(&device->ref_count) == 0);
+ kfree(device);
+}
+
+/*
+ * Get the inputdevice object if exists and its refcount > 1
+ */
+static struct mousevsc_dev *get_input_device(struct hv_device *device)
+{
+ struct mousevsc_dev *input_dev;
+
+ input_dev = (struct mousevsc_dev *)device->ext;
+
+/*
+ * FIXME
+ * This sure isn't a valid thing to print for debugging, no matter
+ * what the intention is...
+ *
+ * printk(KERN_ERR "-------------------------> REFCOUNT = %d",
+ * input_dev->ref_count);
+ */
+
+ if (input_dev && atomic_read(&input_dev->ref_count) > 1)
+ atomic_inc(&input_dev->ref_count);
+ else
+ input_dev = NULL;
+
+ return input_dev;
+}
+
+/*
+ * Get the inputdevice object iff exists and its refcount > 0
+ */
+static struct mousevsc_dev *must_get_input_device(struct hv_device *device)
+{
+ struct mousevsc_dev *input_dev;
+
+ input_dev = (struct mousevsc_dev *)device->ext;
+
+ if (input_dev && atomic_read(&input_dev->ref_count))
+ atomic_inc(&input_dev->ref_count);
+ else
+ input_dev = NULL;
+
+ return input_dev;
+}
+
+static void put_input_device(struct hv_device *device)
+{
+ struct mousevsc_dev *input_dev;
+
+ input_dev = (struct mousevsc_dev *)device->ext;
+
+ atomic_dec(&input_dev->ref_count);
+}
+
+/*
+ * Drop ref count to 1 to effectively disable get_input_device()
+ */
+static struct mousevsc_dev *release_input_device(struct hv_device *device)
+{
+ struct mousevsc_dev *input_dev;
+
+ input_dev = (struct mousevsc_dev *)device->ext;
+
+ /* Busy wait until the ref drop to 2, then set it to 1 */
+ while (atomic_cmpxchg(&input_dev->ref_count, 2, 1) != 2)
+ udelay(100);
+
+ return input_dev;
+}
+
+/*
+ * Drop ref count to 0. No one can use input_device object.
+ */
+static struct mousevsc_dev *final_release_input_device(struct hv_device *device)
+{
+ struct mousevsc_dev *input_dev;
+
+ input_dev = (struct mousevsc_dev *)device->ext;
+
+ /* Busy wait until the ref drop to 1, then set it to 0 */
+ while (atomic_cmpxchg(&input_dev->ref_count, 1, 0) != 1)
+ udelay(100);
+
+ device->ext = NULL;
+ return input_dev;
+}
+
+static void mousevsc_on_send_completion(struct hv_device *device,
+ struct vmpacket_descriptor *packet)
+{
+ struct mousevsc_dev *input_dev;
+ void *request;
+
+ input_dev = must_get_input_device(device);
+ if (!input_dev) {
+ pr_err("unable to get input device...device being destroyed?");
+ return;
+ }
+
+ request = (void *)(unsigned long)packet->trans_id;
+
+ if (request == &input_dev->protocol_req) {
+ /* FIXME */
+ /* Shouldn't we be doing something here? */
+ }
+
+ put_input_device(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;
+
+ /* Save the device attr */
+ memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
+ sizeof(struct hv_input_dev_info));
+
+ /* Save the hid desc */
+ desc = &device_info->hid_descriptor;
+ WARN_ON(desc->bLength > 0);
+
+ input_device->hid_desc = kzalloc(desc->bLength, GFP_KERNEL);
+
+ if (!input_device->hid_desc) {
+ pr_err("unable to allocate hid descriptor - size %d", desc->bLength);
+ goto Cleanup;
+ }
+
+ memcpy(input_device->hid_desc, desc, desc->bLength);
+
+ /* Save the report desc */
+ input_device->report_desc_size = desc->desc[0].wDescriptorLength;
+ input_device->report_desc = kzalloc(input_device->report_desc_size,
+ GFP_KERNEL);
+
+ if (!input_device->report_desc) {
+ pr_err("unable to allocate report descriptor - size %d",
+ input_device->report_desc_size);
+ 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 = PipeMessageData;
+ ack.size = sizeof(struct synthhid_device_info_ack);
+
+ ack.ack.header.type = SynthHidInitialDeviceInfoAck;
+ 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) {
+ pr_err("unable to send synthhid device info ack - ret %d",
+ ret);
+ goto Cleanup;
+ }
+
+ input_device->device_wait_condition = 1;
+ wake_up(&input_device->dev_info_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;
+ input_device->device_wait_condition = 1;
+ wake_up(&input_device->dev_info_wait_event);
+}
+
+static void mousevsc_on_receive_input_report(struct mousevsc_dev *input_device,
+ struct synthhid_input_report *input_report)
+{
+ struct hv_driver *input_drv;
+
+ if (!input_device->init_complete) {
+ pr_info("Initialization incomplete...ignoring input_report msg");
+ return;
+ }
+
+ input_drv = drv_to_hv_drv(input_device->device->device.driver);
+
+ inputreport_callback(input_device->device,
+ input_report->buffer,
+ input_report->header.size);
+}
+
+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;
+
+ input_dev = must_get_input_device(device);
+ if (!input_dev) {
+ pr_err("unable to get input device...device being destroyed?");
+ return;
+ }
+
+ pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
+ (packet->offset8 << 3));
+
+ if (pipe_msg->type != PipeMessageData) {
+ pr_err("unknown pipe msg type - type %d len %d",
+ pipe_msg->type, pipe_msg->size);
+ put_input_device(device);
+ return ;
+ }
+
+ hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
+
+ switch (hid_msg->header.type) {
+ case SynthHidProtocolResponse:
+ memcpy(&input_dev->protocol_resp, pipe_msg,
+ pipe_msg->size + sizeof(struct pipe_prt_msg) -
+ sizeof(unsigned char));
+ input_dev->protocol_wait_condition = 1;
+ wake_up(&input_dev->protocol_wait_event);
+ break;
+
+ case SynthHidInitialDeviceInfo:
+ 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 SynthHidInputReport:
+ mousevsc_on_receive_input_report(input_dev,
+ (struct synthhid_input_report *)&pipe_msg->data[0]);
+
+ break;
+ default:
+ pr_err("unsupported hid msg type - type %d len %d",
+ hid_msg->header.type, hid_msg->header.size);
+ break;
+ }
+
+ put_input_device(device);
+}
+
+static void mousevsc_on_channel_callback(void *context)
+{
+ const int packetSize = 0x100;
+ int ret = 0;
+ struct hv_device *device = (struct hv_device *)context;
+ struct mousevsc_dev *input_dev;
+
+ u32 bytes_recvd;
+ u64 req_id;
+ unsigned char packet[0x100];
+ struct vmpacket_descriptor *desc;
+ unsigned char *buffer = packet;
+ int bufferlen = packetSize;
+
+ input_dev = must_get_input_device(device);
+
+ if (!input_dev) {
+ pr_err("unable to get input device...device being destroyed?");
+ return;
+ }
+
+ 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:
+ mousevsc_on_send_completion(
+ device, desc);
+ 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 {
+ /*
+ * pr_debug("nothing else to read...");
+ * reset
+ */
+ if (bufferlen > packetSize) {
+ kfree(buffer);
+
+ buffer = packet;
+ bufferlen = packetSize;
+ }
+ break;
+ }
+ } else if (ret == -2) {
+ /* Handle large packet */
+ bufferlen = bytes_recvd;
+ buffer = kzalloc(bytes_recvd, GFP_KERNEL);
+
+ if (buffer == NULL) {
+ buffer = packet;
+ bufferlen = packetSize;
+
+ /* Try again next time around */
+ pr_err("unable to allocate buffer of size %d!",
+ bytes_recvd);
+ break;
+ }
+ }
+ } while (1);
+
+ put_input_device(device);
+
+ return;
+}
+
+static int mousevsc_connect_to_vsp(struct hv_device *device)
+{
+ int ret = 0;
+ struct mousevsc_dev *input_dev;
+ struct mousevsc_prt_msg *request;
+ struct mousevsc_prt_msg *response;
+
+ input_dev = get_input_device(device);
+
+ if (!input_dev) {
+ pr_err("unable to get input device...device being destroyed?");
+ return -1;
+ }
+
+ init_waitqueue_head(&input_dev->protocol_wait_event);
+ init_waitqueue_head(&input_dev->dev_info_wait_event);
+
+ request = &input_dev->protocol_req;
+
+ /*
+ * Now, initiate the vsc/vsp initialization protocol on the open channel
+ */
+ memset(request, 0, sizeof(struct mousevsc_prt_msg));
+
+ request->type = PipeMessageData;
+ request->size = sizeof(struct synthhid_protocol_request);
+
+ request->request.header.type = SynthHidProtocolRequest;
+ request->request.header.size = sizeof(unsigned long);
+ request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
+
+ pr_info("synthhid protocol request...");
+
+ 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) {
+ pr_err("unable to send synthhid protocol request.");
+ goto Cleanup;
+ }
+
+ input_dev->protocol_wait_condition = 0;
+ wait_event_timeout(input_dev->protocol_wait_event,
+ input_dev->protocol_wait_condition, msecs_to_jiffies(1000));
+ if (input_dev->protocol_wait_condition == 0) {
+ ret = -ETIMEDOUT;
+ goto Cleanup;
+ }
+
+ response = &input_dev->protocol_resp;
+
+ if (!response->response.approved) {
+ pr_err("synthhid protocol request failed (version %d)",
+ SYNTHHID_INPUT_VERSION);
+ ret = -1;
+ goto Cleanup;
+ }
+
+ input_dev->device_wait_condition = 0;
+ wait_event_timeout(input_dev->dev_info_wait_event,
+ input_dev->device_wait_condition, msecs_to_jiffies(1000));
+ if (input_dev->device_wait_condition == 0) {
+ ret = -ETIMEDOUT;
+ goto Cleanup;
+ }
+
+ /*
+ * We should have gotten the device attr, hid desc and report
+ * desc at this point
+ */
+ if (!input_dev->dev_info_status)
+ pr_info("**** input channel up and running!! ****");
+ else
+ ret = -1;
+
+Cleanup:
+ put_input_device(device);
+
+ return ret;
+}
+
+static int mousevsc_on_device_add(struct hv_device *device,
+ void *additional_info)
+{
+ int ret = 0;
+ struct mousevsc_dev *input_dev;
+ struct hv_driver *input_drv;
+ struct hv_input_dev_info dev_info;
+
+ input_dev = alloc_input_device(device);
+
+ if (!input_dev) {
+ ret = -1;
+ goto Cleanup;
+ }
+
+ input_dev->init_complete = false;
+
+ /* Open the channel */
+ 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) {
+ pr_err("unable to open channel: %d", ret);
+ free_input_device(input_dev);
+ return -1;
+ }
+
+ pr_info("InputVsc channel open: %d", ret);
+
+ ret = mousevsc_connect_to_vsp(device);
+
+ if (ret != 0) {
+ pr_err("unable to connect channel: %d", ret);
+
+ vmbus_close(device->channel);
+ free_input_device(input_dev);
+ return ret;
+ }
+
+ input_drv = drv_to_hv_drv(input_dev->device->device.driver);
+
+ dev_info.vendor = input_dev->hid_dev_info.vendor;
+ dev_info.product = input_dev->hid_dev_info.product;
+ dev_info.version = input_dev->hid_dev_info.version;
+ strcpy(dev_info.name, "Microsoft Vmbus HID-compliant Mouse");
+
+ /* Send the device info back up */
+ deviceinfo_callback(device, &dev_info);
+
+ /* Send the report desc back up */
+ /* 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;
+
+Cleanup:
+ return ret;
+}
+
+static int mousevsc_on_device_remove(struct hv_device *device)
+{
+ struct mousevsc_dev *input_dev;
+ int ret = 0;
+
+ pr_info("disabling input device (%p)...",
+ device->ext);
+
+ input_dev = release_input_device(device);
+
+
+ /*
+ * At this point, all outbound traffic should be disable. We only
+ * allow inbound traffic (responses) to proceed
+ *
+ * so that outstanding requests can be completed.
+ */
+ while (input_dev->num_outstanding_req) {
+ pr_info("waiting for %d requests to complete...",
+ input_dev->num_outstanding_req);
+
+ udelay(100);
+ }
+
+ pr_info("removing input device (%p)...", device->ext);
+
+ input_dev = final_release_input_device(device);
+
+ pr_info("input device (%p) safe to remove", input_dev);
+
+ /* Close the channel */
+ vmbus_close(device->channel);
+
+ free_input_device(input_dev);
+
+ return ret;
+}
+
+
+/*
+ * Data types
+ */
+struct input_device_context {
+ struct hv_device *device_ctx;
+ struct hid_device *hid_device;
+ struct hv_input_dev_info device_info;
+ int connected;
+};
+
+
+static void deviceinfo_callback(struct hv_device *dev, struct hv_input_dev_info *info)
+{
+ struct input_device_context *input_device_ctx =
+ dev_get_drvdata(&dev->device);
+
+ memcpy(&input_device_ctx->device_info, info,
+ sizeof(struct hv_input_dev_info));
+
+ DPRINT_INFO(INPUTVSC_DRV, "%s", __func__);
+}
+
+static void inputreport_callback(struct hv_device *dev, void *packet, u32 len)
+{
+ int ret = 0;
+
+ struct input_device_context *input_dev_ctx =
+ dev_get_drvdata(&dev->device);
+
+ ret = hid_input_report(input_dev_ctx->hid_device,
+ HID_INPUT_REPORT, packet, len, 1);
+
+ DPRINT_DBG(INPUTVSC_DRV, "hid_input_report (ret %d)", ret);
+}
+
+static int mousevsc_hid_open(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void mousevsc_hid_close(struct hid_device *hid)
+{
+}
+
+static int mousevsc_probe(struct hv_device *dev)
+{
+ int ret = 0;
+
+ struct input_device_context *input_dev_ctx;
+
+ input_dev_ctx = kmalloc(sizeof(struct input_device_context),
+ GFP_KERNEL);
+
+ dev_set_drvdata(&dev->device, input_dev_ctx);
+
+ /* Call to the vsc driver to add the device */
+ ret = mousevsc_on_device_add(dev, NULL);
+
+ if (ret != 0) {
+ DPRINT_ERR(INPUTVSC_DRV, "unable to add input vsc device");
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mousevsc_remove(struct hv_device *dev)
+{
+ int ret = 0;
+
+ struct input_device_context *input_dev_ctx;
+
+ input_dev_ctx = kmalloc(sizeof(struct input_device_context),
+ GFP_KERNEL);
+
+ dev_set_drvdata(&dev->device, input_dev_ctx);
+
+ if (input_dev_ctx->connected) {
+ hidinput_disconnect(input_dev_ctx->hid_device);
+ input_dev_ctx->connected = 0;
+ }
+
+ /*
+ * Call to the vsc driver to let it know that the device
+ * is being removed
+ */
+ ret = mousevsc_on_device_remove(dev);
+
+ if (ret != 0) {
+ DPRINT_ERR(INPUTVSC_DRV,
+ "unable to remove vsc device (ret %d)", ret);
+ }
+
+ kfree(input_dev_ctx);
+
+ return ret;
+}
+
+static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
+{
+ struct input_device_context *input_device_ctx =
+ dev_get_drvdata(&dev->device);
+ struct hid_device *hid_dev;
+
+ /* hid_debug = -1; */
+ hid_dev = kmalloc(sizeof(struct hid_device), GFP_KERNEL);
+
+ if (hid_parse_report(hid_dev, packet, len)) {
+ DPRINT_INFO(INPUTVSC_DRV, "Unable to call hd_parse_report");
+ return;
+ }
+
+ if (hid_dev) {
+ DPRINT_INFO(INPUTVSC_DRV, "hid_device created");
+
+ hid_dev->ll_driver->open = mousevsc_hid_open;
+ hid_dev->ll_driver->close = mousevsc_hid_close;
+
+ hid_dev->bus = BUS_VIRTUAL;
+ hid_dev->vendor = input_device_ctx->device_info.vendor;
+ hid_dev->product = input_device_ctx->device_info.product;
+ hid_dev->version = input_device_ctx->device_info.version;
+ hid_dev->dev = dev->device;
+
+ sprintf(hid_dev->name, "%s",
+ input_device_ctx->device_info.name);
+
+ /*
+ * HJ Do we want to call it with a 0
+ */
+ if (!hidinput_connect(hid_dev, 0)) {
+ hid_dev->claimed |= HID_CLAIMED_INPUT;
+
+ input_device_ctx->connected = 1;
+
+ DPRINT_INFO(INPUTVSC_DRV,
+ "HID device claimed by input\n");
+ }
+
+ if (!hid_dev->claimed) {
+ DPRINT_ERR(INPUTVSC_DRV,
+ "HID device not claimed by "
+ "input or hiddev\n");
+ }
+
+ input_device_ctx->hid_device = hid_dev;
+ }
+
+ kfree(hid_dev);
+}
+
+
+static struct hv_driver mousevsc_drv = {
+ .probe = mousevsc_probe,
+ .remove = mousevsc_remove,
+};
+
+static void mousevsc_drv_exit(void)
+{
+ vmbus_child_driver_unregister(&mousevsc_drv.driver);
+}
+
+static int __init mousevsc_init(void)
+{
+ struct hv_driver *drv = &mousevsc_drv;
+
+ DPRINT_INFO(INPUTVSC_DRV, "Hyper-V Mouse driver initializing.");
+
+ memcpy(&drv->dev_type, &mouse_guid,
+ sizeof(struct hv_guid));
+
+ drv->driver.name = driver_name;
+
+ /* The driver belongs to vmbus */
+ vmbus_child_driver_register(&drv->driver);
+
+ return 0;
+}
+
+static void __exit mousevsc_exit(void)
+{
+ mousevsc_drv_exit();
+}
+
+/*
+ * We don't want to automatically load this driver just yet, it's quite
+ * broken. It's safe if you want to load it yourself manually, but
+ * don't inflict it on unsuspecting users, that's just mean.
+ */
+#if 0
+
+/*
+ * We use a PCI table to determine if we should autoload this driver This is
+ * needed by distro tools to determine if the hyperv drivers should be
+ * installed and/or configured. We don't do anything else with the table, but
+ * it needs to be present.
+ */
+const static struct pci_device_id microsoft_hv_pci_table[] = {
+ { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
+module_init(mousevsc_init);
+module_exit(mousevsc_exit);
+
diff --git a/drivers/staging/hv/hv_timesource.c b/drivers/staging/hv/hv_timesource.c
index d3be8af50f61..0efb04915255 100644
--- a/drivers/staging/hv/hv_timesource.c
+++ b/drivers/staging/hv/hv_timesource.c
@@ -5,9 +5,9 @@
* Copyright (C) 2010, Novell, Inc.
* Author : K. Y. Srinivasan <ksrinivasan@novell.com>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,6 +20,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/version.h>
#include <linux/clocksource.h>
@@ -27,23 +28,11 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/dmi.h>
+#include <asm/hyperv.h>
+#include <asm/mshyperv.h>
+#include <asm/hypervisor.h>
#define HV_CLOCK_SHIFT 22
-/*
- * HyperV defined synthetic CPUID leaves:
- */
-#define HV_CPUID_SIGNATURE 0x40000000
-#define HV_CPUID_MIN 0x40000005
-#define HV_HYPERVISOR_PRESENT_BIT 0x80000000
-#define HV_CPUID_FEATURES 0x40000003
-#define HV_CPUID_RECOMMENDATIONS 0x40000004
-
-/*
- * HyperV defined synthetic MSRs
- */
-
-#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
-
static cycle_t read_hv_clock(struct clocksource *arg)
{
@@ -94,49 +83,16 @@ hv_timesource_pci_table[] __maybe_unused = {
MODULE_DEVICE_TABLE(pci, hv_timesource_pci_table);
-static int __init hv_detect_hyperv(void)
-{
- u32 eax, ebx, ecx, edx;
- char hyp_signature[13];
-
- cpuid(1, &eax, &ebx, &ecx, &edx);
-
- if (!(ecx & HV_HYPERVISOR_PRESENT_BIT))
- return 1;
-
- cpuid(HV_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
- *(u32 *)(hyp_signature + 0) = ebx;
- *(u32 *)(hyp_signature + 4) = ecx;
- *(u32 *)(hyp_signature + 8) = edx;
-
- if ((eax < HV_CPUID_MIN) || (memcmp("Microsoft Hv", hyp_signature, 12)))
- return 1;
-
- /*
- * Extract the features, recommendations etc.
- */
- cpuid(HV_CPUID_FEATURES, &eax, &ebx, &ecx, &edx);
- if (!(eax & 0x10)) {
- printk(KERN_WARNING "HyperV Time Ref Counter not available!\n");
- return 1;
- }
-
- cpuid(HV_CPUID_RECOMMENDATIONS, &eax, &ebx, &ecx, &edx);
- printk(KERN_INFO "HyperV recommendations: %x\n", eax);
- printk(KERN_INFO "HyperV spin count: %x\n", ebx);
- return 0;
-}
-
-
static int __init init_hv_clocksource(void)
{
- if (hv_detect_hyperv())
+ if ((x86_hyper != &x86_hyper_ms_hyperv) ||
+ !(ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE))
return -ENODEV;
if (!dmi_check_system(hv_timesource_dmi_table))
return -ENODEV;
- printk(KERN_INFO "Registering HyperV clock source\n");
+ pr_info("Registering HyperV clock source\n");
return clocksource_register(&hyperv_cs);
}
diff --git a/drivers/staging/hv/hyperv_utils.c b/drivers/staging/hv/hv_util.c
index fa78ba052551..c164b54b4cd7 100644
--- a/drivers/staging/hv/hyperv_utils.c
+++ b/drivers/staging/hv/hv_util.c
@@ -18,6 +18,8 @@
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -27,23 +29,17 @@
#include <linux/dmi.h>
#include <linux/pci.h>
-#include "logging.h"
-#include "osd.h"
-#include "vmbus.h"
-#include "VmbusPacketFormat.h"
-#include "VmbusChannelInterface.h"
-#include "VersionInfo.h"
-#include "Channel.h"
-#include "VmbusPrivate.h"
-#include "VmbusApi.h"
-#include "utils.h"
+#include "hyperv.h"
+#include "hv_kvp.h"
+static u8 *shut_txf_buf;
+static u8 *time_txf_buf;
+static u8 *hbeat_txf_buf;
static void shutdown_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
- u8 *buf;
- u32 buflen, recvlen;
+ u32 recvlen;
u64 requestid;
u8 execute_shutdown = false;
@@ -52,24 +48,20 @@ static void shutdown_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp;
struct icmsg_negotiate *negop = NULL;
- buflen = PAGE_SIZE;
- buf = kmalloc(buflen, GFP_ATOMIC);
-
- VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);
+ vmbus_recvpacket(channel, shut_txf_buf,
+ PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
- DPRINT_DBG(VMBUS, "shutdown packet: len=%d, requestid=%lld",
- recvlen, requestid);
-
- icmsghdrp = (struct icmsg_hdr *)&buf[
+ icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- prep_negotiate_resp(icmsghdrp, negop, buf);
+ prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf);
} else {
- shutdown_msg = (struct shutdown_msg_data *)&buf[
- sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
+ shutdown_msg =
+ (struct shutdown_msg_data *)&shut_txf_buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
switch (shutdown_msg->flags) {
case 0:
@@ -77,29 +69,27 @@ static void shutdown_onchannelcallback(void *context)
icmsghdrp->status = HV_S_OK;
execute_shutdown = true;
- DPRINT_INFO(VMBUS, "Shutdown request received -"
- " gracefull shutdown initiated");
+ pr_info("Shutdown request received -"
+ " graceful shutdown initiated\n");
break;
default:
icmsghdrp->status = HV_E_FAIL;
execute_shutdown = false;
- DPRINT_INFO(VMBUS, "Shutdown request received -"
- " Invalid request");
+ pr_info("Shutdown request received -"
+ " Invalid request\n");
break;
- };
+ }
}
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
- VmbusChannelSendPacket(channel, buf,
+ vmbus_sendpacket(channel, shut_txf_buf,
recvlen, requestid,
- VmbusPacketTypeDataInBand, 0);
+ VM_PKT_DATA_INBAND, 0);
}
- kfree(buf);
-
if (execute_shutdown == true)
orderly_poweroff(false);
}
@@ -150,28 +140,22 @@ static inline void adj_guesttime(u64 hosttime, u8 flags)
static void timesync_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
- u8 *buf;
- u32 buflen, recvlen;
+ u32 recvlen;
u64 requestid;
struct icmsg_hdr *icmsghdrp;
struct ictimesync_data *timedatap;
- buflen = PAGE_SIZE;
- buf = kmalloc(buflen, GFP_ATOMIC);
-
- VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);
+ vmbus_recvpacket(channel, time_txf_buf,
+ PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
- DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld",
- recvlen, requestid);
-
- icmsghdrp = (struct icmsg_hdr *)&buf[
+ icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- prep_negotiate_resp(icmsghdrp, NULL, buf);
+ prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf);
} else {
- timedatap = (struct ictimesync_data *)&buf[
+ timedatap = (struct ictimesync_data *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
adj_guesttime(timedatap->parenttime, timedatap->flags);
@@ -180,12 +164,10 @@ static void timesync_onchannelcallback(void *context)
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
- VmbusChannelSendPacket(channel, buf,
+ vmbus_sendpacket(channel, time_txf_buf,
recvlen, requestid,
- VmbusPacketTypeDataInBand, 0);
+ VM_PKT_DATA_INBAND, 0);
}
-
- kfree(buf);
}
/*
@@ -196,36 +178,25 @@ static void timesync_onchannelcallback(void *context)
static void heartbeat_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
- u8 *buf;
- u32 buflen, recvlen;
+ u32 recvlen;
u64 requestid;
struct icmsg_hdr *icmsghdrp;
struct heartbeat_msg_data *heartbeat_msg;
- buflen = PAGE_SIZE;
- buf = kmalloc(buflen, GFP_ATOMIC);
-
- VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);
+ vmbus_recvpacket(channel, hbeat_txf_buf,
+ PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
- DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld",
- recvlen, requestid);
-
- icmsghdrp = (struct icmsg_hdr *)&buf[
- sizeof(struct vmbuspipe_hdr)];
-
- icmsghdrp = (struct icmsg_hdr *)&buf[
+ icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- prep_negotiate_resp(icmsghdrp, NULL, buf);
+ prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf);
} else {
- heartbeat_msg = (struct heartbeat_msg_data *)&buf[
- sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
-
- DPRINT_DBG(VMBUS, "heartbeat seq = %lld",
- heartbeat_msg->seq_num);
+ heartbeat_msg =
+ (struct heartbeat_msg_data *)&hbeat_txf_buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
heartbeat_msg->seq_num += 1;
}
@@ -233,12 +204,10 @@ static void heartbeat_onchannelcallback(void *context)
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
- VmbusChannelSendPacket(channel, buf,
+ vmbus_sendpacket(channel, hbeat_txf_buf,
recvlen, requestid,
- VmbusPacketTypeDataInBand, 0);
+ VM_PKT_DATA_INBAND, 0);
}
-
- kfree(buf);
}
static const struct pci_device_id __initconst
@@ -248,6 +217,7 @@ hv_utils_pci_table[] __maybe_unused = {
};
MODULE_DEVICE_TABLE(pci, hv_utils_pci_table);
+
static const struct dmi_system_id __initconst
hv_utils_dmi_table[] __maybe_unused = {
{
@@ -265,38 +235,67 @@ MODULE_DEVICE_TABLE(dmi, hv_utils_dmi_table);
static int __init init_hyperv_utils(void)
{
- printk(KERN_INFO "Registering HyperV Utility Driver\n");
+ pr_info("Registering HyperV Utility Driver\n");
+
+ if (hv_kvp_init())
+ return -ENODEV;
+
+
+ if (!dmi_check_system(hv_utils_dmi_table))
+ return -ENODEV;
+
+ shut_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ time_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ hbeat_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+ if (!shut_txf_buf || !time_txf_buf || !hbeat_txf_buf) {
+ pr_info("Unable to allocate memory for receive buffer\n");
+ kfree(shut_txf_buf);
+ kfree(time_txf_buf);
+ kfree(hbeat_txf_buf);
+ return -ENOMEM;
+ }
- hv_cb_utils[HV_SHUTDOWN_MSG].channel->OnChannelCallback =
- &shutdown_onchannelcallback;
hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback;
- hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback =
- &timesync_onchannelcallback;
hv_cb_utils[HV_TIMESYNC_MSG].callback = &timesync_onchannelcallback;
- hv_cb_utils[HV_HEARTBEAT_MSG].channel->OnChannelCallback =
- &heartbeat_onchannelcallback;
hv_cb_utils[HV_HEARTBEAT_MSG].callback = &heartbeat_onchannelcallback;
+ hv_cb_utils[HV_KVP_MSG].callback = &hv_kvp_onchannelcallback;
+
return 0;
}
static void exit_hyperv_utils(void)
{
- printk(KERN_INFO "De-Registered HyperV Utility Driver\n");
+ pr_info("De-Registered HyperV Utility Driver\n");
+
+ if (hv_cb_utils[HV_SHUTDOWN_MSG].channel != NULL)
+ hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_SHUTDOWN_MSG].callback = NULL;
+
+ if (hv_cb_utils[HV_TIMESYNC_MSG].channel != NULL)
+ hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_TIMESYNC_MSG].callback = NULL;
+
+ if (hv_cb_utils[HV_HEARTBEAT_MSG].channel != NULL)
+ hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_HEARTBEAT_MSG].callback = NULL;
- hv_cb_utils[HV_SHUTDOWN_MSG].channel->OnChannelCallback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_SHUTDOWN_MSG].callback = &chn_cb_negotiate;
+ if (hv_cb_utils[HV_KVP_MSG].channel != NULL)
+ hv_cb_utils[HV_KVP_MSG].channel->onchannel_callback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_KVP_MSG].callback = NULL;
- hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_TIMESYNC_MSG].callback = &chn_cb_negotiate;
+ hv_kvp_deinit();
- hv_cb_utils[HV_HEARTBEAT_MSG].channel->OnChannelCallback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate;
+ kfree(shut_txf_buf);
+ kfree(time_txf_buf);
+ kfree(hbeat_txf_buf);
}
module_init(init_hyperv_utils);
diff --git a/drivers/staging/hv/hyperv.h b/drivers/staging/hv/hyperv.h
new file mode 100644
index 000000000000..8175b25af656
--- /dev/null
+++ b/drivers/staging/hv/hyperv.h
@@ -0,0 +1,953 @@
+/*
+ *
+ * Copyright (c) 2011, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
+ *
+ */
+
+#ifndef _HYPERV_H
+#define _HYPERV_H
+
+#include <linux/scatterlist.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/version.h>
+
+
+#include <asm/hyperv.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+#include "hv_compat.h"
+#endif
+
+struct hv_guid {
+ unsigned char data[16];
+};
+
+#define MAX_PAGE_BUFFER_COUNT 16
+#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
+
+#pragma pack(push, 1)
+
+/* Single-page buffer */
+struct hv_page_buffer {
+ u32 len;
+ u32 offset;
+ u64 pfn;
+};
+
+/* Multiple-page buffer */
+struct hv_multipage_buffer {
+ /* Length and Offset determines the # of pfns in the array */
+ u32 len;
+ u32 offset;
+ u64 pfn_array[MAX_MULTIPAGE_BUFFER_COUNT];
+};
+
+/* 0x18 includes the proprietary packet header */
+#define MAX_PAGE_BUFFER_PACKET (0x18 + \
+ (sizeof(struct hv_page_buffer) * \
+ MAX_PAGE_BUFFER_COUNT))
+#define MAX_MULTIPAGE_BUFFER_PACKET (0x18 + \
+ sizeof(struct hv_multipage_buffer))
+
+
+#pragma pack(pop)
+
+struct hv_ring_buffer {
+ /* Offset in bytes from the start of ring data below */
+ u32 write_index;
+
+ /* Offset in bytes from the start of ring data below */
+ u32 read_index;
+
+ u32 interrupt_mask;
+
+ /* Pad it to PAGE_SIZE so that data starts on page boundary */
+ u8 reserved[4084];
+
+ /* NOTE:
+ * The interrupt_mask field is used only for channels but since our
+ * vmbus connection also uses this data structure and its data starts
+ * here, we commented out this field.
+ */
+
+ /*
+ * Ring data starts here + RingDataStartOffset
+ * !!! DO NOT place any fields below this !!!
+ */
+ u8 buffer[0];
+} __packed;
+
+struct hv_ring_buffer_info {
+ struct hv_ring_buffer *ring_buffer;
+ u32 ring_size; /* Include the shared header */
+ spinlock_t ring_lock;
+
+ u32 ring_datasize; /* < ring_size */
+ u32 ring_data_startoffset;
+};
+
+struct hv_ring_buffer_debug_info {
+ u32 current_interrupt_mask;
+ u32 current_read_index;
+ u32 current_write_index;
+ u32 bytes_avail_toread;
+ u32 bytes_avail_towrite;
+};
+
+/*
+ * We use the same version numbering for all Hyper-V modules.
+ *
+ * Definition of versioning is as follows;
+ *
+ * Major Number Changes for these scenarios;
+ * 1. When a new version of Windows Hyper-V
+ * is released.
+ * 2. A Major change has occurred in the
+ * Linux IC's.
+ * (For example the merge for the first time
+ * into the kernel) Every time the Major Number
+ * changes, the Revision number is reset to 0.
+ * Minor Number Changes when new functionality is added
+ * to the Linux IC's that is not a bug fix.
+ *
+ * 3.1 - Added completed hv_utils driver. Shutdown/Heartbeat/Timesync
+ */
+#define HV_DRV_VERSION "3.1"
+
+
+/*
+ * A revision number of vmbus that is used for ensuring both ends on a
+ * partition are using compatible versions.
+ */
+#define VMBUS_REVISION_NUMBER 13
+
+/* Make maximum size of pipe payload of 16K */
+#define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)
+
+/* Define PipeMode values. */
+#define VMBUS_PIPE_TYPE_BYTE 0x00000000
+#define VMBUS_PIPE_TYPE_MESSAGE 0x00000004
+
+/* The size of the user defined data buffer for non-pipe offers. */
+#define MAX_USER_DEFINED_BYTES 120
+
+/* The size of the user defined data buffer for pipe offers. */
+#define MAX_PIPE_USER_DEFINED_BYTES 116
+
+/*
+ * At the center of the Channel Management library is the Channel Offer. This
+ * struct contains the fundamental information about an offer.
+ */
+struct vmbus_channel_offer {
+ struct hv_guid if_type;
+ struct hv_guid if_instance;
+ u64 int_latency; /* in 100ns units */
+ u32 if_revision;
+ u32 server_ctx_size; /* in bytes */
+ u16 chn_flags;
+ u16 mmio_megabytes; /* in bytes * 1024 * 1024 */
+
+ union {
+ /* Non-pipes: The user has MAX_USER_DEFINED_BYTES bytes. */
+ struct {
+ unsigned char user_def[MAX_USER_DEFINED_BYTES];
+ } std;
+
+ /*
+ * Pipes:
+ * The following sructure is an integrated pipe protocol, which
+ * is implemented on top of standard user-defined data. Pipe
+ * clients have MAX_PIPE_USER_DEFINED_BYTES left for their own
+ * use.
+ */
+ struct {
+ u32 pipe_mode;
+ unsigned char user_def[MAX_PIPE_USER_DEFINED_BYTES];
+ } pipe;
+ } u;
+ u32 padding;
+} __packed;
+
+/* Server Flags */
+#define VMBUS_CHANNEL_ENUMERATE_DEVICE_INTERFACE 1
+#define VMBUS_CHANNEL_SERVER_SUPPORTS_TRANSFER_PAGES 2
+#define VMBUS_CHANNEL_SERVER_SUPPORTS_GPADLS 4
+#define VMBUS_CHANNEL_NAMED_PIPE_MODE 0x10
+#define VMBUS_CHANNEL_LOOPBACK_OFFER 0x100
+#define VMBUS_CHANNEL_PARENT_OFFER 0x200
+#define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION 0x400
+
+struct vmpacket_descriptor {
+ u16 type;
+ u16 offset8;
+ u16 len8;
+ u16 flags;
+ u64 trans_id;
+} __packed;
+
+struct vmpacket_header {
+ u32 prev_pkt_start_offset;
+ struct vmpacket_descriptor descriptor;
+} __packed;
+
+struct vmtransfer_page_range {
+ u32 byte_count;
+ u32 byte_offset;
+} __packed;
+
+struct vmtransfer_page_packet_header {
+ struct vmpacket_descriptor d;
+ u16 xfer_pageset_id;
+ bool sender_owns_set;
+ u8 reserved;
+ u32 range_cnt;
+ struct vmtransfer_page_range ranges[1];
+} __packed;
+
+struct vmgpadl_packet_header {
+ struct vmpacket_descriptor d;
+ u32 gpadl;
+ u32 reserved;
+} __packed;
+
+struct vmadd_remove_transfer_page_set {
+ struct vmpacket_descriptor d;
+ u32 gpadl;
+ u16 xfer_pageset_id;
+ u16 reserved;
+} __packed;
+
+/*
+ * This structure defines a range in guest physical space that can be made to
+ * look virtually contiguous.
+ */
+struct gpa_range {
+ u32 byte_count;
+ u32 byte_offset;
+ u64 pfn_array[0];
+};
+
+/*
+ * This is the format for an Establish Gpadl packet, which contains a handle by
+ * which this GPADL will be known and a set of GPA ranges associated with it.
+ * This can be converted to a MDL by the guest OS. If there are multiple GPA
+ * ranges, then the resulting MDL will be "chained," representing multiple VA
+ * ranges.
+ */
+struct vmestablish_gpadl {
+ struct vmpacket_descriptor d;
+ u32 gpadl;
+ u32 range_cnt;
+ struct gpa_range range[1];
+} __packed;
+
+/*
+ * This is the format for a Teardown Gpadl packet, which indicates that the
+ * GPADL handle in the Establish Gpadl packet will never be referenced again.
+ */
+struct vmteardown_gpadl {
+ struct vmpacket_descriptor d;
+ u32 gpadl;
+ u32 reserved; /* for alignment to a 8-byte boundary */
+} __packed;
+
+/*
+ * This is the format for a GPA-Direct packet, which contains a set of GPA
+ * ranges, in addition to commands and/or data.
+ */
+struct vmdata_gpa_direct {
+ struct vmpacket_descriptor d;
+ u32 reserved;
+ u32 range_cnt;
+ struct gpa_range range[1];
+} __packed;
+
+/* This is the format for a Additional Data Packet. */
+struct vmadditional_data {
+ struct vmpacket_descriptor d;
+ u64 total_bytes;
+ u32 offset;
+ u32 byte_cnt;
+ unsigned char data[1];
+} __packed;
+
+union vmpacket_largest_possible_header {
+ struct vmpacket_descriptor simple_hdr;
+ struct vmtransfer_page_packet_header xfer_page_hdr;
+ struct vmgpadl_packet_header gpadl_hdr;
+ struct vmadd_remove_transfer_page_set add_rm_xfer_page_hdr;
+ struct vmestablish_gpadl establish_gpadl_hdr;
+ struct vmteardown_gpadl teardown_gpadl_hdr;
+ struct vmdata_gpa_direct data_gpa_direct_hdr;
+};
+
+#define VMPACKET_DATA_START_ADDRESS(__packet) \
+ (void *)(((unsigned char *)__packet) + \
+ ((struct vmpacket_descriptor)__packet)->offset8 * 8)
+
+#define VMPACKET_DATA_LENGTH(__packet) \
+ ((((struct vmpacket_descriptor)__packet)->len8 - \
+ ((struct vmpacket_descriptor)__packet)->offset8) * 8)
+
+#define VMPACKET_TRANSFER_MODE(__packet) \
+ (((struct IMPACT)__packet)->type)
+
+enum vmbus_packet_type {
+ VM_PKT_INVALID = 0x0,
+ VM_PKT_SYNCH = 0x1,
+ VM_PKT_ADD_XFER_PAGESET = 0x2,
+ VM_PKT_RM_XFER_PAGESET = 0x3,
+ VM_PKT_ESTABLISH_GPADL = 0x4,
+ VM_PKT_TEARDOWN_GPADL = 0x5,
+ VM_PKT_DATA_INBAND = 0x6,
+ VM_PKT_DATA_USING_XFER_PAGES = 0x7,
+ VM_PKT_DATA_USING_GPADL = 0x8,
+ VM_PKT_DATA_USING_GPA_DIRECT = 0x9,
+ VM_PKT_CANCEL_REQUEST = 0xa,
+ VM_PKT_COMP = 0xb,
+ VM_PKT_DATA_USING_ADDITIONAL_PKT = 0xc,
+ VM_PKT_ADDITIONAL_DATA = 0xd
+};
+
+#define VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED 1
+
+
+/* Version 1 messages */
+enum vmbus_channel_message_type {
+ CHANNELMSG_INVALID = 0,
+ CHANNELMSG_OFFERCHANNEL = 1,
+ CHANNELMSG_RESCIND_CHANNELOFFER = 2,
+ CHANNELMSG_REQUESTOFFERS = 3,
+ CHANNELMSG_ALLOFFERS_DELIVERED = 4,
+ CHANNELMSG_OPENCHANNEL = 5,
+ CHANNELMSG_OPENCHANNEL_RESULT = 6,
+ CHANNELMSG_CLOSECHANNEL = 7,
+ CHANNELMSG_GPADL_HEADER = 8,
+ CHANNELMSG_GPADL_BODY = 9,
+ CHANNELMSG_GPADL_CREATED = 10,
+ CHANNELMSG_GPADL_TEARDOWN = 11,
+ CHANNELMSG_GPADL_TORNDOWN = 12,
+ CHANNELMSG_RELID_RELEASED = 13,
+ CHANNELMSG_INITIATE_CONTACT = 14,
+ CHANNELMSG_VERSION_RESPONSE = 15,
+ CHANNELMSG_UNLOAD = 16,
+#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
+ CHANNELMSG_VIEWRANGE_ADD = 17,
+ CHANNELMSG_VIEWRANGE_REMOVE = 18,
+#endif
+ CHANNELMSG_COUNT
+};
+
+struct vmbus_channel_message_header {
+ enum vmbus_channel_message_type msgtype;
+ u32 padding;
+} __packed;
+
+/* Query VMBus Version parameters */
+struct vmbus_channel_query_vmbus_version {
+ struct vmbus_channel_message_header header;
+ u32 version;
+} __packed;
+
+/* VMBus Version Supported parameters */
+struct vmbus_channel_version_supported {
+ struct vmbus_channel_message_header header;
+ bool version_supported;
+} __packed;
+
+/* Offer Channel parameters */
+struct vmbus_channel_offer_channel {
+ struct vmbus_channel_message_header header;
+ struct vmbus_channel_offer offer;
+ u32 child_relid;
+ u8 monitorid;
+ bool monitor_allocated;
+} __packed;
+
+/* Rescind Offer parameters */
+struct vmbus_channel_rescind_offer {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+} __packed;
+
+/*
+ * Request Offer -- no parameters, SynIC message contains the partition ID
+ * Set Snoop -- no parameters, SynIC message contains the partition ID
+ * Clear Snoop -- no parameters, SynIC message contains the partition ID
+ * All Offers Delivered -- no parameters, SynIC message contains the partition
+ * ID
+ * Flush Client -- no parameters, SynIC message contains the partition ID
+ */
+
+/* Open Channel parameters */
+struct vmbus_channel_open_channel {
+ struct vmbus_channel_message_header header;
+
+ /* Identifies the specific VMBus channel that is being opened. */
+ u32 child_relid;
+
+ /* ID making a particular open request at a channel offer unique. */
+ u32 openid;
+
+ /* GPADL for the channel's ring buffer. */
+ u32 ringbuffer_gpadlhandle;
+
+ /* GPADL for the channel's server context save area. */
+ u32 server_contextarea_gpadlhandle;
+
+ /*
+ * The upstream ring buffer begins at offset zero in the memory
+ * described by RingBufferGpadlHandle. The downstream ring buffer
+ * follows it at this offset (in pages).
+ */
+ u32 downstream_ringbuffer_pageoffset;
+
+ /* User-specific data to be passed along to the server endpoint. */
+ unsigned char userdata[MAX_USER_DEFINED_BYTES];
+} __packed;
+
+/* Open Channel Result parameters */
+struct vmbus_channel_open_result {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 openid;
+ u32 status;
+} __packed;
+
+/* Close channel parameters; */
+struct vmbus_channel_close_channel {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+} __packed;
+
+/* Channel Message GPADL */
+#define GPADL_TYPE_RING_BUFFER 1
+#define GPADL_TYPE_SERVER_SAVE_AREA 2
+#define GPADL_TYPE_TRANSACTION 8
+
+/*
+ * The number of PFNs in a GPADL message is defined by the number of
+ * pages that would be spanned by ByteCount and ByteOffset. If the
+ * implied number of PFNs won't fit in this packet, there will be a
+ * follow-up packet that contains more.
+ */
+struct vmbus_channel_gpadl_header {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 gpadl;
+ u16 range_buflen;
+ u16 rangecount;
+ struct gpa_range range[0];
+} __packed;
+
+/* This is the followup packet that contains more PFNs. */
+struct vmbus_channel_gpadl_body {
+ struct vmbus_channel_message_header header;
+ u32 msgnumber;
+ u32 gpadl;
+ u64 pfn[0];
+} __packed;
+
+struct vmbus_channel_gpadl_created {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 gpadl;
+ u32 creation_status;
+} __packed;
+
+struct vmbus_channel_gpadl_teardown {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+ u32 gpadl;
+} __packed;
+
+struct vmbus_channel_gpadl_torndown {
+ struct vmbus_channel_message_header header;
+ u32 gpadl;
+} __packed;
+
+#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD
+struct vmbus_channel_view_range_add {
+ struct vmbus_channel_message_header header;
+ PHYSICAL_ADDRESS viewrange_base;
+ u64 viewrange_length;
+ u32 child_relid;
+} __packed;
+
+struct vmbus_channel_view_range_remove {
+ struct vmbus_channel_message_header header;
+ PHYSICAL_ADDRESS viewrange_base;
+ u32 child_relid;
+} __packed;
+#endif
+
+struct vmbus_channel_relid_released {
+ struct vmbus_channel_message_header header;
+ u32 child_relid;
+} __packed;
+
+struct vmbus_channel_initiate_contact {
+ struct vmbus_channel_message_header header;
+ u32 vmbus_version_requested;
+ u32 padding2;
+ u64 interrupt_page;
+ u64 monitor_page1;
+ u64 monitor_page2;
+} __packed;
+
+struct vmbus_channel_version_response {
+ struct vmbus_channel_message_header header;
+ bool version_supported;
+} __packed;
+
+enum vmbus_channel_state {
+ CHANNEL_OFFER_STATE,
+ CHANNEL_OPENING_STATE,
+ CHANNEL_OPEN_STATE,
+};
+
+struct vmbus_channel_debug_info {
+ u32 relid;
+ enum vmbus_channel_state state;
+ struct hv_guid interfacetype;
+ struct hv_guid interface_instance;
+ u32 monitorid;
+ u32 servermonitor_pending;
+ u32 servermonitor_latency;
+ u32 servermonitor_connectionid;
+ u32 clientmonitor_pending;
+ u32 clientmonitor_latency;
+ u32 clientmonitor_connectionid;
+
+ struct hv_ring_buffer_debug_info inbound;
+ struct hv_ring_buffer_debug_info outbound;
+};
+
+/*
+ * Represents each channel msg on the vmbus connection This is a
+ * variable-size data structure depending on the msg type itself
+ */
+struct vmbus_channel_msginfo {
+ /* Bookkeeping stuff */
+ struct list_head msglistentry;
+
+ /* So far, this is only used to handle gpadl body message */
+ struct list_head submsglist;
+
+ /* Synchronize the request/response if needed */
+ struct completion waitevent;
+ union {
+ struct vmbus_channel_version_supported version_supported;
+ struct vmbus_channel_open_result open_result;
+ struct vmbus_channel_gpadl_torndown gpadl_torndown;
+ struct vmbus_channel_gpadl_created gpadl_created;
+ struct vmbus_channel_version_response version_response;
+ } response;
+
+ u32 msgsize;
+ /*
+ * The channel message that goes out on the "wire".
+ * It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
+ */
+ unsigned char msg[0];
+};
+
+struct vmbus_close_msg {
+ struct vmbus_channel_msginfo info;
+ struct vmbus_channel_close_channel msg;
+};
+
+struct vmbus_channel {
+ struct list_head listentry;
+
+ struct hv_device *device_obj;
+
+ struct work_struct work;
+
+ enum vmbus_channel_state state;
+ /*
+ * For util channels, stash the
+ * the service index for easy access.
+ */
+ s8 util_index;
+
+ struct vmbus_channel_offer_channel offermsg;
+ /*
+ * These are based on the OfferMsg.MonitorId.
+ * Save it here for easy access.
+ */
+ u8 monitor_grp;
+ u8 monitor_bit;
+
+ u32 ringbuffer_gpadlhandle;
+
+ /* Allocated memory for ring buffer */
+ void *ringbuffer_pages;
+ u32 ringbuffer_pagecount;
+ struct hv_ring_buffer_info outbound; /* send to parent */
+ struct hv_ring_buffer_info inbound; /* receive from parent */
+ spinlock_t inbound_lock;
+ struct workqueue_struct *controlwq;
+
+ struct vmbus_close_msg close_msg;
+
+ /* Channel callback are invoked in this workqueue context */
+ /* HANDLE dataWorkQueue; */
+
+ void (*onchannel_callback)(void *context);
+ void *channel_callback_context;
+};
+
+void free_channel(struct vmbus_channel *channel);
+
+void vmbus_onmessage(void *context);
+
+int vmbus_request_offers(void);
+
+/* The format must be the same as struct vmdata_gpa_direct */
+struct vmbus_channel_packet_page_buffer {
+ u16 type;
+ u16 dataoffset8;
+ u16 length8;
+ u16 flags;
+ u64 transactionid;
+ u32 reserved;
+ u32 rangecount;
+ struct hv_page_buffer range[MAX_PAGE_BUFFER_COUNT];
+} __packed;
+
+/* The format must be the same as struct vmdata_gpa_direct */
+struct vmbus_channel_packet_multipage_buffer {
+ u16 type;
+ u16 dataoffset8;
+ u16 length8;
+ u16 flags;
+ u64 transactionid;
+ u32 reserved;
+ u32 rangecount; /* Always 1 in this case */
+ struct hv_multipage_buffer range;
+} __packed;
+
+
+extern int vmbus_open(struct vmbus_channel *channel,
+ u32 send_ringbuffersize,
+ u32 recv_ringbuffersize,
+ void *userdata,
+ u32 userdatalen,
+ void(*onchannel_callback)(void *context),
+ void *context);
+
+extern void vmbus_close(struct vmbus_channel *channel);
+
+extern int vmbus_sendpacket(struct vmbus_channel *channel,
+ const void *buffer,
+ u32 bufferLen,
+ u64 requestid,
+ enum vmbus_packet_type type,
+ u32 flags);
+
+extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
+ struct hv_page_buffer pagebuffers[],
+ u32 pagecount,
+ void *buffer,
+ u32 bufferlen,
+ u64 requestid);
+
+extern int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
+ struct hv_multipage_buffer *mpb,
+ void *buffer,
+ u32 bufferlen,
+ u64 requestid);
+
+extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
+ void *kbuffer,
+ u32 size,
+ u32 *gpadl_handle);
+
+extern int vmbus_teardown_gpadl(struct vmbus_channel *channel,
+ u32 gpadl_handle);
+
+extern int vmbus_recvpacket(struct vmbus_channel *channel,
+ void *buffer,
+ u32 bufferlen,
+ u32 *buffer_actual_len,
+ u64 *requestid);
+
+extern int vmbus_recvpacket_raw(struct vmbus_channel *channel,
+ void *buffer,
+ u32 bufferlen,
+ u32 *buffer_actual_len,
+ u64 *requestid);
+
+
+extern void vmbus_get_debug_info(struct vmbus_channel *channel,
+ struct vmbus_channel_debug_info *debug);
+
+extern void vmbus_ontimer(unsigned long data);
+
+
+#define LOWORD(dw) ((unsigned short)(dw))
+#define HIWORD(dw) ((unsigned short)(((unsigned int) (dw) >> 16) & 0xFFFF))
+
+
+#define VMBUS 0x0001
+#define STORVSC 0x0002
+#define NETVSC 0x0004
+#define INPUTVSC 0x0008
+#define BLKVSC 0x0010
+#define VMBUS_DRV 0x0100
+#define STORVSC_DRV 0x0200
+#define NETVSC_DRV 0x0400
+#define INPUTVSC_DRV 0x0800
+#define BLKVSC_DRV 0x1000
+
+#define ALL_MODULES (VMBUS |\
+ STORVSC |\
+ NETVSC |\
+ INPUTVSC |\
+ BLKVSC |\
+ VMBUS_DRV |\
+ STORVSC_DRV |\
+ NETVSC_DRV |\
+ INPUTVSC_DRV|\
+ BLKVSC_DRV)
+
+/* Logging Level */
+#define ERROR_LVL 3
+#define WARNING_LVL 4
+#define INFO_LVL 6
+#define DEBUG_LVL 7
+#define DEBUG_LVL_ENTEREXIT 8
+#define DEBUG_RING_LVL 9
+
+extern unsigned int vmbus_loglevel;
+
+#define DPRINT(mod, lvl, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (lvl <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_DEBUG #mod": %s() " fmt "\n", __func__, ## args);\
+ } while (0)
+
+#define DPRINT_DBG(mod, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (DEBUG_LVL <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_DEBUG #mod": %s() " fmt "\n", __func__, ## args);\
+ } while (0)
+
+#define DPRINT_INFO(mod, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (INFO_LVL <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_INFO #mod": " fmt "\n", ## args);\
+ } while (0)
+
+#define DPRINT_WARN(mod, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (WARNING_LVL <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_WARNING #mod": WARNING! " fmt "\n", ## args);\
+ } while (0)
+
+#define DPRINT_ERR(mod, fmt, args...) do {\
+ if ((mod & (HIWORD(vmbus_loglevel))) && \
+ (ERROR_LVL <= LOWORD(vmbus_loglevel))) \
+ printk(KERN_ERR #mod": %s() ERROR!! " fmt "\n", \
+ __func__, ## args);\
+ } while (0)
+
+
+
+struct hv_driver;
+struct hv_device;
+
+struct hv_dev_port_info {
+ u32 int_mask;
+ u32 read_idx;
+ u32 write_idx;
+ u32 bytes_avail_toread;
+ u32 bytes_avail_towrite;
+};
+
+struct hv_device_info {
+ u32 chn_id;
+ u32 chn_state;
+ struct hv_guid chn_type;
+ struct hv_guid chn_instance;
+
+ u32 monitor_id;
+ u32 server_monitor_pending;
+ u32 server_monitor_latency;
+ u32 server_monitor_conn_id;
+ u32 client_monitor_pending;
+ u32 client_monitor_latency;
+ u32 client_monitor_conn_id;
+
+ struct hv_dev_port_info inbound;
+ struct hv_dev_port_info outbound;
+};
+
+/* Base driver object */
+struct hv_driver {
+ const char *name;
+
+ /* the device type supported by this driver */
+ struct hv_guid dev_type;
+
+ struct device_driver driver;
+
+ int (*probe)(struct hv_device *);
+ int (*remove)(struct hv_device *);
+ void (*shutdown)(struct hv_device *);
+
+};
+
+/* Base device object */
+struct hv_device {
+ /* the device type id of this device */
+ struct hv_guid dev_type;
+
+ /* the device instance id of this device */
+ struct hv_guid dev_instance;
+
+ struct device device;
+
+ struct vmbus_channel *channel;
+
+ /* Device extension; */
+ void *ext;
+};
+
+
+static inline struct hv_device *device_to_hv_device(struct device *d)
+{
+ return container_of(d, struct hv_device, device);
+}
+
+static inline struct hv_driver *drv_to_hv_drv(struct device_driver *d)
+{
+ return container_of(d, struct hv_driver, driver);
+}
+
+
+/* Vmbus interface */
+int vmbus_child_driver_register(struct device_driver *drv);
+void vmbus_child_driver_unregister(struct device_driver *drv);
+
+/*
+ * Common header for Hyper-V ICs
+ */
+
+#define ICMSGTYPE_NEGOTIATE 0
+#define ICMSGTYPE_HEARTBEAT 1
+#define ICMSGTYPE_KVPEXCHANGE 2
+#define ICMSGTYPE_SHUTDOWN 3
+#define ICMSGTYPE_TIMESYNC 4
+#define ICMSGTYPE_VSS 5
+
+#define ICMSGHDRFLAG_TRANSACTION 1
+#define ICMSGHDRFLAG_REQUEST 2
+#define ICMSGHDRFLAG_RESPONSE 4
+
+#define HV_S_OK 0x00000000
+#define HV_E_FAIL 0x80004005
+#define HV_ERROR_NOT_SUPPORTED 0x80070032
+#define HV_ERROR_MACHINE_LOCKED 0x800704F7
+
+struct vmbuspipe_hdr {
+ u32 flags;
+ u32 msgsize;
+} __packed;
+
+struct ic_version {
+ u16 major;
+ u16 minor;
+} __packed;
+
+struct icmsg_hdr {
+ struct ic_version icverframe;
+ u16 icmsgtype;
+ struct ic_version icvermsg;
+ u16 icmsgsize;
+ u32 status;
+ u8 ictransaction_id;
+ u8 icflags;
+ u8 reserved[2];
+} __packed;
+
+struct icmsg_negotiate {
+ u16 icframe_vercnt;
+ u16 icmsg_vercnt;
+ u32 reserved;
+ struct ic_version icversion_data[1]; /* any size array */
+} __packed;
+
+struct shutdown_msg_data {
+ u32 reason_code;
+ u32 timeout_seconds;
+ u32 flags;
+ u8 display_message[2048];
+} __packed;
+
+struct heartbeat_msg_data {
+ u64 seq_num;
+ u32 reserved[8];
+} __packed;
+
+/* Time Sync IC defs */
+#define ICTIMESYNCFLAG_PROBE 0
+#define ICTIMESYNCFLAG_SYNC 1
+#define ICTIMESYNCFLAG_SAMPLE 2
+
+#ifdef __x86_64__
+#define WLTIMEDELTA 116444736000000000L /* in 100ns unit */
+#else
+#define WLTIMEDELTA 116444736000000000LL
+#endif
+
+struct ictimesync_data {
+ u64 parenttime;
+ u64 childtime;
+ u64 roundtriptime;
+ u8 flags;
+} __packed;
+
+/* Index for each IC struct in array hv_cb_utils[] */
+#define HV_SHUTDOWN_MSG 0
+#define HV_TIMESYNC_MSG 1
+#define HV_HEARTBEAT_MSG 2
+#define HV_KVP_MSG 3
+
+struct hyperv_service_callback {
+ u8 msg_type;
+ char *log_msg;
+ unsigned char data[16];
+ struct vmbus_channel *channel;
+ void (*callback) (void *context);
+};
+
+extern void prep_negotiate_resp(struct icmsg_hdr *,
+ struct icmsg_negotiate *, u8 *);
+extern void chn_cb_negotiate(void *);
+extern struct hyperv_service_callback hv_cb_utils[];
+
+#endif /* _HYPERV_H */
diff --git a/drivers/staging/hv/rndis.h b/drivers/staging/hv/hyperv_net.h
index 723e1f15b90d..27f987b48dfe 100644
--- a/drivers/staging/hv/rndis.h
+++ b/drivers/staging/hv/hyperv_net.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2009, Microsoft Corporation.
+ * Copyright (c) 2011, Microsoft Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -18,11 +18,385 @@
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
*
*/
-#ifndef _RNDIS_H_
-#define _RNDIS_H_
+#ifndef _HYPERV_NET_H
+#define _HYPERV_NET_H
+
+#include <linux/list.h>
+#include "hyperv.h"
+
+/* Fwd declaration */
+struct hv_netvsc_packet;
+
+/* Represent the xfer page packet which contains 1 or more netvsc packet */
+struct xferpage_packet {
+ struct list_head list_ent;
+
+ /* # of netvsc packets this xfer packet contains */
+ u32 count;
+};
+
+/* The number of pages which are enough to cover jumbo frame buffer. */
+#define NETVSC_PACKET_MAXPAGE 4
+
+/*
+ * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame
+ * within the RNDIS
+ */
+struct hv_netvsc_packet {
+ /* Bookkeeping stuff */
+ struct list_head list_ent;
+
+ struct hv_device *device;
+ bool is_data_pkt;
+
+ /*
+ * Valid only for receives when we break a xfer page packet
+ * into multiple netvsc packets
+ */
+ struct xferpage_packet *xfer_page_pkt;
+
+ union {
+ struct {
+ u64 recv_completion_tid;
+ void *recv_completion_ctx;
+ void (*recv_completion)(void *context);
+ } recv;
+ struct {
+ u64 send_completion_tid;
+ void *send_completion_ctx;
+ void (*send_completion)(void *context);
+ } send;
+ } completion;
+
+ /* This points to the memory after page_buf */
+ void *extension;
+
+ u32 total_data_buflen;
+ /* Points to the send/receive buffer where the ethernet frame is */
+ u32 page_buf_cnt;
+ struct hv_page_buffer page_buf[NETVSC_PACKET_MAXPAGE];
+};
+
+struct netvsc_device_info {
+ unsigned char mac_adr[6];
+ bool link_state; /* 0 - link up, 1 - link down */
+ int ring_size;
+};
+
+/* Interface */
+int netvsc_device_add(struct hv_device *device, void *additional_info);
+int netvsc_device_remove(struct hv_device *device);
+int netvsc_send(struct hv_device *device,
+ struct hv_netvsc_packet *packet);
+void netvsc_linkstatus_callback(struct hv_device *device_obj,
+ unsigned int status);
+int netvsc_recv_callback(struct hv_device *device_obj,
+ struct hv_netvsc_packet *packet);
+int netvsc_initialize(struct hv_driver *drv);
+int rndis_filter_open(struct hv_device *dev);
+int rndis_filter_close(struct hv_device *dev);
+int rndis_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 refcnt;
+ atomic_t num_outstanding_sends;
+ /*
+ * List of free preallocated hv_netvsc_packet to represent receive
+ * packet
+ */
+ struct list_head recv_pkt_list;
+ spinlock_t recv_pkt_list_lock;
+
+ /* Receive buffer allocated by us but manages by NetVSP */
+ void *recv_buf;
+ u32 recv_buf_size;
+ u32 recv_buf_gpadl_handle;
+ u32 recv_section_cnt;
+ struct nvsp_1_receive_buffer_section *recv_section;
+
+ /* Used for NetVSP initialization protocol */
+ struct completion channel_init_wait;
+ struct nvsp_message channel_init_pkt;
+
+ struct nvsp_message revoke_packet;
+ /* unsigned char HwMacAddr[HW_MACADDR_LEN]; */
+
+ /* Holds rndis device info */
+ void *extension;
+};
+
/* Status codes */
@@ -288,24 +662,24 @@
#define RNDIS_DF_RAW_DATA 0x00000004
/* Remote NDIS medium types. */
-#define RNdisMedium802_3 0x00000000
-#define RNdisMedium802_5 0x00000001
-#define RNdisMediumFddi 0x00000002
-#define RNdisMediumWan 0x00000003
-#define RNdisMediumLocalTalk 0x00000004
-#define RNdisMediumArcnetRaw 0x00000006
-#define RNdisMediumArcnet878_2 0x00000007
-#define RNdisMediumAtm 0x00000008
-#define RNdisMediumWirelessWan 0x00000009
-#define RNdisMediumIrda 0x0000000a
-#define RNdisMediumCoWan 0x0000000b
+#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 RNdisMediumMax 0x0000000d
+#define RNDIS_MEDIUM_MAX 0x0000000d
/* Remote NDIS medium connection states. */
-#define RNdisMediaStateConnected 0x00000000
-#define RNdisMediaStateDisconnected 0x00000001
+#define RNDIS_MEDIA_STATE_CONNECTED 0x00000000
+#define RNDIS_MEDIA_STATE_DISCONNECTED 0x00000001
/* Remote NDIS version numbers */
#define RNDIS_MAJOR_VERSION 0x00000001
@@ -314,106 +688,106 @@
/* NdisInitialize message */
struct rndis_initialize_request {
- u32 RequestId;
- u32 MajorVersion;
- u32 MinorVersion;
- u32 MaxTransferSize;
+ u32 req_id;
+ u32 major_ver;
+ u32 minor_ver;
+ u32 max_xfer_size;
};
/* Response to NdisInitialize */
struct rndis_initialize_complete {
- u32 RequestId;
- u32 Status;
- u32 MajorVersion;
- u32 MinorVersion;
- u32 DeviceFlags;
- u32 Medium;
- u32 MaxPacketsPerMessage;
- u32 MaxTransferSize;
- u32 PacketAlignmentFactor;
- u32 AFListOffset;
- u32 AFListSize;
+ 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 AddressFamily;
- u32 MajorVersion;
- u32 MinorVersion;
+ u32 address_family;
+ u32 major_ver;
+ u32 minor_ver;
};
/* NdisHalt message */
struct rndis_halt_request {
- u32 RequestId;
+ u32 req_id;
};
/* NdisQueryRequest message */
struct rndis_query_request {
- u32 RequestId;
- u32 Oid;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
- u32 DeviceVcHandle;
+ u32 req_id;
+ u32 oid;
+ u32 info_buflen;
+ u32 info_buf_offset;
+ u32 dev_vc_handle;
};
/* Response to NdisQueryRequest */
struct rndis_query_complete {
- u32 RequestId;
- u32 Status;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
+ u32 req_id;
+ u32 status;
+ u32 info_buflen;
+ u32 info_buf_offset;
};
/* NdisSetRequest message */
struct rndis_set_request {
- u32 RequestId;
- u32 Oid;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
- u32 DeviceVcHandle;
+ u32 req_id;
+ u32 oid;
+ u32 info_buflen;
+ u32 info_buf_offset;
+ u32 dev_vc_handle;
};
/* Response to NdisSetRequest */
struct rndis_set_complete {
- u32 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/* NdisReset message */
struct rndis_reset_request {
- u32 Reserved;
+ u32 reserved;
};
/* Response to NdisReset */
struct rndis_reset_complete {
- u32 Status;
- u32 AddressingReset;
+ u32 status;
+ u32 addressing_reset;
};
/* NdisMIndicateStatus message */
struct rndis_indicate_status {
- u32 Status;
- u32 StatusBufferLength;
- u32 StatusBufferOffset;
+ 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 DiagStatus;
- u32 ErrorOffset;
+ u32 diag_status;
+ u32 error_offset;
};
/* NdisKeepAlive message */
struct rndis_keepalive_request {
- u32 RequestId;
+ u32 req_id;
};
/* Response to NdisKeepAlive */
struct rndis_keepalive_complete {
- u32 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/*
@@ -422,39 +796,39 @@ struct rndis_keepalive_complete {
* to 0 for connectionless data, otherwise it contains the VC handle.
*/
struct rndis_packet {
- u32 DataOffset;
- u32 DataLength;
- u32 OOBDataOffset;
- u32 OOBDataLength;
- u32 NumOOBDataElements;
- u32 PerPacketInfoOffset;
- u32 PerPacketInfoLength;
- u32 VcHandle;
- u32 Reserved;
+ 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 ClassInformationOffset;
+ 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 PerPacketInformationOffset;
+ 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 ParameterNameOffset;
- u32 ParameterNameLength;
- u32 ParameterType;
- u32 ParameterValueOffset;
- u32 ParameterValueLength;
+ 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 */
@@ -466,187 +840,218 @@ struct rndis_config_parameter_info {
/* CoNdisMiniportCreateVc message */
struct rcondis_mp_create_vc {
- u32 RequestId;
- u32 NdisVcHandle;
+ u32 req_id;
+ u32 ndis_vc_handle;
};
/* Response to CoNdisMiniportCreateVc */
struct rcondis_mp_create_vc_complete {
- u32 RequestId;
- u32 DeviceVcHandle;
- u32 Status;
+ u32 req_id;
+ u32 dev_vc_handle;
+ u32 status;
};
/* CoNdisMiniportDeleteVc message */
struct rcondis_mp_delete_vc {
- u32 RequestId;
- u32 DeviceVcHandle;
+ u32 req_id;
+ u32 dev_vc_handle;
};
/* Response to CoNdisMiniportDeleteVc */
struct rcondis_mp_delete_vc_complete {
- u32 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/* CoNdisMiniportQueryRequest message */
struct rcondis_mp_query_request {
- u32 RequestId;
- u32 RequestType;
- u32 Oid;
- u32 DeviceVcHandle;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
+ 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 RequestId;
- u32 RequestType;
- u32 Oid;
- u32 DeviceVcHandle;
- u32 InformationBufferLength;
- u32 InformationBufferOffset;
+ 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 NdisVcHandle;
- u32 Status;
- u32 StatusBufferLength;
- u32 StatusBufferOffset;
+ u32 ndis_vc_handle;
+ u32 status;
+ u32 status_buflen;
+ u32 status_buf_offset;
};
/* CONDIS Call/VC parameters */
struct rcondis_specific_parameters {
- u32 ParameterType;
- u32 ParameterLength;
- u32 ParameterOffset;
+ u32 parameter_type;
+ u32 parameter_length;
+ u32 parameter_lffset;
};
struct rcondis_media_parameters {
- u32 Flags;
- u32 Reserved1;
- u32 Reserved2;
- struct rcondis_specific_parameters MediaSpecific;
+ u32 flags;
+ u32 reserved1;
+ u32 reserved2;
+ struct rcondis_specific_parameters media_specific;
};
struct rndis_flowspec {
- u32 TokenRate;
- u32 TokenBucketSize;
- u32 PeakBandwidth;
- u32 Latency;
- u32 DelayVariation;
- u32 ServiceType;
- u32 MaxSduSize;
- u32 MinimumPolicedSize;
+ 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 CallMgrSpecific;
+ struct rndis_flowspec transmit;
+ struct rndis_flowspec receive;
+ struct rcondis_specific_parameters call_mgr_specific;
};
/* CoNdisMiniportActivateVc message */
struct rcondis_mp_activate_vc_request {
- u32 RequestId;
- u32 Flags;
- u32 DeviceVcHandle;
- u32 MediaParamsOffset;
- u32 MediaParamsLength;
- u32 CallMgrParamsOffset;
- u32 CallMgrParamsLength;
+ 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 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/* CoNdisMiniportDeactivateVc message */
struct rcondis_mp_deactivate_vc_request {
- u32 RequestId;
- u32 Flags;
- u32 DeviceVcHandle;
+ u32 req_id;
+ u32 flags;
+ u32 dev_vc_handle;
};
/* Response to CoNdisMiniportDeactivateVc */
struct rcondis_mp_deactivate_vc_complete {
- u32 RequestId;
- u32 Status;
+ u32 req_id;
+ u32 status;
};
/* union with all of the RNDIS messages */
union rndis_message_container {
- struct rndis_packet Packet;
- struct rndis_initialize_request InitializeRequest;
- struct rndis_halt_request HaltRequest;
- struct rndis_query_request QueryRequest;
- struct rndis_set_request SetRequest;
- struct rndis_reset_request ResetRequest;
- struct rndis_keepalive_request KeepaliveRequest;
- struct rndis_indicate_status IndicateStatus;
- struct rndis_initialize_complete InitializeComplete;
- struct rndis_query_complete QueryComplete;
- struct rndis_set_complete SetComplete;
- struct rndis_reset_complete ResetComplete;
- struct rndis_keepalive_complete KeepaliveComplete;
- struct rcondis_mp_create_vc CoMiniportCreateVc;
- struct rcondis_mp_delete_vc CoMiniportDeleteVc;
- struct rcondis_indicate_status CoIndicateStatus;
- struct rcondis_mp_activate_vc_request CoMiniportActivateVc;
- struct rcondis_mp_deactivate_vc_request CoMiniportDeactivateVc;
- struct rcondis_mp_create_vc_complete CoMiniportCreateVcComplete;
- struct rcondis_mp_delete_vc_complete CoMiniportDeleteVcComplete;
- struct rcondis_mp_activate_vc_complete CoMiniportActivateVcComplete;
- struct rcondis_mp_deactivate_vc_complete CoMiniportDeactivateVcComplete;
+ 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 NdisMessageType;
+ u32 ndis_msg_type;
/* Total length of this message, from the beginning */
/* of the sruct rndis_message, in bytes. */
- u32 MessageLength;
+ u32 msg_len;
/* Actual message */
- union rndis_message_container 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(Message) \
- (sizeof(Message) + (sizeof(struct rndis_message) - \
+#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(Message) \
- (((unsigned char *)(Message)) + Message->InformationBufferOffset)
+#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(Message) \
- (((unsigned char *)(Message)) + Message->StatusBufferOffset)
+#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(Message) \
- (((unsigned char *)(Message)) + Message->OOBDataOffset)
+#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(Message) \
- (((unsigned char *)(Message)) + Message->PerPacketInfoOffset)
+#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(RndisMessage) \
- ((void *) &RndisMessage->Message)
+#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(RndisMessage) \
- ((void *) RndisMessage)
+#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 /* _RNDIS_H_ */
+#endif /* _HYPERV_NET_H */
diff --git a/drivers/staging/hv/hyperv_storage.h b/drivers/staging/hv/hyperv_storage.h
new file mode 100644
index 000000000000..a01f9a07c988
--- /dev/null
+++ b/drivers/staging/hv/hyperv_storage.h
@@ -0,0 +1,334 @@
+/*
+ *
+ * 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_STORAGE_H
+#define _HYPERV_STORAGE_H
+
+
+/* vstorage.w revision number. This is used in the case of a version match, */
+/* to alert the user that structure sizes may be mismatched even though the */
+/* protocol versions match. */
+
+
+#define REVISION_STRING(REVISION_) #REVISION_
+#define FILL_VMSTOR_REVISION(RESULT_LVALUE_) \
+ do { \
+ 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)
+
+
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include "hyperv_storage.h"
+#include "hyperv.h"
+
+/* Defines */
+#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
+#define BLKVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
+
+#define STORVSC_MAX_IO_REQUESTS 128
+
+/*
+ * In Hyper-V, each port/path/target maps to 1 scsi host adapter. In
+ * reality, the path/target is not used (ie always set to 0) so our
+ * scsi host adapter essentially has 1 bus with 1 target that contains
+ * up to 256 luns.
+ */
+#define STORVSC_MAX_LUNS_PER_TARGET 64
+#define STORVSC_MAX_TARGETS 1
+#define STORVSC_MAX_CHANNELS 1
+
+struct hv_storvsc_request;
+
+/* Matches Windows-end */
+enum storvsc_request_type {
+ WRITE_TYPE,
+ READ_TYPE,
+ UNKNOWN_TYPE,
+};
+
+
+struct hv_storvsc_request {
+ struct hv_storvsc_request *request;
+ struct hv_device *device;
+
+ /* Synchronize the request/response if needed */
+ struct completion wait_event;
+
+ unsigned char *sense_buffer;
+ void *context;
+ void (*on_io_completion)(struct hv_storvsc_request *request);
+ struct hv_multipage_buffer data_buffer;
+
+ struct vstor_packet vstor_packet;
+};
+
+
+struct storvsc_device_info {
+ u32 ring_buffer_size;
+ unsigned int port_number;
+ unsigned char path_id;
+ unsigned char target_id;
+};
+
+struct storvsc_major_info {
+ int major;
+ int index;
+ bool do_register;
+ char *devname;
+ char *diskname;
+};
+
+/* A storvsc device is a device object that contains a vmbus channel */
+struct storvsc_device {
+ struct hv_device *device;
+
+ /* 0 indicates the device is being destroyed */
+ atomic_t ref_count;
+
+ bool drain_notify;
+ atomic_t num_outstanding_req;
+
+ wait_queue_head_t waiting_to_drain;
+
+ /*
+ * Each unique Port/Path/Target represents 1 channel ie scsi
+ * controller. In reality, the pathid, targetid is always 0
+ * and the port is set by us
+ */
+ unsigned int port_number;
+ unsigned char path_id;
+ unsigned char target_id;
+
+ /* Used for vsc/vsp channel reset process */
+ struct hv_storvsc_request init_request;
+ struct hv_storvsc_request reset_request;
+};
+
+
+/* Get the stordevice object iff exists and its refcount > 1 */
+static inline struct storvsc_device *get_stor_device(struct hv_device *device)
+{
+ struct storvsc_device *stor_device;
+
+ stor_device = (struct storvsc_device *)device->ext;
+ if (stor_device && atomic_read(&stor_device->ref_count) > 1)
+ atomic_inc(&stor_device->ref_count);
+ else
+ stor_device = NULL;
+
+ return stor_device;
+}
+
+
+static inline void put_stor_device(struct hv_device *device)
+{
+ struct storvsc_device *stor_device;
+
+ stor_device = (struct storvsc_device *)device->ext;
+
+ atomic_dec(&stor_device->ref_count);
+}
+
+static inline void storvsc_wait_to_drain(struct storvsc_device *dev)
+{
+ dev->drain_notify = true;
+ wait_event(dev->waiting_to_drain,
+ atomic_read(&dev->num_outstanding_req) == 0);
+ dev->drain_notify = false;
+}
+
+/* Interface */
+
+int storvsc_dev_add(struct hv_device *device,
+ void *additional_info);
+int storvsc_dev_remove(struct hv_device *device);
+
+int storvsc_do_io(struct hv_device *device,
+ struct hv_storvsc_request *request);
+
+int storvsc_get_major_info(struct storvsc_device_info *device_info,
+ struct storvsc_major_info *major_info);
+
+#endif /* _HYPERV_STORAGE_H */
diff --git a/drivers/staging/hv/hyperv_vmbus.h b/drivers/staging/hv/hyperv_vmbus.h
new file mode 100644
index 000000000000..349ad80ce328
--- /dev/null
+++ b/drivers/staging/hv/hyperv_vmbus.h
@@ -0,0 +1,629 @@
+/*
+ *
+ * Copyright (c) 2011, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
+ *
+ */
+
+#ifndef _HYPERV_VMBUS_H
+#define _HYPERV_VMBUS_H
+
+#include <linux/list.h>
+#include <asm/sync_bitops.h>
+#include <linux/atomic.h>
+
+#include "hyperv.h"
+
+/*
+ * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
+ * is set by CPUID(HVCPUID_VERSION_FEATURES).
+ */
+enum hv_cpuid_function {
+ HVCPUID_VERSION_FEATURES = 0x00000001,
+ HVCPUID_VENDOR_MAXFUNCTION = 0x40000000,
+ HVCPUID_INTERFACE = 0x40000001,
+
+ /*
+ * The remaining functions depend on the value of
+ * HVCPUID_INTERFACE
+ */
+ HVCPUID_VERSION = 0x40000002,
+ HVCPUID_FEATURES = 0x40000003,
+ HVCPUID_ENLIGHTENMENT_INFO = 0x40000004,
+ HVCPUID_IMPLEMENTATION_LIMITS = 0x40000005,
+};
+
+/* Define version of the synthetic interrupt controller. */
+#define HV_SYNIC_VERSION (1)
+
+/* Define the expected SynIC version. */
+#define HV_SYNIC_VERSION_1 (0x1)
+
+/* Define synthetic interrupt controller message constants. */
+#define HV_MESSAGE_SIZE (256)
+#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240)
+#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
+#define HV_ANY_VP (0xFFFFFFFF)
+
+/* Define synthetic interrupt controller flag constants. */
+#define HV_EVENT_FLAGS_COUNT (256 * 8)
+#define HV_EVENT_FLAGS_BYTE_COUNT (256)
+#define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32))
+
+/* Define hypervisor message types. */
+enum hv_message_type {
+ HVMSG_NONE = 0x00000000,
+
+ /* Memory access messages. */
+ HVMSG_UNMAPPED_GPA = 0x80000000,
+ HVMSG_GPA_INTERCEPT = 0x80000001,
+
+ /* Timer notification messages. */
+ HVMSG_TIMER_EXPIRED = 0x80000010,
+
+ /* Error messages. */
+ HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
+ HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021,
+ HVMSG_UNSUPPORTED_FEATURE = 0x80000022,
+
+ /* Trace buffer complete messages. */
+ HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040,
+
+ /* Platform-specific processor intercept messages. */
+ HVMSG_X64_IOPORT_INTERCEPT = 0x80010000,
+ HVMSG_X64_MSR_INTERCEPT = 0x80010001,
+ HVMSG_X64_CPUID_INTERCEPT = 0x80010002,
+ HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003,
+ HVMSG_X64_APIC_EOI = 0x80010004,
+ HVMSG_X64_LEGACY_FP_ERROR = 0x80010005
+};
+
+/* Define the number of synthetic interrupt sources. */
+#define HV_SYNIC_SINT_COUNT (16)
+#define HV_SYNIC_STIMER_COUNT (4)
+
+/* Define invalid partition identifier. */
+#define HV_PARTITION_ID_INVALID ((u64)0x0)
+
+/* Define connection identifier type. */
+union hv_connection_id {
+ u32 asu32;
+ struct {
+ u32 id:24;
+ u32 reserved:8;
+ } u;
+};
+
+/* Define port identifier type. */
+union hv_port_id {
+ u32 asu32;
+ struct {
+ u32 id:24;
+ u32 reserved:8;
+ } u ;
+};
+
+/* Define port type. */
+enum hv_port_type {
+ HVPORT_MSG = 1,
+ HVPORT_EVENT = 2,
+ HVPORT_MONITOR = 3
+};
+
+/* Define port information structure. */
+struct hv_port_info {
+ enum hv_port_type port_type;
+ u32 padding;
+ union {
+ struct {
+ u32 target_sint;
+ u32 target_vp;
+ u64 rsvdz;
+ } message_port_info;
+ struct {
+ u32 target_sint;
+ u32 target_vp;
+ u16 base_flag_bumber;
+ u16 flag_count;
+ u32 rsvdz;
+ } event_port_info;
+ struct {
+ u64 monitor_address;
+ u64 rsvdz;
+ } monitor_port_info;
+ };
+};
+
+struct hv_connection_info {
+ enum hv_port_type port_type;
+ u32 padding;
+ union {
+ struct {
+ u64 rsvdz;
+ } message_connection_info;
+ struct {
+ u64 rsvdz;
+ } event_connection_info;
+ struct {
+ u64 monitor_address;
+ } monitor_connection_info;
+ };
+};
+
+/* Define synthetic interrupt controller message flags. */
+union hv_message_flags {
+ u8 asu8;
+ struct {
+ u8 msg_pending:1;
+ u8 reserved:7;
+ };
+};
+
+/* Define synthetic interrupt controller message header. */
+struct hv_message_header {
+ enum hv_message_type message_type;
+ u8 payload_size;
+ union hv_message_flags message_flags;
+ u8 reserved[2];
+ union {
+ u64 sender;
+ union hv_port_id port;
+ };
+};
+
+/* Define timer message payload structure. */
+struct hv_timer_message_payload {
+ u32 timer_index;
+ u32 reserved;
+ u64 expiration_time; /* When the timer expired */
+ u64 delivery_time; /* When the message was delivered */
+};
+
+/* Define synthetic interrupt controller message format. */
+struct hv_message {
+ struct hv_message_header header;
+ union {
+ u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+ } u ;
+};
+
+/* Define the number of message buffers associated with each port. */
+#define HV_PORT_MESSAGE_BUFFER_COUNT (16)
+
+/* Define the synthetic interrupt message page layout. */
+struct hv_message_page {
+ struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
+};
+
+/* Define the synthetic interrupt controller event flags format. */
+union hv_synic_event_flags {
+ u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT];
+ u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT];
+};
+
+/* Define the synthetic interrupt flags page layout. */
+struct hv_synic_event_flags_page {
+ union hv_synic_event_flags sintevent_flags[HV_SYNIC_SINT_COUNT];
+};
+
+/* Define SynIC control register. */
+union hv_synic_scontrol {
+ u64 as_uint64;
+ struct {
+ u64 enable:1;
+ u64 reserved:63;
+ };
+};
+
+/* Define synthetic interrupt source. */
+union hv_synic_sint {
+ u64 as_uint64;
+ struct {
+ u64 vector:8;
+ u64 reserved1:8;
+ u64 masked:1;
+ u64 auto_eoi:1;
+ u64 reserved2:46;
+ };
+};
+
+/* Define the format of the SIMP register */
+union hv_synic_simp {
+ u64 as_uint64;
+ struct {
+ u64 simp_enabled:1;
+ u64 preserved:11;
+ u64 base_simp_gpa:52;
+ };
+};
+
+/* Define the format of the SIEFP register */
+union hv_synic_siefp {
+ u64 as_uint64;
+ struct {
+ u64 siefp_enabled:1;
+ u64 preserved:11;
+ u64 base_siefp_gpa:52;
+ };
+};
+
+/* Definitions for the monitored notification facility */
+union hv_monitor_trigger_group {
+ u64 as_uint64;
+ struct {
+ u32 pending;
+ u32 armed;
+ };
+};
+
+struct hv_monitor_parameter {
+ union hv_connection_id connectionid;
+ u16 flagnumber;
+ u16 rsvdz;
+};
+
+union hv_monitor_trigger_state {
+ u32 asu32;
+
+ struct {
+ u32 group_enable:4;
+ u32 rsvdz:28;
+ };
+};
+
+/* struct hv_monitor_page Layout */
+/* ------------------------------------------------------ */
+/* | 0 | TriggerState (4 bytes) | Rsvd1 (4 bytes) | */
+/* | 8 | TriggerGroup[0] | */
+/* | 10 | TriggerGroup[1] | */
+/* | 18 | TriggerGroup[2] | */
+/* | 20 | TriggerGroup[3] | */
+/* | 28 | Rsvd2[0] | */
+/* | 30 | Rsvd2[1] | */
+/* | 38 | Rsvd2[2] | */
+/* | 40 | NextCheckTime[0][0] | NextCheckTime[0][1] | */
+/* | ... | */
+/* | 240 | Latency[0][0..3] | */
+/* | 340 | Rsvz3[0] | */
+/* | 440 | Parameter[0][0] | */
+/* | 448 | Parameter[0][1] | */
+/* | ... | */
+/* | 840 | Rsvd4[0] | */
+/* ------------------------------------------------------ */
+struct hv_monitor_page {
+ union hv_monitor_trigger_state trigger_state;
+ u32 rsvdz1;
+
+ union hv_monitor_trigger_group trigger_group[4];
+ u64 rsvdz2[3];
+
+ s32 next_checktime[4][32];
+
+ u16 latency[4][32];
+ u64 rsvdz3[32];
+
+ struct hv_monitor_parameter parameter[4][32];
+
+ u8 rsvdz4[1984];
+};
+
+/* Declare the various hypercall operations. */
+enum hv_call_code {
+ HVCALL_POST_MESSAGE = 0x005c,
+ HVCALL_SIGNAL_EVENT = 0x005d,
+};
+
+/* Definition of the hv_post_message hypercall input structure. */
+struct hv_input_post_message {
+ union hv_connection_id connectionid;
+ u32 reserved;
+ enum hv_message_type message_type;
+ u32 payload_size;
+ u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+};
+
+/* Definition of the hv_signal_event hypercall input structure. */
+struct hv_input_signal_event {
+ union hv_connection_id connectionid;
+ u16 flag_number;
+ u16 rsvdz;
+};
+
+/*
+ * Versioning definitions used for guests reporting themselves to the
+ * hypervisor, and visa versa.
+ */
+
+/* Version info reported by guest OS's */
+enum hv_guest_os_vendor {
+ HVGUESTOS_VENDOR_MICROSOFT = 0x0001
+};
+
+enum hv_guest_os_microsoft_ids {
+ HVGUESTOS_MICROSOFT_UNDEFINED = 0x00,
+ HVGUESTOS_MICROSOFT_MSDOS = 0x01,
+ HVGUESTOS_MICROSOFT_WINDOWS3X = 0x02,
+ HVGUESTOS_MICROSOFT_WINDOWS9X = 0x03,
+ HVGUESTOS_MICROSOFT_WINDOWSNT = 0x04,
+ HVGUESTOS_MICROSOFT_WINDOWSCE = 0x05
+};
+
+/*
+ * Declare the MSR used to identify the guest OS.
+ */
+#define HV_X64_MSR_GUEST_OS_ID 0x40000000
+
+union hv_x64_msr_guest_os_id_contents {
+ u64 as_uint64;
+ struct {
+ u64 build_number:16;
+ u64 service_version:8; /* Service Pack, etc. */
+ u64 minor_version:8;
+ u64 major_version:8;
+ u64 os_id:8; /* enum hv_guest_os_microsoft_ids (if Vendor=MS) */
+ u64 vendor_id:16; /* enum hv_guest_os_vendor */
+ };
+};
+
+/*
+ * Declare the MSR used to setup pages used to communicate with the hypervisor.
+ */
+#define HV_X64_MSR_HYPERCALL 0x40000001
+
+union hv_x64_msr_hypercall_contents {
+ u64 as_uint64;
+ struct {
+ u64 enable:1;
+ u64 reserved:11;
+ u64 guest_physical_address:52;
+ };
+};
+
+
+enum {
+ VMBUS_MESSAGE_CONNECTION_ID = 1,
+ VMBUS_MESSAGE_PORT_ID = 1,
+ VMBUS_EVENT_CONNECTION_ID = 2,
+ VMBUS_EVENT_PORT_ID = 2,
+ VMBUS_MONITOR_CONNECTION_ID = 3,
+ VMBUS_MONITOR_PORT_ID = 3,
+ VMBUS_MESSAGE_SINT = 2,
+};
+
+/* #defines */
+
+#define HV_PRESENT_BIT 0x80000000
+
+#define HV_LINUX_GUEST_ID_LO 0x00000000
+#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
+#define HV_LINUX_GUEST_ID (((u64)HV_LINUX_GUEST_ID_HI << 32) | \
+ HV_LINUX_GUEST_ID_LO)
+
+#define HV_CPU_POWER_MANAGEMENT (1 << 0)
+#define HV_RECOMMENDATIONS_MAX 4
+
+#define HV_X64_MAX 5
+#define HV_CAPS_MAX 8
+
+
+#define HV_HYPERCALL_PARAM_ALIGN sizeof(u64)
+
+
+/* Service definitions */
+
+#define HV_SERVICE_PARENT_PORT (0)
+#define HV_SERVICE_PARENT_CONNECTION (0)
+
+#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0)
+#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1)
+#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2)
+#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3)
+
+#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1)
+#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2)
+#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3)
+#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4)
+#define HV_SERVICE_MAX_MESSAGE_ID (4)
+
+#define HV_SERVICE_PROTOCOL_VERSION (0x0010)
+#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64
+
+/* #define VMBUS_REVISION_NUMBER 6 */
+
+/* Our local vmbus's port and connection id. Anything >0 is fine */
+/* #define VMBUS_PORT_ID 11 */
+
+/* 628180B8-308D-4c5e-B7DB-1BEB62E62EF4 */
+static const struct hv_guid VMBUS_SERVICE_ID = {
+ .data = {
+ 0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c,
+ 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4
+ },
+};
+
+#define MAX_NUM_CPUS 32
+
+
+struct hv_input_signal_event_buffer {
+ u64 align8;
+ struct hv_input_signal_event event;
+};
+
+struct hv_context {
+ /* We only support running on top of Hyper-V
+ * So at this point this really can only contain the Hyper-V ID
+ */
+ u64 guestid;
+
+ void *hypercall_page;
+
+ bool synic_initialized;
+
+ /*
+ * This is used as an input param to HvCallSignalEvent hypercall. The
+ * input param is immutable in our usage and must be dynamic mem (vs
+ * stack or global). */
+ struct hv_input_signal_event_buffer *signal_event_buffer;
+ /* 8-bytes aligned of the buffer above */
+ struct hv_input_signal_event *signal_event_param;
+
+ void *synic_message_page[MAX_NUM_CPUS];
+ void *synic_event_page[MAX_NUM_CPUS];
+};
+
+extern struct hv_context hv_context;
+
+
+/* Hv Interface */
+
+extern int hv_init(void);
+
+extern void hv_cleanup(void);
+
+extern u16 hv_post_message(union hv_connection_id connection_id,
+ enum hv_message_type message_type,
+ void *payload, size_t payload_size);
+
+extern u16 hv_signal_event(void);
+
+extern void hv_synic_init(void *irqarg);
+
+extern void hv_synic_cleanup(void *arg);
+
+
+/* Interface */
+
+
+int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
+ u32 buflen);
+
+void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
+
+int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
+ struct scatterlist *sglist,
+ u32 sgcount);
+
+int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
+ u32 buflen);
+
+int hv_ringbuffer_read(struct hv_ring_buffer_info *ring_info,
+ void *buffer,
+ u32 buflen,
+ u32 offset);
+
+u32 hv_get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *ring_info);
+
+void hv_dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix);
+
+void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
+ struct hv_ring_buffer_debug_info *debug_info);
+
+/*
+ * Maximum channels is determined by the size of the interrupt page
+ * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt
+ * and the other is receive endpoint interrupt
+ */
+#define MAX_NUM_CHANNELS ((PAGE_SIZE >> 1) << 3) /* 16348 channels */
+
+/* The value here must be in multiple of 32 */
+/* TODO: Need to make this configurable */
+#define MAX_NUM_CHANNELS_SUPPORTED 256
+
+
+enum vmbus_connect_state {
+ DISCONNECTED,
+ CONNECTING,
+ CONNECTED,
+ DISCONNECTING
+};
+
+#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT
+
+struct vmbus_connection {
+ enum vmbus_connect_state conn_state;
+
+ atomic_t next_gpadl_handle;
+
+ /*
+ * Represents channel interrupts. Each bit position represents a
+ * channel. When a channel sends an interrupt via VMBUS, it finds its
+ * bit in the sendInterruptPage, set it and calls Hv to generate a port
+ * event. The other end receives the port event and parse the
+ * recvInterruptPage to see which bit is set
+ */
+ void *int_page;
+ void *send_int_page;
+ void *recv_int_page;
+
+ /*
+ * 2 pages - 1st page for parent->child notification and 2nd
+ * is child->parent notification
+ */
+ void *monitor_pages;
+ struct list_head chn_msg_list;
+ spinlock_t channelmsg_lock;
+
+ /* List of channels */
+ struct list_head chn_list;
+ spinlock_t channel_lock;
+
+ struct workqueue_struct *work_queue;
+};
+
+
+struct vmbus_msginfo {
+ /* Bookkeeping stuff */
+ struct list_head msglist_entry;
+
+ /* The message itself */
+ unsigned char msg[0];
+};
+
+
+extern struct vmbus_connection vmbus_connection;
+
+/* General vmbus interface */
+
+struct hv_device *vmbus_child_device_create(struct hv_guid *type,
+ struct hv_guid *instance,
+ struct vmbus_channel *channel);
+
+int vmbus_child_device_register(struct hv_device *child_device_obj);
+void vmbus_child_device_unregister(struct hv_device *device_obj);
+
+/* static void */
+/* VmbusChildDeviceDestroy( */
+/* struct hv_device *); */
+
+struct vmbus_channel *relid2channel(u32 relid);
+
+
+/* Connection interface */
+
+int vmbus_connect(void);
+
+int vmbus_post_msg(void *buffer, size_t buflen);
+
+int vmbus_set_event(u32 child_relid);
+
+void vmbus_on_event(unsigned long data);
+
+
+#endif /* _HYPERV_VMBUS_H */
diff --git a/drivers/staging/hv/include/asm/hyperv.h b/drivers/staging/hv/include/asm/hyperv.h
new file mode 100644
index 000000000000..5df477ac3af7
--- /dev/null
+++ b/drivers/staging/hv/include/asm/hyperv.h
@@ -0,0 +1,193 @@
+#ifndef _ASM_X86_HYPERV_H
+#define _ASM_X86_HYPERV_H
+
+#include <linux/types.h>
+
+/*
+ * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
+ * is set by CPUID(HvCpuIdFunctionVersionAndFeatures).
+ */
+#define HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS 0x40000000
+#define HYPERV_CPUID_INTERFACE 0x40000001
+#define HYPERV_CPUID_VERSION 0x40000002
+#define HYPERV_CPUID_FEATURES 0x40000003
+#define HYPERV_CPUID_ENLIGHTMENT_INFO 0x40000004
+#define HYPERV_CPUID_IMPLEMENT_LIMITS 0x40000005
+
+#define HYPERV_HYPERVISOR_PRESENT_BIT 0x80000000
+#define HYPERV_CPUID_MIN 0x40000005
+#define HYPERV_CPUID_MAX 0x4000ffff
+
+/*
+ * Feature identification. EAX indicates which features are available
+ * to the partition based upon the current partition privileges.
+ */
+
+/* VP Runtime (HV_X64_MSR_VP_RUNTIME) available */
+#define HV_X64_MSR_VP_RUNTIME_AVAILABLE (1 << 0)
+/* Partition Reference Counter (HV_X64_MSR_TIME_REF_COUNT) available*/
+#define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1)
+/*
+ * Basic SynIC MSRs (HV_X64_MSR_SCONTROL through HV_X64_MSR_EOM
+ * and HV_X64_MSR_SINT0 through HV_X64_MSR_SINT15) available
+ */
+#define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2)
+/*
+ * Synthetic Timer MSRs (HV_X64_MSR_STIMER0_CONFIG through
+ * HV_X64_MSR_STIMER3_COUNT) available
+ */
+#define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3)
+/*
+ * APIC access MSRs (HV_X64_MSR_EOI, HV_X64_MSR_ICR and HV_X64_MSR_TPR)
+ * are available
+ */
+#define HV_X64_MSR_APIC_ACCESS_AVAILABLE (1 << 4)
+/* Hypercall MSRs (HV_X64_MSR_GUEST_OS_ID and HV_X64_MSR_HYPERCALL) available*/
+#define HV_X64_MSR_HYPERCALL_AVAILABLE (1 << 5)
+/* Access virtual processor index MSR (HV_X64_MSR_VP_INDEX) available*/
+#define HV_X64_MSR_VP_INDEX_AVAILABLE (1 << 6)
+/* Virtual system reset MSR (HV_X64_MSR_RESET) is available*/
+#define HV_X64_MSR_RESET_AVAILABLE (1 << 7)
+ /*
+ * Access statistics pages MSRs (HV_X64_MSR_STATS_PARTITION_RETAIL_PAGE,
+ * HV_X64_MSR_STATS_PARTITION_INTERNAL_PAGE, HV_X64_MSR_STATS_VP_RETAIL_PAGE,
+ * HV_X64_MSR_STATS_VP_INTERNAL_PAGE) available
+ */
+#define HV_X64_MSR_STAT_PAGES_AVAILABLE (1 << 8)
+
+/*
+ * Feature identification: EBX indicates which flags were specified at
+ * partition creation. The format is the same as the partition creation
+ * flag structure defined in section Partition Creation Flags.
+ */
+#define HV_X64_CREATE_PARTITIONS (1 << 0)
+#define HV_X64_ACCESS_PARTITION_ID (1 << 1)
+#define HV_X64_ACCESS_MEMORY_POOL (1 << 2)
+#define HV_X64_ADJUST_MESSAGE_BUFFERS (1 << 3)
+#define HV_X64_POST_MESSAGES (1 << 4)
+#define HV_X64_SIGNAL_EVENTS (1 << 5)
+#define HV_X64_CREATE_PORT (1 << 6)
+#define HV_X64_CONNECT_PORT (1 << 7)
+#define HV_X64_ACCESS_STATS (1 << 8)
+#define HV_X64_DEBUGGING (1 << 11)
+#define HV_X64_CPU_POWER_MANAGEMENT (1 << 12)
+#define HV_X64_CONFIGURE_PROFILER (1 << 13)
+
+/*
+ * Feature identification. EDX indicates which miscellaneous features
+ * are available to the partition.
+ */
+/* The MWAIT instruction is available (per section MONITOR / MWAIT) */
+#define HV_X64_MWAIT_AVAILABLE (1 << 0)
+/* Guest debugging support is available */
+#define HV_X64_GUEST_DEBUGGING_AVAILABLE (1 << 1)
+/* Performance Monitor support is available*/
+#define HV_X64_PERF_MONITOR_AVAILABLE (1 << 2)
+/* Support for physical CPU dynamic partitioning events is available*/
+#define HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE (1 << 3)
+/*
+ * Support for passing hypercall input parameter block via XMM
+ * registers is available
+ */
+#define HV_X64_HYPERCALL_PARAMS_XMM_AVAILABLE (1 << 4)
+/* Support for a virtual guest idle state is available */
+#define HV_X64_GUEST_IDLE_STATE_AVAILABLE (1 << 5)
+
+/*
+ * Implementation recommendations. Indicates which behaviors the hypervisor
+ * recommends the OS implement for optimal performance.
+ */
+ /*
+ * Recommend using hypercall for address space switches rather
+ * than MOV to CR3 instruction
+ */
+#define HV_X64_MWAIT_RECOMMENDED (1 << 0)
+/* Recommend using hypercall for local TLB flushes rather
+ * than INVLPG or MOV to CR3 instructions */
+#define HV_X64_LOCAL_TLB_FLUSH_RECOMMENDED (1 << 1)
+/*
+ * Recommend using hypercall for remote TLB flushes rather
+ * than inter-processor interrupts
+ */
+#define HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED (1 << 2)
+/*
+ * Recommend using MSRs for accessing APIC registers
+ * EOI, ICR and TPR rather than their memory-mapped counterparts
+ */
+#define HV_X64_APIC_ACCESS_RECOMMENDED (1 << 3)
+/* Recommend using the hypervisor-provided MSR to initiate a system RESET */
+#define HV_X64_SYSTEM_RESET_RECOMMENDED (1 << 4)
+/*
+ * Recommend using relaxed timing for this partition. If used,
+ * the VM should disable any watchdog timeouts that rely on the
+ * timely delivery of external interrupts
+ */
+#define HV_X64_RELAXED_TIMING_RECOMMENDED (1 << 5)
+
+/* MSR used to identify the guest OS. */
+#define HV_X64_MSR_GUEST_OS_ID 0x40000000
+
+/* MSR used to setup pages used to communicate with the hypervisor. */
+#define HV_X64_MSR_HYPERCALL 0x40000001
+
+/* MSR used to provide vcpu index */
+#define HV_X64_MSR_VP_INDEX 0x40000002
+
+/* MSR used to read the per-partition time reference counter */
+#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
+
+/* Define the virtual APIC registers */
+#define HV_X64_MSR_EOI 0x40000070
+#define HV_X64_MSR_ICR 0x40000071
+#define HV_X64_MSR_TPR 0x40000072
+#define HV_X64_MSR_APIC_ASSIST_PAGE 0x40000073
+
+/* Define synthetic interrupt controller model specific registers. */
+#define HV_X64_MSR_SCONTROL 0x40000080
+#define HV_X64_MSR_SVERSION 0x40000081
+#define HV_X64_MSR_SIEFP 0x40000082
+#define HV_X64_MSR_SIMP 0x40000083
+#define HV_X64_MSR_EOM 0x40000084
+#define HV_X64_MSR_SINT0 0x40000090
+#define HV_X64_MSR_SINT1 0x40000091
+#define HV_X64_MSR_SINT2 0x40000092
+#define HV_X64_MSR_SINT3 0x40000093
+#define HV_X64_MSR_SINT4 0x40000094
+#define HV_X64_MSR_SINT5 0x40000095
+#define HV_X64_MSR_SINT6 0x40000096
+#define HV_X64_MSR_SINT7 0x40000097
+#define HV_X64_MSR_SINT8 0x40000098
+#define HV_X64_MSR_SINT9 0x40000099
+#define HV_X64_MSR_SINT10 0x4000009A
+#define HV_X64_MSR_SINT11 0x4000009B
+#define HV_X64_MSR_SINT12 0x4000009C
+#define HV_X64_MSR_SINT13 0x4000009D
+#define HV_X64_MSR_SINT14 0x4000009E
+#define HV_X64_MSR_SINT15 0x4000009F
+
+
+#define HV_X64_MSR_HYPERCALL_ENABLE 0x00000001
+#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT 12
+#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_MASK \
+ (~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1))
+
+/* Declare the various hypercall operations. */
+#define HV_X64_HV_NOTIFY_LONG_SPIN_WAIT 0x0008
+
+#define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE 0x00000001
+#define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12
+#define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_MASK \
+ (~((1ull << HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT) - 1))
+
+#define HV_PROCESSOR_POWER_STATE_C0 0
+#define HV_PROCESSOR_POWER_STATE_C1 1
+#define HV_PROCESSOR_POWER_STATE_C2 2
+#define HV_PROCESSOR_POWER_STATE_C3 3
+
+/* hypercall status code */
+#define HV_STATUS_SUCCESS 0
+#define HV_STATUS_INVALID_HYPERCALL_CODE 2
+#define HV_STATUS_INVALID_HYPERCALL_INPUT 3
+#define HV_STATUS_INVALID_ALIGNMENT 4
+
+#endif
diff --git a/drivers/staging/hv/include/asm/mshyperv.h b/drivers/staging/hv/include/asm/mshyperv.h
new file mode 100644
index 000000000000..87b5199356df
--- /dev/null
+++ b/drivers/staging/hv/include/asm/mshyperv.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_X86_MSHYPER_H
+#define _ASM_X86_MSHYPER_H
+
+#include <linux/types.h>
+#include <asm/hyperv.h>
+
+struct ms_hyperv_info {
+ u32 features;
+ u32 hints;
+};
+
+extern struct ms_hyperv_info ms_hyperv;
+extern void *x86_hyper;
+extern int x86_hyper_ms_hyperv;
+
+#endif
diff --git a/drivers/staging/hv/include/linux/atomic.h b/drivers/staging/hv/include/linux/atomic.h
new file mode 100644
index 000000000000..2e5735a35afa
--- /dev/null
+++ b/drivers/staging/hv/include/linux/atomic.h
@@ -0,0 +1,5 @@
+#ifndef _LINUX_ATOMIC_H
+#define _LINUX_ATOMIC_H
+#include <asm/atomic.h>
+
+#endif
diff --git a/drivers/staging/hv/logging.h b/drivers/staging/hv/logging.h
deleted file mode 100644
index 20d4d12023de..000000000000
--- a/drivers/staging/hv/logging.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _LOGGING_H_
-#define _LOGGING_H_
-
-/* #include <linux/init.h> */
-/* #include <linux/module.h> */
-
-
-#define VMBUS 0x0001
-#define STORVSC 0x0002
-#define NETVSC 0x0004
-#define INPUTVSC 0x0008
-#define BLKVSC 0x0010
-#define VMBUS_DRV 0x0100
-#define STORVSC_DRV 0x0200
-#define NETVSC_DRV 0x0400
-#define INPUTVSC_DRV 0x0800
-#define BLKVSC_DRV 0x1000
-
-#define ALL_MODULES (VMBUS |\
- STORVSC |\
- NETVSC |\
- INPUTVSC |\
- BLKVSC |\
- VMBUS_DRV |\
- STORVSC_DRV |\
- NETVSC_DRV |\
- INPUTVSC_DRV|\
- BLKVSC_DRV)
-
-/* Logging Level */
-#define ERROR_LVL 3
-#define WARNING_LVL 4
-#define INFO_LVL 6
-#define DEBUG_LVL 7
-#define DEBUG_LVL_ENTEREXIT 8
-#define DEBUG_RING_LVL 9
-
-extern unsigned int vmbus_loglevel;
-
-#define DPRINT(mod, lvl, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (lvl <= LOWORD(vmbus_loglevel))) \
- printk(KERN_DEBUG #mod": %s() " fmt "\n", __func__, ## args);\
- } while (0)
-
-#define DPRINT_DBG(mod, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (DEBUG_LVL <= LOWORD(vmbus_loglevel))) \
- printk(KERN_DEBUG #mod": %s() " fmt "\n", __func__, ## args);\
- } while (0)
-
-#define DPRINT_INFO(mod, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (INFO_LVL <= LOWORD(vmbus_loglevel))) \
- printk(KERN_INFO #mod": " fmt "\n", ## args);\
- } while (0)
-
-#define DPRINT_WARN(mod, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (WARNING_LVL <= LOWORD(vmbus_loglevel))) \
- printk(KERN_WARNING #mod": WARNING! " fmt "\n", ## args);\
- } while (0)
-
-#define DPRINT_ERR(mod, fmt, args...) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (ERROR_LVL <= LOWORD(vmbus_loglevel))) \
- printk(KERN_ERR #mod": %s() ERROR!! " fmt "\n", \
- __func__, ## args);\
- } while (0)
-
-#endif /* _LOGGING_H_ */
diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
new file mode 100644
index 000000000000..267df745d3f9
--- /dev/null
+++ b/drivers/staging/hv/netvsc.c
@@ -0,0 +1,1015 @@
+/*
+ * 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 "hyperv.h"
+#include "hyperv_net.h"
+
+