blob: 103748818fd536d664c02aa4a289a2021fd93251 [file] [log] [blame]
Hank Janssen3e7ee492009-07-13 16:02:34 -07001/*
Hank Janssen3e7ee492009-07-13 16:02:34 -07002 * Copyright (c) 2009, Microsoft Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Authors:
18 * Haiyang Zhang <haiyangz@microsoft.com>
19 * Hank Janssen <hjanssen@microsoft.com>
Hank Janssen3e7ee492009-07-13 16:02:34 -070020 */
Greg Kroah-Hartman5654e932009-07-14 15:08:20 -070021#include <linux/kernel.h>
Greg Kroah-Hartmana0086dc2009-08-17 17:22:08 -070022#include <linux/mm.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Hank Janssenc88c4e42010-05-04 15:55:05 -070024#include <linux/module.h>
Greg Kroah-Hartman4983b392009-08-19 16:14:47 -070025#include "osd.h"
Greg Kroah-Hartman645954c2009-08-28 16:22:59 -070026#include "logging.h"
Greg Kroah-Hartman72daf322010-05-05 22:45:25 -070027#include "vmbus_private.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070028
Bill Pemberton454f18a2009-07-27 16:47:24 -040029/* Internal routines */
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -070030static int VmbusChannelCreateGpadlHeader(
Haiyang Zhang39d70a42010-09-30 10:52:13 -070031 void *kbuffer, /* must be phys and virt contiguous */
32 u32 size, /* page-size multiple */
33 struct vmbus_channel_msginfo **msginfo,
34 u32 *messagecount);
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -070035static void DumpVmbusChannel(struct vmbus_channel *channel);
36static void VmbusChannelSetEvent(struct vmbus_channel *channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -070037
38
39#if 0
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070040static void DumpMonitorPage(struct hv_monitor_page *MonitorPage)
Hank Janssen3e7ee492009-07-13 16:02:34 -070041{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070042 int i = 0;
43 int j = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -070044
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070045 DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d",
46 MonitorPage, MonitorPage->TriggerState);
Hank Janssen3e7ee492009-07-13 16:02:34 -070047
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070048 for (i = 0; i < 4; i++)
49 DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i,
50 MonitorPage->TriggerGroup[i].AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -070051
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070052 for (i = 0; i < 4; i++) {
53 for (j = 0; j < 32; j++) {
54 DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j,
55 MonitorPage->Latency[i][j]);
Hank Janssen3e7ee492009-07-13 16:02:34 -070056 }
57 }
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070058 for (i = 0; i < 4; i++) {
59 for (j = 0; j < 32; j++) {
60 DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j,
61 MonitorPage->Parameter[i][j].ConnectionId.Asu32);
62 DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j,
63 MonitorPage->Parameter[i][j].FlagNumber);
Hank Janssen3e7ee492009-07-13 16:02:34 -070064 }
65 }
66}
67#endif
68
Hank Janssen3e189512010-03-04 22:11:00 +000069/*
70 * VmbusChannelSetEvent - Trigger an event notification on the specified
71 * channel.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070072 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -070073static void VmbusChannelSetEvent(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -070074{
Haiyang Zhang39d70a42010-09-30 10:52:13 -070075 struct hv_monitor_page *monitorpage;
Hank Janssen3e7ee492009-07-13 16:02:34 -070076
Haiyang Zhang39d70a42010-09-30 10:52:13 -070077 if (channel->OfferMsg.MonitorAllocated) {
Bill Pemberton454f18a2009-07-27 16:47:24 -040078 /* Each u32 represents 32 channels */
Haiyang Zhang39d70a42010-09-30 10:52:13 -070079 set_bit(channel->OfferMsg.ChildRelId & 31,
Bill Pemberton7c369f42009-07-29 17:00:11 -040080 (unsigned long *) gVmbusConnection.SendInterruptPage +
Haiyang Zhang39d70a42010-09-30 10:52:13 -070081 (channel->OfferMsg.ChildRelId >> 5));
Hank Janssen3e7ee492009-07-13 16:02:34 -070082
Haiyang Zhang39d70a42010-09-30 10:52:13 -070083 monitorpage = gVmbusConnection.MonitorPages;
84 monitorpage++; /* Get the child to parent monitor page */
Hank Janssen3e7ee492009-07-13 16:02:34 -070085
Haiyang Zhang39d70a42010-09-30 10:52:13 -070086 set_bit(channel->MonitorBit,
87 (unsigned long *)&monitorpage->TriggerGroup
88 [channel->MonitorGroup].Pending);
Bill Pemberton7c369f42009-07-29 17:00:11 -040089
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070090 } else {
Haiyang Zhang39d70a42010-09-30 10:52:13 -070091 VmbusSetEvent(channel->OfferMsg.ChildRelId);
Hank Janssen3e7ee492009-07-13 16:02:34 -070092 }
Hank Janssen3e7ee492009-07-13 16:02:34 -070093}
94
95#if 0
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -070096static void VmbusChannelClearEvent(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -070097{
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -070098 struct hv_monitor_page *monitorPage;
Hank Janssen3e7ee492009-07-13 16:02:34 -070099
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700100 if (Channel->OfferMsg.MonitorAllocated) {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400101 /* Each u32 represents 32 channels */
Bill Pemberton7c369f42009-07-29 17:00:11 -0400102 clear_bit(Channel->OfferMsg.ChildRelId & 31,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700103 (unsigned long *)gVmbusConnection.SendInterruptPage +
104 (Channel->OfferMsg.ChildRelId >> 5));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700105
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700106 monitorPage =
107 (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400108 monitorPage++; /* Get the child to parent monitor page */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700109
Bill Pemberton7c369f42009-07-29 17:00:11 -0400110 clear_bit(Channel->MonitorBit,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700111 (unsigned long *)&monitorPage->TriggerGroup
112 [Channel->MonitorGroup].Pending);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700113 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700114}
115
116#endif
Hank Janssen3e189512010-03-04 22:11:00 +0000117/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700118 * VmbusChannelGetDebugInfo -Retrieve various channel debug info
119 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700120void VmbusChannelGetDebugInfo(struct vmbus_channel *channel,
121 struct vmbus_channel_debug_info *debuginfo)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700122{
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700123 struct hv_monitor_page *monitorpage;
124 u8 monitor_group = (u8)channel->OfferMsg.MonitorId / 32;
125 u8 monitor_offset = (u8)channel->OfferMsg.MonitorId % 32;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400126 /* u32 monitorBit = 1 << monitorOffset; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700127
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700128 debuginfo->RelId = channel->OfferMsg.ChildRelId;
129 debuginfo->State = channel->State;
130 memcpy(&debuginfo->InterfaceType,
131 &channel->OfferMsg.Offer.InterfaceType, sizeof(struct hv_guid));
132 memcpy(&debuginfo->InterfaceInstance,
133 &channel->OfferMsg.Offer.InterfaceInstance,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700134 sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700135
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700136 monitorpage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700137
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700138 debuginfo->MonitorId = channel->OfferMsg.MonitorId;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700139
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700140 debuginfo->ServerMonitorPending =
141 monitorpage->TriggerGroup[monitor_group].Pending;
142 debuginfo->ServerMonitorLatency =
143 monitorpage->Latency[monitor_group][monitor_offset];
144 debuginfo->ServerMonitorConnectionId =
145 monitorpage->Parameter[monitor_group]
146 [monitor_offset].ConnectionId.u.Id;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700147
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700148 monitorpage++;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700149
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700150 debuginfo->ClientMonitorPending =
151 monitorpage->TriggerGroup[monitor_group].Pending;
152 debuginfo->ClientMonitorLatency =
153 monitorpage->Latency[monitor_group][monitor_offset];
154 debuginfo->ClientMonitorConnectionId =
155 monitorpage->Parameter[monitor_group]
156 [monitor_offset].ConnectionId.u.Id;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700157
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700158 RingBufferGetDebugInfo(&channel->Inbound, &debuginfo->Inbound);
159 RingBufferGetDebugInfo(&channel->Outbound, &debuginfo->Outbound);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700160}
161
Hank Janssen3e189512010-03-04 22:11:00 +0000162/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700163 * VmbusChannelOpen - Open the specified channel.
164 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700165int VmbusChannelOpen(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
166 u32 recv_ringbuffer_size, void *userdata, u32 userdatalen,
167 void (*onchannelcallback)(void *context), void *context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700168{
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700169 struct vmbus_channel_open_channel *openMsg;
Bill Pembertonb94ef342010-05-05 15:27:37 -0400170 struct vmbus_channel_msginfo *openInfo = NULL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700171 void *in, *out;
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700172 unsigned long flags;
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400173 int ret, err = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700174
Bill Pemberton454f18a2009-07-27 16:47:24 -0400175 /* Aligned to page size */
Bill Pemberton0ace2472010-05-05 15:27:40 -0400176 /* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */
177 /* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700178
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700179 newchannel->OnChannelCallback = onchannelcallback;
180 newchannel->ChannelCallbackContext = context;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700181
Bill Pemberton454f18a2009-07-27 16:47:24 -0400182 /* Allocate the ring buffer */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700183 out = osd_PageAlloc((send_ringbuffer_size + recv_ringbuffer_size)
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700184 >> PAGE_SHIFT);
Bill Pemberton7e052d92010-05-05 15:27:30 -0400185 if (!out)
186 return -ENOMEM;
187
Bill Pemberton0ace2472010-05-05 15:27:40 -0400188 /* ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700189
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700190 in = (void *)((unsigned long)out + send_ringbuffer_size);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700191
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700192 newchannel->RingBufferPages = out;
193 newchannel->RingBufferPageCount = (send_ringbuffer_size +
194 recv_ringbuffer_size) >> PAGE_SHIFT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700195
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700196 ret = RingBufferInit(&newchannel->Outbound, out, send_ringbuffer_size);
Haiyang Zhangfd4dc882010-05-13 15:56:30 +0000197 if (ret != 0) {
Bill Pemberton3324fb42010-05-05 15:27:49 -0400198 err = ret;
199 goto errorout;
200 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700201
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700202 ret = RingBufferInit(&newchannel->Inbound, in, recv_ringbuffer_size);
Haiyang Zhangfd4dc882010-05-13 15:56:30 +0000203 if (ret != 0) {
Bill Pemberton3324fb42010-05-05 15:27:49 -0400204 err = ret;
205 goto errorout;
206 }
207
Hank Janssen3e7ee492009-07-13 16:02:34 -0700208
Bill Pemberton454f18a2009-07-27 16:47:24 -0400209 /* Establish the gpadl for the ring buffer */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700210 DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700211 newchannel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700212
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700213 newchannel->RingBufferGpadlHandle = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700214
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700215 ret = VmbusChannelEstablishGpadl(newchannel,
216 newchannel->Outbound.RingBuffer,
217 send_ringbuffer_size +
218 recv_ringbuffer_size,
219 &newchannel->RingBufferGpadlHandle);
Bill Pembertonb94ef342010-05-05 15:27:37 -0400220
Haiyang Zhangfd4dc882010-05-13 15:56:30 +0000221 if (ret != 0) {
Bill Pembertonb94ef342010-05-05 15:27:37 -0400222 err = ret;
223 goto errorout;
224 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700225
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700226 DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p "
227 "size %d recv ring %p size %d, downstreamoffset %d>",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700228 newchannel, newchannel->OfferMsg.ChildRelId,
229 newchannel->RingBufferGpadlHandle,
230 newchannel->Outbound.RingBuffer,
231 newchannel->Outbound.RingSize,
232 newchannel->Inbound.RingBuffer,
233 newchannel->Inbound.RingSize,
234 send_ringbuffer_size);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700235
Bill Pemberton454f18a2009-07-27 16:47:24 -0400236 /* Create and init the channel open message */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700237 openInfo = kmalloc(sizeof(*openInfo) +
238 sizeof(struct vmbus_channel_open_channel),
239 GFP_KERNEL);
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400240 if (!openInfo) {
241 err = -ENOMEM;
242 goto errorout;
243 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700244
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700245 openInfo->WaitEvent = osd_WaitEventCreate();
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400246 if (!openInfo->WaitEvent) {
247 err = -ENOMEM;
248 goto errorout;
249 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700250
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700251 openMsg = (struct vmbus_channel_open_channel *)openInfo->Msg;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700252 openMsg->Header.MessageType = ChannelMessageOpenChannel;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700253 openMsg->OpenId = newchannel->OfferMsg.ChildRelId; /* FIXME */
254 openMsg->ChildRelId = newchannel->OfferMsg.ChildRelId;
255 openMsg->RingBufferGpadlHandle = newchannel->RingBufferGpadlHandle;
256 openMsg->DownstreamRingBufferPageOffset = send_ringbuffer_size >>
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700257 PAGE_SHIFT;
258 openMsg->ServerContextAreaGpadlHandle = 0; /* TODO */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700259
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700260 if (userdatalen > MAX_USER_DEFINED_BYTES) {
Bill Pembertonc827f942010-05-05 15:27:38 -0400261 err = -EINVAL;
262 goto errorout;
263 }
264
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700265 if (userdatalen)
266 memcpy(openMsg->UserData, userdata, userdatalen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700267
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700268 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Bill Pemberton53af5452009-09-11 21:46:44 -0400269 list_add_tail(&openInfo->MsgListEntry,
270 &gVmbusConnection.ChannelMsgList);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700271 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700272
273 DPRINT_DBG(VMBUS, "Sending channel open msg...");
274
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700275 ret = VmbusPostMessage(openMsg,
276 sizeof(struct vmbus_channel_open_channel));
277 if (ret != 0) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700278 DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
279 goto Cleanup;
280 }
281
Bill Pemberton454f18a2009-07-27 16:47:24 -0400282 /* FIXME: Need to time-out here */
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700283 osd_WaitEventWait(openInfo->WaitEvent);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700284
285 if (openInfo->Response.OpenResult.Status == 0)
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700286 DPRINT_INFO(VMBUS, "channel <%p> open success!!", newchannel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700287 else
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700288 DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700289 newchannel, openInfo->Response.OpenResult.Status);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700290
291Cleanup:
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700292 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Bill Pemberton53af5452009-09-11 21:46:44 -0400293 list_del(&openInfo->MsgListEntry);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700294 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700295
Bill Pemberton420beac2009-07-29 17:00:10 -0400296 kfree(openInfo->WaitEvent);
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700297 kfree(openInfo);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700298 return 0;
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400299
300errorout:
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700301 RingBufferCleanup(&newchannel->Outbound);
302 RingBufferCleanup(&newchannel->Inbound);
303 osd_PageFree(out, (send_ringbuffer_size + recv_ringbuffer_size)
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400304 >> PAGE_SHIFT);
305 kfree(openInfo);
306 return err;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700307}
308
Hank Janssen3e189512010-03-04 22:11:00 +0000309/*
310 * DumpGpadlBody - Dump the gpadl body message to the console for
311 * debugging purposes.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700312 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700313static void DumpGpadlBody(struct vmbus_channel_gpadl_body *gpadl, u32 len)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700314{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700315 int i;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700316 int pfncount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700317
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700318 pfncount = (len - sizeof(struct vmbus_channel_gpadl_body)) /
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700319 sizeof(u64);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700320 DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", len, pfncount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700321
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700322 for (i = 0; i < pfncount; i++)
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700323 DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700324 i, gpadl->Pfn[i]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700325}
326
Hank Janssen3e189512010-03-04 22:11:00 +0000327/*
328 * DumpGpadlHeader - Dump the gpadl header message to the console for
329 * debugging purposes.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700330 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700331static void DumpGpadlHeader(struct vmbus_channel_gpadl_header *gpadl)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700332{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700333 int i, j;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700334 int pagecount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700335
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700336 DPRINT_DBG(VMBUS,
337 "gpadl header - relid %d, range count %d, range buflen %d",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700338 gpadl->ChildRelId, gpadl->RangeCount, gpadl->RangeBufLen);
339 for (i = 0; i < gpadl->RangeCount; i++) {
340 pagecount = gpadl->Range[i].ByteCount >> PAGE_SHIFT;
341 pagecount = (pagecount > 26) ? 26 : pagecount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700342
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700343 DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d "
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700344 "page count %d", i, gpadl->Range[i].ByteCount,
345 gpadl->Range[i].ByteOffset, pagecount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700346
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700347 for (j = 0; j < pagecount; j++)
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700348 DPRINT_DBG(VMBUS, "%d) pfn %llu", j,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700349 gpadl->Range[i].PfnArray[j]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700350 }
351}
352
Hank Janssen3e189512010-03-04 22:11:00 +0000353/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700354 * VmbusChannelCreateGpadlHeader - Creates a gpadl for the specified buffer
355 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700356static int VmbusChannelCreateGpadlHeader(void *kbuffer, u32 size,
357 struct vmbus_channel_msginfo **msginfo,
358 u32 *messagecount)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700359{
360 int i;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700361 int pagecount;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700362 unsigned long long pfn;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700363 struct vmbus_channel_gpadl_header *gpadl_header;
364 struct vmbus_channel_gpadl_body *gpadl_body;
365 struct vmbus_channel_msginfo *msgheader;
366 struct vmbus_channel_msginfo *msgbody = NULL;
367 u32 msgsize;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700368
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700369 int pfnsum, pfncount, pfnleft, pfncurr, pfnsize;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700370
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700371 /* ASSERT((kbuffer & (PAGE_SIZE-1)) == 0); */
Bill Pemberton0ace2472010-05-05 15:27:40 -0400372 /* ASSERT((Size & (PAGE_SIZE-1)) == 0); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700373
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700374 pagecount = size >> PAGE_SHIFT;
375 pfn = virt_to_phys(kbuffer) >> PAGE_SHIFT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700376
Bill Pemberton454f18a2009-07-27 16:47:24 -0400377 /* do we need a gpadl body msg */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700378 pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700379 sizeof(struct vmbus_channel_gpadl_header) -
380 sizeof(struct gpa_range);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700381 pfncount = pfnsize / sizeof(u64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700382
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700383 if (pagecount > pfncount) {
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700384 /* we need a gpadl body */
Bill Pemberton454f18a2009-07-27 16:47:24 -0400385 /* fill in the header */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700386 msgsize = sizeof(struct vmbus_channel_msginfo) +
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700387 sizeof(struct vmbus_channel_gpadl_header) +
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700388 sizeof(struct gpa_range) + pfncount * sizeof(u64);
389 msgheader = kzalloc(msgsize, GFP_KERNEL);
390 if (!msgheader)
Bill Pembertond1c250b2010-05-05 15:27:35 -0400391 goto nomem;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700392
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700393 INIT_LIST_HEAD(&msgheader->SubMsgList);
394 msgheader->MessageSize = msgsize;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700395
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700396 gpadl_header = (struct vmbus_channel_gpadl_header *)
397 msgheader->Msg;
398 gpadl_header->RangeCount = 1;
399 gpadl_header->RangeBufLen = sizeof(struct gpa_range) +
400 pagecount * sizeof(u64);
401 gpadl_header->Range[0].ByteOffset = 0;
402 gpadl_header->Range[0].ByteCount = size;
403 for (i = 0; i < pfncount; i++)
404 gpadl_header->Range[0].PfnArray[i] = pfn+i;
405 *msginfo = msgheader;
406 *messagecount = 1;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700407
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700408 pfnsum = pfncount;
409 pfnleft = pagecount - pfncount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700410
Bill Pemberton454f18a2009-07-27 16:47:24 -0400411 /* how many pfns can we fit */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700412 pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700413 sizeof(struct vmbus_channel_gpadl_body);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700414 pfncount = pfnsize / sizeof(u64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700415
Bill Pemberton454f18a2009-07-27 16:47:24 -0400416 /* fill in the body */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700417 while (pfnleft) {
418 if (pfnleft > pfncount)
419 pfncurr = pfncount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700420 else
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700421 pfncurr = pfnleft;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700422
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700423 msgsize = sizeof(struct vmbus_channel_msginfo) +
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700424 sizeof(struct vmbus_channel_gpadl_body) +
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700425 pfncurr * sizeof(u64);
426 msgbody = kzalloc(msgsize, GFP_KERNEL);
Bill Pembertond1c250b2010-05-05 15:27:35 -0400427 /* FIXME: we probably need to more if this fails */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700428 if (!msgbody)
Bill Pembertond1c250b2010-05-05 15:27:35 -0400429 goto nomem;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700430 msgbody->MessageSize = msgsize;
431 (*messagecount)++;
432 gpadl_body =
433 (struct vmbus_channel_gpadl_body *)msgbody->Msg;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700434
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700435 /*
436 * FIXME:
437 * Gpadl is u32 and we are using a pointer which could
438 * be 64-bit
439 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700440 /* gpadl_body->Gpadl = kbuffer; */
441 for (i = 0; i < pfncurr; i++)
442 gpadl_body->Pfn[i] = pfn + pfnsum + i;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700443
Bill Pemberton454f18a2009-07-27 16:47:24 -0400444 /* add to msg header */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700445 list_add_tail(&msgbody->MsgListEntry,
446 &msgheader->SubMsgList);
447 pfnsum += pfncurr;
448 pfnleft -= pfncurr;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700449 }
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700450 } else {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400451 /* everything fits in a header */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700452 msgsize = sizeof(struct vmbus_channel_msginfo) +
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700453 sizeof(struct vmbus_channel_gpadl_header) +
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700454 sizeof(struct gpa_range) + pagecount * sizeof(u64);
455 msgheader = kzalloc(msgsize, GFP_KERNEL);
456 if (msgheader == NULL)
Kulikov Vasiliye3eb7cd2010-07-16 20:13:51 +0400457 goto nomem;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700458 msgheader->MessageSize = msgsize;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700459
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700460 gpadl_header = (struct vmbus_channel_gpadl_header *)
461 msgheader->Msg;
462 gpadl_header->RangeCount = 1;
463 gpadl_header->RangeBufLen = sizeof(struct gpa_range) +
464 pagecount * sizeof(u64);
465 gpadl_header->Range[0].ByteOffset = 0;
466 gpadl_header->Range[0].ByteCount = size;
467 for (i = 0; i < pagecount; i++)
468 gpadl_header->Range[0].PfnArray[i] = pfn+i;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700469
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700470 *msginfo = msgheader;
471 *messagecount = 1;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700472 }
473
474 return 0;
Bill Pembertond1c250b2010-05-05 15:27:35 -0400475nomem:
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700476 kfree(msgheader);
477 kfree(msgbody);
Bill Pembertond1c250b2010-05-05 15:27:35 -0400478 return -ENOMEM;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700479}
480
Hank Janssen3e189512010-03-04 22:11:00 +0000481/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700482 * VmbusChannelEstablishGpadl - Estabish a GPADL for the specified buffer
483 *
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700484 * @channel: a channel
485 * @kbuffer: from kmalloc
486 * @size: page-size multiple
487 * @gpadl_handle: some funky thing
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700488 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700489int VmbusChannelEstablishGpadl(struct vmbus_channel *channel, void *kbuffer,
490 u32 size, u32 *gpadl_handle)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700491{
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700492 struct vmbus_channel_gpadl_header *gpadlmsg;
493 struct vmbus_channel_gpadl_body *gpadl_body;
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700494 /* struct vmbus_channel_gpadl_created *gpadlCreated; */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700495 struct vmbus_channel_msginfo *msginfo = NULL;
496 struct vmbus_channel_msginfo *submsginfo;
497 u32 msgcount;
Bill Pemberton53af5452009-09-11 21:46:44 -0400498 struct list_head *curr;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700499 u32 next_gpadl_handle;
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700500 unsigned long flags;
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400501 int ret = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700502
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700503 next_gpadl_handle = atomic_read(&gVmbusConnection.NextGpadlHandle);
Bill Pembertonf4888412009-07-29 17:00:12 -0400504 atomic_inc(&gVmbusConnection.NextGpadlHandle);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700505
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700506 ret = VmbusChannelCreateGpadlHeader(kbuffer, size, &msginfo, &msgcount);
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400507 if (ret)
508 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700509
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700510 msginfo->WaitEvent = osd_WaitEventCreate();
511 if (!msginfo->WaitEvent) {
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400512 ret = -ENOMEM;
513 goto Cleanup;
514 }
515
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700516 gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->Msg;
517 gpadlmsg->Header.MessageType = ChannelMessageGpadlHeader;
518 gpadlmsg->ChildRelId = channel->OfferMsg.ChildRelId;
519 gpadlmsg->Gpadl = next_gpadl_handle;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700520
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700521 DumpGpadlHeader(gpadlmsg);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700522
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700523 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700524 list_add_tail(&msginfo->MsgListEntry,
Bill Pemberton53af5452009-09-11 21:46:44 -0400525 &gVmbusConnection.ChannelMsgList);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700526
Bill Pemberton53af5452009-09-11 21:46:44 -0400527 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700528 DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700529 kbuffer, size, msgcount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700530
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700531 DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700532 msginfo->MessageSize - sizeof(*msginfo));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700533
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700534 ret = VmbusPostMessage(gpadlmsg, msginfo->MessageSize -
535 sizeof(*msginfo));
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700536 if (ret != 0) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700537 DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
538 goto Cleanup;
539 }
540
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700541 if (msgcount > 1) {
542 list_for_each(curr, &msginfo->SubMsgList) {
Bill Pemberton53af5452009-09-11 21:46:44 -0400543
544 /* FIXME: should this use list_entry() instead ? */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700545 submsginfo = (struct vmbus_channel_msginfo *)curr;
546 gpadl_body =
547 (struct vmbus_channel_gpadl_body *)submsginfo->Msg;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700548
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700549 gpadl_body->Header.MessageType =
550 ChannelMessageGpadlBody;
551 gpadl_body->Gpadl = next_gpadl_handle;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700552
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700553 DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700554 submsginfo->MessageSize -
555 sizeof(*submsginfo));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700556
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700557 DumpGpadlBody(gpadl_body, submsginfo->MessageSize -
558 sizeof(*submsginfo));
559 ret = VmbusPostMessage(gpadl_body,
560 submsginfo->MessageSize -
561 sizeof(*submsginfo));
Haiyang Zhangfd4dc882010-05-13 15:56:30 +0000562 if (ret != 0)
Bill Pemberton99259152010-05-05 15:27:36 -0400563 goto Cleanup;
564
Hank Janssen3e7ee492009-07-13 16:02:34 -0700565 }
566 }
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700567 osd_WaitEventWait(msginfo->WaitEvent);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700568
Bill Pemberton454f18a2009-07-27 16:47:24 -0400569 /* At this point, we received the gpadl created msg */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700570 DPRINT_DBG(VMBUS, "Received GPADL created "
571 "(relid %d, status %d handle %x)",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700572 channel->OfferMsg.ChildRelId,
573 msginfo->Response.GpadlCreated.CreationStatus,
574 gpadlmsg->Gpadl);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700575
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700576 *gpadl_handle = gpadlmsg->Gpadl;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700577
578Cleanup:
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700579 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700580 list_del(&msginfo->MsgListEntry);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700581 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700582
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700583 kfree(msginfo->WaitEvent);
584 kfree(msginfo);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700585 return ret;
586}
587
Hank Janssen3e189512010-03-04 22:11:00 +0000588/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700589 * VmbusChannelTeardownGpadl -Teardown the specified GPADL handle
590 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700591int VmbusChannelTeardownGpadl(struct vmbus_channel *channel, u32 gpadl_handle)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700592{
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700593 struct vmbus_channel_gpadl_teardown *msg;
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -0700594 struct vmbus_channel_msginfo *info;
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700595 unsigned long flags;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700596 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700597
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700598 /* ASSERT(gpadl_handle != 0); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700599
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700600 info = kmalloc(sizeof(*info) +
601 sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400602 if (!info)
603 return -ENOMEM;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700604
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700605 info->WaitEvent = osd_WaitEventCreate();
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400606 if (!info->WaitEvent) {
607 kfree(info);
608 return -ENOMEM;
609 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700610
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700611 msg = (struct vmbus_channel_gpadl_teardown *)info->Msg;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700612
613 msg->Header.MessageType = ChannelMessageGpadlTeardown;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700614 msg->ChildRelId = channel->OfferMsg.ChildRelId;
615 msg->Gpadl = gpadl_handle;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700616
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700617 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Bill Pemberton53af5452009-09-11 21:46:44 -0400618 list_add_tail(&info->MsgListEntry,
619 &gVmbusConnection.ChannelMsgList);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700620 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700621
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700622 ret = VmbusPostMessage(msg,
623 sizeof(struct vmbus_channel_gpadl_teardown));
624 if (ret != 0) {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400625 /* TODO: */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700626 /* something... */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700627 }
628
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700629 osd_WaitEventWait(info->WaitEvent);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700630
Bill Pemberton454f18a2009-07-27 16:47:24 -0400631 /* Received a torndown response */
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700632 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Bill Pemberton53af5452009-09-11 21:46:44 -0400633 list_del(&info->MsgListEntry);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700634 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700635
Bill Pemberton420beac2009-07-29 17:00:10 -0400636 kfree(info->WaitEvent);
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700637 kfree(info);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700638 return ret;
639}
640
Hank Janssen3e189512010-03-04 22:11:00 +0000641/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700642 * VmbusChannelClose - Close the specified channel
643 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700644void VmbusChannelClose(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700645{
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700646 struct vmbus_channel_close_channel *msg;
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -0700647 struct vmbus_channel_msginfo *info;
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -0700648 unsigned long flags;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700649 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700650
Bill Pemberton454f18a2009-07-27 16:47:24 -0400651 /* Stop callback and cancel the timer asap */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700652 channel->OnChannelCallback = NULL;
653 del_timer_sync(&channel->poll_timer);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700654
Bill Pemberton454f18a2009-07-27 16:47:24 -0400655 /* Send a closing message */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700656 info = kmalloc(sizeof(*info) +
657 sizeof(struct vmbus_channel_close_channel), GFP_KERNEL);
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400658 /* FIXME: can't do anything other than return here because the
659 * function is void */
660 if (!info)
661 return;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700662
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700663 /* info->waitEvent = osd_WaitEventCreate(); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700664
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700665 msg = (struct vmbus_channel_close_channel *)info->Msg;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700666 msg->Header.MessageType = ChannelMessageCloseChannel;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700667 msg->ChildRelId = channel->OfferMsg.ChildRelId;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700668
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700669 ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_close_channel));
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700670 if (ret != 0) {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400671 /* TODO: */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700672 /* something... */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700673 }
674
Bill Pemberton454f18a2009-07-27 16:47:24 -0400675 /* Tear down the gpadl for the channel's ring buffer */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700676 if (channel->RingBufferGpadlHandle)
677 VmbusChannelTeardownGpadl(channel,
678 channel->RingBufferGpadlHandle);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700679
Bill Pemberton454f18a2009-07-27 16:47:24 -0400680 /* TODO: Send a msg to release the childRelId */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700681
Bill Pemberton454f18a2009-07-27 16:47:24 -0400682 /* Cleanup the ring buffers for this channel */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700683 RingBufferCleanup(&channel->Outbound);
684 RingBufferCleanup(&channel->Inbound);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700685
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700686 osd_PageFree(channel->RingBufferPages, channel->RingBufferPageCount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700687
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700688 kfree(info);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700689
Bill Pemberton454f18a2009-07-27 16:47:24 -0400690 /*
691 * If we are closing the channel during an error path in
692 * opening the channel, don't free the channel since the
693 * caller will free the channel
694 */
695
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700696 if (channel->State == CHANNEL_OPEN_STATE) {
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -0700697 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700698 list_del(&channel->ListEntry);
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -0700699 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700700
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700701 FreeVmbusChannel(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700702 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700703}
704
Hank Janssenc88c4e42010-05-04 15:55:05 -0700705/**
706 * VmbusChannelSendPacket() - Send the specified buffer on the given channel
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700707 * @channel: Pointer to vmbus_channel structure.
708 * @buffer: Pointer to the buffer you want to receive the data into.
709 * @bufferlen: Maximum size of what the the buffer will hold
710 * @requestid: Identifier of the request
711 * @type: Type of packet that is being send e.g. negotiate, time
Hank Janssenc88c4e42010-05-04 15:55:05 -0700712 * packet etc.
713 *
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700714 * Sends data in @buffer directly to hyper-v via the vmbus
Hank Janssenc88c4e42010-05-04 15:55:05 -0700715 * This will send the data unparsed to hyper-v.
716 *
717 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700718 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700719int VmbusChannelSendPacket(struct vmbus_channel *channel, const void *buffer,
720 u32 bufferlen, u64 requestid,
721 enum vmbus_packet_type type, u32 flags)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700722{
Greg Kroah-Hartman8dc0a062009-08-27 16:02:36 -0700723 struct vmpacket_descriptor desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700724 u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
725 u32 packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64));
726 struct scatterlist bufferlist[3];
727 u64 aligned_data = 0;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700728 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700729
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700730 DPRINT_DBG(VMBUS, "channel %p buffer %p len %d",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700731 channel, buffer, bufferlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700732
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700733 DumpVmbusChannel(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700734
Bill Pemberton0ace2472010-05-05 15:27:40 -0400735 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700736
Bill Pemberton454f18a2009-07-27 16:47:24 -0400737 /* Setup the descriptor */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700738 desc.Type = type; /* VmbusPacketTypeDataInBand; */
739 desc.Flags = flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700740 /* in 8-bytes granularity */
741 desc.DataOffset8 = sizeof(struct vmpacket_descriptor) >> 3;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700742 desc.Length8 = (u16)(packetlen_aligned >> 3);
743 desc.TransactionId = requestid;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700744
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700745 sg_init_table(bufferlist, 3);
746 sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
747 sg_set_buf(&bufferlist[1], buffer, bufferlen);
748 sg_set_buf(&bufferlist[2], &aligned_data,
749 packetlen_aligned - packetlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700750
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700751 ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700752
Bill Pemberton454f18a2009-07-27 16:47:24 -0400753 /* TODO: We should determine if this is optional */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700754 if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
755 VmbusChannelSetEvent(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700756
Hank Janssen3e7ee492009-07-13 16:02:34 -0700757 return ret;
758}
Hank Janssenc88c4e42010-05-04 15:55:05 -0700759EXPORT_SYMBOL(VmbusChannelSendPacket);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700760
Hank Janssen3e189512010-03-04 22:11:00 +0000761/*
762 * VmbusChannelSendPacketPageBuffer - Send a range of single-page buffer
763 * packets using a GPADL Direct packet type.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700764 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700765int VmbusChannelSendPacketPageBuffer(struct vmbus_channel *channel,
766 struct hv_page_buffer pagebuffers[],
767 u32 pagecount, void *buffer, u32 bufferlen,
768 u64 requestid)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700769{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700770 int ret;
771 int i;
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000772 struct vmbus_channel_packet_page_buffer desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700773 u32 descsize;
774 u32 packetlen;
775 u32 packetlen_aligned;
776 struct scatterlist bufferlist[3];
777 u64 aligned_data = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700778
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700779 if (pagecount > MAX_PAGE_BUFFER_COUNT)
Bill Pemberton002b53e2010-05-05 15:27:39 -0400780 return -EINVAL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700781
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700782 DumpVmbusChannel(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700783
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700784 /*
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000785 * Adjust the size down since vmbus_channel_packet_page_buffer is the
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700786 * largest size we support
787 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700788 descsize = sizeof(struct vmbus_channel_packet_page_buffer) -
789 ((MAX_PAGE_BUFFER_COUNT - pagecount) *
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700790 sizeof(struct hv_page_buffer));
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700791 packetlen = descsize + bufferlen;
792 packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700793
Bill Pemberton0ace2472010-05-05 15:27:40 -0400794 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700795
Bill Pemberton454f18a2009-07-27 16:47:24 -0400796 /* Setup the descriptor */
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000797 desc.type = VmbusPacketTypeDataUsingGpaDirect;
798 desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700799 desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
800 desc.length8 = (u16)(packetlen_aligned >> 3);
801 desc.transactionid = requestid;
802 desc.rangecount = pagecount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700803
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700804 for (i = 0; i < pagecount; i++) {
805 desc.range[i].Length = pagebuffers[i].Length;
806 desc.range[i].Offset = pagebuffers[i].Offset;
807 desc.range[i].Pfn = pagebuffers[i].Pfn;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700808 }
809
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700810 sg_init_table(bufferlist, 3);
811 sg_set_buf(&bufferlist[0], &desc, descsize);
812 sg_set_buf(&bufferlist[1], buffer, bufferlen);
813 sg_set_buf(&bufferlist[2], &aligned_data,
814 packetlen_aligned - packetlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700815
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700816 ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700817
Bill Pemberton454f18a2009-07-27 16:47:24 -0400818 /* TODO: We should determine if this is optional */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700819 if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
820 VmbusChannelSetEvent(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700821
Hank Janssen3e7ee492009-07-13 16:02:34 -0700822 return ret;
823}
824
Hank Janssen3e189512010-03-04 22:11:00 +0000825/*
826 * VmbusChannelSendPacketMultiPageBuffer - Send a multi-page buffer packet
827 * using a GPADL Direct packet type.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700828 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700829int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel *channel,
830 struct hv_multipage_buffer *multi_pagebuffer,
831 void *buffer, u32 bufferlen, u64 requestid)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700832{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700833 int ret;
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000834 struct vmbus_channel_packet_multipage_buffer desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700835 u32 descsize;
836 u32 packetlen;
837 u32 packetlen_aligned;
838 struct scatterlist bufferlist[3];
839 u64 aligned_data = 0;
840 u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->Offset,
841 multi_pagebuffer->Length);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700842
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700843 DumpVmbusChannel(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700844
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700845 DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700846 multi_pagebuffer->Offset,
847 multi_pagebuffer->Length, pfncount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700848
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700849 if ((pfncount < 0) || (pfncount > MAX_MULTIPAGE_BUFFER_COUNT))
Bill Pemberton002b53e2010-05-05 15:27:39 -0400850 return -EINVAL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700851
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700852 /*
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000853 * Adjust the size down since vmbus_channel_packet_multipage_buffer is
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700854 * the largest size we support
855 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700856 descsize = sizeof(struct vmbus_channel_packet_multipage_buffer) -
857 ((MAX_MULTIPAGE_BUFFER_COUNT - pfncount) *
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700858 sizeof(u64));
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700859 packetlen = descsize + bufferlen;
860 packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700861
Bill Pemberton0ace2472010-05-05 15:27:40 -0400862 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700863
Bill Pemberton454f18a2009-07-27 16:47:24 -0400864 /* Setup the descriptor */
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000865 desc.type = VmbusPacketTypeDataUsingGpaDirect;
866 desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700867 desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
868 desc.length8 = (u16)(packetlen_aligned >> 3);
869 desc.transactionid = requestid;
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000870 desc.rangecount = 1;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700871
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700872 desc.range.Length = multi_pagebuffer->Length;
873 desc.range.Offset = multi_pagebuffer->Offset;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700874
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700875 memcpy(desc.range.PfnArray, multi_pagebuffer->PfnArray,
876 pfncount * sizeof(u64));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700877
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700878 sg_init_table(bufferlist, 3);
879 sg_set_buf(&bufferlist[0], &desc, descsize);
880 sg_set_buf(&bufferlist[1], buffer, bufferlen);
881 sg_set_buf(&bufferlist[2], &aligned_data,
882 packetlen_aligned - packetlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700883
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700884 ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700885
Bill Pemberton454f18a2009-07-27 16:47:24 -0400886 /* TODO: We should determine if this is optional */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700887 if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
888 VmbusChannelSetEvent(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700889
Hank Janssen3e7ee492009-07-13 16:02:34 -0700890 return ret;
891}
892
Hank Janssenc88c4e42010-05-04 15:55:05 -0700893
894/**
895 * VmbusChannelRecvPacket() - Retrieve the user packet on the specified channel
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700896 * @channel: Pointer to vmbus_channel structure.
897 * @buffer: Pointer to the buffer you want to receive the data into.
898 * @bufferlen: Maximum size of what the the buffer will hold
899 * @buffer_actual_len: The actual size of the data after it was received
900 * @requestid: Identifier of the request
Hank Janssenc88c4e42010-05-04 15:55:05 -0700901 *
902 * Receives directly from the hyper-v vmbus and puts the data it received
903 * into Buffer. This will receive the data unparsed from hyper-v.
904 *
905 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700906 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700907int VmbusChannelRecvPacket(struct vmbus_channel *channel, void *buffer,
908 u32 bufferlen, u32 *buffer_actual_len, u64 *requestid)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700909{
Greg Kroah-Hartman8dc0a062009-08-27 16:02:36 -0700910 struct vmpacket_descriptor desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700911 u32 packetlen;
912 u32 userlen;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700913 int ret;
Greg Kroah-Hartman54411c42009-07-15 14:48:32 -0700914 unsigned long flags;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700915
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700916 *buffer_actual_len = 0;
917 *requestid = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700918
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700919 spin_lock_irqsave(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700920
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700921 ret = RingBufferPeek(&channel->Inbound, &desc,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700922 sizeof(struct vmpacket_descriptor));
923 if (ret != 0) {
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700924 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700925
Bill Pemberton454f18a2009-07-27 16:47:24 -0400926 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700927 return 0;
928 }
929
Bill Pemberton454f18a2009-07-27 16:47:24 -0400930 /* VmbusChannelClearEvent(Channel); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700931
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700932 packetlen = desc.Length8 << 3;
933 userlen = packetlen - (desc.DataOffset8 << 3);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400934 /* ASSERT(userLen > 0); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700935
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700936 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
937 "flag %d tid %llx pktlen %d datalen %d> ",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700938 channel, channel->OfferMsg.ChildRelId, desc.Type,
939 desc.Flags, desc.TransactionId, packetlen, userlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700940
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700941 *buffer_actual_len = userlen;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700942
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700943 if (userlen > bufferlen) {
944 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700945
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700946 DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700947 bufferlen, userlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700948 return -1;
949 }
950
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700951 *requestid = desc.TransactionId;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700952
Bill Pemberton454f18a2009-07-27 16:47:24 -0400953 /* Copy over the packet to the user buffer */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700954 ret = RingBufferRead(&channel->Inbound, buffer, userlen,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700955 (desc.DataOffset8 << 3));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700956
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700957 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700958
Hank Janssen3e7ee492009-07-13 16:02:34 -0700959 return 0;
960}
Hank Janssenc88c4e42010-05-04 15:55:05 -0700961EXPORT_SYMBOL(VmbusChannelRecvPacket);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700962
Hank Janssen3e189512010-03-04 22:11:00 +0000963/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700964 * VmbusChannelRecvPacketRaw - Retrieve the raw packet on the specified channel
965 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700966int VmbusChannelRecvPacketRaw(struct vmbus_channel *channel, void *buffer,
967 u32 bufferlen, u32 *buffer_actual_len,
968 u64 *requestid)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700969{
Greg Kroah-Hartman8dc0a062009-08-27 16:02:36 -0700970 struct vmpacket_descriptor desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700971 u32 packetlen;
972 u32 userlen;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700973 int ret;
Greg Kroah-Hartman54411c42009-07-15 14:48:32 -0700974 unsigned long flags;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700975
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700976 *buffer_actual_len = 0;
977 *requestid = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700978
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700979 spin_lock_irqsave(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700980
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700981 ret = RingBufferPeek(&channel->Inbound, &desc,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700982 sizeof(struct vmpacket_descriptor));
983 if (ret != 0) {
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700984 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700985
Bill Pemberton454f18a2009-07-27 16:47:24 -0400986 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700987 return 0;
988 }
989
Bill Pemberton454f18a2009-07-27 16:47:24 -0400990 /* VmbusChannelClearEvent(Channel); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700991
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700992 packetlen = desc.Length8 << 3;
993 userlen = packetlen - (desc.DataOffset8 << 3);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700994
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700995 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
996 "flag %d tid %llx pktlen %d datalen %d> ",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700997 channel, channel->OfferMsg.ChildRelId, desc.Type,
998 desc.Flags, desc.TransactionId, packetlen, userlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700999
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001000 *buffer_actual_len = packetlen;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001001
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001002 if (packetlen > bufferlen) {
1003 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001004
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -07001005 DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but "
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001006 "got space for only %d bytes", packetlen, bufferlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001007 return -2;
1008 }
1009
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001010 *requestid = desc.TransactionId;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001011
Bill Pemberton454f18a2009-07-27 16:47:24 -04001012 /* Copy over the entire packet to the user buffer */
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001013 ret = RingBufferRead(&channel->Inbound, buffer, packetlen, 0);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001014
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001015 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001016 return 0;
1017}
1018
Hank Janssen3e189512010-03-04 22:11:00 +00001019/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -07001020 * VmbusChannelOnChannelEvent - Channel event callback
1021 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001022void VmbusChannelOnChannelEvent(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001023{
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001024 DumpVmbusChannel(channel);
Bill Pemberton0ace2472010-05-05 15:27:40 -04001025 /* ASSERT(Channel->OnChannelCallback); */
Haiyang Zhang5996b3d2009-11-20 16:29:17 +00001026
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001027 channel->OnChannelCallback(channel->ChannelCallbackContext);
Haiyang Zhang5996b3d2009-11-20 16:29:17 +00001028
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001029 mod_timer(&channel->poll_timer, jiffies + usecs_to_jiffies(100));
Hank Janssen3e7ee492009-07-13 16:02:34 -07001030}
1031
Hank Janssen3e189512010-03-04 22:11:00 +00001032/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -07001033 * VmbusChannelOnTimer - Timer event callback
1034 */
Greg Kroah-Hartman46a05252009-08-17 17:21:31 -07001035void VmbusChannelOnTimer(unsigned long data)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001036{
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -07001037 struct vmbus_channel *channel = (struct vmbus_channel *)data;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001038
Chris Nicholson0fa37b12010-02-20 20:36:23 +00001039 if (channel->OnChannelCallback)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001040 channel->OnChannelCallback(channel->ChannelCallbackContext);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001041}
1042
Hank Janssen3e189512010-03-04 22:11:00 +00001043/*
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -07001044 * DumpVmbusChannel - Dump vmbus channel info to the console
1045 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001046static void DumpVmbusChannel(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001047{
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001048 DPRINT_DBG(VMBUS, "Channel (%d)", channel->OfferMsg.ChildRelId);
1049 DumpRingInfo(&channel->Outbound, "Outbound ");
1050 DumpRingInfo(&channel->Inbound, "Inbound ");
Hank Janssen3e7ee492009-07-13 16:02:34 -07001051}