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