Drivers: hv: Get rid of an unnecessary check in vmbus_prep_negotiate_resp()
[pandora-kernel.git] / drivers / 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 #include <linux/hyperv.h>
32
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
41 /**
42  * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
43  * @icmsghdrp: Pointer to msg header structure
44  * @icmsg_negotiate: Pointer to negotiate message structure
45  * @buf: Raw buffer channel data
46  *
47  * @icmsghdrp is of type &struct icmsg_hdr.
48  * @negop is of type &struct icmsg_negotiate.
49  * Set up and fill in default negotiate response message. This response can
50  * come from both the vmbus driver and the hv_utils driver. The current api
51  * will respond properly to both Windows 2008 and Windows 2008-R2 operating
52  * systems.
53  *
54  * Mainly used by Hyper-V drivers.
55  */
56 void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
57                                struct icmsg_negotiate *negop, u8 *buf)
58 {
59         icmsghdrp->icmsgsize = 0x10;
60
61         negop = (struct icmsg_negotiate *)&buf[
62                 sizeof(struct vmbuspipe_hdr) +
63                 sizeof(struct icmsg_hdr)];
64
65         if (negop->icframe_vercnt == 2 &&
66            negop->icversion_data[1].major == 3) {
67                 negop->icversion_data[0].major = 3;
68                 negop->icversion_data[0].minor = 0;
69                 negop->icversion_data[1].major = 3;
70                 negop->icversion_data[1].minor = 0;
71         } else {
72                 negop->icversion_data[0].major = 1;
73                 negop->icversion_data[0].minor = 0;
74                 negop->icversion_data[1].major = 1;
75                 negop->icversion_data[1].minor = 0;
76         }
77
78         negop->icframe_vercnt = 1;
79         negop->icmsg_vercnt = 1;
80 }
81
82 EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
83
84 /*
85  * alloc_channel - Allocate and initialize a vmbus channel object
86  */
87 static struct vmbus_channel *alloc_channel(void)
88 {
89         struct vmbus_channel *channel;
90
91         channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
92         if (!channel)
93                 return NULL;
94
95         spin_lock_init(&channel->inbound_lock);
96
97         channel->controlwq = create_workqueue("hv_vmbus_ctl");
98         if (!channel->controlwq) {
99                 kfree(channel);
100                 return NULL;
101         }
102
103         return channel;
104 }
105
106 /*
107  * release_hannel - Release the vmbus channel object itself
108  */
109 static void release_channel(struct work_struct *work)
110 {
111         struct vmbus_channel *channel = container_of(work,
112                                                      struct vmbus_channel,
113                                                      work);
114
115         destroy_workqueue(channel->controlwq);
116
117         kfree(channel);
118 }
119
120 /*
121  * free_channel - Release the resources used by the vmbus channel object
122  */
123 static void free_channel(struct vmbus_channel *channel)
124 {
125
126         /*
127          * We have to release the channel's workqueue/thread in the vmbus's
128          * workqueue/thread context
129          * ie we can't destroy ourselves.
130          */
131         INIT_WORK(&channel->work, release_channel);
132         queue_work(vmbus_connection.work_queue, &channel->work);
133 }
134
135
136
137 /*
138  * vmbus_process_rescind_offer -
139  * Rescind the offer by initiating a device removal
140  */
141 static void vmbus_process_rescind_offer(struct work_struct *work)
142 {
143         struct vmbus_channel *channel = container_of(work,
144                                                      struct vmbus_channel,
145                                                      work);
146
147         vmbus_device_unregister(channel->device_obj);
148 }
149
150 void vmbus_free_channels(void)
151 {
152         struct vmbus_channel *channel;
153
154         list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
155                 vmbus_device_unregister(channel->device_obj);
156                 kfree(channel->device_obj);
157                 free_channel(channel);
158         }
159 }
160
161 /*
162  * vmbus_process_offer - Process the offer by creating a channel/device
163  * associated with this offer
164  */
165 static void vmbus_process_offer(struct work_struct *work)
166 {
167         struct vmbus_channel *newchannel = container_of(work,
168                                                         struct vmbus_channel,
169                                                         work);
170         struct vmbus_channel *channel;
171         bool fnew = true;
172         int ret;
173         unsigned long flags;
174
175         /* The next possible work is rescind handling */
176         INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
177
178         /* Make sure this is a new offer */
179         spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
180
181         list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
182                 if (!uuid_le_cmp(channel->offermsg.offer.if_type,
183                         newchannel->offermsg.offer.if_type) &&
184                         !uuid_le_cmp(channel->offermsg.offer.if_instance,
185                                 newchannel->offermsg.offer.if_instance)) {
186                         fnew = false;
187                         break;
188                 }
189         }
190
191         if (fnew)
192                 list_add_tail(&newchannel->listentry,
193                               &vmbus_connection.chn_list);
194
195         spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
196
197         if (!fnew) {
198                 free_channel(newchannel);
199                 return;
200         }
201
202         /*
203          * Start the process of binding this offer to the driver
204          * We need to set the DeviceObject field before calling
205          * vmbus_child_dev_add()
206          */
207         newchannel->device_obj = vmbus_device_create(
208                 &newchannel->offermsg.offer.if_type,
209                 &newchannel->offermsg.offer.if_instance,
210                 newchannel);
211
212         /*
213          * Add the new device to the bus. This will kick off device-driver
214          * binding which eventually invokes the device driver's AddDevice()
215          * method.
216          */
217         ret = vmbus_device_register(newchannel->device_obj);
218         if (ret != 0) {
219                 pr_err("unable to add child device object (relid %d)\n",
220                            newchannel->offermsg.child_relid);
221
222                 spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
223                 list_del(&newchannel->listentry);
224                 spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
225                 kfree(newchannel->device_obj);
226
227                 free_channel(newchannel);
228         } else {
229                 /*
230                  * This state is used to indicate a successful open
231                  * so that when we do close the channel normally, we
232                  * can cleanup properly
233                  */
234                 newchannel->state = CHANNEL_OPEN_STATE;
235         }
236 }
237
238 /*
239  * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
240  *
241  */
242 static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
243 {
244         struct vmbus_channel_offer_channel *offer;
245         struct vmbus_channel *newchannel;
246         uuid_le *guidtype;
247         uuid_le *guidinstance;
248
249         offer = (struct vmbus_channel_offer_channel *)hdr;
250
251         guidtype = &offer->offer.if_type;
252         guidinstance = &offer->offer.if_instance;
253
254         /* Allocate the channel object and save this offer. */
255         newchannel = alloc_channel();
256         if (!newchannel) {
257                 pr_err("Unable to allocate channel object\n");
258                 return;
259         }
260
261         memcpy(&newchannel->offermsg, offer,
262                sizeof(struct vmbus_channel_offer_channel));
263         newchannel->monitor_grp = (u8)offer->monitorid / 32;
264         newchannel->monitor_bit = (u8)offer->monitorid % 32;
265
266         INIT_WORK(&newchannel->work, vmbus_process_offer);
267         queue_work(newchannel->controlwq, &newchannel->work);
268 }
269
270 /*
271  * vmbus_onoffer_rescind - Rescind offer handler.
272  *
273  * We queue a work item to process this offer synchronously
274  */
275 static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
276 {
277         struct vmbus_channel_rescind_offer *rescind;
278         struct vmbus_channel *channel;
279
280         rescind = (struct vmbus_channel_rescind_offer *)hdr;
281         channel = relid2channel(rescind->child_relid);
282
283         if (channel == NULL)
284                 /* Just return here, no channel found */
285                 return;
286
287         /* work is initialized for vmbus_process_rescind_offer() from
288          * vmbus_process_offer() where the channel got created */
289         queue_work(channel->controlwq, &channel->work);
290 }
291
292 /*
293  * vmbus_onoffers_delivered -
294  * This is invoked when all offers have been delivered.
295  *
296  * Nothing to do here.
297  */
298 static void vmbus_onoffers_delivered(
299                         struct vmbus_channel_message_header *hdr)
300 {
301 }
302
303 /*
304  * vmbus_onopen_result - Open result handler.
305  *
306  * This is invoked when we received a response to our channel open request.
307  * Find the matching request, copy the response and signal the requesting
308  * thread.
309  */
310 static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
311 {
312         struct vmbus_channel_open_result *result;
313         struct vmbus_channel_msginfo *msginfo;
314         struct vmbus_channel_message_header *requestheader;
315         struct vmbus_channel_open_channel *openmsg;
316         unsigned long flags;
317
318         result = (struct vmbus_channel_open_result *)hdr;
319
320         /*
321          * Find the open msg, copy the result and signal/unblock the wait event
322          */
323         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
324
325         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
326                                 msglistentry) {
327                 requestheader =
328                         (struct vmbus_channel_message_header *)msginfo->msg;
329
330                 if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
331                         openmsg =
332                         (struct vmbus_channel_open_channel *)msginfo->msg;
333                         if (openmsg->child_relid == result->child_relid &&
334                             openmsg->openid == result->openid) {
335                                 memcpy(&msginfo->response.open_result,
336                                        result,
337                                        sizeof(
338                                         struct vmbus_channel_open_result));
339                                 complete(&msginfo->waitevent);
340                                 break;
341                         }
342                 }
343         }
344         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
345 }
346
347 /*
348  * vmbus_ongpadl_created - GPADL created handler.
349  *
350  * This is invoked when we received a response to our gpadl create request.
351  * Find the matching request, copy the response and signal the requesting
352  * thread.
353  */
354 static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
355 {
356         struct vmbus_channel_gpadl_created *gpadlcreated;
357         struct vmbus_channel_msginfo *msginfo;
358         struct vmbus_channel_message_header *requestheader;
359         struct vmbus_channel_gpadl_header *gpadlheader;
360         unsigned long flags;
361
362         gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
363
364         /*
365          * Find the establish msg, copy the result and signal/unblock the wait
366          * event
367          */
368         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
369
370         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
371                                 msglistentry) {
372                 requestheader =
373                         (struct vmbus_channel_message_header *)msginfo->msg;
374
375                 if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
376                         gpadlheader =
377                         (struct vmbus_channel_gpadl_header *)requestheader;
378
379                         if ((gpadlcreated->child_relid ==
380                              gpadlheader->child_relid) &&
381                             (gpadlcreated->gpadl == gpadlheader->gpadl)) {
382                                 memcpy(&msginfo->response.gpadl_created,
383                                        gpadlcreated,
384                                        sizeof(
385                                         struct vmbus_channel_gpadl_created));
386                                 complete(&msginfo->waitevent);
387                                 break;
388                         }
389                 }
390         }
391         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
392 }
393
394 /*
395  * vmbus_ongpadl_torndown - GPADL torndown handler.
396  *
397  * This is invoked when we received a response to our gpadl teardown request.
398  * Find the matching request, copy the response and signal the requesting
399  * thread.
400  */
401 static void vmbus_ongpadl_torndown(
402                         struct vmbus_channel_message_header *hdr)
403 {
404         struct vmbus_channel_gpadl_torndown *gpadl_torndown;
405         struct vmbus_channel_msginfo *msginfo;
406         struct vmbus_channel_message_header *requestheader;
407         struct vmbus_channel_gpadl_teardown *gpadl_teardown;
408         unsigned long flags;
409
410         gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
411
412         /*
413          * Find the open msg, copy the result and signal/unblock the wait event
414          */
415         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
416
417         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
418                                 msglistentry) {
419                 requestheader =
420                         (struct vmbus_channel_message_header *)msginfo->msg;
421
422                 if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
423                         gpadl_teardown =
424                         (struct vmbus_channel_gpadl_teardown *)requestheader;
425
426                         if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
427                                 memcpy(&msginfo->response.gpadl_torndown,
428                                        gpadl_torndown,
429                                        sizeof(
430                                         struct vmbus_channel_gpadl_torndown));
431                                 complete(&msginfo->waitevent);
432                                 break;
433                         }
434                 }
435         }
436         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
437 }
438
439 /*
440  * vmbus_onversion_response - Version response handler
441  *
442  * This is invoked when we received a response to our initiate contact request.
443  * Find the matching request, copy the response and signal the requesting
444  * thread.
445  */
446 static void vmbus_onversion_response(
447                 struct vmbus_channel_message_header *hdr)
448 {
449         struct vmbus_channel_msginfo *msginfo;
450         struct vmbus_channel_message_header *requestheader;
451         struct vmbus_channel_initiate_contact *initiate;
452         struct vmbus_channel_version_response *version_response;
453         unsigned long flags;
454
455         version_response = (struct vmbus_channel_version_response *)hdr;
456         spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
457
458         list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
459                                 msglistentry) {
460                 requestheader =
461                         (struct vmbus_channel_message_header *)msginfo->msg;
462
463                 if (requestheader->msgtype ==
464                     CHANNELMSG_INITIATE_CONTACT) {
465                         initiate =
466                         (struct vmbus_channel_initiate_contact *)requestheader;
467                         memcpy(&msginfo->response.version_response,
468                               version_response,
469                               sizeof(struct vmbus_channel_version_response));
470                         complete(&msginfo->waitevent);
471                 }
472         }
473         spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
474 }
475
476 /* Channel message dispatch table */
477 static struct vmbus_channel_message_table_entry
478         channel_message_table[CHANNELMSG_COUNT] = {
479         {CHANNELMSG_INVALID,                    NULL},
480         {CHANNELMSG_OFFERCHANNEL,               vmbus_onoffer},
481         {CHANNELMSG_RESCIND_CHANNELOFFER,       vmbus_onoffer_rescind},
482         {CHANNELMSG_REQUESTOFFERS,              NULL},
483         {CHANNELMSG_ALLOFFERS_DELIVERED,        vmbus_onoffers_delivered},
484         {CHANNELMSG_OPENCHANNEL,                NULL},
485         {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result},
486         {CHANNELMSG_CLOSECHANNEL,               NULL},
487         {CHANNELMSG_GPADL_HEADER,               NULL},
488         {CHANNELMSG_GPADL_BODY,         NULL},
489         {CHANNELMSG_GPADL_CREATED,              vmbus_ongpadl_created},
490         {CHANNELMSG_GPADL_TEARDOWN,             NULL},
491         {CHANNELMSG_GPADL_TORNDOWN,             vmbus_ongpadl_torndown},
492         {CHANNELMSG_RELID_RELEASED,             NULL},
493         {CHANNELMSG_INITIATE_CONTACT,           NULL},
494         {CHANNELMSG_VERSION_RESPONSE,           vmbus_onversion_response},
495         {CHANNELMSG_UNLOAD,                     NULL},
496 };
497
498 /*
499  * vmbus_onmessage - Handler for channel protocol messages.
500  *
501  * This is invoked in the vmbus worker thread context.
502  */
503 void vmbus_onmessage(void *context)
504 {
505         struct hv_message *msg = context;
506         struct vmbus_channel_message_header *hdr;
507         int size;
508
509         hdr = (struct vmbus_channel_message_header *)msg->u.payload;
510         size = msg->header.payload_size;
511
512         if (hdr->msgtype >= CHANNELMSG_COUNT) {
513                 pr_err("Received invalid channel message type %d size %d\n",
514                            hdr->msgtype, size);
515                 print_hex_dump_bytes("", DUMP_PREFIX_NONE,
516                                      (unsigned char *)msg->u.payload, size);
517                 return;
518         }
519
520         if (channel_message_table[hdr->msgtype].message_handler)
521                 channel_message_table[hdr->msgtype].message_handler(hdr);
522         else
523                 pr_err("Unhandled channel message type %d\n", hdr->msgtype);
524 }
525
526 /*
527  * vmbus_request_offers - Send a request to get all our pending offers.
528  */
529 int vmbus_request_offers(void)
530 {
531         struct vmbus_channel_message_header *msg;
532         struct vmbus_channel_msginfo *msginfo;
533         int ret, t;
534
535         msginfo = kmalloc(sizeof(*msginfo) +
536                           sizeof(struct vmbus_channel_message_header),
537                           GFP_KERNEL);
538         if (!msginfo)
539                 return -ENOMEM;
540
541         init_completion(&msginfo->waitevent);
542
543         msg = (struct vmbus_channel_message_header *)msginfo->msg;
544
545         msg->msgtype = CHANNELMSG_REQUESTOFFERS;
546
547
548         ret = vmbus_post_msg(msg,
549                                sizeof(struct vmbus_channel_message_header));
550         if (ret != 0) {
551                 pr_err("Unable to request offers - %d\n", ret);
552
553                 goto cleanup;
554         }
555
556         t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
557         if (t == 0) {
558                 ret = -ETIMEDOUT;
559                 goto cleanup;
560         }
561
562
563
564 cleanup:
565         kfree(msginfo);
566
567         return ret;
568 }
569
570 /* eof */