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