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