• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/hv/
1/*
2 * 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>
20 */
21#include <linux/kernel.h>
22#include <linux/mm.h>
23#include <linux/slab.h>
24#include <linux/list.h>
25#include <linux/module.h>
26#include <linux/completion.h>
27#include "osd.h"
28#include "logging.h"
29#include "vmbus_private.h"
30#include "utils.h"
31
32struct vmbus_channel_message_table_entry {
33	enum vmbus_channel_message_type messageType;
34	void (*messageHandler)(struct vmbus_channel_message_header *msg);
35};
36
37#define MAX_MSG_TYPES                    3
38#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 7
39
40static const struct hv_guid
41	gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
42	/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
43	/* Storage - SCSI */
44	{
45		.data  = {
46			0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
47			0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
48		}
49	},
50
51	/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
52	/* Network */
53	{
54		.data = {
55			0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
56			0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
57		}
58	},
59
60	/* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
61	/* Input */
62	{
63		.data = {
64			0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
65			0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
66		}
67	},
68
69	/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
70	/* IDE */
71	{
72		.data = {
73			0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
74			0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
75		}
76	},
77	/* 0E0B6031-5213-4934-818B-38D90CED39DB */
78	/* Shutdown */
79	{
80		.data = {
81			0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
82			0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
83		}
84	},
85	/* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
86	/* TimeSync */
87	{
88		.data = {
89			0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
90			0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
91		}
92	},
93	/* {57164f39-9115-4e78-ab55-382f3bd5422d} */
94	/* Heartbeat */
95	{
96		.data = {
97			0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
98			0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
99		}
100	},
101};
102
103
104/**
105 * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
106 * @icmsghdrp: Pointer to msg header structure
107 * @icmsg_negotiate: Pointer to negotiate message structure
108 * @buf: Raw buffer channel data
109 *
110 * @icmsghdrp is of type &struct icmsg_hdr.
111 * @negop is of type &struct icmsg_negotiate.
112 * Set up and fill in default negotiate response message. This response can
113 * come from both the vmbus driver and the hv_utils driver. The current api
114 * will respond properly to both Windows 2008 and Windows 2008-R2 operating
115 * systems.
116 *
117 * Mainly used by Hyper-V drivers.
118 */
119void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
120			     struct icmsg_negotiate *negop,
121			     u8 *buf)
122{
123	if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
124		icmsghdrp->icmsgsize = 0x10;
125
126		negop = (struct icmsg_negotiate *)&buf[
127			sizeof(struct vmbuspipe_hdr) +
128			sizeof(struct icmsg_hdr)];
129
130		if (negop->icframe_vercnt == 2 &&
131		   negop->icversion_data[1].major == 3) {
132			negop->icversion_data[0].major = 3;
133			negop->icversion_data[0].minor = 0;
134			negop->icversion_data[1].major = 3;
135			negop->icversion_data[1].minor = 0;
136		} else {
137			negop->icversion_data[0].major = 1;
138			negop->icversion_data[0].minor = 0;
139			negop->icversion_data[1].major = 1;
140			negop->icversion_data[1].minor = 0;
141		}
142
143		negop->icframe_vercnt = 1;
144		negop->icmsg_vercnt = 1;
145	}
146}
147EXPORT_SYMBOL(prep_negotiate_resp);
148
149/**
150 * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
151 * Hyper-V requests
152 * @context: Pointer to argument structure.
153 *
154 * Set up the default handler for non device driver specific requests
155 * from Hyper-V. This stub responds to the default negotiate messages
156 * that come in for every non IDE/SCSI/Network request.
157 * This behavior is normally overwritten in the hv_utils driver. That
158 * driver handles requests like gracefull shutdown, heartbeats etc.
159 *
160 * Mainly used by Hyper-V drivers.
161 */
162void chn_cb_negotiate(void *context)
163{
164	struct vmbus_channel *channel = context;
165	u8 *buf;
166	u32 buflen, recvlen;
167	u64 requestid;
168
169	struct icmsg_hdr *icmsghdrp;
170	struct icmsg_negotiate *negop = NULL;
171
172	buflen = PAGE_SIZE;
173	buf = kmalloc(buflen, GFP_ATOMIC);
174
175	VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);
176
177	if (recvlen > 0) {
178		icmsghdrp = (struct icmsg_hdr *)&buf[
179			sizeof(struct vmbuspipe_hdr)];
180
181		prep_negotiate_resp(icmsghdrp, negop, buf);
182
183		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
184			| ICMSGHDRFLAG_RESPONSE;
185
186		VmbusChannelSendPacket(channel, buf,
187				       recvlen, requestid,
188				       VmbusPacketTypeDataInBand, 0);
189	}
190
191	kfree(buf);
192}
193EXPORT_SYMBOL(chn_cb_negotiate);
194
195/*
196 * Function table used for message responses for non IDE/SCSI/Network type
197 * messages. (Such as KVP/Shutdown etc)
198 */
199struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
200	/* 0E0B6031-5213-4934-818B-38D90CED39DB */
201	/* Shutdown */
202	{
203		.msg_type = HV_SHUTDOWN_MSG,
204		.data = {
205			0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
206			0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
207		},
208		.callback = chn_cb_negotiate,
209		.log_msg = "Shutdown channel functionality initialized"
210	},
211
212	/* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
213	/* TimeSync */
214	{
215		.msg_type = HV_TIMESYNC_MSG,
216		.data = {
217			0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
218			0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
219		},
220		.callback = chn_cb_negotiate,
221		.log_msg = "Timesync channel functionality initialized"
222	},
223	/* {57164f39-9115-4e78-ab55-382f3bd5422d} */
224	/* Heartbeat */
225	{
226		.msg_type = HV_HEARTBEAT_MSG,
227		.data = {
228			0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
229			0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
230		},
231		.callback = chn_cb_negotiate,
232		.log_msg = "Heartbeat channel functionality initialized"
233	},
234};
235EXPORT_SYMBOL(hv_cb_utils);
236
237/*
238 * AllocVmbusChannel - Allocate and initialize a vmbus channel object
239 */
240struct vmbus_channel *AllocVmbusChannel(void)
241{
242	struct vmbus_channel *channel;
243
244	channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
245	if (!channel)
246		return NULL;
247
248	spin_lock_init(&channel->inbound_lock);
249
250	init_timer(&channel->poll_timer);
251	channel->poll_timer.data = (unsigned long)channel;
252	channel->poll_timer.function = VmbusChannelOnTimer;
253
254	channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
255	if (!channel->ControlWQ) {
256		kfree(channel);
257		return NULL;
258	}
259
260	return channel;
261}
262
263/*
264 * ReleaseVmbusChannel - Release the vmbus channel object itself
265 */
266static inline void ReleaseVmbusChannel(void *context)
267{
268	struct vmbus_channel *channel = context;
269
270	DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
271	destroy_workqueue(channel->ControlWQ);
272	DPRINT_DBG(VMBUS, "channel released (%p)", channel);
273
274	kfree(channel);
275}
276
277/*
278 * FreeVmbusChannel - Release the resources used by the vmbus channel object
279 */
280void FreeVmbusChannel(struct vmbus_channel *Channel)
281{
282	del_timer_sync(&Channel->poll_timer);
283
284	/*
285	 * We have to release the channel's workqueue/thread in the vmbus's
286	 * workqueue/thread context
287	 * ie we can't destroy ourselves.
288	 */
289	osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
290			      Channel);
291}
292
293
294DECLARE_COMPLETION(hv_channel_ready);
295
296/*
297 * Count initialized channels, and ensure all channels are ready when hv_vmbus
298 * module loading completes.
299 */
300static void count_hv_channel(void)
301{
302	static int counter;
303	unsigned long flags;
304
305	spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
306	if (++counter == MAX_MSG_TYPES)
307		complete(&hv_channel_ready);
308	spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
309}
310
311
312/*
313 * VmbusChannelProcessOffer - Process the offer by creating a channel/device
314 * associated with this offer
315 */
316static void VmbusChannelProcessOffer(void *context)
317{
318	struct vmbus_channel *newChannel = context;
319	struct vmbus_channel *channel;
320	bool fNew = true;
321	int ret;
322	int cnt;
323	unsigned long flags;
324
325	/* Make sure this is a new offer */
326	spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
327
328	list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
329		if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
330			    &newChannel->OfferMsg.Offer.InterfaceType,
331			    sizeof(struct hv_guid)) &&
332		    !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
333			    &newChannel->OfferMsg.Offer.InterfaceInstance,
334			    sizeof(struct hv_guid))) {
335			fNew = false;
336			break;
337		}
338	}
339
340	if (fNew)
341		list_add_tail(&newChannel->ListEntry,
342			      &gVmbusConnection.ChannelList);
343
344	spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
345
346	if (!fNew) {
347		DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
348			   newChannel->OfferMsg.ChildRelId);
349		FreeVmbusChannel(newChannel);
350		return;
351	}
352
353	/*
354	 * Start the process of binding this offer to the driver
355	 * We need to set the DeviceObject field before calling
356	 * VmbusChildDeviceAdd()
357	 */
358	newChannel->DeviceObject = VmbusChildDeviceCreate(
359		&newChannel->OfferMsg.Offer.InterfaceType,
360		&newChannel->OfferMsg.Offer.InterfaceInstance,
361		newChannel);
362
363	DPRINT_DBG(VMBUS, "child device object allocated - %p",
364		   newChannel->DeviceObject);
365
366	/*
367	 * Add the new device to the bus. This will kick off device-driver
368	 * binding which eventually invokes the device driver's AddDevice()
369	 * method.
370	 */
371	ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
372	if (ret != 0) {
373		DPRINT_ERR(VMBUS,
374			   "unable to add child device object (relid %d)",
375			   newChannel->OfferMsg.ChildRelId);
376
377		spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
378		list_del(&newChannel->ListEntry);
379		spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
380
381		FreeVmbusChannel(newChannel);
382	} else {
383		/*
384		 * This state is used to indicate a successful open
385		 * so that when we do close the channel normally, we
386		 * can cleanup properly
387		 */
388		newChannel->State = CHANNEL_OPEN_STATE;
389
390		/* Open IC channels */
391		for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
392			if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType,
393				   &hv_cb_utils[cnt].data,
394				   sizeof(struct hv_guid)) == 0 &&
395				VmbusChannelOpen(newChannel, 2 * PAGE_SIZE,
396						 2 * PAGE_SIZE, NULL, 0,
397						 hv_cb_utils[cnt].callback,
398						 newChannel) == 0) {
399				hv_cb_utils[cnt].channel = newChannel;
400				DPRINT_INFO(VMBUS, "%s",
401						hv_cb_utils[cnt].log_msg);
402				count_hv_channel();
403			}
404		}
405	}
406}
407
408/*
409 * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
410 */
411static void VmbusChannelProcessRescindOffer(void *context)
412{
413	struct vmbus_channel *channel = context;
414
415	VmbusChildDeviceRemove(channel->DeviceObject);
416}
417
418/*
419 * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
420 *
421 * We ignore all offers except network and storage offers. For each network and
422 * storage offers, we create a channel object and queue a work item to the
423 * channel object to process the offer synchronously
424 */
425static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
426{
427	struct vmbus_channel_offer_channel *offer;
428	struct vmbus_channel *newChannel;
429	struct hv_guid *guidType;
430	struct hv_guid *guidInstance;
431	int i;
432	int fSupported = 0;
433
434	offer = (struct vmbus_channel_offer_channel *)hdr;
435	for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
436		if (memcmp(&offer->Offer.InterfaceType,
437		    &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
438			fSupported = 1;
439			break;
440		}
441	}
442
443	if (!fSupported) {
444		DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
445			   "child relid %d", offer->ChildRelId);
446		return;
447	}
448
449	guidType = &offer->Offer.InterfaceType;
450	guidInstance = &offer->Offer.InterfaceInstance;
451
452	DPRINT_INFO(VMBUS, "Channel offer notification - "
453		    "child relid %d monitor id %d allocated %d, "
454		    "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
455		    "%02x%02x%02x%02x%02x%02x%02x%02x} "
456		    "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
457		    "%02x%02x%02x%02x%02x%02x%02x%02x}",
458		    offer->ChildRelId, offer->MonitorId,
459		    offer->MonitorAllocated,
460		    guidType->data[3], guidType->data[2],
461		    guidType->data[1], guidType->data[0],
462		    guidType->data[5], guidType->data[4],
463		    guidType->data[7], guidType->data[6],
464		    guidType->data[8], guidType->data[9],
465		    guidType->data[10], guidType->data[11],
466		    guidType->data[12], guidType->data[13],
467		    guidType->data[14], guidType->data[15],
468		    guidInstance->data[3], guidInstance->data[2],
469		    guidInstance->data[1], guidInstance->data[0],
470		    guidInstance->data[5], guidInstance->data[4],
471		    guidInstance->data[7], guidInstance->data[6],
472		    guidInstance->data[8], guidInstance->data[9],
473		    guidInstance->data[10], guidInstance->data[11],
474		    guidInstance->data[12], guidInstance->data[13],
475		    guidInstance->data[14], guidInstance->data[15]);
476
477	/* Allocate the channel object and save this offer. */
478	newChannel = AllocVmbusChannel();
479	if (!newChannel) {
480		DPRINT_ERR(VMBUS, "unable to allocate channel object");
481		return;
482	}
483
484	DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
485
486	memcpy(&newChannel->OfferMsg, offer,
487	       sizeof(struct vmbus_channel_offer_channel));
488	newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
489	newChannel->MonitorBit = (u8)offer->MonitorId % 32;
490
491	/* TODO: Make sure the offer comes from our parent partition */
492	osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
493			      newChannel);
494}
495
496/*
497 * VmbusChannelOnOfferRescind - Rescind offer handler.
498 *
499 * We queue a work item to process this offer synchronously
500 */
501static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
502{
503	struct vmbus_channel_rescind_offer *rescind;
504	struct vmbus_channel *channel;
505
506	rescind = (struct vmbus_channel_rescind_offer *)hdr;
507	channel = GetChannelFromRelId(rescind->ChildRelId);
508	if (channel == NULL) {
509		DPRINT_DBG(VMBUS, "channel not found for relId %d",
510			   rescind->ChildRelId);
511		return;
512	}
513
514	osd_schedule_callback(channel->ControlWQ,
515			      VmbusChannelProcessRescindOffer,
516			      channel);
517}
518
519/*
520 * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
521 *
522 * Nothing to do here.
523 */
524static void VmbusChannelOnOffersDelivered(
525			struct vmbus_channel_message_header *hdr)
526{
527}
528
529/*
530 * VmbusChannelOnOpenResult - Open result handler.
531 *
532 * This is invoked when we received a response to our channel open request.
533 * Find the matching request, copy the response and signal the requesting
534 * thread.
535 */
536static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
537{
538	struct vmbus_channel_open_result *result;
539	struct list_head *curr;
540	struct vmbus_channel_msginfo *msgInfo;
541	struct vmbus_channel_message_header *requestHeader;
542	struct vmbus_channel_open_channel *openMsg;
543	unsigned long flags;
544
545	result = (struct vmbus_channel_open_result *)hdr;
546	DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
547
548	/*
549	 * Find the open msg, copy the result and signal/unblock the wait event
550	 */
551	spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
552
553	list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
554		msgInfo = (struct vmbus_channel_msginfo *)curr;
555		requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
556
557		if (requestHeader->MessageType == ChannelMessageOpenChannel) {
558			openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
559			if (openMsg->ChildRelId == result->ChildRelId &&
560			    openMsg->OpenId == result->OpenId) {
561				memcpy(&msgInfo->Response.OpenResult,
562				       result,
563				       sizeof(struct vmbus_channel_open_result));
564				osd_WaitEventSet(msgInfo->WaitEvent);
565				break;
566			}
567		}
568	}
569	spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
570}
571
572/*
573 * VmbusChannelOnGpadlCreated - GPADL created handler.
574 *
575 * This is invoked when we received a response to our gpadl create request.
576 * Find the matching request, copy the response and signal the requesting
577 * thread.
578 */
579static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
580{
581	struct vmbus_channel_gpadl_created *gpadlCreated;
582	struct list_head *curr;
583	struct vmbus_channel_msginfo *msgInfo;
584	struct vmbus_channel_message_header *requestHeader;
585	struct vmbus_channel_gpadl_header *gpadlHeader;
586	unsigned long flags;
587
588	gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
589	DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
590		   gpadlCreated->CreationStatus);
591
592	/*
593	 * Find the establish msg, copy the result and signal/unblock the wait
594	 * event
595	 */
596	spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
597
598	list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
599		msgInfo = (struct vmbus_channel_msginfo *)curr;
600		requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
601
602		if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
603			gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
604
605			if ((gpadlCreated->ChildRelId ==
606			     gpadlHeader->ChildRelId) &&
607			    (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
608				memcpy(&msgInfo->Response.GpadlCreated,
609				       gpadlCreated,
610				       sizeof(struct vmbus_channel_gpadl_created));
611				osd_WaitEventSet(msgInfo->WaitEvent);
612				break;
613			}
614		}
615	}
616	spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
617}
618
619/*
620 * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
621 *
622 * This is invoked when we received a response to our gpadl teardown request.
623 * Find the matching request, copy the response and signal the requesting
624 * thread.
625 */
626static void VmbusChannelOnGpadlTorndown(
627			struct vmbus_channel_message_header *hdr)
628{
629	struct vmbus_channel_gpadl_torndown *gpadlTorndown;
630	struct list_head *curr;
631	struct vmbus_channel_msginfo *msgInfo;
632	struct vmbus_channel_message_header *requestHeader;
633	struct vmbus_channel_gpadl_teardown *gpadlTeardown;
634	unsigned long flags;
635
636	gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
637
638	/*
639	 * Find the open msg, copy the result and signal/unblock the wait event
640	 */
641	spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
642
643	list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
644		msgInfo = (struct vmbus_channel_msginfo *)curr;
645		requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
646
647		if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
648			gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
649
650			if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
651				memcpy(&msgInfo->Response.GpadlTorndown,
652				       gpadlTorndown,
653				       sizeof(struct vmbus_channel_gpadl_torndown));
654				osd_WaitEventSet(msgInfo->WaitEvent);
655				break;
656			}
657		}
658	}
659	spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
660}
661
662/*
663 * VmbusChannelOnVersionResponse - Version response handler
664 *
665 * This is invoked when we received a response to our initiate contact request.
666 * Find the matching request, copy the response and signal the requesting
667 * thread.
668 */
669static void VmbusChannelOnVersionResponse(
670		struct vmbus_channel_message_header *hdr)
671{
672	struct list_head *curr;
673	struct vmbus_channel_msginfo *msgInfo;
674	struct vmbus_channel_message_header *requestHeader;
675	struct vmbus_channel_initiate_contact *initiate;
676	struct vmbus_channel_version_response *versionResponse;
677	unsigned long flags;
678
679	versionResponse = (struct vmbus_channel_version_response *)hdr;
680	spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
681
682	list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
683		msgInfo = (struct vmbus_channel_msginfo *)curr;
684		requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
685
686		if (requestHeader->MessageType ==
687		    ChannelMessageInitiateContact) {
688			initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
689			memcpy(&msgInfo->Response.VersionResponse,
690			      versionResponse,
691			      sizeof(struct vmbus_channel_version_response));
692			osd_WaitEventSet(msgInfo->WaitEvent);
693		}
694	}
695	spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
696}
697
698/* Channel message dispatch table */
699static struct vmbus_channel_message_table_entry
700	gChannelMessageTable[ChannelMessageCount] = {
701	{ChannelMessageInvalid,			NULL},
702	{ChannelMessageOfferChannel,		VmbusChannelOnOffer},
703	{ChannelMessageRescindChannelOffer,	VmbusChannelOnOfferRescind},
704	{ChannelMessageRequestOffers,		NULL},
705	{ChannelMessageAllOffersDelivered,	VmbusChannelOnOffersDelivered},
706	{ChannelMessageOpenChannel,		NULL},
707	{ChannelMessageOpenChannelResult,	VmbusChannelOnOpenResult},
708	{ChannelMessageCloseChannel,		NULL},
709	{ChannelMessageGpadlHeader,		NULL},
710	{ChannelMessageGpadlBody,		NULL},
711	{ChannelMessageGpadlCreated,		VmbusChannelOnGpadlCreated},
712	{ChannelMessageGpadlTeardown,		NULL},
713	{ChannelMessageGpadlTorndown,		VmbusChannelOnGpadlTorndown},
714	{ChannelMessageRelIdReleased,		NULL},
715	{ChannelMessageInitiateContact,		NULL},
716	{ChannelMessageVersionResponse,		VmbusChannelOnVersionResponse},
717	{ChannelMessageUnload,			NULL},
718};
719
720/*
721 * VmbusOnChannelMessage - Handler for channel protocol messages.
722 *
723 * This is invoked in the vmbus worker thread context.
724 */
725void VmbusOnChannelMessage(void *Context)
726{
727	struct hv_message *msg = Context;
728	struct vmbus_channel_message_header *hdr;
729	int size;
730
731	hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
732	size = msg->Header.PayloadSize;
733
734	DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
735
736	if (hdr->MessageType >= ChannelMessageCount) {
737		DPRINT_ERR(VMBUS,
738			   "Received invalid channel message type %d size %d",
739			   hdr->MessageType, size);
740		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
741				     (unsigned char *)msg->u.Payload, size);
742		kfree(msg);
743		return;
744	}
745
746	if (gChannelMessageTable[hdr->MessageType].messageHandler)
747		gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
748	else
749		DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
750			   hdr->MessageType);
751
752	/* Free the msg that was allocated in VmbusOnMsgDPC() */
753	kfree(msg);
754}
755
756/*
757 * VmbusChannelRequestOffers - Send a request to get all our pending offers.
758 */
759int VmbusChannelRequestOffers(void)
760{
761	struct vmbus_channel_message_header *msg;
762	struct vmbus_channel_msginfo *msgInfo;
763	int ret;
764
765	msgInfo = kmalloc(sizeof(*msgInfo) +
766			  sizeof(struct vmbus_channel_message_header),
767			  GFP_KERNEL);
768	if (!msgInfo)
769		return -ENOMEM;
770
771	msgInfo->WaitEvent = osd_WaitEventCreate();
772	if (!msgInfo->WaitEvent) {
773		kfree(msgInfo);
774		return -ENOMEM;
775	}
776
777	msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
778
779	msg->MessageType = ChannelMessageRequestOffers;
780
781	/*SpinlockAcquire(gVmbusConnection.channelMsgLock);
782	INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
783			 &msgInfo->msgListEntry);
784	SpinlockRelease(gVmbusConnection.channelMsgLock);*/
785
786	ret = VmbusPostMessage(msg,
787			       sizeof(struct vmbus_channel_message_header));
788	if (ret != 0) {
789		DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
790
791		/*SpinlockAcquire(gVmbusConnection.channelMsgLock);
792		REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
793		SpinlockRelease(gVmbusConnection.channelMsgLock);*/
794
795		goto Cleanup;
796	}
797	/* osd_WaitEventWait(msgInfo->waitEvent); */
798
799	/*SpinlockAcquire(gVmbusConnection.channelMsgLock);
800	REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
801	SpinlockRelease(gVmbusConnection.channelMsgLock);*/
802
803
804Cleanup:
805	if (msgInfo) {
806		kfree(msgInfo->WaitEvent);
807		kfree(msgInfo);
808	}
809
810	return ret;
811}
812
813/*
814 * VmbusChannelReleaseUnattachedChannels - Release channels that are
815 * unattached/unconnected ie (no drivers associated)
816 */
817void VmbusChannelReleaseUnattachedChannels(void)
818{
819	struct vmbus_channel *channel, *pos;
820	struct vmbus_channel *start = NULL;
821	unsigned long flags;
822
823	spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
824
825	list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
826				 ListEntry) {
827		if (channel == start)
828			break;
829
830		if (!channel->DeviceObject->Driver) {
831			list_del(&channel->ListEntry);
832			DPRINT_INFO(VMBUS,
833				    "Releasing unattached device object %p",
834				    channel->DeviceObject);
835
836			VmbusChildDeviceRemove(channel->DeviceObject);
837			FreeVmbusChannel(channel);
838		} else {
839			if (!start)
840				start = channel;
841		}
842	}
843
844	spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
845}
846
847/* eof */
848