9p: Optimize TCREATE by eliminating a redundant fid clone.
[pandora-kernel.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_ENTER(VMBUS);
270
271         DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
272         destroy_workqueue(channel->ControlWQ);
273         DPRINT_DBG(VMBUS, "channel released (%p)", channel);
274
275         kfree(channel);
276
277         DPRINT_EXIT(VMBUS);
278 }
279
280 /*
281  * FreeVmbusChannel - Release the resources used by the vmbus channel object
282  */
283 void FreeVmbusChannel(struct vmbus_channel *Channel)
284 {
285         del_timer_sync(&Channel->poll_timer);
286
287         /*
288          * We have to release the channel's workqueue/thread in the vmbus's
289          * workqueue/thread context
290          * ie we can't destroy ourselves.
291          */
292         osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
293                               Channel);
294 }
295
296 /*
297  * VmbusChannelProcessOffer - Process the offer by creating a channel/device
298  * associated with this offer
299  */
300 static void VmbusChannelProcessOffer(void *context)
301 {
302         struct vmbus_channel *newChannel = context;
303         struct vmbus_channel *channel;
304         bool fNew = true;
305         int ret;
306         int cnt;
307         unsigned long flags;
308
309         DPRINT_ENTER(VMBUS);
310
311         /* Make sure this is a new offer */
312         spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
313
314         list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
315                 if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
316                             &newChannel->OfferMsg.Offer.InterfaceType,
317                             sizeof(struct hv_guid)) &&
318                     !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
319                             &newChannel->OfferMsg.Offer.InterfaceInstance,
320                             sizeof(struct hv_guid))) {
321                         fNew = false;
322                         break;
323                 }
324         }
325
326         if (fNew)
327                 list_add_tail(&newChannel->ListEntry,
328                               &gVmbusConnection.ChannelList);
329
330         spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
331
332         if (!fNew) {
333                 DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
334                            newChannel->OfferMsg.ChildRelId);
335                 FreeVmbusChannel(newChannel);
336                 DPRINT_EXIT(VMBUS);
337                 return;
338         }
339
340         /*
341          * Start the process of binding this offer to the driver
342          * We need to set the DeviceObject field before calling
343          * VmbusChildDeviceAdd()
344          */
345         newChannel->DeviceObject = VmbusChildDeviceCreate(
346                 &newChannel->OfferMsg.Offer.InterfaceType,
347                 &newChannel->OfferMsg.Offer.InterfaceInstance,
348                 newChannel);
349
350         DPRINT_DBG(VMBUS, "child device object allocated - %p",
351                    newChannel->DeviceObject);
352
353         /*
354          * Add the new device to the bus. This will kick off device-driver
355          * binding which eventually invokes the device driver's AddDevice()
356          * method.
357          */
358         ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
359         if (ret != 0) {
360                 DPRINT_ERR(VMBUS,
361                            "unable to add child device object (relid %d)",
362                            newChannel->OfferMsg.ChildRelId);
363
364                 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
365                 list_del(&newChannel->ListEntry);
366                 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
367
368                 FreeVmbusChannel(newChannel);
369         } else {
370                 /*
371                  * This state is used to indicate a successful open
372                  * so that when we do close the channel normally, we
373                  * can cleanup properly
374                  */
375                 newChannel->State = CHANNEL_OPEN_STATE;
376                 cnt = 0;
377
378                 while (cnt != MAX_MSG_TYPES) {
379                         if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType,
380                                    &hv_cb_utils[cnt].data,
381                                    sizeof(struct hv_guid)) == 0) {
382                                 DPRINT_INFO(VMBUS, "%s",
383                                             hv_cb_utils[cnt].log_msg);
384
385                                 if (VmbusChannelOpen(newChannel, 2 * PAGE_SIZE,
386                                                     2 * PAGE_SIZE, NULL, 0,
387                                                     hv_cb_utils[cnt].callback,
388                                                     newChannel) == 0)
389                                         hv_cb_utils[cnt].channel = newChannel;
390                         }
391                         cnt++;
392                 }
393         }
394         DPRINT_EXIT(VMBUS);
395 }
396
397 /*
398  * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
399  */
400 static void VmbusChannelProcessRescindOffer(void *context)
401 {
402         struct vmbus_channel *channel = context;
403
404         DPRINT_ENTER(VMBUS);
405         VmbusChildDeviceRemove(channel->DeviceObject);
406         DPRINT_EXIT(VMBUS);
407 }
408
409 /*
410  * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
411  *
412  * We ignore all offers except network and storage offers. For each network and
413  * storage offers, we create a channel object and queue a work item to the
414  * channel object to process the offer synchronously
415  */
416 static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
417 {
418         struct vmbus_channel_offer_channel *offer;
419         struct vmbus_channel *newChannel;
420         struct hv_guid *guidType;
421         struct hv_guid *guidInstance;
422         int i;
423         int fSupported = 0;
424
425         DPRINT_ENTER(VMBUS);
426
427         offer = (struct vmbus_channel_offer_channel *)hdr;
428         for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
429                 if (memcmp(&offer->Offer.InterfaceType,
430                     &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
431                         fSupported = 1;
432                         break;
433                 }
434         }
435
436         if (!fSupported) {
437                 DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
438                            "child relid %d", offer->ChildRelId);
439                 DPRINT_EXIT(VMBUS);
440                 return;
441         }
442
443         guidType = &offer->Offer.InterfaceType;
444         guidInstance = &offer->Offer.InterfaceInstance;
445
446         DPRINT_INFO(VMBUS, "Channel offer notification - "
447                     "child relid %d monitor id %d allocated %d, "
448                     "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
449                     "%02x%02x%02x%02x%02x%02x%02x%02x} "
450                     "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
451                     "%02x%02x%02x%02x%02x%02x%02x%02x}",
452                     offer->ChildRelId, offer->MonitorId,
453                     offer->MonitorAllocated,
454                     guidType->data[3], guidType->data[2],
455                     guidType->data[1], guidType->data[0],
456                     guidType->data[5], guidType->data[4],
457                     guidType->data[7], guidType->data[6],
458                     guidType->data[8], guidType->data[9],
459                     guidType->data[10], guidType->data[11],
460                     guidType->data[12], guidType->data[13],
461                     guidType->data[14], guidType->data[15],
462                     guidInstance->data[3], guidInstance->data[2],
463                     guidInstance->data[1], guidInstance->data[0],
464                     guidInstance->data[5], guidInstance->data[4],
465                     guidInstance->data[7], guidInstance->data[6],
466                     guidInstance->data[8], guidInstance->data[9],
467                     guidInstance->data[10], guidInstance->data[11],
468                     guidInstance->data[12], guidInstance->data[13],
469                     guidInstance->data[14], guidInstance->data[15]);
470
471         /* Allocate the channel object and save this offer. */
472         newChannel = AllocVmbusChannel();
473         if (!newChannel) {
474                 DPRINT_ERR(VMBUS, "unable to allocate channel object");
475                 return;
476         }
477
478         DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
479
480         memcpy(&newChannel->OfferMsg, offer,
481                sizeof(struct vmbus_channel_offer_channel));
482         newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
483         newChannel->MonitorBit = (u8)offer->MonitorId % 32;
484
485         /* TODO: Make sure the offer comes from our parent partition */
486         osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
487                               newChannel);
488
489         DPRINT_EXIT(VMBUS);
490 }
491
492 /*
493  * VmbusChannelOnOfferRescind - Rescind offer handler.
494  *
495  * We queue a work item to process this offer synchronously
496  */
497 static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
498 {
499         struct vmbus_channel_rescind_offer *rescind;
500         struct vmbus_channel *channel;
501
502         DPRINT_ENTER(VMBUS);
503
504         rescind = (struct vmbus_channel_rescind_offer *)hdr;
505         channel = GetChannelFromRelId(rescind->ChildRelId);
506         if (channel == NULL) {
507                 DPRINT_DBG(VMBUS, "channel not found for relId %d",
508                            rescind->ChildRelId);
509                 return;
510         }
511
512         osd_schedule_callback(channel->ControlWQ,
513                               VmbusChannelProcessRescindOffer,
514                               channel);
515
516         DPRINT_EXIT(VMBUS);
517 }
518
519 /*
520  * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
521  *
522  * Nothing to do here.
523  */
524 static void VmbusChannelOnOffersDelivered(
525                         struct vmbus_channel_message_header *hdr)
526 {
527         DPRINT_ENTER(VMBUS);
528         DPRINT_EXIT(VMBUS);
529 }
530
531 /*
532  * VmbusChannelOnOpenResult - Open result handler.
533  *
534  * This is invoked when we received a response to our channel open request.
535  * Find the matching request, copy the response and signal the requesting
536  * thread.
537  */
538 static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
539 {
540         struct vmbus_channel_open_result *result;
541         struct list_head *curr;
542         struct vmbus_channel_msginfo *msgInfo;
543         struct vmbus_channel_message_header *requestHeader;
544         struct vmbus_channel_open_channel *openMsg;
545         unsigned long flags;
546
547         DPRINT_ENTER(VMBUS);
548
549         result = (struct vmbus_channel_open_result *)hdr;
550         DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
551
552         /*
553          * Find the open msg, copy the result and signal/unblock the wait event
554          */
555         spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
556
557         list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
558 /* FIXME: this should probably use list_entry() instead */
559                 msgInfo = (struct vmbus_channel_msginfo *)curr;
560                 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
561
562                 if (requestHeader->MessageType == ChannelMessageOpenChannel) {
563                         openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
564                         if (openMsg->ChildRelId == result->ChildRelId &&
565                             openMsg->OpenId == result->OpenId) {
566                                 memcpy(&msgInfo->Response.OpenResult,
567                                        result,
568                                        sizeof(struct vmbus_channel_open_result));
569                                 osd_WaitEventSet(msgInfo->WaitEvent);
570                                 break;
571                         }
572                 }
573         }
574         spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
575
576         DPRINT_EXIT(VMBUS);
577 }
578
579 /*
580  * VmbusChannelOnGpadlCreated - GPADL created handler.
581  *
582  * This is invoked when we received a response to our gpadl create request.
583  * Find the matching request, copy the response and signal the requesting
584  * thread.
585  */
586 static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
587 {
588         struct vmbus_channel_gpadl_created *gpadlCreated;
589         struct list_head *curr;
590         struct vmbus_channel_msginfo *msgInfo;
591         struct vmbus_channel_message_header *requestHeader;
592         struct vmbus_channel_gpadl_header *gpadlHeader;
593         unsigned long flags;
594
595         DPRINT_ENTER(VMBUS);
596
597         gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
598         DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
599                    gpadlCreated->CreationStatus);
600
601         /*
602          * Find the establish msg, copy the result and signal/unblock the wait
603          * event
604          */
605         spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
606
607         list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
608 /* FIXME: this should probably use list_entry() instead */
609                 msgInfo = (struct vmbus_channel_msginfo *)curr;
610                 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
611
612                 if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
613                         gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
614
615                         if ((gpadlCreated->ChildRelId ==
616                              gpadlHeader->ChildRelId) &&
617                             (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
618                                 memcpy(&msgInfo->Response.GpadlCreated,
619                                        gpadlCreated,
620                                        sizeof(struct vmbus_channel_gpadl_created));
621                                 osd_WaitEventSet(msgInfo->WaitEvent);
622                                 break;
623                         }
624                 }
625         }
626         spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
627
628         DPRINT_EXIT(VMBUS);
629 }
630
631 /*
632  * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
633  *
634  * This is invoked when we received a response to our gpadl teardown request.
635  * Find the matching request, copy the response and signal the requesting
636  * thread.
637  */
638 static void VmbusChannelOnGpadlTorndown(
639                         struct vmbus_channel_message_header *hdr)
640 {
641         struct vmbus_channel_gpadl_torndown *gpadlTorndown;
642         struct list_head *curr;
643         struct vmbus_channel_msginfo *msgInfo;
644         struct vmbus_channel_message_header *requestHeader;
645         struct vmbus_channel_gpadl_teardown *gpadlTeardown;
646         unsigned long flags;
647
648         DPRINT_ENTER(VMBUS);
649
650         gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
651
652         /*
653          * Find the open msg, copy the result and signal/unblock the wait event
654          */
655         spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
656
657         list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
658 /* FIXME: this should probably use list_entry() instead */
659                 msgInfo = (struct vmbus_channel_msginfo *)curr;
660                 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
661
662                 if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
663                         gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
664
665                         if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
666                                 memcpy(&msgInfo->Response.GpadlTorndown,
667                                        gpadlTorndown,
668                                        sizeof(struct vmbus_channel_gpadl_torndown));
669                                 osd_WaitEventSet(msgInfo->WaitEvent);
670                                 break;
671                         }
672                 }
673         }
674         spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
675
676         DPRINT_EXIT(VMBUS);
677 }
678
679 /*
680  * VmbusChannelOnVersionResponse - Version response handler
681  *
682  * This is invoked when we received a response to our initiate contact request.
683  * Find the matching request, copy the response and signal the requesting
684  * thread.
685  */
686 static void VmbusChannelOnVersionResponse(
687                 struct vmbus_channel_message_header *hdr)
688 {
689         struct list_head *curr;
690         struct vmbus_channel_msginfo *msgInfo;
691         struct vmbus_channel_message_header *requestHeader;
692         struct vmbus_channel_initiate_contact *initiate;
693         struct vmbus_channel_version_response *versionResponse;
694         unsigned long flags;
695
696         DPRINT_ENTER(VMBUS);
697
698         versionResponse = (struct vmbus_channel_version_response *)hdr;
699         spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
700
701         list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
702 /* FIXME: this should probably use list_entry() instead */
703                 msgInfo = (struct vmbus_channel_msginfo *)curr;
704                 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
705
706                 if (requestHeader->MessageType ==
707                     ChannelMessageInitiateContact) {
708                         initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
709                         memcpy(&msgInfo->Response.VersionResponse,
710                               versionResponse,
711                               sizeof(struct vmbus_channel_version_response));
712                         osd_WaitEventSet(msgInfo->WaitEvent);
713                 }
714         }
715         spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
716
717         DPRINT_EXIT(VMBUS);
718 }
719
720 /* Channel message dispatch table */
721 static struct vmbus_channel_message_table_entry
722         gChannelMessageTable[ChannelMessageCount] = {
723         {ChannelMessageInvalid,                 NULL},
724         {ChannelMessageOfferChannel,            VmbusChannelOnOffer},
725         {ChannelMessageRescindChannelOffer,     VmbusChannelOnOfferRescind},
726         {ChannelMessageRequestOffers,           NULL},
727         {ChannelMessageAllOffersDelivered,      VmbusChannelOnOffersDelivered},
728         {ChannelMessageOpenChannel,             NULL},
729         {ChannelMessageOpenChannelResult,       VmbusChannelOnOpenResult},
730         {ChannelMessageCloseChannel,            NULL},
731         {ChannelMessageGpadlHeader,             NULL},
732         {ChannelMessageGpadlBody,               NULL},
733         {ChannelMessageGpadlCreated,            VmbusChannelOnGpadlCreated},
734         {ChannelMessageGpadlTeardown,           NULL},
735         {ChannelMessageGpadlTorndown,           VmbusChannelOnGpadlTorndown},
736         {ChannelMessageRelIdReleased,           NULL},
737         {ChannelMessageInitiateContact,         NULL},
738         {ChannelMessageVersionResponse,         VmbusChannelOnVersionResponse},
739         {ChannelMessageUnload,                  NULL},
740 };
741
742 /*
743  * VmbusOnChannelMessage - Handler for channel protocol messages.
744  *
745  * This is invoked in the vmbus worker thread context.
746  */
747 void VmbusOnChannelMessage(void *Context)
748 {
749         struct hv_message *msg = Context;
750         struct vmbus_channel_message_header *hdr;
751         int size;
752
753         DPRINT_ENTER(VMBUS);
754
755         hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
756         size = msg->Header.PayloadSize;
757
758         DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
759
760         if (hdr->MessageType >= ChannelMessageCount) {
761                 DPRINT_ERR(VMBUS,
762                            "Received invalid channel message type %d size %d",
763                            hdr->MessageType, size);
764                 print_hex_dump_bytes("", DUMP_PREFIX_NONE,
765                                      (unsigned char *)msg->u.Payload, size);
766                 kfree(msg);
767                 return;
768         }
769
770         if (gChannelMessageTable[hdr->MessageType].messageHandler)
771                 gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
772         else
773                 DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
774                            hdr->MessageType);
775
776         /* Free the msg that was allocated in VmbusOnMsgDPC() */
777         kfree(msg);
778         DPRINT_EXIT(VMBUS);
779 }
780
781 /*
782  * VmbusChannelRequestOffers - Send a request to get all our pending offers.
783  */
784 int VmbusChannelRequestOffers(void)
785 {
786         struct vmbus_channel_message_header *msg;
787         struct vmbus_channel_msginfo *msgInfo;
788         int ret;
789
790         DPRINT_ENTER(VMBUS);
791
792         msgInfo = kmalloc(sizeof(*msgInfo) +
793                           sizeof(struct vmbus_channel_message_header),
794                           GFP_KERNEL);
795         if (!msgInfo)
796                 return -ENOMEM;
797
798         msgInfo->WaitEvent = osd_WaitEventCreate();
799         if (!msgInfo->WaitEvent) {
800                 kfree(msgInfo);
801                 return -ENOMEM;
802         }
803
804         msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
805
806         msg->MessageType = ChannelMessageRequestOffers;
807
808         /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
809         INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
810                          &msgInfo->msgListEntry);
811         SpinlockRelease(gVmbusConnection.channelMsgLock);*/
812
813         ret = VmbusPostMessage(msg,
814                                sizeof(struct vmbus_channel_message_header));
815         if (ret != 0) {
816                 DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
817
818                 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
819                 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
820                 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
821
822                 goto Cleanup;
823         }
824         /* osd_WaitEventWait(msgInfo->waitEvent); */
825
826         /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
827         REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
828         SpinlockRelease(gVmbusConnection.channelMsgLock);*/
829
830
831 Cleanup:
832         if (msgInfo) {
833                 kfree(msgInfo->WaitEvent);
834                 kfree(msgInfo);
835         }
836
837         DPRINT_EXIT(VMBUS);
838         return ret;
839 }
840
841 /*
842  * VmbusChannelReleaseUnattachedChannels - Release channels that are
843  * unattached/unconnected ie (no drivers associated)
844  */
845 void VmbusChannelReleaseUnattachedChannels(void)
846 {
847         struct vmbus_channel *channel, *pos;
848         struct vmbus_channel *start = NULL;
849         unsigned long flags;
850
851         spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
852
853         list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
854                                  ListEntry) {
855                 if (channel == start)
856                         break;
857
858                 if (!channel->DeviceObject->Driver) {
859                         list_del(&channel->ListEntry);
860                         DPRINT_INFO(VMBUS,
861                                     "Releasing unattached device object %p",
862                                     channel->DeviceObject);
863
864                         VmbusChildDeviceRemove(channel->DeviceObject);
865                         FreeVmbusChannel(channel);
866                 } else {
867                         if (!start)
868                                 start = channel;
869                 }
870         }
871
872         spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
873 }
874
875 /* eof */