Staging: hv: make the Hyper-V virtual network driver build
[safe/jmp/linux-2.6] / drivers / staging / hv / NetVsc.c
1 /*
2  *
3  * Copyright (c) 2009, Microsoft Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16  * Place - Suite 330, Boston, MA 02111-1307 USA.
17  *
18  * Authors:
19  *   Hank Janssen  <hjanssen@microsoft.com>
20  *
21  */
22
23 #define KERNEL_2_6_27
24
25 #include "include/logging.h"
26 #include "NetVsc.h"
27 #include "RndisFilter.h"
28
29
30 //
31 // Globals
32 //
33 static const char* gDriverName="netvsc";
34
35 // {F8615163-DF3E-46c5-913F-F2D2F965ED0E}
36 static const GUID gNetVscDeviceType={
37         .Data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
38 };
39
40
41 //
42 // Internal routines
43 //
44 static int
45 NetVscOnDeviceAdd(
46         DEVICE_OBJECT   *Device,
47         void                    *AdditionalInfo
48         );
49
50 static int
51 NetVscOnDeviceRemove(
52         DEVICE_OBJECT *Device
53         );
54
55 static void
56 NetVscOnCleanup(
57         DRIVER_OBJECT *Driver
58         );
59
60 static void
61 NetVscOnChannelCallback(
62         PVOID context
63         );
64
65 static int
66 NetVscInitializeSendBufferWithNetVsp(
67         DEVICE_OBJECT                   *Device
68         );
69
70 static int
71 NetVscInitializeReceiveBufferWithNetVsp(
72         DEVICE_OBJECT                   *Device
73         );
74
75 static int
76 NetVscDestroySendBuffer(
77         NETVSC_DEVICE   *NetDevice
78         );
79
80 static int
81 NetVscDestroyReceiveBuffer(
82         NETVSC_DEVICE   *NetDevice
83         );
84
85 static int
86 NetVscConnectToVsp(
87         DEVICE_OBJECT           *Device
88         );
89
90 static void
91 NetVscOnSendCompletion(
92         DEVICE_OBJECT           *Device,
93         VMPACKET_DESCRIPTOR *Packet
94         );
95
96 static int
97 NetVscOnSend(
98         DEVICE_OBJECT   *Device,
99         NETVSC_PACKET   *Packet
100         );
101
102 static void
103 NetVscOnReceive(
104         DEVICE_OBJECT           *Device,
105         VMPACKET_DESCRIPTOR *Packet
106         );
107
108 static void
109 NetVscOnReceiveCompletion(
110         PVOID Context
111         );
112
113 static void
114 NetVscSendReceiveCompletion(
115         DEVICE_OBJECT   *Device,
116         UINT64                  TransactionId
117         );
118
119 static inline NETVSC_DEVICE* AllocNetDevice(DEVICE_OBJECT *Device)
120 {
121         NETVSC_DEVICE *netDevice;
122
123         netDevice = MemAllocZeroed(sizeof(NETVSC_DEVICE));
124         if (!netDevice)
125                 return NULL;
126
127         // Set to 2 to allow both inbound and outbound traffic
128         InterlockedCompareExchange(&netDevice->RefCount, 2, 0);
129
130         netDevice->Device = Device;
131         Device->Extension = netDevice;
132
133         return netDevice;
134 }
135
136 static inline void FreeNetDevice(NETVSC_DEVICE *Device)
137 {
138         ASSERT(Device->RefCount == 0);
139         Device->Device->Extension = NULL;
140         MemFree(Device);
141 }
142
143
144 // Get the net device object iff exists and its refcount > 1
145 static inline NETVSC_DEVICE* GetOutboundNetDevice(DEVICE_OBJECT *Device)
146 {
147         NETVSC_DEVICE *netDevice;
148
149         netDevice = (NETVSC_DEVICE*)Device->Extension;
150         if (netDevice && netDevice->RefCount > 1)
151         {
152                 InterlockedIncrement(&netDevice->RefCount);
153         }
154         else
155         {
156                 netDevice = NULL;
157         }
158
159         return netDevice;
160 }
161
162 // Get the net device object iff exists and its refcount > 0
163 static inline NETVSC_DEVICE* GetInboundNetDevice(DEVICE_OBJECT  *Device)
164 {
165         NETVSC_DEVICE *netDevice;
166
167         netDevice = (NETVSC_DEVICE*)Device->Extension;
168         if (netDevice && netDevice->RefCount)
169         {
170                 InterlockedIncrement(&netDevice->RefCount);
171         }
172         else
173         {
174                 netDevice = NULL;
175         }
176
177         return netDevice;
178 }
179
180 static inline void PutNetDevice(DEVICE_OBJECT *Device)
181 {
182         NETVSC_DEVICE *netDevice;
183
184         netDevice = (NETVSC_DEVICE*)Device->Extension;
185         ASSERT(netDevice);
186
187         InterlockedDecrement(&netDevice->RefCount);
188 }
189
190 static inline NETVSC_DEVICE* ReleaseOutboundNetDevice(DEVICE_OBJECT *Device)
191 {
192         NETVSC_DEVICE *netDevice;
193
194         netDevice = (NETVSC_DEVICE*)Device->Extension;
195         if (netDevice == NULL)
196                 return NULL;
197
198         // Busy wait until the ref drop to 2, then set it to 1
199         while (InterlockedCompareExchange(&netDevice->RefCount, 1, 2) != 2)
200         {
201                 Sleep(100);
202         }
203
204         return netDevice;
205 }
206
207 static inline NETVSC_DEVICE* ReleaseInboundNetDevice(DEVICE_OBJECT *Device)
208 {
209         NETVSC_DEVICE *netDevice;
210
211         netDevice = (NETVSC_DEVICE*)Device->Extension;
212         if (netDevice == NULL)
213                 return NULL;
214
215         // Busy wait until the ref drop to 1, then set it to 0
216         while (InterlockedCompareExchange(&netDevice->RefCount, 0, 1) != 1)
217         {
218                 Sleep(100);
219         }
220
221         Device->Extension = NULL;
222         return netDevice;
223 }
224
225 /*++;
226
227
228 Name:
229         NetVscInitialize()
230
231 Description:
232         Main entry point
233
234 --*/
235 int
236 NetVscInitialize(
237         DRIVER_OBJECT *drv
238         )
239 {
240         NETVSC_DRIVER_OBJECT* driver = (NETVSC_DRIVER_OBJECT*)drv;
241         int ret=0;
242
243         DPRINT_ENTER(NETVSC);
244
245         DPRINT_DBG(NETVSC, "sizeof(NETVSC_PACKET)=%d, sizeof(NVSP_MESSAGE)=%d, sizeof(VMTRANSFER_PAGE_PACKET_HEADER)=%d",
246                 sizeof(NETVSC_PACKET), sizeof(NVSP_MESSAGE), sizeof(VMTRANSFER_PAGE_PACKET_HEADER));
247
248         // Make sure we are at least 2 pages since 1 page is used for control
249         ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1));
250
251         drv->name = gDriverName;
252         memcpy(&drv->deviceType, &gNetVscDeviceType, sizeof(GUID));
253
254         // Make sure it is set by the caller
255         ASSERT(driver->OnReceiveCallback);
256         ASSERT(driver->OnLinkStatusChanged);
257
258         // Setup the dispatch table
259         driver->Base.OnDeviceAdd                = NetVscOnDeviceAdd;
260         driver->Base.OnDeviceRemove             = NetVscOnDeviceRemove;
261         driver->Base.OnCleanup                  = NetVscOnCleanup;
262
263         driver->OnSend                                  = NetVscOnSend;
264
265         RndisFilterInit(driver);
266
267         DPRINT_EXIT(NETVSC);
268
269         return ret;
270 }
271
272 static int
273 NetVscInitializeReceiveBufferWithNetVsp(
274         DEVICE_OBJECT   *Device
275         )
276 {
277         int ret=0;
278         NETVSC_DEVICE *netDevice;
279         NVSP_MESSAGE *initPacket;
280
281         DPRINT_ENTER(NETVSC);
282
283         netDevice = GetOutboundNetDevice(Device);
284         if (!netDevice)
285         {
286                 DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?");
287                 DPRINT_EXIT(NETVSC);
288                 return -1;
289         }
290         ASSERT(netDevice->ReceiveBufferSize > 0);
291         ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE-1)) == 0); // page-size grandularity
292
293         netDevice->ReceiveBuffer = PageAlloc(netDevice->ReceiveBufferSize >> PAGE_SHIFT);
294         if (!netDevice->ReceiveBuffer)
295         {
296                 DPRINT_ERR(NETVSC, "unable to allocate receive buffer of size %d", netDevice->ReceiveBufferSize);
297                 ret = -1;
298                 goto Cleanup;
299         }
300         ASSERT(((ULONG_PTR)netDevice->ReceiveBuffer & (PAGE_SIZE-1)) == 0); // page-aligned buffer
301
302         DPRINT_INFO(NETVSC, "Establishing receive buffer's GPADL...");
303
304         // Establish the gpadl handle for this buffer on this channel.
305         // Note: This call uses the vmbus connection rather than the channel to establish
306         // the gpadl handle.
307         ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device,
308                                                                                                                                 netDevice->ReceiveBuffer,
309                                                                                                                                 netDevice->ReceiveBufferSize,
310                                                                                                                                 &netDevice->ReceiveBufferGpadlHandle);
311
312         if (ret != 0)
313         {
314                 DPRINT_ERR(NETVSC, "unable to establish receive buffer's gpadl");
315                 goto Cleanup;
316         }
317
318         //WaitEventWait(ext->ChannelInitEvent);
319
320         // Notify the NetVsp of the gpadl handle
321         DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer...");
322
323         initPacket = &netDevice->ChannelInitPacket;
324
325         memset(initPacket, 0, sizeof(NVSP_MESSAGE));
326
327     initPacket->Header.MessageType = NvspMessage1TypeSendReceiveBuffer;
328     initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->ReceiveBufferGpadlHandle;
329     initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID;
330
331         // Send the gpadl notification request
332         ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
333                                                                                                                         initPacket,
334                                                                                                                         sizeof(NVSP_MESSAGE),
335                                                                                                                         (ULONG_PTR)initPacket,
336                                                                                                                         VmbusPacketTypeDataInBand,
337                                                                                                                         VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
338         if (ret != 0)
339         {
340                 DPRINT_ERR(NETVSC, "unable to send receive buffer's gpadl to netvsp");
341                 goto Cleanup;
342         }
343
344         WaitEventWait(netDevice->ChannelInitEvent);
345
346         // Check the response
347         if (initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status != NvspStatusSuccess)
348         {
349                 DPRINT_ERR(NETVSC,
350                         "Unable to complete receive buffer initialzation with NetVsp - status %d",
351                         initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status);
352                 ret = -1;
353                 goto Cleanup;
354         }
355
356         // Parse the response
357         ASSERT(netDevice->ReceiveSectionCount == 0);
358         ASSERT(netDevice->ReceiveSections == NULL);
359
360         netDevice->ReceiveSectionCount = initPacket->Messages.Version1Messages.SendReceiveBufferComplete.NumSections;
361
362         netDevice->ReceiveSections = MemAlloc(netDevice->ReceiveSectionCount * sizeof(NVSP_1_RECEIVE_BUFFER_SECTION));
363         if (netDevice->ReceiveSections == NULL)
364         {
365                 ret = -1;
366                 goto Cleanup;
367         }
368
369         memcpy(netDevice->ReceiveSections,
370                 initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Sections,
371                 netDevice->ReceiveSectionCount * sizeof(NVSP_1_RECEIVE_BUFFER_SECTION));
372
373         DPRINT_INFO(NETVSC,
374                 "Receive sections info (count %d, offset %d, endoffset %d, suballoc size %d, num suballocs %d)",
375                 netDevice->ReceiveSectionCount, netDevice->ReceiveSections[0].Offset, netDevice->ReceiveSections[0].EndOffset,
376                 netDevice->ReceiveSections[0].SubAllocationSize, netDevice->ReceiveSections[0].NumSubAllocations);
377
378
379         //For 1st release, there should only be 1 section that represents the entire receive buffer
380         if (netDevice->ReceiveSectionCount != 1 ||
381                 netDevice->ReceiveSections->Offset != 0 )
382         {
383                 ret = -1;
384                 goto Cleanup;
385         }
386
387         goto Exit;
388
389 Cleanup:
390         NetVscDestroyReceiveBuffer(netDevice);
391
392 Exit:
393         PutNetDevice(Device);
394         DPRINT_EXIT(NETVSC);
395         return ret;
396 }
397
398
399 static int
400 NetVscInitializeSendBufferWithNetVsp(
401         DEVICE_OBJECT   *Device
402         )
403 {
404         int ret=0;
405         NETVSC_DEVICE *netDevice;
406         NVSP_MESSAGE *initPacket;
407
408         DPRINT_ENTER(NETVSC);
409
410         netDevice = GetOutboundNetDevice(Device);
411         if (!netDevice)
412         {
413                 DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?");
414                 DPRINT_EXIT(NETVSC);
415                 return -1;
416         }
417         ASSERT(netDevice->SendBufferSize > 0);
418         ASSERT((netDevice->SendBufferSize & (PAGE_SIZE-1)) == 0); // page-size grandularity
419
420         netDevice->SendBuffer = PageAlloc(netDevice->SendBufferSize >> PAGE_SHIFT);
421         if (!netDevice->SendBuffer)
422         {
423                 DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d", netDevice->SendBufferSize);
424                 ret = -1;
425                 goto Cleanup;
426         }
427         ASSERT(((ULONG_PTR)netDevice->SendBuffer & (PAGE_SIZE-1)) == 0); // page-aligned buffer
428
429         DPRINT_INFO(NETVSC, "Establishing send buffer's GPADL...");
430
431         // Establish the gpadl handle for this buffer on this channel.
432         // Note: This call uses the vmbus connection rather than the channel to establish
433         // the gpadl handle.
434         ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device,
435                                                                                                                                 netDevice->SendBuffer,
436                                                                                                                                 netDevice->SendBufferSize,
437                                                                                                                                 &netDevice->SendBufferGpadlHandle);
438
439         if (ret != 0)
440         {
441                 DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl");
442                 goto Cleanup;
443         }
444
445         //WaitEventWait(ext->ChannelInitEvent);
446
447         // Notify the NetVsp of the gpadl handle
448         DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer...");
449
450         initPacket = &netDevice->ChannelInitPacket;
451
452         memset(initPacket, 0, sizeof(NVSP_MESSAGE));
453
454     initPacket->Header.MessageType = NvspMessage1TypeSendSendBuffer;
455     initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->SendBufferGpadlHandle;
456     initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_SEND_BUFFER_ID;
457
458         // Send the gpadl notification request
459         ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
460                                                                                                                         initPacket,
461                                                                                                                         sizeof(NVSP_MESSAGE),
462                                                                                                                         (ULONG_PTR)initPacket,
463                                                                                                                         VmbusPacketTypeDataInBand,
464                                                                                                                         VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
465         if (ret != 0)
466         {
467                 DPRINT_ERR(NETVSC, "unable to send receive buffer's gpadl to netvsp");
468                 goto Cleanup;
469         }
470
471         WaitEventWait(netDevice->ChannelInitEvent);
472
473         // Check the response
474         if (initPacket->Messages.Version1Messages.SendSendBufferComplete.Status != NvspStatusSuccess)
475         {
476                 DPRINT_ERR(NETVSC,
477                         "Unable to complete send buffer initialzation with NetVsp - status %d",
478                         initPacket->Messages.Version1Messages.SendSendBufferComplete.Status);
479                 ret = -1;
480                 goto Cleanup;
481         }
482
483         netDevice->SendSectionSize = initPacket->Messages.Version1Messages.SendSendBufferComplete.SectionSize;
484
485         goto Exit;
486
487 Cleanup:
488         NetVscDestroySendBuffer(netDevice);
489
490 Exit:
491         PutNetDevice(Device);
492         DPRINT_EXIT(NETVSC);
493         return ret;
494 }
495
496 static int
497 NetVscDestroyReceiveBuffer(
498         NETVSC_DEVICE   *NetDevice
499         )
500 {
501         NVSP_MESSAGE *revokePacket;
502         int ret=0;
503
504
505         DPRINT_ENTER(NETVSC);
506
507         // If we got a section count, it means we received a SendReceiveBufferComplete msg
508         // (ie sent NvspMessage1TypeSendReceiveBuffer msg) therefore, we need to send a revoke msg here
509         if (NetDevice->ReceiveSectionCount)
510         {
511                 DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeReceiveBuffer...");
512
513                 // Send the revoke receive buffer
514                 revokePacket = &NetDevice->RevokePacket;
515                 memset(revokePacket, 0, sizeof(NVSP_MESSAGE));
516
517                 revokePacket->Header.MessageType = NvspMessage1TypeRevokeReceiveBuffer;
518                 revokePacket->Messages.Version1Messages.RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID;
519
520                 ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(NetDevice->Device,
521                                                                                                                                                         revokePacket,
522                                                                                                                                                         sizeof(NVSP_MESSAGE),
523                                                                                                                                                         (ULONG_PTR)revokePacket,
524                                                                                                                                                         VmbusPacketTypeDataInBand,
525                                                                                                                                                         0);
526                 // If we failed here, we might as well return and have a leak rather than continue and a bugchk
527                 if (ret != 0)
528                 {
529                         DPRINT_ERR(NETVSC, "unable to send revoke receive buffer to netvsp");
530                         DPRINT_EXIT(NETVSC);
531                         return -1;
532                 }
533         }
534
535         // Teardown the gpadl on the vsp end
536         if (NetDevice->ReceiveBufferGpadlHandle)
537         {
538                 DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL...");
539
540                 ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(NetDevice->Device,
541                                                                                                                                                                 NetDevice->ReceiveBufferGpadlHandle);
542
543                 // If we failed here, we might as well return and have a leak rather than continue and a bugchk
544                 if (ret != 0)
545                 {
546                         DPRINT_ERR(NETVSC, "unable to teardown receive buffer's gpadl");
547                         DPRINT_EXIT(NETVSC);
548                         return -1;
549                 }
550                 NetDevice->ReceiveBufferGpadlHandle = 0;
551         }
552
553         if (NetDevice->ReceiveBuffer)
554         {
555                 DPRINT_INFO(NETVSC, "Freeing up receive buffer...");
556
557                 // Free up the receive buffer
558                 PageFree(NetDevice->ReceiveBuffer, NetDevice->ReceiveBufferSize >> PAGE_SHIFT);
559                 NetDevice->ReceiveBuffer = NULL;
560         }
561
562         if (NetDevice->ReceiveSections)
563         {
564                 MemFree(NetDevice->ReceiveSections);
565                 NetDevice->ReceiveSections = NULL;
566                 NetDevice->ReceiveSectionCount = 0;
567         }
568
569         DPRINT_EXIT(NETVSC);
570
571         return ret;
572 }
573
574
575
576
577 static int
578 NetVscDestroySendBuffer(
579         NETVSC_DEVICE   *NetDevice
580         )
581 {
582         NVSP_MESSAGE *revokePacket;
583         int ret=0;
584
585
586         DPRINT_ENTER(NETVSC);
587
588         // If we got a section count, it means we received a SendReceiveBufferComplete msg
589         // (ie sent NvspMessage1TypeSendReceiveBuffer msg) therefore, we need to send a revoke msg here
590         if (NetDevice->SendSectionSize)
591         {
592                 DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeSendBuffer...");
593
594                 // Send the revoke send buffer
595                 revokePacket = &NetDevice->RevokePacket;
596                 memset(revokePacket, 0, sizeof(NVSP_MESSAGE));
597
598                 revokePacket->Header.MessageType = NvspMessage1TypeRevokeSendBuffer;
599                 revokePacket->Messages.Version1Messages.RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID;
600
601                 ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(NetDevice->Device,
602                                                                                                                                                         revokePacket,
603                                                                                                                                                         sizeof(NVSP_MESSAGE),
604                                                                                                                                                         (ULONG_PTR)revokePacket,
605                                                                                                                                                         VmbusPacketTypeDataInBand,
606                                                                                                                                                         0);
607                 // If we failed here, we might as well return and have a leak rather than continue and a bugchk
608                 if (ret != 0)
609                 {
610                         DPRINT_ERR(NETVSC, "unable to send revoke send buffer to netvsp");
611                         DPRINT_EXIT(NETVSC);
612                         return -1;
613                 }
614         }
615
616         // Teardown the gpadl on the vsp end
617         if (NetDevice->SendBufferGpadlHandle)
618         {
619                 DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL...");
620
621                 ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(NetDevice->Device,
622                                                                                                                                                                 NetDevice->SendBufferGpadlHandle);
623
624                 // If we failed here, we might as well return and have a leak rather than continue and a bugchk
625                 if (ret != 0)
626                 {
627                         DPRINT_ERR(NETVSC, "unable to teardown send buffer's gpadl");
628                         DPRINT_EXIT(NETVSC);
629                         return -1;
630                 }
631                 NetDevice->SendBufferGpadlHandle = 0;
632         }
633
634         if (NetDevice->SendBuffer)
635         {
636                 DPRINT_INFO(NETVSC, "Freeing up send buffer...");
637
638                 // Free up the receive buffer
639                 PageFree(NetDevice->SendBuffer, NetDevice->SendBufferSize >> PAGE_SHIFT);
640                 NetDevice->SendBuffer = NULL;
641         }
642
643         DPRINT_EXIT(NETVSC);
644
645         return ret;
646 }
647
648
649
650 static int
651 NetVscConnectToVsp(
652         DEVICE_OBJECT   *Device
653         )
654 {
655         int ret=0;
656         NETVSC_DEVICE *netDevice;
657         NVSP_MESSAGE *initPacket;
658         int ndisVersion;
659
660         DPRINT_ENTER(NETVSC);
661
662         netDevice = GetOutboundNetDevice(Device);
663         if (!netDevice)
664         {
665                 DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?");
666                 DPRINT_EXIT(NETVSC);
667                 return -1;
668         }
669
670         initPacket = &netDevice->ChannelInitPacket;
671
672         memset(initPacket, 0, sizeof(NVSP_MESSAGE));
673         initPacket->Header.MessageType = NvspMessageTypeInit;
674     initPacket->Messages.InitMessages.Init.MinProtocolVersion = NVSP_MIN_PROTOCOL_VERSION;
675     initPacket->Messages.InitMessages.Init.MaxProtocolVersion = NVSP_MAX_PROTOCOL_VERSION;
676
677         DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit...");
678
679         // Send the init request
680         ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
681                                                                                                                         initPacket,
682                                                                                                                         sizeof(NVSP_MESSAGE),
683                                                                                                                         (ULONG_PTR)initPacket,
684                                                                                                                         VmbusPacketTypeDataInBand,
685                                                                                                                         VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
686
687         if( ret != 0)
688         {
689                 DPRINT_ERR(NETVSC, "unable to send NvspMessageTypeInit");
690                 goto Cleanup;
691         }
692
693         WaitEventWait(netDevice->ChannelInitEvent);
694
695         // Now, check the response
696         //ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT);
697         DPRINT_INFO(NETVSC, "NvspMessageTypeInit status(%d) max mdl chain (%d)",
698                 initPacket->Messages.InitMessages.InitComplete.Status,
699                 initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength);
700
701         if (initPacket->Messages.InitMessages.InitComplete.Status != NvspStatusSuccess)
702         {
703                 DPRINT_ERR(NETVSC, "unable to initialize with netvsp (status 0x%x)", initPacket->Messages.InitMessages.InitComplete.Status);
704                 ret = -1;
705                 goto Cleanup;
706         }
707
708         if (initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion != NVSP_PROTOCOL_VERSION_1)
709         {
710                 DPRINT_ERR(NETVSC, "unable to initialize with netvsp (version expected 1 got %d)",
711                         initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion);
712                 ret = -1;
713                 goto Cleanup;
714         }
715         DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendNdisVersion...");
716
717         // Send the ndis version
718         memset(initPacket, 0, sizeof(NVSP_MESSAGE));
719
720     ndisVersion = 0x00050000;
721
722     initPacket->Header.MessageType = NvspMessage1TypeSendNdisVersion;
723     initPacket->Messages.Version1Messages.SendNdisVersion.NdisMajorVersion = (ndisVersion & 0xFFFF0000) >> 16;
724     initPacket->Messages.Version1Messages.SendNdisVersion.NdisMinorVersion = ndisVersion & 0xFFFF;
725
726         // Send the init request
727         ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
728                                                                                                                         initPacket,
729                                                                                                                         sizeof(NVSP_MESSAGE),
730                                                                                                                         (ULONG_PTR)initPacket,
731                                                                                                                         VmbusPacketTypeDataInBand,
732                                                                                                                         0);
733         if (ret != 0)
734         {
735                 DPRINT_ERR(NETVSC, "unable to send NvspMessage1TypeSendNdisVersion");
736                 ret = -1;
737                 goto Cleanup;
738         }
739         //
740         // BUGBUG - We have to wait for the above msg since the netvsp uses KMCL which acknowledges packet (completion packet)
741         // since our Vmbus always set the VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag
742         //WaitEventWait(NetVscChannel->ChannelInitEvent);
743
744         // Post the big receive buffer to NetVSP
745         ret = NetVscInitializeReceiveBufferWithNetVsp(Device);
746         if (ret == 0)
747         {
748                 ret = NetVscInitializeSendBufferWithNetVsp(Device);
749         }
750
751 Cleanup:
752         PutNetDevice(Device);
753         DPRINT_EXIT(NETVSC);
754         return ret;
755 }
756
757 static void
758 NetVscDisconnectFromVsp(
759         NETVSC_DEVICE   *NetDevice
760         )
761 {
762         DPRINT_ENTER(NETVSC);
763
764         NetVscDestroyReceiveBuffer(NetDevice);
765         NetVscDestroySendBuffer(NetDevice);
766
767         DPRINT_EXIT(NETVSC);
768 }
769
770
771 /*++
772
773 Name:
774         NetVscOnDeviceAdd()
775
776 Description:
777         Callback when the device belonging to this driver is added
778
779 --*/
780 int
781 NetVscOnDeviceAdd(
782         DEVICE_OBJECT   *Device,
783         void                    *AdditionalInfo
784         )
785 {
786         int ret=0;
787         int i;
788
789         NETVSC_DEVICE* netDevice;
790         NETVSC_PACKET* packet;
791         LIST_ENTRY *entry;
792
793         NETVSC_DRIVER_OBJECT *netDriver = (NETVSC_DRIVER_OBJECT*) Device->Driver;;
794
795         DPRINT_ENTER(NETVSC);
796
797         netDevice = AllocNetDevice(Device);
798         if (!netDevice)
799         {
800                 ret = -1;
801                 goto Cleanup;
802         }
803
804         DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", netDevice);
805
806         // Initialize the NetVSC channel extension
807         netDevice->ReceiveBufferSize = NETVSC_RECEIVE_BUFFER_SIZE;
808         netDevice->ReceivePacketListLock = SpinlockCreate();
809
810         netDevice->SendBufferSize = NETVSC_SEND_BUFFER_SIZE;
811
812         INITIALIZE_LIST_HEAD(&netDevice->ReceivePacketList);
813
814         for (i=0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++)
815         {
816                 packet = MemAllocZeroed(sizeof(NETVSC_PACKET) + (NETVSC_RECEIVE_SG_COUNT* sizeof(PAGE_BUFFER)));
817                 if (!packet)
818                 {
819                         DPRINT_DBG(NETVSC, "unable to allocate netvsc pkts for receive pool (wanted %d got %d)", NETVSC_RECEIVE_PACKETLIST_COUNT, i);
820                         break;
821                 }
822
823                 INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &packet->ListEntry);
824         }
825         netDevice->ChannelInitEvent = WaitEventCreate();
826
827         // Open the channel
828         ret = Device->Driver->VmbusChannelInterface.Open(Device,
829                                                                                                                 netDriver->RingBufferSize,
830                                                                                                                 netDriver->RingBufferSize,
831                                                                                                                 NULL, 0,
832                                                                                                                 NetVscOnChannelCallback,
833                                                                                                                 Device
834                                                                                                                 );
835
836         if (ret != 0)
837         {
838                 DPRINT_ERR(NETVSC, "unable to open channel: %d", ret);
839                 ret = -1;
840                 goto Cleanup;
841         }
842
843         // Channel is opened
844         DPRINT_INFO(NETVSC, "*** NetVSC channel opened successfully! ***");
845
846         // Connect with the NetVsp
847         ret = NetVscConnectToVsp(Device);
848         if (ret != 0)
849         {
850                 DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret);
851                 ret = -1;
852                 goto Close;
853         }
854
855         DPRINT_INFO(NETVSC, "*** NetVSC channel handshake result - %d ***", ret);
856
857         DPRINT_EXIT(NETVSC);
858         return ret;
859
860 Close:
861         // Now, we can close the channel safely
862         Device->Driver->VmbusChannelInterface.Close(Device);
863
864 Cleanup:
865
866         if (netDevice)
867         {
868                 WaitEventClose(netDevice->ChannelInitEvent);
869
870                 while (!IsListEmpty(&netDevice->ReceivePacketList))
871                 {
872                         entry = REMOVE_HEAD_LIST(&netDevice->ReceivePacketList);
873                         packet = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry);
874                         MemFree(packet);
875                 }
876
877                 SpinlockClose(netDevice->ReceivePacketListLock);
878
879                 ReleaseOutboundNetDevice(Device);
880                 ReleaseInboundNetDevice(Device);
881
882                 FreeNetDevice(netDevice);
883         }
884
885         DPRINT_EXIT(NETVSC);
886         return ret;
887 }
888
889
890 /*++
891
892 Name:
893         NetVscOnDeviceRemove()
894
895 Description:
896         Callback when the root bus device is removed
897
898 --*/
899 int
900 NetVscOnDeviceRemove(
901         DEVICE_OBJECT *Device
902         )
903 {
904         NETVSC_DEVICE *netDevice;
905         NETVSC_PACKET *netvscPacket;
906         int ret=0;
907         LIST_ENTRY *entry;
908
909         DPRINT_ENTER(NETVSC);
910
911         DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...", Device->Extension);
912
913         // Stop outbound traffic ie sends and receives completions
914         netDevice = ReleaseOutboundNetDevice(Device);
915         if (!netDevice)
916         {
917                 DPRINT_ERR(NETVSC, "No net device present!!");
918                 return -1;
919         }
920
921         // Wait for all send completions
922         while (netDevice->NumOutstandingSends)
923         {
924                 DPRINT_INFO(NETVSC, "waiting for %d requests to complete...", netDevice->NumOutstandingSends);
925
926                 Sleep(100);
927         }
928
929         DPRINT_INFO(NETVSC, "Disconnecting from netvsp...");
930
931         NetVscDisconnectFromVsp(netDevice);
932
933         DPRINT_INFO(NETVSC, "Disabling inbound traffic on net device (%p)...", Device->Extension);
934
935         // Stop inbound traffic ie receives and sends completions
936         netDevice = ReleaseInboundNetDevice(Device);
937
938         // At this point, no one should be accessing netDevice except in here
939         DPRINT_INFO(NETVSC, "net device (%p) safe to remove", netDevice);
940
941         // Now, we can close the channel safely
942         Device->Driver->VmbusChannelInterface.Close(Device);
943
944         // Release all resources
945         while (!IsListEmpty(&netDevice->ReceivePacketList))
946         {
947                 entry = REMOVE_HEAD_LIST(&netDevice->ReceivePacketList);
948                 netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry);
949
950                 MemFree(netvscPacket);
951         }
952
953         SpinlockClose(netDevice->ReceivePacketListLock);
954         WaitEventClose(netDevice->ChannelInitEvent);
955         FreeNetDevice(netDevice);
956
957         DPRINT_EXIT(NETVSC);
958         return ret;
959 }
960
961
962
963 /*++
964
965 Name:
966         NetVscOnCleanup()
967
968 Description:
969         Perform any cleanup when the driver is removed
970
971 --*/
972 void
973 NetVscOnCleanup(
974         DRIVER_OBJECT *drv
975         )
976 {
977         DPRINT_ENTER(NETVSC);
978
979         DPRINT_EXIT(NETVSC);
980 }
981
982 static void
983 NetVscOnSendCompletion(
984         DEVICE_OBJECT           *Device,
985         VMPACKET_DESCRIPTOR *Packet
986         )
987 {
988         NETVSC_DEVICE* netDevice;
989         NVSP_MESSAGE *nvspPacket;
990         NETVSC_PACKET *nvscPacket;
991
992         DPRINT_ENTER(NETVSC);
993
994         netDevice = GetInboundNetDevice(Device);
995         if (!netDevice)
996         {
997                 DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?");
998                 DPRINT_EXIT(NETVSC);
999                 return;
1000         }
1001
1002         nvspPacket = (NVSP_MESSAGE*)((ULONG_PTR)Packet + (Packet->DataOffset8 << 3));
1003
1004         DPRINT_DBG(NETVSC, "send completion packet - type %d", nvspPacket->Header.MessageType);
1005
1006         if (nvspPacket->Header.MessageType == NvspMessageTypeInitComplete ||
1007                 nvspPacket->Header.MessageType == NvspMessage1TypeSendReceiveBufferComplete ||
1008                 nvspPacket->Header.MessageType == NvspMessage1TypeSendSendBufferComplete)
1009         {
1010                 // Copy the response back
1011                 memcpy(&netDevice->ChannelInitPacket, nvspPacket, sizeof(NVSP_MESSAGE));
1012                 WaitEventSet(netDevice->ChannelInitEvent);
1013         }
1014         else if (nvspPacket->Header.MessageType == NvspMessage1TypeSendRNDISPacketComplete)
1015         {
1016                 // Get the send context
1017                 nvscPacket = (NETVSC_PACKET *)(ULONG_PTR)Packet->TransactionId;
1018                 ASSERT(nvscPacket);
1019
1020                 // Notify the layer above us
1021                 nvscPacket->Completion.Send.OnSendCompletion(nvscPacket->Completion.Send.SendCompletionContext);
1022
1023                 InterlockedDecrement(&netDevice->NumOutstandingSends);
1024         }
1025         else
1026         {
1027                 DPRINT_ERR(NETVSC, "Unknown send completion packet type - %d received!!", nvspPacket->Header.MessageType);
1028         }
1029
1030         PutNetDevice(Device);
1031         DPRINT_EXIT(NETVSC);
1032 }
1033
1034
1035
1036 static int
1037 NetVscOnSend(
1038         DEVICE_OBJECT *Device,
1039         NETVSC_PACKET *Packet
1040         )
1041 {
1042         NETVSC_DEVICE* netDevice;
1043         int ret=0;
1044
1045         NVSP_MESSAGE sendMessage;
1046
1047         DPRINT_ENTER(NETVSC);
1048
1049         netDevice = GetOutboundNetDevice(Device);
1050         if (!netDevice)
1051         {
1052                 DPRINT_ERR(NETVSC, "net device (%p) shutting down...ignoring outbound packets", netDevice);
1053                 DPRINT_EXIT(NETVSC);
1054                 return -2;
1055         }
1056
1057         sendMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacket;
1058         if (Packet->IsDataPacket)
1059             sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 0;// 0 is RMC_DATA;
1060         else
1061                 sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 1;// 1 is RMC_CONTROL;
1062
1063         // Not using send buffer section
1064     sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionIndex = 0xFFFFFFFF;
1065     sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0;
1066
1067         if (Packet->PageBufferCount)
1068         {
1069                 ret = Device->Driver->VmbusChannelInterface.SendPacketPageBuffer(Device,
1070                                                                                                                                                         Packet->PageBuffers,
1071                                                                                                                                                         Packet->PageBufferCount,
1072                                                                                                                                                         &sendMessage,
1073                                                                                                                                                         sizeof(NVSP_MESSAGE),
1074                                                                                                                                                         (ULONG_PTR)Packet);
1075         }
1076         else
1077         {
1078                 ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
1079                                                                                                                                 &sendMessage,
1080                                                                                                                                 sizeof(NVSP_MESSAGE),
1081                                                                                                                                 (ULONG_PTR)Packet,
1082                                                                                                                                 VmbusPacketTypeDataInBand,
1083                                                                                                                                 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
1084
1085         }
1086
1087         if (ret != 0)
1088         {
1089                 DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d", Packet, ret);
1090         }
1091
1092         InterlockedIncrement(&netDevice->NumOutstandingSends);
1093         PutNetDevice(Device);
1094
1095         DPRINT_EXIT(NETVSC);
1096         return ret;
1097 }
1098
1099
1100 static void
1101 NetVscOnReceive(
1102         DEVICE_OBJECT           *Device,
1103         VMPACKET_DESCRIPTOR *Packet
1104         )
1105 {
1106         NETVSC_DEVICE* netDevice;
1107         VMTRANSFER_PAGE_PACKET_HEADER *vmxferpagePacket;
1108         NVSP_MESSAGE *nvspPacket;
1109         NETVSC_PACKET *netvscPacket=NULL;
1110         LIST_ENTRY* entry;
1111         ULONG_PTR start;
1112         ULONG_PTR end, endVirtual;
1113         //NETVSC_DRIVER_OBJECT *netvscDriver;
1114         XFERPAGE_PACKET *xferpagePacket=NULL;
1115         LIST_ENTRY listHead;
1116
1117         int i=0, j=0;
1118         int count=0, bytesRemain=0;
1119
1120         DPRINT_ENTER(NETVSC);
1121
1122         netDevice = GetInboundNetDevice(Device);
1123         if (!netDevice)
1124         {
1125                 DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?");
1126                 DPRINT_EXIT(NETVSC);
1127                 return;
1128         }
1129
1130         // All inbound packets other than send completion should be xfer page packet
1131         if (Packet->Type != VmbusPacketTypeDataUsingTransferPages)
1132         {
1133                 DPRINT_ERR(NETVSC, "Unknown packet type received - %d", Packet->Type);
1134                 PutNetDevice(Device);
1135                 return;
1136         }
1137
1138         nvspPacket = (NVSP_MESSAGE*)((ULONG_PTR)Packet + (Packet->DataOffset8 << 3));
1139
1140         // Make sure this is a valid nvsp packet
1141         if (nvspPacket->Header.MessageType != NvspMessage1TypeSendRNDISPacket )
1142         {
1143                 DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d", nvspPacket->Header.MessageType);
1144                 PutNetDevice(Device);
1145                 return;
1146         }
1147
1148         DPRINT_DBG(NETVSC, "NVSP packet received - type %d", nvspPacket->Header.MessageType);
1149
1150         vmxferpagePacket = (VMTRANSFER_PAGE_PACKET_HEADER*)Packet;
1151
1152         if (vmxferpagePacket->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID)
1153         {
1154                 DPRINT_ERR(NETVSC, "Invalid xfer page set id - expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID, vmxferpagePacket->TransferPageSetId);
1155                 PutNetDevice(Device);
1156                 return;
1157         }
1158
1159         DPRINT_DBG(NETVSC, "xfer page - range count %d", vmxferpagePacket->RangeCount);
1160
1161         INITIALIZE_LIST_HEAD(&listHead);
1162
1163         // Grab free packets (range count + 1) to represent this xfer page packet. +1 to represent
1164         // the xfer page packet itself. We grab it here so that we know exactly how many we can fulfil
1165         SpinlockAcquire(netDevice->ReceivePacketListLock);
1166         while (!IsListEmpty(&netDevice->ReceivePacketList))
1167         {
1168                 entry = REMOVE_HEAD_LIST(&netDevice->ReceivePacketList);
1169                 netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry);
1170
1171                 INSERT_TAIL_LIST(&listHead, &netvscPacket->ListEntry);
1172
1173                 if (++count == vmxferpagePacket->RangeCount + 1)
1174                         break;
1175         }
1176         SpinlockRelease(netDevice->ReceivePacketListLock);
1177
1178         // We need at least 2 netvsc pkts (1 to represent the xfer page and at least 1 for the range)
1179         // i.e. we can handled some of the xfer page packet ranges...
1180         if (count < 2)
1181         {
1182                 DPRINT_ERR(NETVSC, "Got only %d netvsc pkt...needed %d pkts. Dropping this xfer page packet completely!", count, vmxferpagePacket->RangeCount+1);
1183
1184                 // Return it to the freelist
1185                 SpinlockAcquire(netDevice->ReceivePacketListLock);
1186                 for (i=count; i != 0; i--)
1187                 {
1188                         entry = REMOVE_HEAD_LIST(&listHead);
1189                         netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry);
1190
1191                         INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &netvscPacket->ListEntry);
1192                 }
1193                 SpinlockRelease(netDevice->ReceivePacketListLock);
1194
1195                 NetVscSendReceiveCompletion(Device, vmxferpagePacket->d.TransactionId);
1196
1197                 PutNetDevice(Device);
1198                 return;
1199         }
1200
1201         // Remove the 1st packet to represent the xfer page packet itself
1202         entry = REMOVE_HEAD_LIST(&listHead);
1203         xferpagePacket = CONTAINING_RECORD(entry, XFERPAGE_PACKET, ListEntry);
1204         xferpagePacket->Count = count - 1; // This is how much we can satisfy
1205         ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= vmxferpagePacket->RangeCount);
1206
1207         if (xferpagePacket->Count != vmxferpagePacket->RangeCount)
1208         {
1209                 DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer page...got %d", vmxferpagePacket->RangeCount, xferpagePacket->Count);
1210         }
1211
1212         // Each range represents 1 RNDIS pkt that contains 1 ethernet frame
1213         for (i=0; i < (count - 1); i++)
1214         {
1215                 entry = REMOVE_HEAD_LIST(&listHead);
1216                 netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry);
1217
1218                 // Initialize the netvsc packet
1219                 netvscPacket->XferPagePacket = xferpagePacket;
1220                 netvscPacket->Completion.Recv.OnReceiveCompletion = NetVscOnReceiveCompletion;
1221                 netvscPacket->Completion.Recv.ReceiveCompletionContext = netvscPacket;
1222                 netvscPacket->Device = Device;
1223                 netvscPacket->Completion.Recv.ReceiveCompletionTid = vmxferpagePacket->d.TransactionId; // Save this so that we can send it back
1224
1225                 netvscPacket->TotalDataBufferLength = vmxferpagePacket->Ranges[i].ByteCount;
1226                 netvscPacket->PageBufferCount = 1;
1227
1228                 ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + vmxferpagePacket->Ranges[i].ByteCount < netDevice->ReceiveBufferSize);
1229
1230                 netvscPacket->PageBuffers[0].Length = vmxferpagePacket->Ranges[i].ByteCount;
1231
1232                 start = GetPhysicalAddress((void*)((ULONG_PTR)netDevice->ReceiveBuffer + vmxferpagePacket->Ranges[i].ByteOffset));
1233
1234                 netvscPacket->PageBuffers[0].Pfn = start >> PAGE_SHIFT;
1235                 endVirtual = (ULONG_PTR)netDevice->ReceiveBuffer
1236                     + vmxferpagePacket->Ranges[i].ByteOffset
1237                     + vmxferpagePacket->Ranges[i].ByteCount -1;
1238                 end = GetPhysicalAddress((void*)endVirtual);
1239
1240                 // Calculate the page relative offset
1241                 netvscPacket->PageBuffers[0].Offset = vmxferpagePacket->Ranges[i].ByteOffset & (PAGE_SIZE -1);
1242                 if ((end >> PAGE_SHIFT) != (start>>PAGE_SHIFT)) {
1243                     //Handle frame across multiple pages:
1244                     netvscPacket->PageBuffers[0].Length =
1245                         (netvscPacket->PageBuffers[0].Pfn <<PAGE_SHIFT) + PAGE_SIZE - start;
1246                     bytesRemain = netvscPacket->TotalDataBufferLength - netvscPacket->PageBuffers[0].Length;
1247                     for (j=1; j<NETVSC_PACKET_MAXPAGE; j++) {
1248                         netvscPacket->PageBuffers[j].Offset = 0;
1249                         if (bytesRemain <= PAGE_SIZE) {
1250                             netvscPacket->PageBuffers[j].Length = bytesRemain;
1251                             bytesRemain = 0;
1252                         } else {
1253                             netvscPacket->PageBuffers[j].Length = PAGE_SIZE;
1254                             bytesRemain -= PAGE_SIZE;
1255                         }
1256                         netvscPacket->PageBuffers[j].Pfn =
1257                             GetPhysicalAddress((void*)(endVirtual - bytesRemain)) >> PAGE_SHIFT;
1258                         netvscPacket->PageBufferCount++;
1259                         if (bytesRemain == 0)
1260                             break;
1261                     }
1262                     ASSERT(bytesRemain == 0);
1263                 }
1264                 DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => (pfn %llx, offset %u, len %u)",
1265                         i,
1266                         vmxferpagePacket->Ranges[i].ByteOffset,
1267                         vmxferpagePacket->Ranges[i].ByteCount,
1268                         netvscPacket->PageBuffers[0].Pfn,
1269                         netvscPacket->PageBuffers[0].Offset,
1270                         netvscPacket->PageBuffers[0].Length);
1271
1272                 // Pass it to the upper layer
1273                 ((NETVSC_DRIVER_OBJECT*)Device->Driver)->OnReceiveCallback(Device, netvscPacket);
1274
1275                 NetVscOnReceiveCompletion(netvscPacket->Completion.Recv.ReceiveCompletionContext);
1276         }
1277
1278         ASSERT(IsListEmpty(&listHead));
1279
1280         PutNetDevice(Device);
1281         DPRINT_EXIT(NETVSC);
1282 }
1283
1284
1285 static void
1286 NetVscSendReceiveCompletion(
1287         DEVICE_OBJECT   *Device,
1288         UINT64                  TransactionId
1289         )
1290 {
1291         NVSP_MESSAGE recvcompMessage;
1292         int retries=0;
1293         int ret=0;
1294
1295         DPRINT_DBG(NETVSC, "Sending receive completion pkt - %llx", TransactionId);
1296
1297         recvcompMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacketComplete;
1298
1299         // FIXME: Pass in the status
1300         recvcompMessage.Messages.Version1Messages.SendRNDISPacketComplete.Status = NvspStatusSuccess;
1301
1302 retry_send_cmplt:
1303         // Send the completion
1304         ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
1305                                                                                                                         &recvcompMessage,
1306                                                                                                                         sizeof(NVSP_MESSAGE),
1307                                                                                                                         TransactionId,
1308                                                                                                                         VmbusPacketTypeCompletion,
1309                                                                                                                         0);
1310         if (ret == 0) // success
1311         {
1312                 // no-op
1313         }
1314         else if (ret == -1) // no more room...wait a bit and attempt to retry 3 times
1315         {
1316                 retries++;
1317                 DPRINT_ERR(NETVSC, "unable to send receive completion pkt (tid %llx)...retrying %d", TransactionId, retries);
1318
1319                 if (retries < 4)
1320                 {
1321                         Sleep(100);
1322                         goto retry_send_cmplt;
1323                 }
1324                 else
1325                 {
1326                         DPRINT_ERR(NETVSC, "unable to send receive completion pkt (tid %llx)...give up retrying", TransactionId);
1327                 }
1328         }
1329         else
1330         {
1331                 DPRINT_ERR(NETVSC, "unable to send receive completion pkt - %llx", TransactionId);
1332         }
1333 }
1334
1335 //
1336 // Send a receive completion packet to RNDIS device (ie NetVsp)
1337 //
1338 static void
1339 NetVscOnReceiveCompletion(
1340         PVOID Context)
1341 {
1342         NETVSC_PACKET *packet = (NETVSC_PACKET*)Context;
1343         DEVICE_OBJECT *device = (DEVICE_OBJECT*)packet->Device;
1344         NETVSC_DEVICE* netDevice;
1345         UINT64  transactionId=0;
1346         BOOL fSendReceiveComp = FALSE;
1347
1348         DPRINT_ENTER(NETVSC);
1349
1350         ASSERT(packet->XferPagePacket);
1351
1352         // Even though it seems logical to do a GetOutboundNetDevice() here to send out receive completion,
1353         // we are using GetInboundNetDevice() since we may have disable outbound traffic already.
1354         netDevice = GetInboundNetDevice(device);
1355         if (!netDevice)
1356         {
1357                 DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?");
1358                 DPRINT_EXIT(NETVSC);
1359                 return;
1360         }
1361
1362         // Overloading use of the lock.
1363         SpinlockAcquire(netDevice->ReceivePacketListLock);
1364
1365         ASSERT(packet->XferPagePacket->Count > 0);
1366         packet->XferPagePacket->Count--;
1367
1368         // Last one in the line that represent 1 xfer page packet.
1369         // Return the xfer page packet itself to the freelist
1370         if (packet->XferPagePacket->Count == 0)
1371         {
1372                 fSendReceiveComp = TRUE;
1373                 transactionId = packet->Completion.Recv.ReceiveCompletionTid;
1374
1375                 INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &packet->XferPagePacket->ListEntry);
1376         }
1377
1378         // Put the packet back
1379         INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &packet->ListEntry);
1380         SpinlockRelease(netDevice->ReceivePacketListLock);
1381
1382         // Send a receive completion for the xfer page packet
1383         if (fSendReceiveComp)
1384         {
1385                 NetVscSendReceiveCompletion(device, transactionId);
1386         }
1387
1388         PutNetDevice(device);
1389         DPRINT_EXIT(NETVSC);
1390 }
1391
1392
1393
1394 void
1395 NetVscOnChannelCallback(
1396         PVOID Context
1397         )
1398 {
1399         const int netPacketSize=2048;
1400         int ret=0;
1401         DEVICE_OBJECT *device=(DEVICE_OBJECT*)Context;
1402         NETVSC_DEVICE *netDevice;
1403
1404         UINT32 bytesRecvd;
1405         UINT64 requestId;
1406         UCHAR packet[netPacketSize];
1407         VMPACKET_DESCRIPTOR *desc;
1408         UCHAR   *buffer=packet;
1409         int             bufferlen=netPacketSize;
1410
1411
1412         DPRINT_ENTER(NETVSC);
1413
1414         ASSERT(device);
1415
1416         netDevice = GetInboundNetDevice(device);
1417         if (!netDevice)
1418         {
1419                 DPRINT_ERR(NETVSC, "net device (%p) shutting down...ignoring inbound packets", netDevice);
1420                 DPRINT_EXIT(NETVSC);
1421                 return;
1422         }
1423
1424         do
1425         {
1426                 ret = device->Driver->VmbusChannelInterface.RecvPacketRaw(device,
1427                                                                                                                                         buffer,
1428                                                                                                                                         bufferlen,
1429                                                                                                                                         &bytesRecvd,
1430                                                                                                                                         &requestId);
1431
1432                 if (ret == 0)
1433                 {
1434                         if (bytesRecvd > 0)
1435                         {
1436                                 DPRINT_DBG(NETVSC, "receive %d bytes, tid %llx", bytesRecvd, requestId);
1437
1438                                 desc = (VMPACKET_DESCRIPTOR*)buffer;
1439                                 switch (desc->Type)
1440                                 {
1441                                         case VmbusPacketTypeCompletion:
1442                                                 NetVscOnSendCompletion(device, desc);
1443                                                 break;
1444
1445                                         case VmbusPacketTypeDataUsingTransferPages:
1446                                                 NetVscOnReceive(device, desc);
1447                                                 break;
1448
1449                                         default:
1450                                                 DPRINT_ERR(NETVSC, "unhandled packet type %d, tid %llx len %d\n", desc->Type, requestId, bytesRecvd);
1451                                                 break;
1452                                 }
1453
1454                                 // reset
1455                                 if (bufferlen > netPacketSize)
1456                                 {
1457                                         MemFree(buffer);
1458
1459                                         buffer = packet;
1460                                         bufferlen = netPacketSize;
1461                                 }
1462                         }
1463                         else
1464                         {
1465                                 //DPRINT_DBG(NETVSC, "nothing else to read...");
1466
1467                                 // reset
1468                                 if (bufferlen > netPacketSize)
1469                                 {
1470                                         MemFree(buffer);
1471
1472                                         buffer = packet;
1473                                         bufferlen = netPacketSize;
1474                                 }
1475
1476                                 break;
1477                         }
1478                 }
1479                 else if (ret == -2) // Handle large packet
1480                 {
1481                         buffer = MemAllocAtomic(bytesRecvd);
1482                         if (buffer == NULL)
1483                         {
1484                                 // Try again next time around
1485                                 DPRINT_ERR(NETVSC, "unable to allocate buffer of size (%d)!!", bytesRecvd);
1486                                 break;
1487                         }
1488
1489                         bufferlen = bytesRecvd;
1490                 }
1491                 else
1492                 {
1493                         ASSERT(0);
1494                 }
1495         } while (1);
1496
1497         PutNetDevice(device);
1498         DPRINT_EXIT(NETVSC);
1499         return;
1500 }