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 */