Merge branch 'omap-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind...
[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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
23 #include <linux/kernel.h>
24 #include <linux/sched.h>
25 #include <linux/wait.h>
26 #include <linux/mm.h>
27 #include <linux/slab.h>
28 #include <linux/list.h>
29 #include <linux/module.h>
30 #include <linux/completion.h>
31
32 #include "hyperv.h"
33 #include "hyperv_vmbus.h"
34
35 struct vmbus_channel_message_table_entry {
36         enum vmbus_channel_message_type message_type;
37         void (*message_handler)(struct vmbus_channel_message_header *msg);
38 };
39
40 #define MAX_MSG_TYPES                    4
41 #define MAX_NUM_DEVICE_CLASSES_SUPPORTED 8
42
43 static const struct hv_guid
44         supported_device_classes[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
45         /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
46         /* Storage - SCSI */
47         {
48                 .data  = {
49                         0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
50                         0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
51                 }
52         },
53
54         /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
55         /* Network */
56         {
57                 .data = {
58                         0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
59                         0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
60                 }
61         },
62
63         /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
64         /* Input */
65         {
66                 .data = {
67                         0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
68                         0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
69                 }
70         },
71
72         /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
73         /* IDE */
74         {
75                 .data = {
76                         0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
77                         0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
78                 }
79         },
80         /* 0E0B6031-5213-4934-818B-38D90CED39DB */
81         /* Shutdown */
82         {
83                 .data = {
84                         0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
85                         0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
86                 }
87         },
88         /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
89         /* TimeSync */
90         {
91                 .data = {
92                         0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
93                         0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
94                 }
95         },
96         /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
97         /* Heartbeat */
98         {
99                 .data = {
100                         0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
101                         0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
102                 }
103         },
104         /* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
105         /* KVP */
106         {
107                 .data = {
108                         0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
109                         0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3,  0xe6
110         }
111         },
112
113 };
114
115
116 /**
117  * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
118  * @icmsghdrp: Pointer to msg header structure
119  * @icmsg_negotiate: Pointer to negotiate message structure
120  * @buf: Raw buffer channel data
121  *
122  * @icmsghdrp is of type &struct icmsg_hdr.
123  * @negop is of type &struct icmsg_negotiate.
124  * Set up and fill in default negotiate response message. This response can
125  * come from both the vmbus driver and the hv_utils driver. The current api
126  * will respond properly to both Windows 2008 and Windows 2008-R2 operating
127  * systems.
128  *
129  * Mainly used by Hyper-V drivers.
130  */
131 void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
132                              struct icmsg_negotiate *negop,
133                              u8 *buf)
134 {
135         if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
136                 icmsghdrp->icmsgsize = 0x10;
137
138                 negop = (struct icmsg_negotiate *)&buf[
139                         sizeof(struct vmbuspipe_hdr) +
140                         sizeof(struct icmsg_hdr)];
141
142                 if (negop->icframe_vercnt == 2 &&
143                    negop->icversion_data[1].major == 3) {
144                         negop->icversion_data[0].major = 3;
145                         negop->icversion_data[0].minor = 0;
146                         negop->icversion_data[1].major = 3;
147                         negop->icversion_data[1].minor = 0;
148                 } else {
149                         negop->icversion_data[0].major = 1;
150                         negop->icversion_data[0].minor = 0;
151                         negop->icversion_data[1].major = 1;
152                         negop->icversion_data[1].minor = 0;
153                 }
154
155                 negop->icframe_vercnt = 1;
156                 negop->icmsg_vercnt = 1;
157         }
158 }
159 EXPORT_SYMBOL(prep_negotiate_resp);
160
161 /**
162  * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
163  * Hyper-V requests
164  * @context: Pointer to argument structure.
165  *
166  * Set up the default handler for non device driver specific requests
167  * from Hyper-V. This stub responds to the default negotiate messages
168  * that come in for every non IDE/SCSI/Network request.
169  * This behavior is normally overwritten in the hv_utils driver. That
170  * driver handles requests like graceful shutdown, heartbeats etc.
171  *
172  * Mainly used by Hyper-V drivers.
173  */
174 void chn_cb_negotiate(void *context)
175 {
176         struct vmbus_channel *channel = context;
177         u8 *buf;
178         u32 buflen, recvlen;
179         u64 requestid;
180
181         struct icmsg_hdr *icmsghdrp;
182         struct icmsg_negotiate *negop = NULL;
183
184         if (channel->util_index >= 0) {
185                 /*
186                  * This is a properly initialized util channel.
187                  * Route this callback appropriately and setup state
188                  * so that we don't need to reroute again.
189                  */
190                 if (hv_cb_utils[channel->util_index].callback != NULL) {
191                         /*
192                          * The util driver has established a handler for
193                          * this service; do the magic.
194                          */
195                         channel->onchannel_callback =
196                         hv_cb_utils[channel->util_index].callback;
197                         (hv_cb_utils[channel->util_index].callback)(channel);
198                         return;
199                 }
200         }
201
202         buflen = PAGE_SIZE;
203         buf = kmalloc(buflen, GFP_ATOMIC);
204
205         vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
206
207         if (recvlen > 0) {
208                 icmsghdrp = (struct icmsg_hdr *)&buf[
209                         sizeof(struct vmbuspipe_hdr)];
210
211                 prep_negotiate_resp(icmsghdrp, negop, buf);
212
213                 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
214                         | ICMSGHDRFLAG_RESPONSE;
215
216                 vmbus_sendpacket(channel, buf,
217                                        recvlen, requestid,
218                                        VM_PKT_DATA_INBAND, 0);
219         }
220
221         kfree(buf);
222 }
223 EXPORT_SYMBOL(chn_cb_negotiate);
224
225 /*
226  * Function table used for message responses for non IDE/SCSI/Network type
227  * messages. (Such as KVP/Shutdown etc)
228  */
229 struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
230         /* 0E0B6031-5213-4934-818B-38D90CED39DB */
231         /* Shutdown */
232         {
233                 .msg_type = HV_SHUTDOWN_MSG,
234                 .data = {
235                         0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
236                         0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
237                 },
238                 .log_msg = "Shutdown channel functionality initialized"
239         },
240
241         /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
242         /* TimeSync */
243         {
244                 .msg_type = HV_TIMESYNC_MSG,
245                 .data = {
246                         0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
247                         0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
248                 },
249                 .log_msg = "Timesync channel functionality initialized"
250         },
251         /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
252         /* Heartbeat */
253         {
254                 .msg_type = HV_HEARTBEAT_MSG,
255                 .data = {
256                         0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
257                         0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
258                 },
259                 .log_msg = "Heartbeat channel functionality initialized"
260         },
261         /* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
262         /* KVP */
263         {
264                 .data = {
265                         0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
266                         0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3,  0xe6
267                 },
268                 .log_msg = "KVP channel functionality initialized"
269         },
270 };
271 EXPORT_SYMBOL(hv_cb_utils);
272
273 /*
274  * alloc_channel - Allocate and initialize a vmbus channel object
275  */
276 static struct vmbus_channel *alloc_channel(void)
277 {
278         struct vmbus_channel *channel;
279
280         channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
281         if (!channel)
282                 return NULL;
283
284         spin_lock_init(&channel->inbound_lock);
285
286         init_timer(&channel->poll_timer);
287         channel->poll_timer.data = (unsigned long)channel;
288         channel->poll_timer.function = vmbus_ontimer;
289
290         channel->controlwq = create_workqueue("hv_vmbus_ctl");
291         if (!channel->controlwq) {
292                 kfree(channel);
293                 return NULL;
294         }
295
296         return channel;
297 }
298
299 /*
300  * release_hannel - Release the vmbus channel object itself
301  */
302 static void release_channel(struct work_struct *work)
303 {
304         struct vmbus_channel *channel = container_of(work,
305                                                      struct vmbus_channel,
306                                                      work);
307
308         destroy_workqueue(channel->controlwq);
309
310         kfree(channel);
311 }
312
313 /*
314  * free_channel - Release the resources used by the vmbus channel object
315  */
316 void free_channel(struct vmbus_channel *channel)
317 {
318         del_timer_sync(&channel->poll_timer);
319
320         /*
321          * We have to release the channel's workqueue/thread in the vmbus's
322          * workqueue/thread context
323          * ie we can't destroy ourselves.
324          */
325         INIT_WORK(&channel->work, release_channel);
326         queue_work(vmbus_connection.work_queue, &channel->work);
327 }
328
329
330
331 /*
332  * vmbus_process_rescind_offer -
333  * Rescind the offer by initiating a device removal
334  */
335 static void vmbus_process_rescind_offer(struct work_struct *work)
336 {
337         struct vmbus_channel *channel = container_of(work,
338                                                      struct vmbus_channel,
339                                                      work);
340
341         vmbus_child_device_unregister(channel->device_obj);
342 }
343
344 /*
345  * vmbus_process_offer - Process the offer by creating a channel/device
346  * associated with this offer
347  */
348 static void vmbus_process_offer(struct work_struct *work)
349 {
350         struct vmbus_channel *newchannel = container_of(work,
351                                                         struct vmbus_channel,
352                                                         work);
353         struct vmbus_channel *channel;
354         bool fnew = true;
355         int ret;
356         int cnt;
357         unsigned long flags;
358
359         /* The next possible work is rescind handling */
360         INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
361
362         /* Make sure this is a new offer */
363         spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
364
365         list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
366                 if (!memcmp(&channel->offermsg.offer.if_type,
367                             &newchannel->offermsg.offer.if_type,
368                             sizeof(struct hv_guid)) &&
369                     !memcmp(&channel->offermsg.offer.if_instance,
370                             &newchannel->offermsg.offer.if_instance,
371                             sizeof(struct hv_guid))) {
372                         fnew = false;
373                         break;
374                 }
375         }
376
377         if (fnew)
378                 list_add_tail(&newchannel->listentry,
379                               &vmbus_connection.chn_list);
380
381         spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
382
383         if (!fnew) {
384                 free_channel(newchannel);
385                 return;
386         }
387
388         /*
389          * Start the process of binding this offer to the driver
390          * We need to set the DeviceObject field before calling
391          * vmbus_child_dev_add()
392          */
393         newchannel->device_obj = vmbus_child_device_create(
394                 &newchannel->offermsg.offer.if_type,
395                 &newchannel->offermsg.offer.if_instance,
396                 newchannel);
397
398         /*
399          * Add the new device to the bus. This will kick off device-driver
400          * binding which eventually invokes the device driver's AddDevice()
401          * method.
402          */
403         ret = vmbus_child_device_register(newchannel->device_obj);
404         if (ret != 0) {
405                 pr_err("unable to add child device object (relid %d)\n",
406                            newchannel->offermsg.child_relid);
407
408                 spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
409                 list_del(&newchannel->listentry);
410                 spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
411
412                 free_channel(newchannel);
413         } else {
414                 /*
415                  * This state is used to indicate a successful open
416                  * so that when we do close the channel normally, we
417                  * can cleanup properly
418                  */
419                 newchannel->state = CHANNEL_OPEN_STATE;
420                 newchannel->util_index = -1; /* Invalid index */
421
422                 /* Open IC channels */
423                 for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
424                         if (memcmp(&newchannel->offermsg.offer.if_type,
425                                    &hv_cb_utils[cnt].data,
426                                    sizeof(struct hv_guid)) == 0 &&
427                                 vmbus_open(newchannel, 2 * PAGE_SIZE,
428                                                  2 * PAGE_SIZE, NULL, 0,
429                                                  chn_cb_negotiate,
430                                                  newchannel) == 0) {
431                                 hv_cb_utils[cnt].channel = newchannel;
432                                 newchannel->util_index = cnt;
433
434                                 pr_info("%s\n", hv_cb_utils[cnt].log_msg);
435
436                         }
437                 }
438         }
439 }
440
441 /*
442  * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
443  *
444  * We ignore all offers except network and storage offers. For each network and
445  * storage offers, we create a channel object and queue a work item to the
446  * channel object to process the offer synchronously
447  */
448 static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
449 {
450         struct vmbus_channel_offer_channel *offer;
451         struct vmbus_channel *newchannel;
452         struct hv_guid *guidtype;
453         struct hv_guid *guidinstance;
454         int i;
455         int fsupported = 0;
456
457         offer = (struct vmbus_channel_offer_channel *)hdr;
458         for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
459                 if (memcmp(&offer->offer.if_type,
460                         &supported_device_classes[i],
461                         sizeof(struct hv_guid)) == 0) {
462                         fsupported = 1;
463                         break;
464                 }
465         }
466
467         if (!fsupported)
468                 return;
469
470         guidtype = &offer->offer.if_type;
471         guidinstance = &offer->offer.if_instance;
472
473         /* Allocate the channel object and save this offer. */
474         newchannel = alloc_channel();
475         if (!newchannel) {
476                 pr_err("Unable to allocate channel object\n");
477                 return;
478         }
479
480         memcpy(&newchannel->offermsg, offer,
481                sizeof(struct vmbus_channel_offer_channel));
482         newchannel->monitor_grp = (u8)offer->monitorid / 32;
483         newchannel->monitor_bit = (u8)offer->monitorid % 32;
484
485         /* TODO: Make sure the offer comes from our parent partition */
486         INIT_WORK(&newchannel->work, vmbus_process_offer);
487         queue_work(newchannel->controlwq, &newchannel->work);
488 }
489
490 /*
491  * vmbus_onoffer_rescind - Rescind offer handler.
492  *
493  * We queue a work item to process this offer synchronously
494  */
495 static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
496 {
497         struct vmbus_channel_rescind_offer *rescind;
498         struct vmbus_channel *channel;
499
500         rescind = (struct vmbus_channel_rescind_offer *)hdr;
501         channel = relid2channel(rescind->child_relid);
502
503         if (channel == NULL)
504                 /* Just return here, no channel found */
505                 return;
506
507         /* work is initialized for vmbus_process_rescind_offer() from
508          * vmbus_process_offer() where the channel got created */
509         queue_work(channel->controlwq, &channel->work);
510 }
511
512 /*
513  * vmbus_onoffers_delivered -
514  * This is invoked when all offers have been delivered.
515  *
516  * Nothing to do here.
517  */
518 static void vmbus_onoffers_delivered(
519                         struct vmbus_channel_message_header *hdr)
520 {
521 }
522
523 /*
524  * vmbus_onopen_result - Open result handler.
525  *
526  * This is invoked when we received a response to our channel open request.
527  * Find the matching request, copy the response and signal the requesting
528  * thread.
529  */
530 static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
531 {
532         struct vmbus_channel_open_result *result;
533         struct vmbus_channel_msginfo *msginfo;
534         struct vmbus_channel_message_header *requestheader;
535         struct vmbus_channel_open_channel *openmsg;
536         unsigned long flags;
537
538         result = (struct vmbus_channel_open_result *)hdr;
539
540         /*
541          * Find the open msg, copy the result and signal/unblock the wait event
542          */
543         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
544
545         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
546                                 msglistentry) {
547                 requestheader =
548                         (struct vmbus_channel_message_header *)msginfo->msg;
549
550                 if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
551                         openmsg =
552                         (struct vmbus_channel_open_channel *)msginfo->msg;
553                         if (openmsg->child_relid == result->child_relid &&
554                             openmsg->openid == result->openid) {
555                                 memcpy(&msginfo->response.open_result,
556                                        result,
557                                        sizeof(
558                                         struct vmbus_channel_open_result));
559                                 complete(&msginfo->waitevent);
560                                 break;
561                         }
562                 }
563         }
564         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
565 }
566
567 /*
568  * vmbus_ongpadl_created - GPADL created handler.
569  *
570  * This is invoked when we received a response to our gpadl create request.
571  * Find the matching request, copy the response and signal the requesting
572  * thread.
573  */
574 static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
575 {
576         struct vmbus_channel_gpadl_created *gpadlcreated;
577         struct vmbus_channel_msginfo *msginfo;
578         struct vmbus_channel_message_header *requestheader;
579         struct vmbus_channel_gpadl_header *gpadlheader;
580         unsigned long flags;
581
582         gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
583
584         /*
585          * Find the establish msg, copy the result and signal/unblock the wait
586          * event
587          */
588         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
589
590         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
591                                 msglistentry) {
592                 requestheader =
593                         (struct vmbus_channel_message_header *)msginfo->msg;
594
595                 if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
596                         gpadlheader =
597                         (struct vmbus_channel_gpadl_header *)requestheader;
598
599                         if ((gpadlcreated->child_relid ==
600                              gpadlheader->child_relid) &&
601                             (gpadlcreated->gpadl == gpadlheader->gpadl)) {
602                                 memcpy(&msginfo->response.gpadl_created,
603                                        gpadlcreated,
604                                        sizeof(
605                                         struct vmbus_channel_gpadl_created));
606                                 complete(&msginfo->waitevent);
607                                 break;
608                         }
609                 }
610         }
611         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
612 }
613
614 /*
615  * vmbus_ongpadl_torndown - GPADL torndown handler.
616  *
617  * This is invoked when we received a response to our gpadl teardown request.
618  * Find the matching request, copy the response and signal the requesting
619  * thread.
620  */
621 static void vmbus_ongpadl_torndown(
622                         struct vmbus_channel_message_header *hdr)
623 {
624         struct vmbus_channel_gpadl_torndown *gpadl_torndown;
625         struct vmbus_channel_msginfo *msginfo;
626         struct vmbus_channel_message_header *requestheader;
627         struct vmbus_channel_gpadl_teardown *gpadl_teardown;
628         unsigned long flags;
629
630         gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
631
632         /*
633          * Find the open msg, copy the result and signal/unblock the wait event
634          */
635         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
636
637         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
638                                 msglistentry) {
639                 requestheader =
640                         (struct vmbus_channel_message_header *)msginfo->msg;
641
642                 if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
643                         gpadl_teardown =
644                         (struct vmbus_channel_gpadl_teardown *)requestheader;
645
646                         if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
647                                 memcpy(&msginfo->response.gpadl_torndown,
648                                        gpadl_torndown,
649                                        sizeof(
650                                         struct vmbus_channel_gpadl_torndown));
651                                 complete(&msginfo->waitevent);
652                                 break;
653                         }
654                 }
655         }
656         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
657 }
658
659 /*
660  * vmbus_onversion_response - Version response handler
661  *
662  * This is invoked when we received a response to our initiate contact request.
663  * Find the matching request, copy the response and signal the requesting
664  * thread.
665  */
666 static void vmbus_onversion_response(
667                 struct vmbus_channel_message_header *hdr)
668 {
669         struct vmbus_channel_msginfo *msginfo;
670         struct vmbus_channel_message_header *requestheader;
671         struct vmbus_channel_initiate_contact *initiate;
672         struct vmbus_channel_version_response *version_response;
673         unsigned long flags;
674
675         version_response = (struct vmbus_channel_version_response *)hdr;
676         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
677
678         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
679                                 msglistentry) {
680                 requestheader =
681                         (struct vmbus_channel_message_header *)msginfo->msg;
682
683                 if (requestheader->msgtype ==
684                     CHANNELMSG_INITIATE_CONTACT) {
685                         initiate =
686                         (struct vmbus_channel_initiate_contact *)requestheader;
687                         memcpy(&msginfo->response.version_response,
688                               version_response,
689                               sizeof(struct vmbus_channel_version_response));
690                         complete(&msginfo->waitevent);
691                 }
692         }
693         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
694 }
695
696 /* Channel message dispatch table */
697 static struct vmbus_channel_message_table_entry
698         channel_message_table[CHANNELMSG_COUNT] = {
699         {CHANNELMSG_INVALID,                    NULL},
700         {CHANNELMSG_OFFERCHANNEL,               vmbus_onoffer},
701         {CHANNELMSG_RESCIND_CHANNELOFFER,       vmbus_onoffer_rescind},
702         {CHANNELMSG_REQUESTOFFERS,              NULL},
703         {CHANNELMSG_ALLOFFERS_DELIVERED,        vmbus_onoffers_delivered},
704         {CHANNELMSG_OPENCHANNEL,                NULL},
705         {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result},
706         {CHANNELMSG_CLOSECHANNEL,               NULL},
707         {CHANNELMSG_GPADL_HEADER,               NULL},
708         {CHANNELMSG_GPADL_BODY,         NULL},
709         {CHANNELMSG_GPADL_CREATED,              vmbus_ongpadl_created},
710         {CHANNELMSG_GPADL_TEARDOWN,             NULL},
711         {CHANNELMSG_GPADL_TORNDOWN,             vmbus_ongpadl_torndown},
712         {CHANNELMSG_RELID_RELEASED,             NULL},
713         {CHANNELMSG_INITIATE_CONTACT,           NULL},
714         {CHANNELMSG_VERSION_RESPONSE,           vmbus_onversion_response},
715         {CHANNELMSG_UNLOAD,                     NULL},
716 };
717
718 /*
719  * vmbus_onmessage - Handler for channel protocol messages.
720  *
721  * This is invoked in the vmbus worker thread context.
722  */
723 void vmbus_onmessage(void *context)
724 {
725         struct hv_message *msg = context;
726         struct vmbus_channel_message_header *hdr;
727         int size;
728
729         hdr = (struct vmbus_channel_message_header *)msg->u.payload;
730         size = msg->header.payload_size;
731
732         if (hdr->msgtype >= CHANNELMSG_COUNT) {
733                 pr_err("Received invalid channel message type %d size %d\n",
734                            hdr->msgtype, size);
735                 print_hex_dump_bytes("", DUMP_PREFIX_NONE,
736                                      (unsigned char *)msg->u.payload, size);
737                 return;
738         }
739
740         if (channel_message_table[hdr->msgtype].message_handler)
741                 channel_message_table[hdr->msgtype].message_handler(hdr);
742         else
743                 pr_err("Unhandled channel message type %d\n", hdr->msgtype);
744 }
745
746 /*
747  * vmbus_request_offers - Send a request to get all our pending offers.
748  */
749 int vmbus_request_offers(void)
750 {
751         struct vmbus_channel_message_header *msg;
752         struct vmbus_channel_msginfo *msginfo;
753         int ret, t;
754
755         msginfo = kmalloc(sizeof(*msginfo) +
756                           sizeof(struct vmbus_channel_message_header),
757                           GFP_KERNEL);
758         if (!msginfo)
759                 return -ENOMEM;
760
761         init_completion(&msginfo->waitevent);
762
763         msg = (struct vmbus_channel_message_header *)msginfo->msg;
764
765         msg->msgtype = CHANNELMSG_REQUESTOFFERS;
766
767
768         ret = vmbus_post_msg(msg,
769                                sizeof(struct vmbus_channel_message_header));
770         if (ret != 0) {
771                 pr_err("Unable to request offers - %d\n", ret);
772
773                 goto cleanup;
774         }
775
776         t = wait_for_completion_timeout(&msginfo->waitevent, HZ);
777         if (t == 0) {
778                 ret = -ETIMEDOUT;
779                 goto cleanup;
780         }
781
782
783
784 cleanup:
785         kfree(msginfo);
786
787         return ret;
788 }
789
790 /* eof */