Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1...
[cascardo/linux.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         channel->controlwq = create_workqueue("hv_vmbus_ctl");
287         if (!channel->controlwq) {
288                 kfree(channel);
289                 return NULL;
290         }
291
292         return channel;
293 }
294
295 /*
296  * release_hannel - Release the vmbus channel object itself
297  */
298 static void release_channel(struct work_struct *work)
299 {
300         struct vmbus_channel *channel = container_of(work,
301                                                      struct vmbus_channel,
302                                                      work);
303
304         destroy_workqueue(channel->controlwq);
305
306         kfree(channel);
307 }
308
309 /*
310  * free_channel - Release the resources used by the vmbus channel object
311  */
312 void free_channel(struct vmbus_channel *channel)
313 {
314
315         /*
316          * We have to release the channel's workqueue/thread in the vmbus's
317          * workqueue/thread context
318          * ie we can't destroy ourselves.
319          */
320         INIT_WORK(&channel->work, release_channel);
321         queue_work(vmbus_connection.work_queue, &channel->work);
322 }
323
324
325
326 /*
327  * vmbus_process_rescind_offer -
328  * Rescind the offer by initiating a device removal
329  */
330 static void vmbus_process_rescind_offer(struct work_struct *work)
331 {
332         struct vmbus_channel *channel = container_of(work,
333                                                      struct vmbus_channel,
334                                                      work);
335
336         vmbus_child_device_unregister(channel->device_obj);
337 }
338
339 /*
340  * vmbus_process_offer - Process the offer by creating a channel/device
341  * associated with this offer
342  */
343 static void vmbus_process_offer(struct work_struct *work)
344 {
345         struct vmbus_channel *newchannel = container_of(work,
346                                                         struct vmbus_channel,
347                                                         work);
348         struct vmbus_channel *channel;
349         bool fnew = true;
350         int ret;
351         int cnt;
352         unsigned long flags;
353
354         /* The next possible work is rescind handling */
355         INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
356
357         /* Make sure this is a new offer */
358         spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
359
360         list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
361                 if (!memcmp(&channel->offermsg.offer.if_type,
362                             &newchannel->offermsg.offer.if_type,
363                             sizeof(struct hv_guid)) &&
364                     !memcmp(&channel->offermsg.offer.if_instance,
365                             &newchannel->offermsg.offer.if_instance,
366                             sizeof(struct hv_guid))) {
367                         fnew = false;
368                         break;
369                 }
370         }
371
372         if (fnew)
373                 list_add_tail(&newchannel->listentry,
374                               &vmbus_connection.chn_list);
375
376         spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
377
378         if (!fnew) {
379                 free_channel(newchannel);
380                 return;
381         }
382
383         /*
384          * Start the process of binding this offer to the driver
385          * We need to set the DeviceObject field before calling
386          * vmbus_child_dev_add()
387          */
388         newchannel->device_obj = vmbus_child_device_create(
389                 &newchannel->offermsg.offer.if_type,
390                 &newchannel->offermsg.offer.if_instance,
391                 newchannel);
392
393         /*
394          * Add the new device to the bus. This will kick off device-driver
395          * binding which eventually invokes the device driver's AddDevice()
396          * method.
397          */
398         ret = vmbus_child_device_register(newchannel->device_obj);
399         if (ret != 0) {
400                 pr_err("unable to add child device object (relid %d)\n",
401                            newchannel->offermsg.child_relid);
402
403                 spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
404                 list_del(&newchannel->listentry);
405                 spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
406
407                 free_channel(newchannel);
408         } else {
409                 /*
410                  * This state is used to indicate a successful open
411                  * so that when we do close the channel normally, we
412                  * can cleanup properly
413                  */
414                 newchannel->state = CHANNEL_OPEN_STATE;
415                 newchannel->util_index = -1; /* Invalid index */
416
417                 /* Open IC channels */
418                 for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
419                         if (memcmp(&newchannel->offermsg.offer.if_type,
420                                    &hv_cb_utils[cnt].data,
421                                    sizeof(struct hv_guid)) == 0 &&
422                                 vmbus_open(newchannel, 2 * PAGE_SIZE,
423                                                  2 * PAGE_SIZE, NULL, 0,
424                                                  chn_cb_negotiate,
425                                                  newchannel) == 0) {
426                                 hv_cb_utils[cnt].channel = newchannel;
427                                 newchannel->util_index = cnt;
428
429                                 pr_info("%s\n", hv_cb_utils[cnt].log_msg);
430
431                         }
432                 }
433         }
434 }
435
436 /*
437  * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
438  *
439  * We ignore all offers except network and storage offers. For each network and
440  * storage offers, we create a channel object and queue a work item to the
441  * channel object to process the offer synchronously
442  */
443 static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
444 {
445         struct vmbus_channel_offer_channel *offer;
446         struct vmbus_channel *newchannel;
447         struct hv_guid *guidtype;
448         struct hv_guid *guidinstance;
449         int i;
450         int fsupported = 0;
451
452         offer = (struct vmbus_channel_offer_channel *)hdr;
453         for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
454                 if (memcmp(&offer->offer.if_type,
455                         &supported_device_classes[i],
456                         sizeof(struct hv_guid)) == 0) {
457                         fsupported = 1;
458                         break;
459                 }
460         }
461
462         if (!fsupported)
463                 return;
464
465         guidtype = &offer->offer.if_type;
466         guidinstance = &offer->offer.if_instance;
467
468         /* Allocate the channel object and save this offer. */
469         newchannel = alloc_channel();
470         if (!newchannel) {
471                 pr_err("Unable to allocate channel object\n");
472                 return;
473         }
474
475         memcpy(&newchannel->offermsg, offer,
476                sizeof(struct vmbus_channel_offer_channel));
477         newchannel->monitor_grp = (u8)offer->monitorid / 32;
478         newchannel->monitor_bit = (u8)offer->monitorid % 32;
479
480         INIT_WORK(&newchannel->work, vmbus_process_offer);
481         queue_work(newchannel->controlwq, &newchannel->work);
482 }
483
484 /*
485  * vmbus_onoffer_rescind - Rescind offer handler.
486  *
487  * We queue a work item to process this offer synchronously
488  */
489 static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
490 {
491         struct vmbus_channel_rescind_offer *rescind;
492         struct vmbus_channel *channel;
493
494         rescind = (struct vmbus_channel_rescind_offer *)hdr;
495         channel = relid2channel(rescind->child_relid);
496
497         if (channel == NULL)
498                 /* Just return here, no channel found */
499                 return;
500
501         /* work is initialized for vmbus_process_rescind_offer() from
502          * vmbus_process_offer() where the channel got created */
503         queue_work(channel->controlwq, &channel->work);
504 }
505
506 /*
507  * vmbus_onoffers_delivered -
508  * This is invoked when all offers have been delivered.
509  *
510  * Nothing to do here.
511  */
512 static void vmbus_onoffers_delivered(
513                         struct vmbus_channel_message_header *hdr)
514 {
515 }
516
517 /*
518  * vmbus_onopen_result - Open result handler.
519  *
520  * This is invoked when we received a response to our channel open request.
521  * Find the matching request, copy the response and signal the requesting
522  * thread.
523  */
524 static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
525 {
526         struct vmbus_channel_open_result *result;
527         struct vmbus_channel_msginfo *msginfo;
528         struct vmbus_channel_message_header *requestheader;
529         struct vmbus_channel_open_channel *openmsg;
530         unsigned long flags;
531
532         result = (struct vmbus_channel_open_result *)hdr;
533
534         /*
535          * Find the open msg, copy the result and signal/unblock the wait event
536          */
537         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
538
539         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
540                                 msglistentry) {
541                 requestheader =
542                         (struct vmbus_channel_message_header *)msginfo->msg;
543
544                 if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
545                         openmsg =
546                         (struct vmbus_channel_open_channel *)msginfo->msg;
547                         if (openmsg->child_relid == result->child_relid &&
548                             openmsg->openid == result->openid) {
549                                 memcpy(&msginfo->response.open_result,
550                                        result,
551                                        sizeof(
552                                         struct vmbus_channel_open_result));
553                                 complete(&msginfo->waitevent);
554                                 break;
555                         }
556                 }
557         }
558         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
559 }
560
561 /*
562  * vmbus_ongpadl_created - GPADL created handler.
563  *
564  * This is invoked when we received a response to our gpadl create request.
565  * Find the matching request, copy the response and signal the requesting
566  * thread.
567  */
568 static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
569 {
570         struct vmbus_channel_gpadl_created *gpadlcreated;
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         gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
577
578         /*
579          * Find the establish msg, copy the result and signal/unblock the wait
580          * event
581          */
582         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
583
584         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
585                                 msglistentry) {
586                 requestheader =
587                         (struct vmbus_channel_message_header *)msginfo->msg;
588
589                 if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
590                         gpadlheader =
591                         (struct vmbus_channel_gpadl_header *)requestheader;
592
593                         if ((gpadlcreated->child_relid ==
594                              gpadlheader->child_relid) &&
595                             (gpadlcreated->gpadl == gpadlheader->gpadl)) {
596                                 memcpy(&msginfo->response.gpadl_created,
597                                        gpadlcreated,
598                                        sizeof(
599                                         struct vmbus_channel_gpadl_created));
600                                 complete(&msginfo->waitevent);
601                                 break;
602                         }
603                 }
604         }
605         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
606 }
607
608 /*
609  * vmbus_ongpadl_torndown - GPADL torndown handler.
610  *
611  * This is invoked when we received a response to our gpadl teardown request.
612  * Find the matching request, copy the response and signal the requesting
613  * thread.
614  */
615 static void vmbus_ongpadl_torndown(
616                         struct vmbus_channel_message_header *hdr)
617 {
618         struct vmbus_channel_gpadl_torndown *gpadl_torndown;
619         struct vmbus_channel_msginfo *msginfo;
620         struct vmbus_channel_message_header *requestheader;
621         struct vmbus_channel_gpadl_teardown *gpadl_teardown;
622         unsigned long flags;
623
624         gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
625
626         /*
627          * Find the open msg, copy the result and signal/unblock the wait event
628          */
629         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
630
631         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
632                                 msglistentry) {
633                 requestheader =
634                         (struct vmbus_channel_message_header *)msginfo->msg;
635
636                 if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
637                         gpadl_teardown =
638                         (struct vmbus_channel_gpadl_teardown *)requestheader;
639
640                         if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
641                                 memcpy(&msginfo->response.gpadl_torndown,
642                                        gpadl_torndown,
643                                        sizeof(
644                                         struct vmbus_channel_gpadl_torndown));
645                                 complete(&msginfo->waitevent);
646                                 break;
647                         }
648                 }
649         }
650         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
651 }
652
653 /*
654  * vmbus_onversion_response - Version response handler
655  *
656  * This is invoked when we received a response to our initiate contact request.
657  * Find the matching request, copy the response and signal the requesting
658  * thread.
659  */
660 static void vmbus_onversion_response(
661                 struct vmbus_channel_message_header *hdr)
662 {
663         struct vmbus_channel_msginfo *msginfo;
664         struct vmbus_channel_message_header *requestheader;
665         struct vmbus_channel_initiate_contact *initiate;
666         struct vmbus_channel_version_response *version_response;
667         unsigned long flags;
668
669         version_response = (struct vmbus_channel_version_response *)hdr;
670         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
671
672         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
673                                 msglistentry) {
674                 requestheader =
675                         (struct vmbus_channel_message_header *)msginfo->msg;
676
677                 if (requestheader->msgtype ==
678                     CHANNELMSG_INITIATE_CONTACT) {
679                         initiate =
680                         (struct vmbus_channel_initiate_contact *)requestheader;
681                         memcpy(&msginfo->response.version_response,
682                               version_response,
683                               sizeof(struct vmbus_channel_version_response));
684                         complete(&msginfo->waitevent);
685                 }
686         }
687         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
688 }
689
690 /* Channel message dispatch table */
691 static struct vmbus_channel_message_table_entry
692         channel_message_table[CHANNELMSG_COUNT] = {
693         {CHANNELMSG_INVALID,                    NULL},
694         {CHANNELMSG_OFFERCHANNEL,               vmbus_onoffer},
695         {CHANNELMSG_RESCIND_CHANNELOFFER,       vmbus_onoffer_rescind},
696         {CHANNELMSG_REQUESTOFFERS,              NULL},
697         {CHANNELMSG_ALLOFFERS_DELIVERED,        vmbus_onoffers_delivered},
698         {CHANNELMSG_OPENCHANNEL,                NULL},
699         {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result},
700         {CHANNELMSG_CLOSECHANNEL,               NULL},
701         {CHANNELMSG_GPADL_HEADER,               NULL},
702         {CHANNELMSG_GPADL_BODY,         NULL},
703         {CHANNELMSG_GPADL_CREATED,              vmbus_ongpadl_created},
704         {CHANNELMSG_GPADL_TEARDOWN,             NULL},
705         {CHANNELMSG_GPADL_TORNDOWN,             vmbus_ongpadl_torndown},
706         {CHANNELMSG_RELID_RELEASED,             NULL},
707         {CHANNELMSG_INITIATE_CONTACT,           NULL},
708         {CHANNELMSG_VERSION_RESPONSE,           vmbus_onversion_response},
709         {CHANNELMSG_UNLOAD,                     NULL},
710 };
711
712 /*
713  * vmbus_onmessage - Handler for channel protocol messages.
714  *
715  * This is invoked in the vmbus worker thread context.
716  */
717 void vmbus_onmessage(void *context)
718 {
719         struct hv_message *msg = context;
720         struct vmbus_channel_message_header *hdr;
721         int size;
722
723         hdr = (struct vmbus_channel_message_header *)msg->u.payload;
724         size = msg->header.payload_size;
725
726         if (hdr->msgtype >= CHANNELMSG_COUNT) {
727                 pr_err("Received invalid channel message type %d size %d\n",
728                            hdr->msgtype, size);
729                 print_hex_dump_bytes("", DUMP_PREFIX_NONE,
730                                      (unsigned char *)msg->u.payload, size);
731                 return;
732         }
733
734         if (channel_message_table[hdr->msgtype].message_handler)
735                 channel_message_table[hdr->msgtype].message_handler(hdr);
736         else
737                 pr_err("Unhandled channel message type %d\n", hdr->msgtype);
738 }
739
740 /*
741  * vmbus_request_offers - Send a request to get all our pending offers.
742  */
743 int vmbus_request_offers(void)
744 {
745         struct vmbus_channel_message_header *msg;
746         struct vmbus_channel_msginfo *msginfo;
747         int ret, t;
748
749         msginfo = kmalloc(sizeof(*msginfo) +
750                           sizeof(struct vmbus_channel_message_header),
751                           GFP_KERNEL);
752         if (!msginfo)
753                 return -ENOMEM;
754
755         init_completion(&msginfo->waitevent);
756
757         msg = (struct vmbus_channel_message_header *)msginfo->msg;
758
759         msg->msgtype = CHANNELMSG_REQUESTOFFERS;
760
761
762         ret = vmbus_post_msg(msg,
763                                sizeof(struct vmbus_channel_message_header));
764         if (ret != 0) {
765                 pr_err("Unable to request offers - %d\n", ret);
766
767                 goto cleanup;
768         }
769
770         t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
771         if (t == 0) {
772                 ret = -ETIMEDOUT;
773                 goto cleanup;
774         }
775
776
777
778 cleanup:
779         kfree(msginfo);
780
781         return ret;
782 }
783
784 /* eof */