]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/hv/ChannelMgmt.c
Staging: hv: Remove check for NULL before calling kfree()
[net-next-2.6.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>
5a0e3ad6 23#include <linux/slab.h>
53af545b 24#include <linux/list.h>
c88c4e4c 25#include <linux/module.h>
4983b39a 26#include "osd.h"
645954c5 27#include "logging.h"
3e7ee490 28#include "VmbusPrivate.h"
c88c4e4c 29#include "utils.h"
3e7ee490 30
1d7e907f 31struct vmbus_channel_message_table_entry {
c8212f04
GKH
32 enum vmbus_channel_message_type messageType;
33 void (*messageHandler)(struct vmbus_channel_message_header *msg);
1d7e907f 34};
3e7ee490 35
c88c4e4c
HJ
36#define MAX_MSG_TYPES 1
37#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 5
38
bd60c33e 39static const struct hv_guid
c88c4e4c 40 gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
454f18a9 41 /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
caf26a31
GKH
42 /* Storage - SCSI */
43 {
44 .data = {
45 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
46 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
47 }
48 },
49
454f18a9 50 /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
caf26a31
GKH
51 /* Network */
52 {
53 .data = {
54 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
55 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
56 }
57 },
58
454f18a9 59 /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
caf26a31
GKH
60 /* Input */
61 {
62 .data = {
63 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
64 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
65 }
66 },
3e7ee490 67
caf26a31
GKH
68 /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
69 /* IDE */
70 {
71 .data = {
72 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
73 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
74 }
75 },
c88c4e4c
HJ
76 /* 0E0B6031-5213-4934-818B-38D90CED39DB */
77 /* Shutdown */
78 {
79 .data = {
80 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
81 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
82 }
83 },
3e7ee490
HJ
84};
85
c88c4e4c
HJ
86
87/**
88 * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
89 * @icmsghdrp: Pointer to msg header structure
90 * @icmsg_negotiate: Pointer to negotiate message structure
91 * @buf: Raw buffer channel data
92 *
93 * @icmsghdrp is of type &struct icmsg_hdr.
94 * @negop is of type &struct icmsg_negotiate.
95 * Set up and fill in default negotiate response message. This response can
96 * come from both the vmbus driver and the hv_utils driver. The current api
97 * will respond properly to both Windows 2008 and Windows 2008-R2 operating
98 * systems.
99 *
100 * Mainly used by Hyper-V drivers.
101 */
102void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
103 struct icmsg_negotiate *negop,
104 u8 *buf)
105{
106 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
107 icmsghdrp->icmsgsize = 0x10;
108
109 negop = (struct icmsg_negotiate *)&buf[
110 sizeof(struct vmbuspipe_hdr) +
111 sizeof(struct icmsg_hdr)];
112
113 if (negop->icframe_vercnt == 2 &&
114 negop->icversion_data[1].major == 3) {
115 negop->icversion_data[0].major = 3;
116 negop->icversion_data[0].minor = 0;
117 negop->icversion_data[1].major = 3;
118 negop->icversion_data[1].minor = 0;
119 } else {
120 negop->icversion_data[0].major = 1;
121 negop->icversion_data[0].minor = 0;
122 negop->icversion_data[1].major = 1;
123 negop->icversion_data[1].minor = 0;
124 }
125
126 negop->icframe_vercnt = 1;
127 negop->icmsg_vercnt = 1;
128 }
129}
130EXPORT_SYMBOL(prep_negotiate_resp);
131
132/**
133 * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
134 * Hyper-V requests
135 * @context: Pointer to argument structure.
136 *
137 * Set up the default handler for non device driver specific requests
138 * from Hyper-V. This stub responds to the default negotiate messages
139 * that come in for every non IDE/SCSI/Network request.
140 * This behavior is normally overwritten in the hv_utils driver. That
141 * driver handles requests like gracefull shutdown, heartbeats etc.
142 *
143 * Mainly used by Hyper-V drivers.
144 */
145void chn_cb_negotiate(void *context)
146{
147 struct vmbus_channel *channel = context;
148 u8 *buf;
149 u32 buflen, recvlen;
150 u64 requestid;
151
152 struct icmsg_hdr *icmsghdrp;
153 struct icmsg_negotiate *negop = NULL;
154
155 buflen = PAGE_SIZE;
156 buf = kmalloc(buflen, GFP_ATOMIC);
157
158 VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);
159
160 if (recvlen > 0) {
161 icmsghdrp = (struct icmsg_hdr *)&buf[
162 sizeof(struct vmbuspipe_hdr)];
163
164 prep_negotiate_resp(icmsghdrp, negop, buf);
165
166 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
167 | ICMSGHDRFLAG_RESPONSE;
168
169 VmbusChannelSendPacket(channel, buf,
170 recvlen, requestid,
171 VmbusPacketTypeDataInBand, 0);
172 }
173
174 kfree(buf);
175}
176EXPORT_SYMBOL(chn_cb_negotiate);
177
178/*
179 * Function table used for message responses for non IDE/SCSI/Network type
180 * messages. (Such as KVP/Shutdown etc)
181 */
182struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
183 /* 0E0B6031-5213-4934-818B-38D90CED39DB */
184 /* Shutdown */
185 {
186 .msg_type = HV_SHUTDOWN_MSG,
187 .data = {
188 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
189 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
190 },
191 .callback = chn_cb_negotiate,
192 .log_msg = "Shutdown channel functionality initialized"
193 },
194};
195EXPORT_SYMBOL(hv_cb_utils);
196
3e189519 197/*
bd60c33e
GKH
198 * AllocVmbusChannel - Allocate and initialize a vmbus channel object
199 */
aded7165 200struct vmbus_channel *AllocVmbusChannel(void)
3e7ee490 201{
aded7165 202 struct vmbus_channel *channel;
3e7ee490 203
aded7165 204 channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
3e7ee490 205 if (!channel)
3e7ee490 206 return NULL;
3e7ee490 207
54411c42 208 spin_lock_init(&channel->inbound_lock);
3e7ee490 209
c8a429a4
GKH
210 init_timer(&channel->poll_timer);
211 channel->poll_timer.data = (unsigned long)channel;
212 channel->poll_timer.function = VmbusChannelOnTimer;
3e7ee490 213
de65a384 214 channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
bd60c33e 215 if (!channel->ControlWQ) {
8c69f52a 216 kfree(channel);
3e7ee490
HJ
217 return NULL;
218 }
219
220 return channel;
221}
222
3e189519 223/*
bd60c33e
GKH
224 * ReleaseVmbusChannel - Release the vmbus channel object itself
225 */
226static inline void ReleaseVmbusChannel(void *context)
3e7ee490 227{
bd60c33e 228 struct vmbus_channel *channel = context;
3e7ee490
HJ
229
230 DPRINT_ENTER(VMBUS);
231
232 DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
de65a384 233 destroy_workqueue(channel->ControlWQ);
3e7ee490
HJ
234 DPRINT_DBG(VMBUS, "channel released (%p)", channel);
235
8c69f52a 236 kfree(channel);
3e7ee490
HJ
237
238 DPRINT_EXIT(VMBUS);
239}
240
3e189519 241/*
bd60c33e
GKH
242 * FreeVmbusChannel - Release the resources used by the vmbus channel object
243 */
aded7165 244void FreeVmbusChannel(struct vmbus_channel *Channel)
3e7ee490 245{
5996b3dd 246 del_timer_sync(&Channel->poll_timer);
3e7ee490 247
bd60c33e
GKH
248 /*
249 * We have to release the channel's workqueue/thread in the vmbus's
250 * workqueue/thread context
251 * ie we can't destroy ourselves.
252 */
de65a384 253 osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
bd60c33e 254 Channel);
3e7ee490
HJ
255}
256
3e189519 257/*
c88c4e4c
HJ
258 * VmbusChannelProcessOffer - Process the offer by creating a channel/device
259 * associated with this offer
bd60c33e
GKH
260 */
261static void VmbusChannelProcessOffer(void *context)
3e7ee490 262{
aded7165
GKH
263 struct vmbus_channel *newChannel = context;
264 struct vmbus_channel *channel;
0e727613 265 bool fNew = true;
bd60c33e 266 int ret;
c88c4e4c 267 int cnt;
0f5e44ca 268 unsigned long flags;
3e7ee490
HJ
269
270 DPRINT_ENTER(VMBUS);
271
454f18a9 272 /* Make sure this is a new offer */
0f5e44ca 273 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
3e7ee490 274
53af545b 275 list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
bd60c33e
GKH
276 if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
277 &newChannel->OfferMsg.Offer.InterfaceType,
278 sizeof(struct hv_guid)) &&
279 !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
280 &newChannel->OfferMsg.Offer.InterfaceInstance,
281 sizeof(struct hv_guid))) {
0e727613 282 fNew = false;
3e7ee490
HJ
283 break;
284 }
285 }
286
287 if (fNew)
53af545b
BP
288 list_add_tail(&newChannel->ListEntry,
289 &gVmbusConnection.ChannelList);
bd60c33e 290
0f5e44ca 291 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
3e7ee490 292
bd60c33e
GKH
293 if (!fNew) {
294 DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
295 newChannel->OfferMsg.ChildRelId);
3e7ee490
HJ
296 FreeVmbusChannel(newChannel);
297 DPRINT_EXIT(VMBUS);
298 return;
299 }
300
bd60c33e
GKH
301 /*
302 * Start the process of binding this offer to the driver
303 * We need to set the DeviceObject field before calling
304 * VmbusChildDeviceAdd()
305 */
3e7ee490 306 newChannel->DeviceObject = VmbusChildDeviceCreate(
daaa8cc3
GKH
307 &newChannel->OfferMsg.Offer.InterfaceType,
308 &newChannel->OfferMsg.Offer.InterfaceInstance,
3e7ee490
HJ
309 newChannel);
310
bd60c33e
GKH
311 DPRINT_DBG(VMBUS, "child device object allocated - %p",
312 newChannel->DeviceObject);
3e7ee490 313
454f18a9
BP
314 /*
315 * Add the new device to the bus. This will kick off device-driver
316 * binding which eventually invokes the device driver's AddDevice()
317 * method.
318 */
3e7ee490 319 ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
bd60c33e
GKH
320 if (ret != 0) {
321 DPRINT_ERR(VMBUS,
322 "unable to add child device object (relid %d)",
323 newChannel->OfferMsg.ChildRelId);
3e7ee490 324
0f5e44ca 325 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
53af545b 326 list_del(&newChannel->ListEntry);
0f5e44ca 327 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
3e7ee490
HJ
328
329 FreeVmbusChannel(newChannel);
bd60c33e 330 } else {
454f18a9
BP
331 /*
332 * This state is used to indicate a successful open
333 * so that when we do close the channel normally, we
334 * can cleanup properly
335 */
3e7ee490 336 newChannel->State = CHANNEL_OPEN_STATE;
c88c4e4c
HJ
337 cnt = 0;
338
339 while (cnt != MAX_MSG_TYPES) {
340 if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType,
341 &hv_cb_utils[cnt].data,
342 sizeof(struct hv_guid)) == 0) {
343 DPRINT_INFO(VMBUS, "%s",
344 hv_cb_utils[cnt].log_msg);
345
346 if (VmbusChannelOpen(newChannel, 2 * PAGE_SIZE,
347 2 * PAGE_SIZE, NULL, 0,
348 hv_cb_utils[cnt].callback,
349 newChannel) == 0)
350 hv_cb_utils[cnt].channel = newChannel;
351 }
352 cnt++;
353 }
3e7ee490
HJ
354 }
355 DPRINT_EXIT(VMBUS);
356}
357
3e189519 358/*
bd60c33e
GKH
359 * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
360 */
361static void VmbusChannelProcessRescindOffer(void *context)
3e7ee490 362{
aded7165 363 struct vmbus_channel *channel = context;
3e7ee490
HJ
364
365 DPRINT_ENTER(VMBUS);
3e7ee490 366 VmbusChildDeviceRemove(channel->DeviceObject);
3e7ee490
HJ
367 DPRINT_EXIT(VMBUS);
368}
369
3e189519 370/*
bd60c33e
GKH
371 * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
372 *
373 * We ignore all offers except network and storage offers. For each network and
374 * storage offers, we create a channel object and queue a work item to the
375 * channel object to process the offer synchronously
376 */
82250213 377static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
3e7ee490 378{
bd60c33e 379 struct vmbus_channel_offer_channel *offer;
aded7165 380 struct vmbus_channel *newChannel;
caf26a31
GKH
381 struct hv_guid *guidType;
382 struct hv_guid *guidInstance;
3e7ee490 383 int i;
bd60c33e 384 int fSupported = 0;
3e7ee490
HJ
385
386 DPRINT_ENTER(VMBUS);
387
bd60c33e
GKH
388 offer = (struct vmbus_channel_offer_channel *)hdr;
389 for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
390 if (memcmp(&offer->Offer.InterfaceType,
391 &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
3e7ee490
HJ
392 fSupported = 1;
393 break;
394 }
395 }
396
bd60c33e
GKH
397 if (!fSupported) {
398 DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
399 "child relid %d", offer->ChildRelId);
3e7ee490 400 DPRINT_EXIT(VMBUS);
3e7ee490
HJ
401 return;
402 }
403
404 guidType = &offer->Offer.InterfaceType;
405 guidInstance = &offer->Offer.InterfaceInstance;
406
bd60c33e
GKH
407 DPRINT_INFO(VMBUS, "Channel offer notification - "
408 "child relid %d monitor id %d allocated %d, "
409 "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
410 "%02x%02x%02x%02x%02x%02x%02x%02x} "
411 "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
412 "%02x%02x%02x%02x%02x%02x%02x%02x}",
413 offer->ChildRelId, offer->MonitorId,
414 offer->MonitorAllocated,
415 guidType->data[3], guidType->data[2],
416 guidType->data[1], guidType->data[0],
417 guidType->data[5], guidType->data[4],
418 guidType->data[7], guidType->data[6],
419 guidType->data[8], guidType->data[9],
420 guidType->data[10], guidType->data[11],
421 guidType->data[12], guidType->data[13],
422 guidType->data[14], guidType->data[15],
423 guidInstance->data[3], guidInstance->data[2],
424 guidInstance->data[1], guidInstance->data[0],
425 guidInstance->data[5], guidInstance->data[4],
426 guidInstance->data[7], guidInstance->data[6],
427 guidInstance->data[8], guidInstance->data[9],
428 guidInstance->data[10], guidInstance->data[11],
429 guidInstance->data[12], guidInstance->data[13],
430 guidInstance->data[14], guidInstance->data[15]);
3e7ee490 431
454f18a9 432 /* Allocate the channel object and save this offer. */
3e7ee490 433 newChannel = AllocVmbusChannel();
bd60c33e 434 if (!newChannel) {
3e7ee490
HJ
435 DPRINT_ERR(VMBUS, "unable to allocate channel object");
436 return;
437 }
438
439 DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
440
bd60c33e
GKH
441 memcpy(&newChannel->OfferMsg, offer,
442 sizeof(struct vmbus_channel_offer_channel));
5654e932
GKH
443 newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
444 newChannel->MonitorBit = (u8)offer->MonitorId % 32;
3e7ee490 445
454f18a9 446 /* TODO: Make sure the offer comes from our parent partition */
de65a384
BP
447 osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
448 newChannel);
3e7ee490
HJ
449
450 DPRINT_EXIT(VMBUS);
451}
452
3e189519 453/*
bd60c33e
GKH
454 * VmbusChannelOnOfferRescind - Rescind offer handler.
455 *
456 * We queue a work item to process this offer synchronously
457 */
82250213 458static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
3e7ee490 459{
bd60c33e 460 struct vmbus_channel_rescind_offer *rescind;
aded7165 461 struct vmbus_channel *channel;
3e7ee490
HJ
462
463 DPRINT_ENTER(VMBUS);
464
bd60c33e 465 rescind = (struct vmbus_channel_rescind_offer *)hdr;
3e7ee490 466 channel = GetChannelFromRelId(rescind->ChildRelId);
bd60c33e
GKH
467 if (channel == NULL) {
468 DPRINT_DBG(VMBUS, "channel not found for relId %d",
469 rescind->ChildRelId);
3e7ee490
HJ
470 return;
471 }
472
de65a384
BP
473 osd_schedule_callback(channel->ControlWQ,
474 VmbusChannelProcessRescindOffer,
475 channel);
3e7ee490
HJ
476
477 DPRINT_EXIT(VMBUS);
478}
479
3e189519 480/*
bd60c33e
GKH
481 * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
482 *
483 * Nothing to do here.
484 */
485static void VmbusChannelOnOffersDelivered(
486 struct vmbus_channel_message_header *hdr)
3e7ee490
HJ
487{
488 DPRINT_ENTER(VMBUS);
489 DPRINT_EXIT(VMBUS);
490}
491
3e189519 492/*
bd60c33e
GKH
493 * VmbusChannelOnOpenResult - Open result handler.
494 *
495 * This is invoked when we received a response to our channel open request.
496 * Find the matching request, copy the response and signal the requesting
497 * thread.
498 */
82250213 499static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
3e7ee490 500{
bd60c33e 501 struct vmbus_channel_open_result *result;
53af545b 502 struct list_head *curr;
aded7165 503 struct vmbus_channel_msginfo *msgInfo;
82250213
GKH
504 struct vmbus_channel_message_header *requestHeader;
505 struct vmbus_channel_open_channel *openMsg;
dd0813b6 506 unsigned long flags;
3e7ee490
HJ
507
508 DPRINT_ENTER(VMBUS);
509
bd60c33e 510 result = (struct vmbus_channel_open_result *)hdr;
3e7ee490
HJ
511 DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
512
bd60c33e
GKH
513 /*
514 * Find the open msg, copy the result and signal/unblock the wait event
515 */
dd0813b6 516 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490 517
53af545b
BP
518 list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
519/* FIXME: this should probably use list_entry() instead */
aded7165 520 msgInfo = (struct vmbus_channel_msginfo *)curr;
82250213 521 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490 522
bd60c33e 523 if (requestHeader->MessageType == ChannelMessageOpenChannel) {
82250213 524 openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
3e7ee490 525 if (openMsg->ChildRelId == result->ChildRelId &&
bd60c33e
GKH
526 openMsg->OpenId == result->OpenId) {
527 memcpy(&msgInfo->Response.OpenResult,
528 result,
529 sizeof(struct vmbus_channel_open_result));
bfc30aae 530 osd_WaitEventSet(msgInfo->WaitEvent);
3e7ee490
HJ
531 break;
532 }
533 }
534 }
dd0813b6 535 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490
HJ
536
537 DPRINT_EXIT(VMBUS);
538}
539
3e189519 540/*
bd60c33e
GKH
541 * VmbusChannelOnGpadlCreated - GPADL created handler.
542 *
543 * This is invoked when we received a response to our gpadl create request.
544 * Find the matching request, copy the response and signal the requesting
545 * thread.
546 */
82250213 547static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
3e7ee490 548{
bd60c33e 549 struct vmbus_channel_gpadl_created *gpadlCreated;
53af545b 550 struct list_head *curr;
aded7165 551 struct vmbus_channel_msginfo *msgInfo;
82250213
GKH
552 struct vmbus_channel_message_header *requestHeader;
553 struct vmbus_channel_gpadl_header *gpadlHeader;
dd0813b6 554 unsigned long flags;
3e7ee490
HJ
555
556 DPRINT_ENTER(VMBUS);
557
bd60c33e
GKH
558 gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
559 DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
560 gpadlCreated->CreationStatus);
3e7ee490 561
bd60c33e
GKH
562 /*
563 * Find the establish msg, copy the result and signal/unblock the wait
564 * event
565 */
dd0813b6 566 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490 567
53af545b
BP
568 list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
569/* FIXME: this should probably use list_entry() instead */
aded7165 570 msgInfo = (struct vmbus_channel_msginfo *)curr;
82250213 571 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490 572
bd60c33e 573 if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
82250213 574 gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
3e7ee490 575
bd60c33e
GKH
576 if ((gpadlCreated->ChildRelId ==
577 gpadlHeader->ChildRelId) &&
578 (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
579 memcpy(&msgInfo->Response.GpadlCreated,
580 gpadlCreated,
581 sizeof(struct vmbus_channel_gpadl_created));
bfc30aae 582 osd_WaitEventSet(msgInfo->WaitEvent);
3e7ee490
HJ
583 break;
584 }
585 }
586 }
dd0813b6 587 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490
HJ
588
589 DPRINT_EXIT(VMBUS);
590}
591
3e189519 592/*
bd60c33e
GKH
593 * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
594 *
595 * This is invoked when we received a response to our gpadl teardown request.
596 * Find the matching request, copy the response and signal the requesting
597 * thread.
598 */
599static void VmbusChannelOnGpadlTorndown(
600 struct vmbus_channel_message_header *hdr)
3e7ee490 601{
bd60c33e 602 struct vmbus_channel_gpadl_torndown *gpadlTorndown;
53af545b 603 struct list_head *curr;
aded7165 604 struct vmbus_channel_msginfo *msgInfo;
82250213
GKH
605 struct vmbus_channel_message_header *requestHeader;
606 struct vmbus_channel_gpadl_teardown *gpadlTeardown;
dd0813b6 607 unsigned long flags;
3e7ee490
HJ
608
609 DPRINT_ENTER(VMBUS);
610
bd60c33e
GKH
611 gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
612
613 /*
614 * Find the open msg, copy the result and signal/unblock the wait event
615 */
dd0813b6 616 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490 617
53af545b
BP
618 list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
619/* FIXME: this should probably use list_entry() instead */
aded7165 620 msgInfo = (struct vmbus_channel_msginfo *)curr;
82250213 621 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490 622
bd60c33e 623 if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
82250213 624 gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
3e7ee490 625
bd60c33e
GKH
626 if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
627 memcpy(&msgInfo->Response.GpadlTorndown,
628 gpadlTorndown,
629 sizeof(struct vmbus_channel_gpadl_torndown));
bfc30aae 630 osd_WaitEventSet(msgInfo->WaitEvent);
3e7ee490
HJ
631 break;
632 }
633 }
634 }
dd0813b6 635 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490
HJ
636
637 DPRINT_EXIT(VMBUS);
638}
639
3e189519 640/*
bd60c33e
GKH
641 * VmbusChannelOnVersionResponse - Version response handler
642 *
643 * This is invoked when we received a response to our initiate contact request.
644 * Find the matching request, copy the response and signal the requesting
645 * thread.
646 */
647static void VmbusChannelOnVersionResponse(
648 struct vmbus_channel_message_header *hdr)
3e7ee490 649{
53af545b 650 struct list_head *curr;
aded7165 651 struct vmbus_channel_msginfo *msgInfo;
82250213
GKH
652 struct vmbus_channel_message_header *requestHeader;
653 struct vmbus_channel_initiate_contact *initiate;
bd60c33e 654 struct vmbus_channel_version_response *versionResponse;
dd0813b6 655 unsigned long flags;
3e7ee490
HJ
656
657 DPRINT_ENTER(VMBUS);
658
bd60c33e 659 versionResponse = (struct vmbus_channel_version_response *)hdr;
dd0813b6 660 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490 661
53af545b
BP
662 list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
663/* FIXME: this should probably use list_entry() instead */
aded7165 664 msgInfo = (struct vmbus_channel_msginfo *)curr;
82250213 665 requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490 666
bd60c33e
GKH
667 if (requestHeader->MessageType ==
668 ChannelMessageInitiateContact) {
82250213 669 initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
bd60c33e
GKH
670 memcpy(&msgInfo->Response.VersionResponse,
671 versionResponse,
672 sizeof(struct vmbus_channel_version_response));
bfc30aae 673 osd_WaitEventSet(msgInfo->WaitEvent);
3e7ee490
HJ
674 }
675 }
dd0813b6 676 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
3e7ee490
HJ
677
678 DPRINT_EXIT(VMBUS);
679}
680
c8212f04
GKH
681/* Channel message dispatch table */
682static struct vmbus_channel_message_table_entry
683 gChannelMessageTable[ChannelMessageCount] = {
684 {ChannelMessageInvalid, NULL},
685 {ChannelMessageOfferChannel, VmbusChannelOnOffer},
686 {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind},
687 {ChannelMessageRequestOffers, NULL},
688 {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered},
689 {ChannelMessageOpenChannel, NULL},
690 {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult},
691 {ChannelMessageCloseChannel, NULL},
692 {ChannelMessageGpadlHeader, NULL},
693 {ChannelMessageGpadlBody, NULL},
694 {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated},
695 {ChannelMessageGpadlTeardown, NULL},
696 {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown},
697 {ChannelMessageRelIdReleased, NULL},
698 {ChannelMessageInitiateContact, NULL},
699 {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse},
700 {ChannelMessageUnload, NULL},
701};
702
3e189519 703/*
bd60c33e
GKH
704 * VmbusOnChannelMessage - Handler for channel protocol messages.
705 *
706 * This is invoked in the vmbus worker thread context.
707 */
b239549c 708void VmbusOnChannelMessage(void *Context)
3e7ee490 709{
eacb1b4d 710 struct hv_message *msg = Context;
82250213 711 struct vmbus_channel_message_header *hdr;
3e7ee490
HJ
712 int size;
713
714 DPRINT_ENTER(VMBUS);
715
82250213 716 hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
bd60c33e 717 size = msg->Header.PayloadSize;
3e7ee490
HJ
718
719 DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
720
bd60c33e
GKH
721 if (hdr->MessageType >= ChannelMessageCount) {
722 DPRINT_ERR(VMBUS,
723 "Received invalid channel message type %d size %d",
724 hdr->MessageType, size);
04f50c4d
GKH
725 print_hex_dump_bytes("", DUMP_PREFIX_NONE,
726 (unsigned char *)msg->u.Payload, size);
8c69f52a 727 kfree(msg);
3e7ee490
HJ
728 return;
729 }
730
731 if (gChannelMessageTable[hdr->MessageType].messageHandler)
3e7ee490 732 gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
3e7ee490 733 else
bd60c33e
GKH
734 DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
735 hdr->MessageType);
3e7ee490 736
454f18a9 737 /* Free the msg that was allocated in VmbusOnMsgDPC() */
8c69f52a 738 kfree(msg);
3e7ee490
HJ
739 DPRINT_EXIT(VMBUS);
740}
741
3e189519 742/*
bd60c33e
GKH
743 * VmbusChannelRequestOffers - Send a request to get all our pending offers.
744 */
b239549c 745int VmbusChannelRequestOffers(void)
3e7ee490 746{
82250213 747 struct vmbus_channel_message_header *msg;
aded7165 748 struct vmbus_channel_msginfo *msgInfo;
bd60c33e 749 int ret;
3e7ee490
HJ
750
751 DPRINT_ENTER(VMBUS);
752
bd60c33e
GKH
753 msgInfo = kmalloc(sizeof(*msgInfo) +
754 sizeof(struct vmbus_channel_message_header),
755 GFP_KERNEL);
3e7ee490
HJ
756 ASSERT(msgInfo != NULL);
757
bfc30aae 758 msgInfo->WaitEvent = osd_WaitEventCreate();
82250213 759 msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
3e7ee490
HJ
760
761 msg->MessageType = ChannelMessageRequestOffers;
762
763 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
bd60c33e
GKH
764 INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
765 &msgInfo->msgListEntry);
3e7ee490
HJ
766 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
767
bd60c33e
GKH
768 ret = VmbusPostMessage(msg,
769 sizeof(struct vmbus_channel_message_header));
770 if (ret != 0) {
3e7ee490
HJ
771 DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
772
773 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
774 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
775 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
776
777 goto Cleanup;
778 }
bfc30aae 779 /* osd_WaitEventWait(msgInfo->waitEvent); */
3e7ee490
HJ
780
781 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
782 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
783 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
784
785
786Cleanup:
bd60c33e 787 if (msgInfo) {
420beac4 788 kfree(msgInfo->WaitEvent);
8c69f52a 789 kfree(msgInfo);
3e7ee490
HJ
790 }
791
792 DPRINT_EXIT(VMBUS);
3e7ee490
HJ
793 return ret;
794}
795
3e189519
HJ
796/*
797 * VmbusChannelReleaseUnattachedChannels - Release channels that are
798 * unattached/unconnected ie (no drivers associated)
bd60c33e 799 */
b239549c 800void VmbusChannelReleaseUnattachedChannels(void)
3e7ee490 801{
53af545b 802 struct vmbus_channel *channel, *pos;
aded7165 803 struct vmbus_channel *start = NULL;
0f5e44ca 804 unsigned long flags;
3e7ee490 805
0f5e44ca 806 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
3e7ee490 807
53af545b
BP
808 list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
809 ListEntry) {
3e7ee490
HJ
810 if (channel == start)
811 break;
812
bd60c33e 813 if (!channel->DeviceObject->Driver) {
53af545b 814 list_del(&channel->ListEntry);
bd60c33e
GKH
815 DPRINT_INFO(VMBUS,
816 "Releasing unattached device object %p",
817 channel->DeviceObject);
3e7ee490
HJ
818
819 VmbusChildDeviceRemove(channel->DeviceObject);
820 FreeVmbusChannel(channel);
bd60c33e 821 } else {
3e7ee490 822 if (!start)
3e7ee490 823 start = channel;
3e7ee490
HJ
824 }
825 }
826
0f5e44ca 827 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
3e7ee490
HJ
828}
829
454f18a9 830/* eof */