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