Staging: hv: remove use of internal list routines in NetVsc
[deliverable/linux.git] / drivers / staging / hv / ChannelMgmt.c
CommitLineData
3e7ee490 1/*
3e7ee490
HJ
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>
3e7ee490 20 */
a0086dc5
GKH
21#include <linux/kernel.h>
22#include <linux/mm.h>
4983b39a 23#include "osd.h"
645954c5 24#include "logging.h"
3e7ee490
HJ
25#include "VmbusPrivate.h"
26
1d7e907f 27struct vmbus_channel_message_table_entry {
c8212f04
GKH
28 enum vmbus_channel_message_type messageType;
29 void (*messageHandler)(struct vmbus_channel_message_header *msg);
1d7e907f 30};
3e7ee490 31
3e7ee490 32#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4
bd60c33e
GKH
33static const struct hv_guid
34 gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
454f18a9 35 /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
caf26a31
GKH
36 /* Storage - SCSI */
37 {
38 .data = {
39 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
40 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
41 }
42 },
43
454f18a9 44 /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
caf26a31
GKH
45 /* Network */
46 {
47 .data = {
48 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
49 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
50 }
51 },
52
454f18a9 53 /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
caf26a31
GKH
54 /* Input */
55 {
56 .data = {
57 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
58 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
59 }
60 },
3e7ee490 61
caf26a31
GKH
62 /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
63 /* IDE */
64 {
65 .data = {
66 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
67 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
68 }
69 },
3e7ee490
HJ
70};
71
bd60c33e
GKH
72/**
73 * AllocVmbusChannel - Allocate and initialize a vmbus channel object
74 */
aded7165 75struct vmbus_channel *AllocVmbusChannel(void)
3e7ee490 76{
aded7165 77 struct vmbus_channel *channel;
3e7ee490 78
aded7165 79 channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
3e7ee490 80 if (!channel)
3e7ee490 81 return NULL;
3e7ee490 82
54411c42 83 spin_lock_init(&channel->inbound_lock);
3e7ee490 84
c8a429a4
GKH
85 init_timer(&channel->poll_timer);
86 channel->poll_timer.data = (unsigned long)channel;
87 channel->poll_timer.function = VmbusChannelOnTimer;
3e7ee490 88
de65a384 89 channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
bd60c33e 90 if (!channel->ControlWQ) {
8c69f52a 91 kfree(channel);
3e7ee490
HJ
92 return NULL;
93 }
94
95 return channel;
96}
97
bd60c33e
GKH
98/**
99 * ReleaseVmbusChannel - Release the vmbus channel object itself
100 */
101static inline void ReleaseVmbusChannel(void *context)
3e7ee490 102{
bd60c33e 103 struct vmbus_channel *channel = context;
3e7ee490
HJ
104
105 DPRINT_ENTER(VMBUS);
106
107 DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
de65a384 108 destroy_workqueue(channel->ControlWQ);
3e7ee490
HJ
109 DPRINT_DBG(VMBUS, "channel released (%p)", channel);
110
8c69f52a 111 kfree(channel);
3e7ee490
HJ
112
113 DPRINT_EXIT(VMBUS);
114}
115
bd60c33e
GKH
116/**
117 * FreeVmbusChannel - Release the resources used by the vmbus channel object
118 */
aded7165 119void FreeVmbusChannel(struct vmbus_channel *Channel)
3e7ee490 120{
c8a429a4 121 del_timer(&Channel->poll_timer);
3e7ee490 122
bd60c33e
GKH
123 /*
124 * We have to release the channel's workqueue/thread in the vmbus's
125 * workqueue/thread context
126 * ie we can't destroy ourselves.
127 */
de65a384 128 osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
bd60c33e 129 Channel);
3e7ee490
HJ
130}
131
bd60c33e
GKH
132/**
133 * VmbusChannelProcessOffer - Process the offer by creating a channel/device associated with this offer
134 */
135static void VmbusChannelProcessOffer(void *context)
3e7ee490 136{
aded7165
GKH
137 struct vmbus_channel *newChannel = context;
138 struct vmbus_channel *channel;
bd60c33e
GKH
139 LIST_ENTRY *anchor;
140 LIST_ENTRY *curr;
0e727613 141 bool fNew = true;
bd60c33e 142 int ret;
0f5e44ca 143 unsigned long flags;
3e7ee490
HJ
144
145 DPRINT_ENTER(VMBUS);
146
454f18a9 147 /* Make sure this is a new offer */
0f5e44ca 148 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
3e7ee490 149
bd60c33e
GKH
150 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList) {
151 channel = CONTAINING_RECORD(curr, struct vmbus_channel,
152 ListEntry);
3e7ee490 153
bd60c33e
GKH
154 if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
155 &newChannel->OfferMsg.Offer.InterfaceType,
156 sizeof(struct hv_guid)) &&
157 !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
158 &newChannel->OfferMsg.Offer.InterfaceInstance,
159 sizeof(struct hv_guid))) {
0e727613 160 fNew = false;
3e7ee490
HJ
161 break;
162 }
163 }
164
165 if (fNew)
bd60c33e
GKH
166 INSERT_TAIL_LIST(&gVmbusConnection.ChannelList,
167 &newChannel->ListEntry);
168
0f5e44ca 169 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
3e7ee490 170
bd60c33e
GKH
171 if (!fNew) {
172 DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
173 newChannel->OfferMsg.ChildRelId);
3e7ee490
HJ
174 FreeVmbusChannel(newChannel);
175 DPRINT_EXIT(VMBUS);
176 return;
177 }
178
bd60c33e
GKH
179 /*
180 * Start the process of binding this offer to the driver
181 * We need to set the DeviceObject field before calling
182 * VmbusChildDeviceAdd()
183 */
3e7ee490 184 newChannel->DeviceObject = VmbusChildDeviceCreate(
daaa8cc3
GKH
185 &newChannel->OfferMsg.Offer.InterfaceType,
186 &newChannel->OfferMsg.Offer.InterfaceInstance,
3e7ee490
HJ
187 newChannel);
188
bd60c33e
GKH
189 DPRINT_DBG(VMBUS, "child device object allocated - %p",
190 newChannel->DeviceObject);
3e7ee490 191
454f18a9
BP
192 /*
193 * Add the new device to the bus. This will kick off device-driver
194 * binding which eventually invokes the device driver's AddDevice()
195 * method.
196 */
3e7ee490 197 ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
bd60c33e
GKH
198 if (ret != 0) {
199 DPRINT_ERR(VMBUS,
200 "unable to add child device object (relid %d)",
201 newChannel->OfferMsg.ChildRelId);
3e7ee490 202
0f5e44ca 203 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
3e7ee490 204 REMOVE_ENTRY_LIST(&newChannel->ListEntry);
0f5e44ca 205 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
3e7ee490
HJ
206
207 FreeVmbusChannel(newChannel);
bd60c33e 208 } else {
454f18a9
BP
209 /*
210 * This state is used to indicate a successful open
211 * so that when we do close the channel normally, we
212 * can cleanup properly
213 */
3e7ee490
HJ
214 newChannel->State = CHANNEL_OPEN_STATE;
215 }
216 DPRINT_EXIT(VMBUS);
217}
218
bd60c33e
GKH
219/**
220 * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
221 */
222static void VmbusChannelProcessRescindOffer(void *context)
3e7ee490 223{
aded7165 224 struct vmbus_channel *channel = context;
3e7ee490
HJ
225
226 DPRINT_ENTER(VMBUS);
3e7ee490 227 VmbusChildDeviceRemove(channel->DeviceObject);
3e7ee490
HJ
228 DPRINT_EXIT(VMBUS);
229}
230
bd60c33e
GKH
231/**
232 * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
233 *
234 * We ignore all offers except network and storage offers. For each network and
235 * storage offers, we create a channel object and queue a work item to the
236 * channel object to process the offer synchronously
237 */
82250213 238static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
3e7ee490 239{
bd60c33e 240 struct vmbus_channel_offer_channel *offer;
aded7165 241 struct vmbus_channel *newChannel;
caf26a31
GKH
242 struct hv_guid *guidType;
243 struct hv_guid *guidInstance;
3e7ee490 244 int i;
bd60c33e 245 int fSupported = 0;
3e7ee490
HJ
246
247 DPRINT_ENTER(VMBUS);
248
bd60c33e
GKH
249 offer = (struct vmbus_channel_offer_channel *)hdr;
250 for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
251 if (memcmp(&offer->Offer.InterfaceType,
252 &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
3e7ee490
HJ
253 fSupported = 1;
254 break;
255 }
256 }
257
bd60c33e
GKH
258 if (!fSupported) {
259 DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
260 "child relid %d", offer->ChildRelId);
3e7ee490 261 DPRINT_EXIT(VMBUS);
3e7ee490
HJ
262 return;
263 }
264
265 guidType = &offer->Offer.InterfaceType;
266 guidInstance = &offer->Offer.InterfaceInstance;
267
bd60c33e
GKH
268 DPRINT_INFO(VMBUS, "Channel offer notification - "
269 "child relid %d monitor id %d allocated %d, "
270 "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
271 "%02x%02x%02x%02x%02x%02x%02x%02x} "
272 "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
273 "%02x%02x%02x%02x%02x%02x%02x%02x}",
274 offer->ChildRelId, offer->MonitorId,
275 offer->MonitorAllocated,
276 guidType->data[3], guidType->data[2],
277 guidType->data[1], guidType->data[0],
278 guidType->data[5], guidType->data[4],
279 guidType->data[7], guidType->data[6],
280 guidType->data[8], guidType->data[9],
281 guidType->data[10], guidType->data[11],
282 guidType->data[12], guidType->data[13],
283 guidType->data[14], guidType->data[15],
284 guidInstance->data[3], guidInstance->data[2],
285 guidInstance->data[1], guidInstance->data[0],
286 guidInstance->data[5], guidInstance->data[4],
287 guidInstance->data[7], guidInstance->data[6],
288 guidInstance->data[8], guidInstance->data[9],
289 guidInstance->data[10], guidInstance->data[11],
290 guidInstance->data[12], guidInstance->data[13],
291 guidInstance->data[14], guidInstance->data[15]);
3e7ee490 292
454f18a9 293 /* Allocate the channel object and save this offer. */
3e7ee490 294 newChannel = AllocVmbusChannel();
bd60c33e 295 if (!newChannel) {
3e7ee490
HJ
296 DPRINT_ERR(VMBUS, "unable to allocate channel object");
297 return;
298 }
299
300 DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
301
bd60c33e
GKH
302 memcpy(&newChannel->OfferMsg, offer,
303 sizeof(struct vmbus_channel_offer_channel));
5654e932
GKH
304 newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
305 newChannel->MonitorBit = (u8)offer->MonitorId % 32;
3e7ee490 306
454f18a9 307 /* TODO: Make sure the offer comes from our parent partition */
de65a384
BP
308 osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
309 newChannel);
3e7ee490
HJ
310
311 DPRINT_EXIT(VMBUS);
312}
313
bd60c33e
GKH
314/**
315 * VmbusChannelOnOfferRescind - Rescind offer handler.
316 *
317 * We queue a work item to process this offer synchronously
318 */
82250213 319static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
3e7ee490 320{
bd60c33e 321 struct vmbus_channel_rescind_offer *rescind;
aded7165 322 struct vmbus_channel *channel;
3e7ee490
HJ
323
324 DPRINT_ENTER(VMBUS);
325
bd60c33e 326 rescind = (struct vmbus_channel_rescind_offer *)hdr;
3e7ee490 327 channel = GetChannelFromRelId(rescind->ChildRelId);
bd60c33e
GKH
328 if (channel == NULL) {
329 DPRINT_DBG(VMBUS, "channel not found for relId %d",
330 rescind->ChildRelId);
3e7ee490
HJ
331 return;
332 }
333
de65a384
BP
334 osd_schedule_callback(channel->ControlWQ,
335 VmbusChannelProcessRescindOffer,
336 channel);
3e7ee490
HJ
337
338 DPRINT_EXIT(VMBUS);
339}
340
bd60c33e
GKH
341/**
342 * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
343 *
344 * Nothing to do here.
345 */
346static void VmbusChannelOnOffersDelivered(
347 struct vmbus_channel_message_header *hdr)
3e7ee490
HJ
348{
349 DPRINT_ENTER(VMBUS);
350 DPRINT_EXIT(VMBUS);
351}
352
bd60c33e
GKH
353/**
354 * VmbusChannelOnOpenResult - Open result handler.
355 *
356 * This is invoked when we received a response to our channel open request.
357 * Find the matching request, copy the response and signal the requesting
358 * thread.
359 */
82250213 360static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
3e7ee490 361{
bd60c33e
GKH
362 struct vmbus_channel_open_result *result;
363 LIST_ENTRY *anchor;
364 LIST_ENTRY *curr;
aded7165 365 struct vmbus_channel_msginfo *msgInfo;
82250213
GKH
366 struct vmbus_channel_message_header *requestHeader;
367 struct vmbus_channel_open_channel *openMsg;
dd0813b6 368 unsigned long flags;
3e7ee490
HJ
369
370 DPRINT_ENTER(VMBUS);
371
bd60c33e 372 result = (struct vmbus_channel_open_result *)hdr;
3e7ee490
HJ
373 DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
374
bd60c33e
GKH
375 /*
376 * Find the open msg, copy the result and signal/unblock the wait event
377 */
dd0813b6 378 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490 379
bd60c33e 380 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) {
aded7165 381 msgInfo = (struct vmbus_channel_msginfo *)curr;
82250213 382 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490 383
bd60c33e 384 if (requestHeader->MessageType == ChannelMessageOpenChannel) {
82250213 385 openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
3e7ee490 386 if (openMsg->ChildRelId == result->ChildRelId &&
bd60c33e
GKH
387 openMsg->OpenId == result->OpenId) {
388 memcpy(&msgInfo->Response.OpenResult,
389 result,
390 sizeof(struct vmbus_channel_open_result));
bfc30aae 391 osd_WaitEventSet(msgInfo->WaitEvent);
3e7ee490
HJ
392 break;
393 }
394 }
395 }
dd0813b6 396 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490
HJ
397
398 DPRINT_EXIT(VMBUS);
399}
400
bd60c33e
GKH
401/**
402 * VmbusChannelOnGpadlCreated - GPADL created handler.
403 *
404 * This is invoked when we received a response to our gpadl create request.
405 * Find the matching request, copy the response and signal the requesting
406 * thread.
407 */
82250213 408static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
3e7ee490 409{
bd60c33e 410 struct vmbus_channel_gpadl_created *gpadlCreated;
3e7ee490
HJ
411 LIST_ENTRY *anchor;
412 LIST_ENTRY *curr;
aded7165 413 struct vmbus_channel_msginfo *msgInfo;
82250213
GKH
414 struct vmbus_channel_message_header *requestHeader;
415 struct vmbus_channel_gpadl_header *gpadlHeader;
dd0813b6 416 unsigned long flags;
3e7ee490
HJ
417
418 DPRINT_ENTER(VMBUS);
419
bd60c33e
GKH
420 gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
421 DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
422 gpadlCreated->CreationStatus);
3e7ee490 423
bd60c33e
GKH
424 /*
425 * Find the establish msg, copy the result and signal/unblock the wait
426 * event
427 */
dd0813b6 428 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490 429
bd60c33e 430 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) {
aded7165 431 msgInfo = (struct vmbus_channel_msginfo *)curr;
82250213 432 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490 433
bd60c33e 434 if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
82250213 435 gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
3e7ee490 436
bd60c33e
GKH
437 if ((gpadlCreated->ChildRelId ==
438 gpadlHeader->ChildRelId) &&
439 (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
440 memcpy(&msgInfo->Response.GpadlCreated,
441 gpadlCreated,
442 sizeof(struct vmbus_channel_gpadl_created));
bfc30aae 443 osd_WaitEventSet(msgInfo->WaitEvent);
3e7ee490
HJ
444 break;
445 }
446 }
447 }
dd0813b6 448 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490
HJ
449
450 DPRINT_EXIT(VMBUS);
451}
452
bd60c33e
GKH
453/**
454 * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
455 *
456 * This is invoked when we received a response to our gpadl teardown request.
457 * Find the matching request, copy the response and signal the requesting
458 * thread.
459 */
460static void VmbusChannelOnGpadlTorndown(
461 struct vmbus_channel_message_header *hdr)
3e7ee490 462{
bd60c33e
GKH
463 struct vmbus_channel_gpadl_torndown *gpadlTorndown;
464 LIST_ENTRY *anchor;
465 LIST_ENTRY *curr;
aded7165 466 struct vmbus_channel_msginfo *msgInfo;
82250213
GKH
467 struct vmbus_channel_message_header *requestHeader;
468 struct vmbus_channel_gpadl_teardown *gpadlTeardown;
dd0813b6 469 unsigned long flags;
3e7ee490
HJ
470
471 DPRINT_ENTER(VMBUS);
472
bd60c33e
GKH
473 gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
474
475 /*
476 * Find the open msg, copy the result and signal/unblock the wait event
477 */
dd0813b6 478 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490 479
bd60c33e 480 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) {
aded7165 481 msgInfo = (struct vmbus_channel_msginfo *)curr;
82250213 482 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490 483
bd60c33e 484 if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
82250213 485 gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
3e7ee490 486
bd60c33e
GKH
487 if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
488 memcpy(&msgInfo->Response.GpadlTorndown,
489 gpadlTorndown,
490 sizeof(struct vmbus_channel_gpadl_torndown));
bfc30aae 491 osd_WaitEventSet(msgInfo->WaitEvent);
3e7ee490
HJ
492 break;
493 }
494 }
495 }
dd0813b6 496 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490
HJ
497
498 DPRINT_EXIT(VMBUS);
499}
500
bd60c33e
GKH
501/**
502 * VmbusChannelOnVersionResponse - Version response handler
503 *
504 * This is invoked when we received a response to our initiate contact request.
505 * Find the matching request, copy the response and signal the requesting
506 * thread.
507 */
508static void VmbusChannelOnVersionResponse(
509 struct vmbus_channel_message_header *hdr)
3e7ee490 510{
bd60c33e
GKH
511 LIST_ENTRY *anchor;
512 LIST_ENTRY *curr;
aded7165 513 struct vmbus_channel_msginfo *msgInfo;
82250213
GKH
514 struct vmbus_channel_message_header *requestHeader;
515 struct vmbus_channel_initiate_contact *initiate;
bd60c33e 516 struct vmbus_channel_version_response *versionResponse;
dd0813b6 517 unsigned long flags;
3e7ee490
HJ
518
519 DPRINT_ENTER(VMBUS);
520
bd60c33e 521 versionResponse = (struct vmbus_channel_version_response *)hdr;
dd0813b6 522 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490 523
bd60c33e 524 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) {
aded7165 525 msgInfo = (struct vmbus_channel_msginfo *)curr;
82250213 526 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490 527
bd60c33e
GKH
528 if (requestHeader->MessageType ==
529 ChannelMessageInitiateContact) {
82250213 530 initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
bd60c33e
GKH
531 memcpy(&msgInfo->Response.VersionResponse,
532 versionResponse,
533 sizeof(struct vmbus_channel_version_response));
bfc30aae 534 osd_WaitEventSet(msgInfo->WaitEvent);
3e7ee490
HJ
535 }
536 }
dd0813b6 537 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490
HJ
538
539 DPRINT_EXIT(VMBUS);
540}
541
c8212f04
GKH
542/* Channel message dispatch table */
543static struct vmbus_channel_message_table_entry
544 gChannelMessageTable[ChannelMessageCount] = {
545 {ChannelMessageInvalid, NULL},
546 {ChannelMessageOfferChannel, VmbusChannelOnOffer},
547 {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind},
548 {ChannelMessageRequestOffers, NULL},
549 {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered},
550 {ChannelMessageOpenChannel, NULL},
551 {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult},
552 {ChannelMessageCloseChannel, NULL},
553 {ChannelMessageGpadlHeader, NULL},
554 {ChannelMessageGpadlBody, NULL},
555 {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated},
556 {ChannelMessageGpadlTeardown, NULL},
557 {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown},
558 {ChannelMessageRelIdReleased, NULL},
559 {ChannelMessageInitiateContact, NULL},
560 {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse},
561 {ChannelMessageUnload, NULL},
562};
563
bd60c33e
GKH
564/**
565 * VmbusOnChannelMessage - Handler for channel protocol messages.
566 *
567 * This is invoked in the vmbus worker thread context.
568 */
b239549c 569void VmbusOnChannelMessage(void *Context)
3e7ee490 570{
eacb1b4d 571 struct hv_message *msg = Context;
82250213 572 struct vmbus_channel_message_header *hdr;
3e7ee490
HJ
573 int size;
574
575 DPRINT_ENTER(VMBUS);
576
82250213 577 hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
bd60c33e 578 size = msg->Header.PayloadSize;
3e7ee490
HJ
579
580 DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
581
bd60c33e
GKH
582 if (hdr->MessageType >= ChannelMessageCount) {
583 DPRINT_ERR(VMBUS,
584 "Received invalid channel message type %d size %d",
585 hdr->MessageType, size);
04f50c4d
GKH
586 print_hex_dump_bytes("", DUMP_PREFIX_NONE,
587 (unsigned char *)msg->u.Payload, size);
8c69f52a 588 kfree(msg);
3e7ee490
HJ
589 return;
590 }
591
592 if (gChannelMessageTable[hdr->MessageType].messageHandler)
3e7ee490 593 gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
3e7ee490 594 else
bd60c33e
GKH
595 DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
596 hdr->MessageType);
3e7ee490 597
454f18a9 598 /* Free the msg that was allocated in VmbusOnMsgDPC() */
8c69f52a 599 kfree(msg);
3e7ee490
HJ
600 DPRINT_EXIT(VMBUS);
601}
602
bd60c33e
GKH
603/**
604 * VmbusChannelRequestOffers - Send a request to get all our pending offers.
605 */
b239549c 606int VmbusChannelRequestOffers(void)
3e7ee490 607{
82250213 608 struct vmbus_channel_message_header *msg;
aded7165 609 struct vmbus_channel_msginfo *msgInfo;
bd60c33e 610 int ret;
3e7ee490
HJ
611
612 DPRINT_ENTER(VMBUS);
613
bd60c33e
GKH
614 msgInfo = kmalloc(sizeof(*msgInfo) +
615 sizeof(struct vmbus_channel_message_header),
616 GFP_KERNEL);
3e7ee490
HJ
617 ASSERT(msgInfo != NULL);
618
bfc30aae 619 msgInfo->WaitEvent = osd_WaitEventCreate();
82250213 620 msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490
HJ
621
622 msg->MessageType = ChannelMessageRequestOffers;
623
624 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
bd60c33e
GKH
625 INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
626 &msgInfo->msgListEntry);
3e7ee490
HJ
627 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
628
bd60c33e
GKH
629 ret = VmbusPostMessage(msg,
630 sizeof(struct vmbus_channel_message_header));
631 if (ret != 0) {
3e7ee490
HJ
632 DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
633
634 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
635 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
636 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
637
638 goto Cleanup;
639 }
bfc30aae 640 /* osd_WaitEventWait(msgInfo->waitEvent); */
3e7ee490
HJ
641
642 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
643 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
644 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
645
646
647Cleanup:
bd60c33e 648 if (msgInfo) {
420beac4 649 kfree(msgInfo->WaitEvent);
8c69f52a 650 kfree(msgInfo);
3e7ee490
HJ
651 }
652
653 DPRINT_EXIT(VMBUS);
3e7ee490
HJ
654 return ret;
655}
656
bd60c33e
GKH
657/**
658 * VmbusChannelReleaseUnattachedChannels - Release channels that are unattached/unconnected ie (no drivers associated)
659 */
b239549c 660void VmbusChannelReleaseUnattachedChannels(void)
3e7ee490
HJ
661{
662 LIST_ENTRY *entry;
aded7165
GKH
663 struct vmbus_channel *channel;
664 struct vmbus_channel *start = NULL;
0f5e44ca 665 unsigned long flags;
3e7ee490 666
0f5e44ca 667 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
3e7ee490 668
bd60c33e 669 while (!IsListEmpty(&gVmbusConnection.ChannelList)) {
3e7ee490 670 entry = TOP_LIST_ENTRY(&gVmbusConnection.ChannelList);
bd60c33e
GKH
671 channel = CONTAINING_RECORD(entry, struct vmbus_channel,
672 ListEntry);
3e7ee490
HJ
673
674 if (channel == start)
675 break;
676
bd60c33e 677 if (!channel->DeviceObject->Driver) {
3e7ee490 678 REMOVE_ENTRY_LIST(&channel->ListEntry);
bd60c33e
GKH
679 DPRINT_INFO(VMBUS,
680 "Releasing unattached device object %p",
681 channel->DeviceObject);
3e7ee490
HJ
682
683 VmbusChildDeviceRemove(channel->DeviceObject);
684 FreeVmbusChannel(channel);
bd60c33e 685 } else {
3e7ee490 686 if (!start)
3e7ee490 687 start = channel;
3e7ee490
HJ
688 }
689 }
690
0f5e44ca 691 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
3e7ee490
HJ
692}
693
454f18a9 694/* eof */
This page took 0.126305 seconds and 5 git commands to generate.