channel_mgmt.c 17.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Copyright (c) 2009, Microsoft Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 *
 * Authors:
 *   Haiyang Zhang <haiyangz@microsoft.com>
 *   Hank Janssen  <hjanssen@microsoft.com>
 */
21 22
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

23
#include <linux/kernel.h>
24 25
#include <linux/sched.h>
#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
#define MAX_MSG_TYPES                    4
#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 8
42

43
static const uuid_le
44
	supported_device_classes[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
45
	/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
46 47
	/* Storage - SCSI */
	{
48
		.b  = {
49 50 51 52 53
			0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
			0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
		}
	},

54
	/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
55 56
	/* Network */
	{
57
		.b = {
58 59 60 61 62
			0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
			0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
		}
	},

63
	/* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
64 65
	/* Input */
	{
66
		.b = {
67 68 69 70
			0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
			0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
		}
	},
71

72 73 74
	/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
	/* IDE */
	{
75
		.b = {
76 77 78 79
			0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
			0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
		}
	},
80 81 82
	/* 0E0B6031-5213-4934-818B-38D90CED39DB */
	/* Shutdown */
	{
83
		.b = {
84 85 86 87
			0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
			0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
		}
	},
88 89 90
	/* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
	/* TimeSync */
	{
91
		.b = {
92 93 94 95
			0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
			0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
		}
	},
96 97 98
	/* {57164f39-9115-4e78-ab55-382f3bd5422d} */
	/* Heartbeat */
	{
99
		.b = {
100 101 102 103
			0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
			0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
		}
	},
104 105 106
	/* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
	/* KVP */
	{
107
		.b = {
108 109 110 111 112
			0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
			0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3,  0xe6
	}
	},

113 114
};

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

/**
 * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
 * @icmsghdrp: Pointer to msg header structure
 * @icmsg_negotiate: Pointer to negotiate message structure
 * @buf: Raw buffer channel data
 *
 * @icmsghdrp is of type &struct icmsg_hdr.
 * @negop is of type &struct icmsg_negotiate.
 * Set up and fill in default negotiate response message. This response can
 * come from both the vmbus driver and the hv_utils driver. The current api
 * will respond properly to both Windows 2008 and Windows 2008-R2 operating
 * systems.
 *
 * Mainly used by Hyper-V drivers.
 */
void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
			     struct icmsg_negotiate *negop,
			     u8 *buf)
{
	if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
		icmsghdrp->icmsgsize = 0x10;

		negop = (struct icmsg_negotiate *)&buf[
			sizeof(struct vmbuspipe_hdr) +
			sizeof(struct icmsg_hdr)];

		if (negop->icframe_vercnt == 2 &&
		   negop->icversion_data[1].major == 3) {
			negop->icversion_data[0].major = 3;
			negop->icversion_data[0].minor = 0;
			negop->icversion_data[1].major = 3;
			negop->icversion_data[1].minor = 0;
		} else {
			negop->icversion_data[0].major = 1;
			negop->icversion_data[0].minor = 0;
			negop->icversion_data[1].major = 1;
			negop->icversion_data[1].minor = 0;
		}

		negop->icframe_vercnt = 1;
		negop->icmsg_vercnt = 1;
	}
}
EXPORT_SYMBOL(prep_negotiate_resp);

161
/*
162
 * alloc_channel - Allocate and initialize a vmbus channel object
163
 */
164
static struct vmbus_channel *alloc_channel(void)
165
{
166
	struct vmbus_channel *channel;
167

168
	channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
169 170 171
	if (!channel)
		return NULL;

172
	spin_lock_init(&channel->inbound_lock);
173

174 175
	channel->controlwq = create_workqueue("hv_vmbus_ctl");
	if (!channel->controlwq) {
176
		kfree(channel);
177 178 179 180 181 182
		return NULL;
	}

	return channel;
}

183
/*
184
 * release_hannel - Release the vmbus channel object itself
185
 */
186
static void release_channel(struct work_struct *work)
187
{
188 189 190
	struct vmbus_channel *channel = container_of(work,
						     struct vmbus_channel,
						     work);
191

192
	destroy_workqueue(channel->controlwq);
193

194
	kfree(channel);
195 196
}

197
/*
198
 * free_channel - Release the resources used by the vmbus channel object
199
 */
200
void free_channel(struct vmbus_channel *channel)
201 202
{

203 204 205 206 207
	/*
	 * We have to release the channel's workqueue/thread in the vmbus's
	 * workqueue/thread context
	 * ie we can't destroy ourselves.
	 */
208
	INIT_WORK(&channel->work, release_channel);
209
	queue_work(vmbus_connection.work_queue, &channel->work);
210 211
}

212 213


214 215 216 217 218 219 220 221 222 223
/*
 * vmbus_process_rescind_offer -
 * Rescind the offer by initiating a device removal
 */
static void vmbus_process_rescind_offer(struct work_struct *work)
{
	struct vmbus_channel *channel = container_of(work,
						     struct vmbus_channel,
						     work);

224
	vmbus_device_unregister(channel->device_obj);
225
}
226

227
/*
228
 * vmbus_process_offer - Process the offer by creating a channel/device
229
 * associated with this offer
230
 */
231
static void vmbus_process_offer(struct work_struct *work)
232
{
233 234 235
	struct vmbus_channel *newchannel = container_of(work,
							struct vmbus_channel,
							work);
236
	struct vmbus_channel *channel;
237
	bool fnew = true;
238
	int ret;
239
	unsigned long flags;
240

241 242 243
	/* The next possible work is rescind handling */
	INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);

244
	/* Make sure this is a new offer */
245
	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
246

247
	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
248 249 250 251
		if (!uuid_le_cmp(channel->offermsg.offer.if_type,
			newchannel->offermsg.offer.if_type) &&
			!uuid_le_cmp(channel->offermsg.offer.if_instance,
				newchannel->offermsg.offer.if_instance)) {
252
			fnew = false;
253 254 255 256
			break;
		}
	}

257
	if (fnew)
258
		list_add_tail(&newchannel->listentry,
259
			      &vmbus_connection.chn_list);
260

261
	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
262

263
	if (!fnew) {
264
		free_channel(newchannel);
265 266 267
		return;
	}

268 269 270
	/*
	 * Start the process of binding this offer to the driver
	 * We need to set the DeviceObject field before calling
271
	 * vmbus_child_dev_add()
272
	 */
273
	newchannel->device_obj = vmbus_device_create(
274 275
		&newchannel->offermsg.offer.if_type,
		&newchannel->offermsg.offer.if_instance,
276
		newchannel);
277

278 279 280 281 282
	/*
	 * Add the new device to the bus. This will kick off device-driver
	 * binding which eventually invokes the device driver's AddDevice()
	 * method.
	 */
283
	ret = vmbus_device_register(newchannel->device_obj);
284
	if (ret != 0) {
285
		pr_err("unable to add child device object (relid %d)\n",
286
			   newchannel->offermsg.child_relid);
287

288
		spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
289
		list_del(&newchannel->listentry);
290
		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
291

292
		free_channel(newchannel);
293
	} else {
294 295 296 297 298
		/*
		 * This state is used to indicate a successful open
		 * so that when we do close the channel normally, we
		 * can cleanup properly
		 */
299
		newchannel->state = CHANNEL_OPEN_STATE;
300 301 302
	}
}

303
/*
304
 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
305 306
 *
 */
307
static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
308
{
309
	struct vmbus_channel_offer_channel *offer;
310
	struct vmbus_channel *newchannel;
311 312
	uuid_le *guidtype;
	uuid_le *guidinstance;
313
	int i;
314
	int fsupported = 0;
315

316 317
	offer = (struct vmbus_channel_offer_channel *)hdr;
	for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
318 319
		if (!uuid_le_cmp(offer->offer.if_type,
				supported_device_classes[i])) {
320
			fsupported = 1;
321 322 323 324
			break;
		}
	}

325
	if (!fsupported)
326 327
		return;

328 329
	guidtype = &offer->offer.if_type;
	guidinstance = &offer->offer.if_instance;
330

331
	/* Allocate the channel object and save this offer. */
332
	newchannel = alloc_channel();
333
	if (!newchannel) {
334
		pr_err("Unable to allocate channel object\n");
335 336 337
		return;
	}

338
	memcpy(&newchannel->offermsg, offer,
339
	       sizeof(struct vmbus_channel_offer_channel));
340 341
	newchannel->monitor_grp = (u8)offer->monitorid / 32;
	newchannel->monitor_bit = (u8)offer->monitorid % 32;
342

343 344
	INIT_WORK(&newchannel->work, vmbus_process_offer);
	queue_work(newchannel->controlwq, &newchannel->work);
345 346
}

347
/*
348
 * vmbus_onoffer_rescind - Rescind offer handler.
349 350 351
 *
 * We queue a work item to process this offer synchronously
 */
352
static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
353
{
354
	struct vmbus_channel_rescind_offer *rescind;
355
	struct vmbus_channel *channel;
356

357
	rescind = (struct vmbus_channel_rescind_offer *)hdr;
358
	channel = relid2channel(rescind->child_relid);
359 360 361

	if (channel == NULL)
		/* Just return here, no channel found */
362 363
		return;

364 365 366
	/* work is initialized for vmbus_process_rescind_offer() from
	 * vmbus_process_offer() where the channel got created */
	queue_work(channel->controlwq, &channel->work);
367 368
}

369
/*
370 371
 * vmbus_onoffers_delivered -
 * This is invoked when all offers have been delivered.
372 373 374
 *
 * Nothing to do here.
 */
375
static void vmbus_onoffers_delivered(
376
			struct vmbus_channel_message_header *hdr)
377 378 379
{
}

380
/*
381
 * vmbus_onopen_result - Open result handler.
382 383 384 385 386
 *
 * This is invoked when we received a response to our channel open request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
387
static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
388
{
389
	struct vmbus_channel_open_result *result;
390 391 392
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_open_channel *openmsg;
393
	unsigned long flags;
394

395
	result = (struct vmbus_channel_open_result *)hdr;
396

397 398 399
	/*
	 * Find the open msg, copy the result and signal/unblock the wait event
	 */
400
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
401

402 403
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
404
		requestheader =
405
			(struct vmbus_channel_message_header *)msginfo->msg;
406

407
		if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
408
			openmsg =
409 410 411 412
			(struct vmbus_channel_open_channel *)msginfo->msg;
			if (openmsg->child_relid == result->child_relid &&
			    openmsg->openid == result->openid) {
				memcpy(&msginfo->response.open_result,
413
				       result,
414 415 416
				       sizeof(
					struct vmbus_channel_open_result));
				complete(&msginfo->waitevent);
417 418 419 420
				break;
			}
		}
	}
421
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
422 423
}

424
/*
425
 * vmbus_ongpadl_created - GPADL created handler.
426 427 428 429 430
 *
 * This is invoked when we received a response to our gpadl create request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
431
static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
432
{
433 434 435 436
	struct vmbus_channel_gpadl_created *gpadlcreated;
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_gpadl_header *gpadlheader;
437
	unsigned long flags;
438

439
	gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
440

441 442 443 444
	/*
	 * Find the establish msg, copy the result and signal/unblock the wait
	 * event
	 */
445
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
446

447 448
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
449
		requestheader =
450
			(struct vmbus_channel_message_header *)msginfo->msg;
451

452
		if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
453 454 455
			gpadlheader =
			(struct vmbus_channel_gpadl_header *)requestheader;

456 457 458 459
			if ((gpadlcreated->child_relid ==
			     gpadlheader->child_relid) &&
			    (gpadlcreated->gpadl == gpadlheader->gpadl)) {
				memcpy(&msginfo->response.gpadl_created,
460
				       gpadlcreated,
461 462 463
				       sizeof(
					struct vmbus_channel_gpadl_created));
				complete(&msginfo->waitevent);
464 465 466 467
				break;
			}
		}
	}
468
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
469 470
}

471
/*
472
 * vmbus_ongpadl_torndown - GPADL torndown handler.
473 474 475 476 477
 *
 * This is invoked when we received a response to our gpadl teardown request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
478
static void vmbus_ongpadl_torndown(
479
			struct vmbus_channel_message_header *hdr)
480
{
481 482 483 484
	struct vmbus_channel_gpadl_torndown *gpadl_torndown;
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_gpadl_teardown *gpadl_teardown;
485
	unsigned long flags;
486

487
	gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
488 489 490 491

	/*
	 * Find the open msg, copy the result and signal/unblock the wait event
	 */
492
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
493

494 495
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
496
		requestheader =
497
			(struct vmbus_channel_message_header *)msginfo->msg;
498

499
		if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
500 501
			gpadl_teardown =
			(struct vmbus_channel_gpadl_teardown *)requestheader;
502

503 504
			if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
				memcpy(&msginfo->response.gpadl_torndown,
505
				       gpadl_torndown,
506 507 508
				       sizeof(
					struct vmbus_channel_gpadl_torndown));
				complete(&msginfo->waitevent);
509 510 511 512
				break;
			}
		}
	}
513
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
514 515
}

516
/*
517
 * vmbus_onversion_response - Version response handler
518 519 520 521 522
 *
 * This is invoked when we received a response to our initiate contact request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
523
static void vmbus_onversion_response(
524
		struct vmbus_channel_message_header *hdr)
525
{
526 527
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
528
	struct vmbus_channel_initiate_contact *initiate;
529
	struct vmbus_channel_version_response *version_response;
530
	unsigned long flags;
531

532
	version_response = (struct vmbus_channel_version_response *)hdr;
533
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
534

535 536
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
537
		requestheader =
538
			(struct vmbus_channel_message_header *)msginfo->msg;
539

540 541
		if (requestheader->msgtype ==
		    CHANNELMSG_INITIATE_CONTACT) {
542 543
			initiate =
			(struct vmbus_channel_initiate_contact *)requestheader;
544
			memcpy(&msginfo->response.version_response,
545
			      version_response,
546
			      sizeof(struct vmbus_channel_version_response));
547
			complete(&msginfo->waitevent);
548 549
		}
	}
550
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
551 552
}

553 554
/* Channel message dispatch table */
static struct vmbus_channel_message_table_entry
555
	channel_message_table[CHANNELMSG_COUNT] = {
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
	{CHANNELMSG_INVALID,			NULL},
	{CHANNELMSG_OFFERCHANNEL,		vmbus_onoffer},
	{CHANNELMSG_RESCIND_CHANNELOFFER,	vmbus_onoffer_rescind},
	{CHANNELMSG_REQUESTOFFERS,		NULL},
	{CHANNELMSG_ALLOFFERS_DELIVERED,	vmbus_onoffers_delivered},
	{CHANNELMSG_OPENCHANNEL,		NULL},
	{CHANNELMSG_OPENCHANNEL_RESULT,	vmbus_onopen_result},
	{CHANNELMSG_CLOSECHANNEL,		NULL},
	{CHANNELMSG_GPADL_HEADER,		NULL},
	{CHANNELMSG_GPADL_BODY,		NULL},
	{CHANNELMSG_GPADL_CREATED,		vmbus_ongpadl_created},
	{CHANNELMSG_GPADL_TEARDOWN,		NULL},
	{CHANNELMSG_GPADL_TORNDOWN,		vmbus_ongpadl_torndown},
	{CHANNELMSG_RELID_RELEASED,		NULL},
	{CHANNELMSG_INITIATE_CONTACT,		NULL},
	{CHANNELMSG_VERSION_RESPONSE,		vmbus_onversion_response},
	{CHANNELMSG_UNLOAD,			NULL},
573 574
};

575
/*
576
 * vmbus_onmessage - Handler for channel protocol messages.
577 578 579
 *
 * This is invoked in the vmbus worker thread context.
 */
580
void vmbus_onmessage(void *context)
581
{
582
	struct hv_message *msg = context;
583
	struct vmbus_channel_message_header *hdr;
584 585
	int size;

586 587
	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
	size = msg->header.payload_size;
588

589
	if (hdr->msgtype >= CHANNELMSG_COUNT) {
590
		pr_err("Received invalid channel message type %d size %d\n",
591
			   hdr->msgtype, size);
592
		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
593
				     (unsigned char *)msg->u.payload, size);
594 595 596
		return;
	}

597 598
	if (channel_message_table[hdr->msgtype].message_handler)
		channel_message_table[hdr->msgtype].message_handler(hdr);
599
	else
600
		pr_err("Unhandled channel message type %d\n", hdr->msgtype);
601 602
}

603
/*
604
 * vmbus_request_offers - Send a request to get all our pending offers.
605
 */
606
int vmbus_request_offers(void)
607
{
608
	struct vmbus_channel_message_header *msg;
609
	struct vmbus_channel_msginfo *msginfo;
610
	int ret, t;
611

612
	msginfo = kmalloc(sizeof(*msginfo) +
613 614
			  sizeof(struct vmbus_channel_message_header),
			  GFP_KERNEL);
615
	if (!msginfo)
616
		return -ENOMEM;
617

618
	init_completion(&msginfo->waitevent);
619

620
	msg = (struct vmbus_channel_message_header *)msginfo->msg;
621

622
	msg->msgtype = CHANNELMSG_REQUESTOFFERS;
623 624


625
	ret = vmbus_post_msg(msg,
626 627
			       sizeof(struct vmbus_channel_message_header));
	if (ret != 0) {
628
		pr_err("Unable to request offers - %d\n", ret);
629

630 631
		goto cleanup;
	}
632

633
	t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
634
	if (t == 0) {
635 636
		ret = -ETIMEDOUT;
		goto cleanup;
637 638 639 640
	}



641
cleanup:
642
	kfree(msginfo);
643 644 645 646

	return ret;
}

647
/* eof */