OSDN Git Service

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