83ab43baf10abafd829e4b7b721f14a4061c0877
[people/sha0/winvblock.git] / src / aoe / driver.c
1 /**
2  * Copyright (C) 2009-2010, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  * Copyright 2006-2008, V.
4  * For WinAoE contact information, see http://winaoe.org/
5  *
6  * This file is part of WinVBlock, derived from WinAoE.
7  *
8  * WinVBlock is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * WinVBlock is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /**
23  * @file
24  *
25  * AoE specifics.
26  */
27
28 #include <stdio.h>
29 #include <ntddk.h>
30
31 #include "winvblock.h"
32 #include "wv_stdlib.h"
33 #include "wv_string.h"
34 #include "portable.h"
35 #include "irp.h"
36 #include "driver.h"
37 #include "device.h"
38 #include "disk.h"
39 #include "mount.h"
40 #include "bus.h"
41 #include "aoe.h"
42 #include "registry.h"
43 #include "protocol.h"
44 #include "debug.h"
45
46 #define AOEPROTOCOLVER 1
47
48 extern NTSTATUS STDCALL ZwWaitForSingleObject(
49     IN HANDLE Handle,
50     IN winvblock__bool Alertable,
51     IN PLARGE_INTEGER Timeout OPTIONAL
52   );
53
54 /* Forward declarations. */
55 struct aoe__disk_type_;
56 static void STDCALL aoe__thread_(IN void *);
57 irp__handler aoe__bus_dev_ctl_dispatch;
58 static void aoe__process_abft_(void);
59 static void STDCALL aoe__unload_(IN PDRIVER_OBJECT);
60 static struct aoe__disk_type_ * aoe__create_disk_(void);
61 static device__free_func aoe__free_disk_;
62
63 /** Tag types. */
64 enum aoe__tag_type_
65   {
66     aoe__tag_type_io_,
67     aoe__tag_type_search_drive_
68   };
69
70 #ifdef _MSC_VER
71 #  pragma pack(1)
72 #endif
73
74 /** AoE packet. */
75 struct aoe__packet_
76   {
77     winvblock__uint8 ReservedFlag:2;
78     winvblock__uint8 ErrorFlag:1;
79     winvblock__uint8 ResponseFlag:1;
80     winvblock__uint8 Ver:4;
81     winvblock__uint8 Error;
82     winvblock__uint16 Major;
83     winvblock__uint8 Minor;
84     winvblock__uint8 Command;
85     winvblock__uint32 Tag;
86   
87     winvblock__uint8 WriteAFlag:1;
88     winvblock__uint8 AsyncAFlag:1;
89     winvblock__uint8 Reserved1AFlag:2;
90     winvblock__uint8 DeviceHeadAFlag:1;
91     winvblock__uint8 Reserved2AFlag:1;
92     winvblock__uint8 ExtendedAFlag:1;
93     winvblock__uint8 Reserved3AFlag:1;
94     union
95       {
96         winvblock__uint8 Err;
97         winvblock__uint8 Feature;
98       };
99     winvblock__uint8 Count;
100     union
101       {
102         winvblock__uint8 Cmd;
103         winvblock__uint8 Status;
104       };
105   
106     winvblock__uint8 Lba0;
107     winvblock__uint8 Lba1;
108     winvblock__uint8 Lba2;
109     winvblock__uint8 Lba3;
110     winvblock__uint8 Lba4;
111     winvblock__uint8 Lba5;
112     winvblock__uint16 Reserved;
113   
114     winvblock__uint8 Data[];
115   } __attribute__((__packed__));
116
117 #ifdef _MSC_VER
118 #  pragma pack()
119 #endif
120
121 /** An I/O request. */
122 struct aoe__io_req_
123   {
124     disk__io_mode Mode;
125     winvblock__uint32 SectorCount;
126     winvblock__uint8_ptr Buffer;
127     PIRP Irp;
128     winvblock__uint32 TagCount;
129     winvblock__uint32 TotalTags;
130   };
131
132 /** A work item "tag". */
133 struct aoe__work_tag_
134   {
135     enum aoe__tag_type_ type;
136     device__type_ptr device;
137     struct aoe__io_req_ * request_ptr;
138     winvblock__uint32 Id;
139     struct aoe__packet_ * packet_data;
140     winvblock__uint32 PacketSize;
141     LARGE_INTEGER FirstSendTime;
142     LARGE_INTEGER SendTime;
143     winvblock__uint32 BufferOffset;
144     winvblock__uint32 SectorCount;
145     struct aoe__work_tag_ * next;
146     struct aoe__work_tag_ * previous;
147   };
148
149 /** A disk search. */
150 struct aoe__disk_search_
151   {
152     device__type_ptr device;
153     struct aoe__work_tag_ * tag;
154     struct aoe__disk_search_ * next;
155   };
156
157 enum aoe__search_state_
158   {
159     aoe__search_state_search_nic_,
160     aoe__search_state_get_size_,
161     aoe__search_state_getting_size_,
162     aoe__search_state_get_geometry_,
163     aoe__search_state_getting_geometry_,
164     aoe__search_state_get_max_sectors_per_packet_,
165     aoe__search_state_getting_max_sectors_per_packet_,
166     aoe__search_state_done_
167   };
168
169 /** The AoE disk type. */
170 struct aoe__disk_type_
171   {
172     disk__type_ptr disk;
173     winvblock__uint32 MTU;
174     winvblock__uint8 ClientMac[6];
175     winvblock__uint8 ServerMac[6];
176     winvblock__uint32 Major;
177     winvblock__uint32 Minor;
178     winvblock__uint32 MaxSectorsPerPacket;
179     winvblock__uint32 Timeout;
180     enum aoe__search_state_ search_state;
181     device__free_func * prev_free;
182     LIST_ENTRY tracking;
183   };
184
185 struct aoe__target_list_
186   {
187     aoe__mount_target Target;
188     struct aoe__target_list_ * next;
189   };
190
191 /** Private globals. */
192 static struct aoe__target_list_ * aoe__target_list_ = NULL;
193 static KSPIN_LOCK aoe__target_list_spinlock_;
194 static winvblock__bool aoe__stop_ = FALSE;
195 static KSPIN_LOCK aoe__spinlock_;
196 static KEVENT aoe__thread_sig_evt_;
197 static struct aoe__work_tag_ * aoe__tag_list_ = NULL;
198 static struct aoe__work_tag_ * aoe__tag_list_last_ = NULL;
199 static struct aoe__work_tag_ * aoe__probe_tag_ = NULL;
200 static struct aoe__disk_search_ * aoe__disk_search_list_ = NULL;
201 static LONG aoe__outstanding_tags_ = 0;
202 static HANDLE aoe__thread_handle_;
203 static winvblock__bool aoe__started_ = FALSE;
204 static LIST_ENTRY aoe__disk_list_;
205 static KSPIN_LOCK aoe__disk_list_lock_;
206
207 static irp__handling handling_table[] =
208   {
209     /* Major, minor, any major?, any minor?, handler. */
210     { IRP_MJ_DEVICE_CONTROL, 0, FALSE, TRUE, aoe__bus_dev_ctl_dispatch }
211   };
212
213 /* Yield a pointer to the AoE disk. */
214 static struct aoe__disk_type_ * aoe__get_(device__type_ptr dev_ptr)
215   {
216     return disk__get_ptr(dev_ptr)->ext;
217   }
218
219 static winvblock__bool STDCALL setup_reg(OUT PNTSTATUS status_out)
220   {
221     NTSTATUS status;
222     winvblock__bool Updated = FALSE;
223     WCHAR InterfacesPath[] = L"\\Ndi\\Interfaces\\";
224     WCHAR LinkagePath[] = L"\\Linkage\\";
225     WCHAR NdiPath[] = L"\\Ndi\\";
226     WCHAR DriverServiceNamePath[] =
227       L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
228     OBJECT_ATTRIBUTES SubKeyObject;
229     HANDLE
230       ControlKeyHandle, NetworkClassKeyHandle, SubKeyHandle;
231     winvblock__uint32
232       i, SubkeyIndex, ResultLength, InterfacesKeyStringLength,
233       LinkageKeyStringLength, NdiKeyStringLength, NewValueLength;
234     PWCHAR
235       InterfacesKeyString, LinkageKeyString, NdiKeyString,
236       DriverServiceNameString, NewValue;
237     UNICODE_STRING
238       InterfacesKey, LinkageKey, NdiKey, LowerRange, UpperBind, Service,
239       DriverServiceName;
240     PKEY_BASIC_INFORMATION KeyInformation;
241     PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
242     winvblock__bool Update, Found;
243   
244     DBG("Entry\n");
245   
246     RtlInitUnicodeString(&LowerRange, L"LowerRange");
247     RtlInitUnicodeString(&UpperBind, L"UpperBind");
248     RtlInitUnicodeString(&Service, L"Service");
249   
250     /* Open the network adapter class key. */
251     status = registry__open_key(
252         (L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Class\\"
253           L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\"),
254                         &NetworkClassKeyHandle
255       );
256     if (!NT_SUCCESS(status))
257       goto err_keyopennetworkclass;
258   
259     /* Enumerate through subkeys. */
260     SubkeyIndex = 0;
261     while ((status = ZwEnumerateKey(
262         NetworkClassKeyHandle,
263         SubkeyIndex,
264                         KeyBasicInformation,
265         NULL,
266         0,
267                         &ResultLength
268       )) != STATUS_NO_MORE_ENTRIES)
269       {
270         if ((status != STATUS_SUCCESS) &&
271             (status != STATUS_BUFFER_OVERFLOW) &&
272                 (status != STATUS_BUFFER_TOO_SMALL)
273           )
274                 {
275                   DBG("ZwEnumerateKey 1 failed (%lx)\n", status);
276                   goto e0_1;
277                 }
278         if ((KeyInformation = wv_malloc(ResultLength)) == NULL)
279           {
280             DBG("wv_malloc KeyData failed\n");
281                 goto e0_1;
282                 registry__close_key(NetworkClassKeyHandle);
283                 }
284         if (!(NT_SUCCESS(
285             ZwEnumerateKey(
286                 NetworkClassKeyHandle,
287                 SubkeyIndex,
288                 KeyBasicInformation,
289                           KeyInformation,
290                 ResultLength,
291                 &ResultLength
292           ))))
293                 {
294                   DBG ("ZwEnumerateKey 2 failed\n");
295                   goto e0_2;
296                 }
297   
298         InterfacesKeyStringLength =
299                 KeyInformation->NameLength + sizeof InterfacesPath;
300         InterfacesKeyString = wv_malloc(InterfacesKeyStringLength);
301         if (InterfacesKeyString == NULL)
302           {
303             DBG("wv_malloc InterfacesKeyString failed\n");
304                 goto e0_2;
305                 }
306   
307         RtlCopyMemory(
308             InterfacesKeyString,
309             KeyInformation->Name,
310                       KeyInformation->NameLength
311           );
312         RtlCopyMemory(
313             InterfacesKeyString +
314               (KeyInformation->NameLength / sizeof (WCHAR)),
315                       InterfacesPath,
316             sizeof InterfacesPath
317           );
318         RtlInitUnicodeString(&InterfacesKey, InterfacesKeyString);
319   
320         Update = FALSE;
321         InitializeObjectAttributes(
322             &SubKeyObject,
323             &InterfacesKey,
324                                   OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
325                                   NetworkClassKeyHandle,
326             NULL
327           );
328         if (NT_SUCCESS(ZwOpenKey(&SubKeyHandle, KEY_ALL_ACCESS, &SubKeyObject)))
329                 {
330                   if ((status = ZwQueryValueKey(
331                 SubKeyHandle,
332                 &LowerRange,
333                                       KeyValuePartialInformation,
334                 NULL,
335                 0,
336                                       &ResultLength
337               )) != STATUS_OBJECT_NAME_NOT_FOUND )
338                     {
339                       if ((status != STATUS_SUCCESS) &&
340                     (status != STATUS_BUFFER_OVERFLOW) &&
341                     (status != STATUS_BUFFER_TOO_SMALL))
342                         {
343                           DBG(
344                         "ZwQueryValueKey InterfacesKey 1 failed (%lx)\n",
345                                         status
346                       );
347                           goto e1_1;
348                         }
349                     if ((KeyValueInformation = wv_malloc(ResultLength)) == NULL)
350                   {
351                     DBG("wv_malloc InterfacesKey KeyValueData failed\n");
352                           goto e1_1;
353                         }
354                     if (!(NT_SUCCESS(ZwQueryValueKey(
355                     SubKeyHandle,
356                     &LowerRange,
357                     KeyValuePartialInformation,
358                     KeyValueInformation,
359                     ResultLength,
360                     &ResultLength
361                   ))))
362                         {
363                           DBG("ZwQueryValueKey InterfacesKey 2 failed\n");
364                           goto e1_2;
365                         }
366                 if (wv_memcmpeq(
367                     L"ethernet",
368                     KeyValueInformation->Data,
369                     sizeof L"ethernet"
370                   ))
371                   Update = TRUE;
372                 wv_free(KeyValueInformation);
373                     if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
374                         {
375                           DBG("ZwClose InterfacesKey SubKeyHandle failed\n");
376                           goto e1_0;
377                         }
378                     }
379           }
380         wv_free(InterfacesKeyString);
381   
382         if (Update)
383                 {
384             LinkageKeyStringLength =
385                     KeyInformation->NameLength + sizeof LinkagePath;
386             if ((LinkageKeyString = wv_malloc(LinkageKeyStringLength)) == NULL)
387               {
388                 DBG("wv_malloc LinkageKeyString failed\n");
389                     goto e0_2;
390                     }
391                 RtlCopyMemory(
392                 LinkageKeyString,
393                 KeyInformation->Name,
394                                   KeyInformation->NameLength
395               );
396                   RtlCopyMemory(
397                 LinkageKeyString +
398                 (KeyInformation->NameLength / sizeof (WCHAR)),
399                             LinkagePath,
400                 sizeof LinkagePath
401               );
402                 RtlInitUnicodeString(&LinkageKey, LinkageKeyString);
403   
404                 InitializeObjectAttributes(
405                 &SubKeyObject,
406                 &LinkageKey,
407                                       OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
408                                       NetworkClassKeyHandle,
409                 NULL
410               );
411                   if (!NT_SUCCESS(ZwCreateKey(
412                 &SubKeyHandle,
413                 KEY_ALL_ACCESS,
414                 &SubKeyObject,
415                 0,
416                 NULL,
417                             REG_OPTION_NON_VOLATILE,
418                 NULL
419               )))
420                     {
421                 DBG("ZwCreateKey failed (%lx)\n");
422                       goto e2_0;
423                   }
424                 if ((status = ZwQueryValueKey(
425                 SubKeyHandle,
426                 &UpperBind,
427                                   KeyValuePartialInformation,
428                 NULL,
429                 0,
430                                   &ResultLength
431               )) != STATUS_OBJECT_NAME_NOT_FOUND)
432                     {
433                       if ((status != STATUS_SUCCESS) &&
434                     (status != STATUS_BUFFER_OVERFLOW) &&
435                               (status != STATUS_BUFFER_TOO_SMALL))
436                         {
437                           DBG("ZwQueryValueKey LinkageKey 1 failed (%lx)\n", status);
438                           goto e2_1;
439                         }
440                 if ((KeyValueInformation = wv_malloc(ResultLength)) == NULL)
441                   {
442                     DBG("wv_malloc LinkageKey KeyValueData failed\n");
443                               goto e2_1;
444                         }
445                       if (!(NT_SUCCESS(ZwQueryValueKey(
446                     SubKeyHandle,
447                     &UpperBind,
448                     KeyValuePartialInformation,
449                                 KeyValueInformation,
450                     ResultLength,
451                                 &ResultLength
452                   ))))
453                         {
454                           DBG("ZwQueryValueKey LinkageKey 2 failed\n");
455                           goto e2_2;
456                         }
457   
458                     Found = FALSE;
459                       for (i = 0;
460                     i < (KeyValueInformation->DataLength -
461                                 sizeof winvblock__literal_w / sizeof (WCHAR));
462                             i++)
463                         {
464                     if (wv_memcmpeq(
465                         winvblock__literal_w,
466                         ((PWCHAR)KeyValueInformation->Data) + i,
467                         sizeof winvblock__literal_w
468                       ))
469                       {
470                                 Found = TRUE;
471                               break;
472                             } /* if wv_memcmpeq */
473                         } /* for */
474   
475                 if (Found)
476                         {
477                           NewValueLength = KeyValueInformation->DataLength;
478                     if ((NewValue = wv_malloc(NewValueLength)) == NULL)
479                       {
480                         DBG("wv_malloc NewValue 1 failed\n");
481                                   goto e2_2;
482                             }
483                               RtlCopyMemory(
484                         NewValue,
485                         KeyValueInformation->Data,
486                                           KeyValueInformation->DataLength
487                       );
488                         } /* if Found */
489                       else
490                         {
491                           Updated = TRUE;
492                           NewValueLength = KeyValueInformation->DataLength +
493                             sizeof winvblock__literal_w;
494                     if ((NewValue = wv_malloc(NewValueLength)) == NULL)
495                       {
496                         DBG("wv_malloc NewValue 2 failed\n");
497                               goto e2_2;
498                             }
499                           RtlCopyMemory(
500                         NewValue,
501                         winvblock__literal_w,
502                                           sizeof winvblock__literal_w
503                       );
504                           RtlCopyMemory(
505                         NewValue +
506                                                   (sizeof winvblock__literal_w / sizeof (WCHAR)),
507                                           KeyValueInformation->Data,
508                                           KeyValueInformation->DataLength
509                       );
510                                 } /* else !Found */
511                 wv_free(KeyValueInformation);
512                   }
513                   else
514                     {
515                 Updated = TRUE;
516                       NewValueLength = sizeof winvblock__literal_w + sizeof (WCHAR);
517                 if ((NewValue = wv_mallocz(NewValueLength)) == NULL)
518                   {
519                     DBG("wv_mallocz NewValue 3 failed\n");
520                               goto e2_1;
521                         }
522                     RtlCopyMemory(
523                     NewValue,
524                     winvblock__literal_w,
525                                       sizeof winvblock__literal_w
526                   );
527                   }
528                 if (!NT_SUCCESS(ZwSetValueKey(
529                 SubKeyHandle,
530                 &UpperBind,
531                 0,
532                 REG_MULTI_SZ,
533                 NewValue,
534                           NewValueLength
535               )))
536                     {
537                       DBG("ZwSetValueKey failed\n");
538                 wv_free(NewValue);
539                     goto e2_1;
540                   }
541             wv_free(NewValue);
542                   if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
543                     {
544                 DBG("ZwClose LinkageKey SubKeyHandle failed\n");
545                       goto e2_0;
546                   }
547             wv_free(LinkageKeyString);
548
549                   /* Not sure where this comes from. */
550                   #if 0
551             start nic (
552                 #endif
553                   NdiKeyStringLength = KeyInformation->NameLength + sizeof NdiPath;
554             if ((NdiKeyString = wv_malloc(NdiKeyStringLength)) == NULL)
555               {
556                 DBG("wv_malloc NdiKeyString failed\n");
557                       goto e0_2;
558                   }
559                   RtlCopyMemory(
560                 NdiKeyString,
561                 KeyInformation->Name,
562                                   KeyInformation->NameLength
563               );
564                   RtlCopyMemory(
565                 NdiKeyString + (KeyInformation->NameLength / sizeof (WCHAR)),
566                                   NdiPath,
567                 sizeof NdiPath
568               );
569                   RtlInitUnicodeString(&NdiKey, NdiKeyString);
570
571                   InitializeObjectAttributes(
572                 &SubKeyObject,
573                 &NdiKey,
574                                       OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
575                                       NetworkClassKeyHandle,
576                 NULL
577               );
578                   if (NT_SUCCESS(ZwOpenKey(
579                 &SubKeyHandle,
580                 KEY_ALL_ACCESS,
581                 &SubKeyObject
582               )))
583                     {
584                 if ((status = ZwQueryValueKey(
585                     SubKeyHandle,
586                     &Service,
587                                       KeyValuePartialInformation,
588                     NULL,
589                     0,
590                                       &ResultLength
591                   )) != STATUS_OBJECT_NAME_NOT_FOUND)
592                         {
593                           if ((status != STATUS_SUCCESS) &&
594                                   (status != STATUS_BUFFER_OVERFLOW) &&
595                                 (status != STATUS_BUFFER_TOO_SMALL))
596                             {
597                                 DBG("ZwQueryValueKey NdiKey 1 failed (%lx)\n", status);
598                               goto e3_1;
599                               }
600                   if ((KeyValueInformation = wv_malloc(ResultLength)) == NULL)
601                     {
602                       DBG("wv_malloc NdiKey KeyValueData failed\n");
603                                 goto e3_1;
604                             }
605                           if (!(NT_SUCCESS(ZwQueryValueKey(
606                       SubKeyHandle,
607                       &Service,
608                                       KeyValuePartialInformation,
609                       KeyValueInformation,
610                                     ResultLength,
611                       &ResultLength
612                     ))))
613                             {
614                                 DBG("ZwQueryValueKey NdiKey 2 failed\n");
615                       wv_free(KeyValueInformation);
616                                 goto e3_1;
617                             }
618                             if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
619                             {
620                                 DBG("ZwClose NdiKey SubKeyHandle failed\n");
621                               goto e3_0;
622                               }
623                   DriverServiceNameString = wv_malloc(
624                       sizeof DriverServiceNamePath +
625                         KeyValueInformation->DataLength -
626                         sizeof *DriverServiceNamePath
627                     );
628                   if (DriverServiceNameString == NULL)
629                     {
630                       DBG("wv_malloc DriverServiceNameString failed\n");
631                                 goto e3_0;
632                             }
633   
634                         RtlCopyMemory(
635                       DriverServiceNameString,
636                                             DriverServiceNamePath,
637                                           sizeof DriverServiceNamePath
638                     );
639                           RtlCopyMemory(
640                       DriverServiceNameString +
641                                               (sizeof DriverServiceNamePath / sizeof (WCHAR)) - 1,
642                                           KeyValueInformation->Data,
643                                             KeyValueInformation->DataLength
644                     );
645                           RtlInitUnicodeString(
646                       &DriverServiceName,
647                       DriverServiceNameString
648                     );
649                   #if 0
650                           DBG(
651                       "Starting driver %S -> %08x\n",
652                                         KeyValueInformation->Data,
653                                         ZwLoadDriver(&DriverServiceName)
654                     );
655                   #endif
656                     wv_free(DriverServiceNameString);
657                     wv_free(KeyValueInformation);
658                             }
659                   }
660             wv_free(NdiKeyString);
661               }
662         wv_free(KeyInformation);
663         SubkeyIndex++;
664       } /* while */
665     registry__close_key ( NetworkClassKeyHandle );
666     *status_out = STATUS_SUCCESS;
667     return Updated;
668   
669     e3_1:
670   
671     if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
672       DBG("ZwClose SubKeyHandle failed\n");
673     e3_0:
674   
675     wv_free(NdiKeyString);
676     goto e0_2;
677     e2_2:
678   
679     wv_free(KeyValueInformation);
680     e2_1:
681   
682     if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
683       DBG("ZwClose SubKeyHandle failed\n");
684     e2_0:
685   
686     wv_free(LinkageKeyString);
687     goto e0_2;
688     e1_2:
689   
690     wv_free(KeyValueInformation);
691     e1_1:
692   
693     if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
694       DBG("ZwClose SubKeyHandle failed\n");
695     e1_0:
696   
697     wv_free(InterfacesKeyString);
698     goto e0_2;
699     e0_2:
700   
701     wv_free(KeyInformation);
702     e0_1:
703   
704     registry__close_key(NetworkClassKeyHandle);
705     err_keyopennetworkclass:
706   
707     *status_out = STATUS_UNSUCCESSFUL;
708     return FALSE;
709   }
710
711 /**
712  * Start AoE operations.
713  *
714  * @ret Status          Return status code.
715  */
716 NTSTATUS STDCALL DriverEntry(
717     IN PDRIVER_OBJECT DriverObject,
718     IN PUNICODE_STRING RegistryPath
719   )
720   {
721     NTSTATUS Status;
722     OBJECT_ATTRIBUTES ObjectAttributes;
723     void * ThreadObject;
724   
725     DBG ( "Entry\n" );
726   
727     if ( aoe__started_ )
728       return STATUS_SUCCESS;
729     /* Initialize the global list of AoE disks. */
730     InitializeListHead ( &aoe__disk_list_ );
731     KeInitializeSpinLock ( &aoe__disk_list_lock_ );
732     /* Setup the Registry. */
733     if ( !NT_SUCCESS ( setup_reg ( &Status ) ) )
734       {
735         DBG ( "Could not update Registry!\n" );
736         return Status;
737       }
738     else
739       {
740         DBG ( "Registry updated\n" );
741       }
742     /* Start up the protocol. */
743     if ( !NT_SUCCESS ( Status = Protocol_Start (  ) ) )
744       {
745         DBG ( "Protocol startup failure!\n" );
746         return Status;
747       }
748     /* Allocate and zero-fill the global probe tag. */
749     aoe__probe_tag_ = wv_mallocz(sizeof *aoe__probe_tag_);
750     if (aoe__probe_tag_ == NULL) {
751         DBG ( "Couldn't allocate probe tag; bye!\n" );
752         return STATUS_INSUFFICIENT_RESOURCES;
753       }
754   
755     /* Set up the probe tag's AoE packet reference. */
756     aoe__probe_tag_->PacketSize = sizeof (struct aoe__packet_);
757     /* Allocate and zero-fill the probe tag's packet reference. */
758     aoe__probe_tag_->packet_data = wv_mallocz(
759         aoe__probe_tag_->PacketSize
760       );
761     if (aoe__probe_tag_->packet_data == NULL) {
762         DBG ( "Couldn't allocate aoe__probe_tag_->packet_data\n" );
763         wv_free(aoe__probe_tag_);
764         return STATUS_INSUFFICIENT_RESOURCES;
765       }
766     aoe__probe_tag_->SendTime.QuadPart = 0LL;
767   
768     /* Initialize the probe tag's AoE packet. */
769     aoe__probe_tag_->packet_data->Ver = AOEPROTOCOLVER;
770     aoe__probe_tag_->packet_data->Major =
771       htons ( ( winvblock__uint16 ) - 1 );
772     aoe__probe_tag_->packet_data->Minor = ( winvblock__uint8 ) - 1;
773     aoe__probe_tag_->packet_data->Cmd = 0xec;   /* IDENTIFY DEVICE */
774     aoe__probe_tag_->packet_data->Count = 1;
775   
776     /* Initialize global target-list spinlock. */
777     KeInitializeSpinLock ( &aoe__target_list_spinlock_ );
778   
779     /* Initialize global spin-lock and global thread signal event. */
780     KeInitializeSpinLock ( &aoe__spinlock_ );
781     KeInitializeEvent ( &aoe__thread_sig_evt_, SynchronizationEvent,
782                       FALSE );
783   
784     /* Initialize object attributes. */
785     InitializeObjectAttributes ( &ObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
786                                NULL, NULL );
787   
788     /* Create global thread. */
789     if (!NT_SUCCESS(Status = PsCreateSystemThread(
790         &aoe__thread_handle_,
791         THREAD_ALL_ACCESS,
792                         &ObjectAttributes,
793         NULL,
794         NULL,
795         aoe__thread_,
796                         NULL
797       )))
798       return Error ( "PsCreateSystemThread", Status );
799   
800     if ( !NT_SUCCESS
801          ( Status =
802          ObReferenceObjectByHandle ( aoe__thread_handle_,
803                                      THREAD_ALL_ACCESS, NULL, KernelMode,
804                                      &ThreadObject, NULL ) ) )
805       {
806         ZwClose ( aoe__thread_handle_ );
807         Error ( "ObReferenceObjectByHandle", Status );
808         aoe__stop_ = TRUE;
809         KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
810       }
811   
812     {
813       bus__type_ptr bus_ptr = bus__boot (  );
814       if ( !bus_ptr )
815         {
816         DBG ( "Unable to register for IOCTLs!\n" );
817         }
818       else
819         {
820         irp__reg_table ( &bus_ptr->device->irp_handler_chain, handling_table );
821         }
822     }
823     DriverObject->DriverUnload = aoe__unload_;
824     aoe__process_abft_();
825     aoe__started_ = TRUE;
826     DBG ( "Exit\n" );
827     return Status;
828   }
829
830 /**
831  * Stop AoE operations.
832  */
833 static void STDCALL aoe__unload_(IN PDRIVER_OBJECT DriverObject)
834   {
835     NTSTATUS Status;
836     struct aoe__disk_search_ * disk_searcher, * previous_disk_searcher;
837     struct aoe__work_tag_ * tag;
838     KIRQL Irql, Irql2;
839     struct aoe__target_list_ * Walker, * Next;
840   
841     DBG ( "Entry\n" );
842     /* If we're not already started, there's nothing to do. */
843     if ( !aoe__started_ )
844       return;
845     /* Stop the AoE protocol. */
846     Protocol_Stop (  );
847     /* If we're not already shutting down, signal the event. */
848     if ( !aoe__stop_ )
849       {
850         aoe__stop_ = TRUE;
851         KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
852         /* Wait until the event has been signalled. */
853         if ( !NT_SUCCESS
854            ( Status =
855              ZwWaitForSingleObject ( aoe__thread_handle_, FALSE,
856                                      NULL ) ) )
857         Error ( "AoE_Stop ZwWaitForSingleObject", Status );
858         ZwClose ( aoe__thread_handle_ );
859       }
860   
861     /* Free the target list. */
862     KeAcquireSpinLock ( &aoe__target_list_spinlock_, &Irql2 );
863     Walker = aoe__target_list_;
864     while ( Walker != NULL )
865       {
866         Next = Walker->next;
867         wv_free(Walker);
868         Walker = Next;
869       }
870     KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql2 );
871   
872     /* Wait until we have the global spin-lock. */
873     KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
874   
875     /* Free disk searches in the global disk search list. */
876     disk_searcher = aoe__disk_search_list_;
877     while ( disk_searcher != NULL )
878       {
879         KeSetEvent ( &( disk__get_ptr ( disk_searcher->device )->SearchEvent ),
880                    0, FALSE );
881         previous_disk_searcher = disk_searcher;
882         disk_searcher = disk_searcher->next;
883         wv_free(previous_disk_searcher);
884       }
885   
886     /* Cancel and free all tags in the global tag list. */
887     tag = aoe__tag_list_;
888     while ( tag != NULL )
889       {
890         if ( tag->request_ptr != NULL && --tag->request_ptr->TagCount == 0 )
891         {
892           tag->request_ptr->Irp->IoStatus.Information = 0;
893           tag->request_ptr->Irp->IoStatus.Status = STATUS_CANCELLED;
894           IoCompleteRequest ( tag->request_ptr->Irp, IO_NO_INCREMENT );
895       wv_free(tag->request_ptr);
896         }
897         if ( tag->next == NULL )
898         {
899       wv_free(tag->packet_data);
900       wv_free(tag);
901           tag = NULL;
902         }
903         else
904         {
905           tag = tag->next;
906       wv_free(tag->previous->packet_data);
907       wv_free(tag->previous);
908         }
909       }
910     aoe__tag_list_ = NULL;
911     aoe__tag_list_last_ = NULL;
912   
913     /* Free the global probe tag and its AoE packet. */
914     wv_free(aoe__probe_tag_->packet_data);
915     wv_free(aoe__probe_tag_);
916   
917     /* Release the global spin-lock. */
918     KeReleaseSpinLock ( &aoe__spinlock_, Irql );
919     {
920       bus__type_ptr bus_ptr = bus__boot (  );
921       if ( !bus_ptr )
922         {
923         DBG ( "Unable to un-register IOCTLs!\n" );
924         }
925       else
926         {
927         irp__unreg_table ( &bus_ptr->device->irp_handler_chain,
928                            handling_table );
929         }
930     }
931     aoe__started_ = FALSE;
932     DBG ( "Exit\n" );
933   }
934
935 /**
936  * Search for disk parameters.
937  *
938  * @v dev_ptr           The device extension for the disk.
939  *
940  * Returns TRUE if the disk could be matched, FALSE otherwise.
941  */
942 static disk__init_decl(init)
943   {
944     struct aoe__disk_search_
945       * disk_searcher, * disk_search_walker, * previous_disk_searcher;
946     LARGE_INTEGER Timeout, CurrentTime;
947     struct aoe__work_tag_ * tag, * tag_walker;
948     KIRQL Irql, InnerIrql;
949     LARGE_INTEGER MaxSectorsPerPacketSendTime;
950     winvblock__uint32 MTU;
951     struct aoe__disk_type_ * aoe_disk_ptr;
952   
953     aoe_disk_ptr = aoe__get_ ( disk_ptr->device );
954     /*
955      * Allocate our disk search 
956      */
957     if ((disk_searcher = wv_malloc(sizeof *disk_searcher)) == NULL) {
958         DBG ( "Couldn't allocate for disk_searcher; bye!\n" );
959         return FALSE;
960       }
961   
962     /*
963      * Initialize the disk search 
964      */
965     disk_searcher->device = disk_ptr->device;
966     disk_searcher->next = NULL;
967     aoe_disk_ptr->search_state = aoe__search_state_search_nic_;
968     KeResetEvent ( &disk_ptr->SearchEvent );
969   
970     /*
971      * Wait until we have the global spin-lock 
972      */
973     KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
974   
975     /*
976      * Add our disk search to the global list of disk searches 
977      */
978     if ( aoe__disk_search_list_ == NULL )
979       {
980         aoe__disk_search_list_ = disk_searcher;
981       }
982     else
983       {
984         disk_search_walker = aoe__disk_search_list_;
985         while ( disk_search_walker->next )
986         disk_search_walker = disk_search_walker->next;
987         disk_search_walker->next = disk_searcher;
988       }
989   
990     /*
991      * Release the global spin-lock 
992      */
993     KeReleaseSpinLock ( &aoe__spinlock_, Irql );
994   
995     /*
996      * We go through all the states until the disk is ready for use 
997      */
998     while ( TRUE )
999       {
1000         /*
1001          * Wait for our device's extension's search to be signalled 
1002          */
1003         /*
1004          * TODO: Make the below value a #defined constant 
1005          */
1006         /*
1007          * 500.000 * 100ns = 50.000.000 ns = 50ms 
1008          */
1009         Timeout.QuadPart = -500000LL;
1010         KeWaitForSingleObject ( &disk_ptr->SearchEvent, Executive, KernelMode,
1011                               FALSE, &Timeout );
1012         if ( aoe__stop_ )
1013         {
1014           DBG ( "AoE is shutting down; bye!\n" );
1015           return FALSE;
1016         }
1017   
1018         /*
1019          * Wait until we have the device extension's spin-lock 
1020          */
1021         KeAcquireSpinLock ( &disk_ptr->SpinLock, &Irql );
1022   
1023         if (aoe_disk_ptr->search_state == aoe__search_state_search_nic_)
1024         {
1025           if ( !Protocol_SearchNIC ( aoe_disk_ptr->ClientMac ) )
1026             {
1027               KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1028               continue;
1029             }
1030           else
1031             {
1032               /*
1033                * We found the adapter to use, get MTU next 
1034                */
1035               aoe_disk_ptr->MTU = Protocol_GetMTU ( aoe_disk_ptr->ClientMac );
1036               aoe_disk_ptr->search_state = aoe__search_state_get_size_;
1037             }
1038         }
1039   
1040         if (aoe_disk_ptr->search_state == aoe__search_state_getting_size_)
1041         {
1042           /*
1043            * Still getting the disk's size 
1044            */
1045           KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1046           continue;
1047         }
1048         if (aoe_disk_ptr->search_state == aoe__search_state_getting_geometry_)
1049         {
1050           /*
1051            * Still getting the disk's geometry 
1052            */
1053           KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1054           continue;
1055         }
1056         if (aoe_disk_ptr->search_state ==
1057           aoe__search_state_getting_max_sectors_per_packet_)
1058         {
1059           KeQuerySystemTime ( &CurrentTime );
1060           /*
1061            * TODO: Make the below value a #defined constant 
1062            */
1063           /*
1064            * 2.500.000 * 100ns = 250.000.000 ns = 250ms 
1065            */
1066           if ( CurrentTime.QuadPart >
1067                MaxSectorsPerPacketSendTime.QuadPart + 2500000LL )
1068             {
1069               DBG ( "No reply after 250ms for MaxSectorsPerPacket %d, "
1070                     "giving up\n", aoe_disk_ptr->MaxSectorsPerPacket );
1071               aoe_disk_ptr->MaxSectorsPerPacket--;
1072               aoe_disk_ptr->search_state = aoe__search_state_done_;
1073             }
1074           else
1075             {
1076               /*
1077                * Still getting the maximum sectors per packet count 
1078                */
1079               KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1080               continue;
1081             }
1082         }
1083   
1084         if (aoe_disk_ptr->search_state == aoe__search_state_done_)
1085         {
1086           /*
1087            * We've finished the disk search; perform clean-up 
1088            */
1089           KeAcquireSpinLock ( &aoe__spinlock_, &InnerIrql );
1090   
1091           /*
1092            * Tag clean-up: Find out if our tag is in the global tag list 
1093            */
1094           tag_walker = aoe__tag_list_;
1095           while ( tag_walker != NULL && tag_walker != tag )
1096             tag_walker = tag_walker->next;
1097           if ( tag_walker != NULL )
1098             {
1099               /*
1100                * We found it.  If it's at the beginning of the list, adjust
1101                * the list to point the the next tag
1102                */
1103               if ( tag->previous == NULL )
1104                 aoe__tag_list_ = tag->next;
1105               else
1106                 /*
1107                  * Remove our tag from the list 
1108                  */
1109                 tag->previous->next = tag->next;
1110               /*
1111                * If we 're at the end of the list, adjust the list's end to
1112                * point to the penultimate tag
1113                */
1114               if ( tag->next == NULL )
1115                 aoe__tag_list_last_ = tag->previous;
1116               else
1117                 /*
1118                  * Remove our tag from the list 
1119                  */
1120                 tag->next->previous = tag->previous;
1121               aoe__outstanding_tags_--;
1122               if ( aoe__outstanding_tags_ < 0 )
1123                 DBG ( "aoe__outstanding_tags_ < 0!!\n" );
1124               /*
1125                * Free our tag and its AoE packet 
1126                */
1127           wv_free(tag->packet_data);
1128           wv_free(tag);
1129             }
1130   
1131           /*
1132            * Disk search clean-up 
1133            */
1134           if ( aoe__disk_search_list_ == NULL )
1135             {
1136               DBG ( "aoe__disk_search_list_ == NULL!!\n" );
1137             }
1138           else
1139             {
1140               /*
1141                * Find our disk search in the global list of disk searches 
1142                */
1143               disk_search_walker = aoe__disk_search_list_;
1144               while ( disk_search_walker
1145                       && disk_search_walker->device != disk_ptr->device )
1146                 {
1147                   previous_disk_searcher = disk_search_walker;
1148                   disk_search_walker = disk_search_walker->next;
1149                 }
1150               if ( disk_search_walker )
1151                 {
1152                   /*
1153                    * We found our disk search.  If it's the first one in
1154                    * the list, adjust the list and remove it
1155                    */
1156                   if ( disk_search_walker == aoe__disk_search_list_ )
1157                     aoe__disk_search_list_ = disk_search_walker->next;
1158                   else
1159                     /*
1160                      * Just remove it 
1161                      */
1162                     previous_disk_searcher->next = disk_search_walker->next;
1163                   /*
1164                    * Free our disk search 
1165                    */
1166         wv_free(disk_search_walker);
1167                 }
1168               else
1169                 {
1170                   DBG ( "Disk not found in aoe__disk_search_list_!!\n" );
1171                 }
1172             }
1173   
1174           /*
1175            * Release global and device extension spin-locks 
1176            */
1177           KeReleaseSpinLock ( &aoe__spinlock_, InnerIrql );
1178           KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1179   
1180           DBG ( "Disk size: %I64uM cylinders: %I64u heads: %u "
1181                 "sectors: %u sectors per packet: %u\n",
1182                 disk_ptr->LBADiskSize / 2048, disk_ptr->Cylinders,
1183                 disk_ptr->Heads, disk_ptr->Sectors,
1184                 aoe_disk_ptr->MaxSectorsPerPacket );
1185           return TRUE;
1186         }
1187   
1188         #if 0
1189         if ( aoe_disk_ptr->search_state == aoe__search_state_done_)
1190         #endif
1191         /*
1192          * Establish our tag 
1193          */
1194         if ((tag = wv_mallocz(sizeof *tag)) == NULL) {
1195           DBG ( "Couldn't allocate tag\n" );
1196           KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1197           /*
1198            * Maybe next time around 
1199            */
1200           continue;
1201         }
1202         tag->type = aoe__tag_type_search_drive_;
1203         tag->device = disk_ptr->device;
1204   
1205         /*
1206          * Establish our tag's AoE packet 
1207          */
1208         tag->PacketSize = sizeof (struct aoe__packet_);
1209         if ((tag->packet_data = wv_mallocz(tag->PacketSize)) == NULL) {
1210           DBG ( "Couldn't allocate tag->packet_data\n" );
1211       wv_free(tag);
1212           tag = NULL;
1213           KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1214           /*
1215            * Maybe next time around 
1216            */
1217           continue;
1218         }
1219         tag->packet_data->Ver = AOEPROTOCOLVER;
1220         tag->packet_data->Major =
1221         htons ( ( winvblock__uint16 ) aoe_disk_ptr->Major );
1222         tag->packet_data->Minor = ( winvblock__uint8 ) aoe_disk_ptr->Minor;
1223         tag->packet_data->ExtendedAFlag = TRUE;
1224   
1225         /*
1226          * Initialize the packet appropriately based on our current phase 
1227          */
1228         switch ( aoe_disk_ptr->search_state )
1229         {
1230           case aoe__search_state_get_size_:
1231             /*
1232              * TODO: Make the below value into a #defined constant 
1233              */
1234             tag->packet_data->Cmd = 0xec;       /* IDENTIFY DEVICE */
1235             tag->packet_data->Count = 1;
1236             aoe_disk_ptr->search_state = aoe__search_state_getting_size_;
1237             break;
1238           case aoe__search_state_get_geometry_:
1239             /*
1240              * TODO: Make the below value into a #defined constant 
1241              */
1242             tag->packet_data->Cmd = 0x24;       /* READ SECTOR */
1243             tag->packet_data->Count = 1;
1244             aoe_disk_ptr->search_state = aoe__search_state_getting_geometry_;
1245             break;
1246           case aoe__search_state_get_max_sectors_per_packet_:
1247             /*
1248              * TODO: Make the below value into a #defined constant 
1249              */
1250             tag->packet_data->Cmd = 0x24;       /* READ SECTOR */
1251             tag->packet_data->Count =
1252               ( winvblock__uint8 ) ( ++aoe_disk_ptr->MaxSectorsPerPacket );
1253             KeQuerySystemTime ( &MaxSectorsPerPacketSendTime );
1254             aoe_disk_ptr->search_state =
1255               aoe__search_state_getting_max_sectors_per_packet_;
1256             /*
1257              * TODO: Make the below value into a #defined constant 
1258              */
1259             aoe_disk_ptr->Timeout = 200000;
1260             break;
1261           default:
1262             DBG ( "Undefined search_state!!\n" );
1263         wv_free(tag->packet_data);
1264         wv_free(tag);
1265             /*
1266              * TODO: Do we need to nullify tag here? 
1267              */
1268             KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1269             continue;
1270             break;
1271         }
1272   
1273         /*
1274          * Enqueue our tag 
1275          */
1276         tag->next = NULL;
1277         KeAcquireSpinLock ( &aoe__spinlock_, &InnerIrql );
1278         if ( aoe__tag_list_ == NULL )
1279         {
1280           aoe__tag_list_ = tag;
1281           tag->previous = NULL;
1282         }
1283         else
1284         {
1285           aoe__tag_list_last_->next = tag;
1286           tag->previous = aoe__tag_list_last_;
1287         }
1288         aoe__tag_list_last_ = tag;
1289         KeReleaseSpinLock ( &aoe__spinlock_, InnerIrql );
1290         KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1291       }
1292   }
1293
1294 static disk__io_decl(io)
1295   {
1296     struct aoe__io_req_ * request_ptr;
1297     struct aoe__work_tag_ * tag, * new_tag_list = NULL, * previous_tag = NULL;
1298     KIRQL Irql;
1299     winvblock__uint32 i;
1300     PHYSICAL_ADDRESS PhysicalAddress;
1301     winvblock__uint8_ptr PhysicalMemory;
1302     disk__type_ptr disk_ptr;
1303     struct aoe__disk_type_ * aoe_disk_ptr;
1304   
1305     /*
1306      * Establish pointers to the disk and AoE disk
1307      */
1308     disk_ptr = disk__get_ptr ( dev_ptr );
1309     aoe_disk_ptr = aoe__get_ ( dev_ptr );
1310   
1311     if ( aoe__stop_ )
1312       {
1313         /*
1314          * Shutting down AoE; we can't service this request 
1315          */
1316         irp->IoStatus.Information = 0;
1317         irp->IoStatus.Status = STATUS_CANCELLED;
1318         IoCompleteRequest ( irp, IO_NO_INCREMENT );
1319         return STATUS_CANCELLED;
1320       }
1321   
1322     if ( sector_count < 1 )
1323       {
1324         /*
1325          * A silly request 
1326          */
1327         DBG ( "sector_count < 1; cancelling\n" );
1328         irp->IoStatus.Information = 0;
1329         irp->IoStatus.Status = STATUS_CANCELLED;
1330         IoCompleteRequest ( irp, IO_NO_INCREMENT );
1331         return STATUS_CANCELLED;
1332       }
1333   
1334     /*
1335      * Allocate and zero-fill our request 
1336      */
1337     if ((request_ptr = wv_mallocz(sizeof *request_ptr)) == NULL) {
1338         DBG ( "Couldn't allocate for reques_ptr; bye!\n" );
1339         irp->IoStatus.Information = 0;
1340         irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1341         IoCompleteRequest ( irp, IO_NO_INCREMENT );
1342         return STATUS_INSUFFICIENT_RESOURCES;
1343       }
1344   
1345     /*
1346      * Initialize the request 
1347      */
1348     request_ptr->Mode = mode;
1349     request_ptr->SectorCount = sector_count;
1350     request_ptr->Buffer = buffer;
1351     request_ptr->Irp = irp;
1352     request_ptr->TagCount = 0;
1353   
1354     /*
1355      * Split the requested sectors into packets in tags
1356      */
1357     for ( i = 0; i < sector_count; i += aoe_disk_ptr->MaxSectorsPerPacket )
1358       {
1359         /*
1360          * Allocate each tag 
1361          */
1362         if ((tag = wv_mallocz(sizeof *tag)) == NULL) {
1363           DBG ( "Couldn't allocate tag; bye!\n" );
1364           /*
1365            * We failed while allocating tags; free the ones we built 
1366            */
1367           tag = new_tag_list;
1368           while ( tag != NULL )
1369             {
1370               previous_tag = tag;
1371               tag = tag->next;
1372           wv_free(previous_tag->packet_data);
1373           wv_free(previous_tag);
1374             }
1375       wv_free(request_ptr);
1376           irp->IoStatus.Information = 0;
1377           irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1378           IoCompleteRequest ( irp, IO_NO_INCREMENT );
1379           return STATUS_INSUFFICIENT_RESOURCES;
1380         }
1381   
1382         /*
1383          * Initialize each tag 
1384          */
1385         tag->type = aoe__tag_type_io_;
1386         tag->request_ptr = request_ptr;
1387         tag->device = dev_ptr;
1388         request_ptr->TagCount++;
1389         tag->Id = 0;
1390         tag->BufferOffset = i * disk_ptr->SectorSize;
1391         tag->SectorCount =
1392         ( ( sector_count - i ) <
1393           aoe_disk_ptr->MaxSectorsPerPacket ? sector_count -
1394           i : aoe_disk_ptr->MaxSectorsPerPacket );
1395   
1396         /*
1397          * Allocate and initialize each tag's AoE packet 
1398          */
1399         tag->PacketSize = sizeof (struct aoe__packet_);
1400         if ( mode == disk__io_mode_write )
1401         tag->PacketSize += tag->SectorCount * disk_ptr->SectorSize;
1402         if ((tag->packet_data = wv_mallocz(tag->PacketSize)) == NULL) {
1403           DBG ( "Couldn't allocate tag->packet_data; bye!\n" );
1404           /*
1405            * We failed while allocating an AoE packet; free
1406            * the tags we built
1407            */
1408       wv_free(tag);
1409           tag = new_tag_list;
1410           while ( tag != NULL )
1411             {
1412               previous_tag = tag;
1413               tag = tag->next;
1414           wv_free(previous_tag->packet_data);
1415           wv_free(previous_tag);
1416             }
1417       wv_free(request_ptr);
1418           irp->IoStatus.Information = 0;
1419           irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1420           IoCompleteRequest ( irp, IO_NO_INCREMENT );
1421           return STATUS_INSUFFICIENT_RESOURCES;
1422         }
1423         tag->packet_data->Ver = AOEPROTOCOLVER;
1424         tag->packet_data->Major =
1425         htons ( ( winvblock__uint16 ) aoe_disk_ptr->Major );
1426         tag->packet_data->Minor = ( winvblock__uint8 ) aoe_disk_ptr->Minor;
1427         tag->packet_data->Tag = 0;
1428         tag->packet_data->Command = 0;
1429         tag->packet_data->ExtendedAFlag = TRUE;
1430         if ( mode == disk__io_mode_read )
1431         {
1432           tag->packet_data->Cmd = 0x24; /* READ SECTOR */
1433         }
1434         else
1435         {
1436           tag->packet_data->Cmd = 0x34; /* WRITE SECTOR */
1437           tag->packet_data->WriteAFlag = 1;
1438         }
1439         tag->packet_data->Count = ( winvblock__uint8 ) tag->SectorCount;
1440         tag->packet_data->Lba0 =
1441         ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 0 ) & 255 );
1442         tag->packet_data->Lba1 =
1443         ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 8 ) & 255 );
1444         tag->packet_data->Lba2 =
1445         ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 16 ) & 255 );
1446         tag->packet_data->Lba3 =
1447         ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 24 ) & 255 );
1448         tag->packet_data->Lba4 =
1449         ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 32 ) & 255 );
1450         tag->packet_data->Lba5 =
1451         ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 40 ) & 255 );
1452   
1453         /*
1454          * For a write request, copy from the buffer into the AoE packet 
1455          */
1456         if ( mode == disk__io_mode_write )
1457         RtlCopyMemory ( tag->packet_data->Data, &buffer[tag->BufferOffset],
1458                         tag->SectorCount * disk_ptr->SectorSize );
1459   
1460         /*
1461          * Add this tag to the request's tag list 
1462          */
1463         tag->previous = previous_tag;
1464         tag->next = NULL;
1465         if ( new_tag_list == NULL )
1466         {
1467           new_tag_list = tag;
1468         }
1469         else
1470         {
1471           previous_tag->next = tag;
1472         }
1473         previous_tag = tag;
1474       }
1475     /*
1476      * Split the requested sectors into packets in tags
1477      */
1478     request_ptr->TotalTags = request_ptr->TagCount;
1479   
1480     /*
1481      * Wait until we have the global spin-lock 
1482      */
1483     KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
1484   
1485     /*
1486      * Enqueue our request's tag list to the global tag list 
1487      */
1488     if ( aoe__tag_list_last_ == NULL )
1489       {
1490         aoe__tag_list_ = new_tag_list;
1491       }
1492     else
1493       {
1494         aoe__tag_list_last_->next = new_tag_list;
1495         new_tag_list->previous = aoe__tag_list_last_;
1496       }
1497     /*
1498      * Adjust the global list to reflect our last tag 
1499      */
1500     aoe__tag_list_last_ = tag;
1501   
1502     irp->IoStatus.Information = 0;
1503     irp->IoStatus.Status = STATUS_PENDING;
1504     IoMarkIrpPending ( irp );
1505   
1506     KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1507     KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
1508     return STATUS_PENDING;
1509   }
1510
1511 static void STDCALL add_target(
1512     IN winvblock__uint8_ptr ClientMac,
1513     IN winvblock__uint8_ptr ServerMac,
1514     winvblock__uint16 Major,
1515     winvblock__uint8 Minor,
1516     LONGLONG LBASize
1517   )
1518   {
1519     struct aoe__target_list_ * Walker, * Last;
1520     KIRQL Irql;
1521   
1522     KeAcquireSpinLock ( &aoe__target_list_spinlock_, &Irql );
1523     Walker = Last = aoe__target_list_;
1524     while ( Walker != NULL )
1525       {
1526         if (wv_memcmpeq(&Walker->Target.ClientMac, ClientMac, 6) &&
1527           wv_memcmpeq(&Walker->Target.ServerMac, ServerMac, 6) &&
1528           Walker->Target.Major == Major
1529           && Walker->Target.Minor == Minor) {
1530           if ( Walker->Target.LBASize != LBASize )
1531             {
1532               DBG ( "LBASize changed for e%d.%d " "(%I64u->%I64u)\n", Major,
1533                     Minor, Walker->Target.LBASize, LBASize );
1534               Walker->Target.LBASize = LBASize;
1535             }
1536           KeQuerySystemTime ( &Walker->Target.ProbeTime );
1537           KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql );
1538           return;
1539         }
1540         Last = Walker;
1541         Walker = Walker->next;
1542       }
1543   
1544     if ((Walker = wv_malloc(sizeof *Walker)) == NULL) {
1545         DBG("wv_malloc Walker\n");
1546         KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql );
1547         return;
1548       }
1549     Walker->next = NULL;
1550     RtlCopyMemory ( Walker->Target.ClientMac, ClientMac, 6 );
1551     RtlCopyMemory ( Walker->Target.ServerMac, ServerMac, 6 );
1552     Walker->Target.Major = Major;
1553     Walker->Target.Minor = Minor;
1554     Walker->Target.LBASize = LBASize;
1555     KeQuerySystemTime ( &Walker->Target.ProbeTime );
1556   
1557     if ( Last == NULL )
1558       {
1559         aoe__target_list_ = Walker;
1560       }
1561     else
1562       {
1563         Last->next = Walker;
1564       }
1565     KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql );
1566   }
1567
1568 /**
1569  * Process an AoE reply.
1570  *
1571  * @v SourceMac         The AoE server's MAC address.
1572  * @v DestinationMac    The AoE client's MAC address.
1573  * @v Data              The AoE packet.
1574  * @v DataSize          The AoE packet's size.
1575  */
1576 NTSTATUS STDCALL aoe__reply(
1577     IN winvblock__uint8_ptr SourceMac,
1578     IN winvblock__uint8_ptr DestinationMac,
1579     IN winvblock__uint8_ptr Data,
1580     IN winvblock__uint32 DataSize
1581   )
1582   {
1583     struct aoe__packet_ * reply = (struct aoe__packet_ *) Data;
1584     LONGLONG LBASize;
1585     struct aoe__work_tag_ * tag;
1586     KIRQL Irql;
1587     winvblock__bool Found = FALSE;
1588     LARGE_INTEGER CurrentTime;
1589     disk__type_ptr disk_ptr;
1590     struct aoe__disk_type_ * aoe_disk_ptr;
1591   
1592     /*
1593      * Discard non-responses 
1594      */
1595     if ( !reply->ResponseFlag )
1596       return STATUS_SUCCESS;
1597   
1598     /*
1599      * If the response matches our probe, add the AoE disk device 
1600      */
1601     if ( aoe__probe_tag_->Id == reply->Tag )
1602       {
1603         RtlCopyMemory ( &LBASize, &reply->Data[200], sizeof ( LONGLONG ) );
1604         add_target ( DestinationMac, SourceMac, ntohs ( reply->Major ),
1605                    reply->Minor, LBASize );
1606         return STATUS_SUCCESS;
1607       }
1608   
1609     /*
1610      * Wait until we have the global spin-lock 
1611      */
1612     KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
1613   
1614     /*
1615      * Search for request tag 
1616      */
1617     if ( aoe__tag_list_ == NULL )
1618       {
1619         KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1620         return STATUS_SUCCESS;
1621       }
1622     tag = aoe__tag_list_;
1623     while ( tag != NULL )
1624       {
1625         if ( ( tag->Id == reply->Tag )
1626            && ( tag->packet_data->Major == reply->Major )
1627            && ( tag->packet_data->Minor == reply->Minor ) )
1628         {
1629           Found = TRUE;
1630           break;
1631         }
1632         tag = tag->next;
1633       }
1634     if ( !Found )
1635       {
1636         KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1637         return STATUS_SUCCESS;
1638       }
1639     else
1640       {
1641         /*
1642          * Remove the tag from the global tag list 
1643          */
1644         if ( tag->previous == NULL )
1645         aoe__tag_list_ = tag->next;
1646         else
1647         tag->previous->next = tag->next;
1648         if ( tag->next == NULL )
1649         aoe__tag_list_last_ = tag->previous;
1650         else
1651         tag->next->previous = tag->previous;
1652         aoe__outstanding_tags_--;
1653         if ( aoe__outstanding_tags_ < 0 )
1654         DBG ( "aoe__outstanding_tags_ < 0!!\n" );
1655         KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
1656       }
1657     KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1658   
1659     /*
1660      * Establish pointers to the disk device and AoE disk
1661      */
1662     disk_ptr = disk__get_ptr ( tag->device );
1663     aoe_disk_ptr = aoe__get_ ( tag->device );
1664   
1665     /*
1666      * If our tag was a discovery request, note the server 
1667      */
1668     if (wv_memcmpeq(aoe_disk_ptr->ServerMac, "\xff\xff\xff\xff\xff\xff", 6)) {
1669         RtlCopyMemory ( aoe_disk_ptr->ServerMac, SourceMac, 6 );
1670         DBG ( "Major: %d minor: %d found on server "
1671             "%02x:%02x:%02x:%02x:%02x:%02x\n", aoe_disk_ptr->Major,
1672             aoe_disk_ptr->Minor, SourceMac[0], SourceMac[1], SourceMac[2],
1673             SourceMac[3], SourceMac[4], SourceMac[5] );
1674       }
1675   
1676     KeQuerySystemTime ( &CurrentTime );
1677     aoe_disk_ptr->Timeout -=
1678       ( winvblock__uint32 ) ( ( aoe_disk_ptr->Timeout -
1679                               ( CurrentTime.QuadPart -
1680                                 tag->FirstSendTime.QuadPart ) ) / 1024 );
1681     /*
1682      * TODO: Replace the values below with #defined constants 
1683      */
1684     if ( aoe_disk_ptr->Timeout > 100000000 )
1685       aoe_disk_ptr->Timeout = 100000000;
1686   
1687     switch ( tag->type )
1688       {
1689         case aoe__tag_type_search_drive_:
1690         KeAcquireSpinLock ( &disk_ptr->SpinLock, &Irql );
1691         switch ( aoe_disk_ptr->search_state )
1692           {
1693             case aoe__search_state_getting_size_:
1694               /*
1695                * The reply tells us the disk size
1696                */
1697               RtlCopyMemory ( &disk_ptr->LBADiskSize, &reply->Data[200],
1698                               sizeof ( LONGLONG ) );
1699               /*
1700                * Next we are concerned with the disk geometry
1701                */
1702               aoe_disk_ptr->search_state = aoe__search_state_get_geometry_;
1703               break;
1704             case aoe__search_state_getting_geometry_:
1705               /*
1706                * FIXME: use real values from partition table.
1707                * We used to truncate a fractional end cylinder, but
1708                * now leave it be in the hopes everyone uses LBA
1709                */
1710               disk_ptr->SectorSize = 512;
1711               disk_ptr->Heads = 255;
1712               disk_ptr->Sectors = 63;
1713               disk_ptr->Cylinders =
1714                 disk_ptr->LBADiskSize / ( disk_ptr->Heads *
1715                                           disk_ptr->Sectors );
1716               /*
1717                * Next we are concerned with the maximum sectors per packet
1718                */
1719               aoe_disk_ptr->search_state =
1720                         aoe__search_state_get_max_sectors_per_packet_;
1721               break;
1722             case aoe__search_state_getting_max_sectors_per_packet_:
1723               DataSize -= sizeof (struct aoe__packet_);
1724               if ( DataSize <
1725                    ( aoe_disk_ptr->MaxSectorsPerPacket *
1726                      disk_ptr->SectorSize ) )
1727                 {
1728                   DBG ( "Packet size too low while getting "
1729                         "MaxSectorsPerPacket (tried %d, got size of %d)\n",
1730                         aoe_disk_ptr->MaxSectorsPerPacket, DataSize );
1731                   aoe_disk_ptr->MaxSectorsPerPacket--;
1732                   aoe_disk_ptr->search_state = aoe__search_state_done_;
1733                 }
1734               else if ( aoe_disk_ptr->MTU <
1735                         ( sizeof (struct aoe__packet_) +
1736                           ( ( aoe_disk_ptr->MaxSectorsPerPacket +
1737                               1 ) * disk_ptr->SectorSize ) ) )
1738                 {
1739                   DBG ( "Got MaxSectorsPerPacket %d at size of %d. "
1740                         "MTU of %d reached\n",
1741                         aoe_disk_ptr->MaxSectorsPerPacket, DataSize,
1742                         aoe_disk_ptr->MTU );
1743                   aoe_disk_ptr->search_state = aoe__search_state_done_;
1744                 }
1745               else
1746                 {
1747                   DBG ( "Got MaxSectorsPerPacket %d at size of %d, "
1748                         "trying next...\n", aoe_disk_ptr->MaxSectorsPerPacket,
1749                         DataSize );
1750                   aoe_disk_ptr->search_state =
1751                     aoe__search_state_get_max_sectors_per_packet_;
1752                 }
1753               break;
1754             default:
1755               DBG ( "Undefined search_state!\n" );
1756               break;
1757           }
1758         KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1759         KeSetEvent ( &disk_ptr->SearchEvent, 0, FALSE );
1760         break;
1761         case aoe__tag_type_io_:
1762         /*
1763          * If the reply is in response to a read request, get our data! 
1764          */
1765         if ( tag->request_ptr->Mode == disk__io_mode_read )
1766           RtlCopyMemory ( &tag->request_ptr->Buffer[tag->BufferOffset],
1767                           reply->Data,
1768                           tag->SectorCount * disk_ptr->SectorSize );
1769         /*
1770          * If this is the last reply expected for the read request,
1771          * complete the IRP and free the request
1772          */
1773         if ( InterlockedDecrement ( &tag->request_ptr->TagCount ) == 0 )
1774           {
1775             tag->request_ptr->Irp->IoStatus.Information =
1776               tag->request_ptr->SectorCount * disk_ptr->SectorSize;
1777             tag->request_ptr->Irp->IoStatus.Status = STATUS_SUCCESS;
1778             Driver_CompletePendingIrp ( tag->request_ptr->Irp );
1779         wv_free(tag->request_ptr);
1780           }
1781         break;
1782         default:
1783         DBG ( "Unknown tag type!!\n" );
1784         break;
1785       }
1786   
1787     KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
1788     wv_free(tag->packet_data);
1789     wv_free(tag);
1790     return STATUS_SUCCESS;
1791   }
1792
1793 void aoe__reset_probe(void)
1794   {
1795     aoe__probe_tag_->SendTime.QuadPart = 0LL;
1796   }
1797
1798 static void STDCALL aoe__thread_(IN void *StartContext)
1799   {
1800     LARGE_INTEGER Timeout, CurrentTime, ProbeTime, ReportTime;
1801     winvblock__uint32 NextTagId = 1;
1802     struct aoe__work_tag_ * tag;
1803     KIRQL Irql;
1804     winvblock__uint32 Sends = 0;
1805     winvblock__uint32 Resends = 0;
1806     winvblock__uint32 ResendFails = 0;
1807     winvblock__uint32 Fails = 0;
1808     winvblock__uint32 RequestTimeout = 0;
1809     disk__type_ptr disk_ptr;
1810     struct aoe__disk_type_ * aoe_disk_ptr;
1811   
1812     DBG ( "Entry\n" );
1813     ReportTime.QuadPart = 0LL;
1814     ProbeTime.QuadPart = 0LL;
1815   
1816     while ( TRUE )
1817       {
1818         /*
1819          * TODO: Make the below value a #defined constant 
1820          */
1821         /*
1822          * 100.000 * 100ns = 10.000.000 ns = 10ms
1823          */
1824         Timeout.QuadPart = -100000LL;
1825         KeWaitForSingleObject ( &aoe__thread_sig_evt_, Executive,
1826                               KernelMode, FALSE, &Timeout );
1827         KeResetEvent ( &aoe__thread_sig_evt_ );
1828         if ( aoe__stop_ )
1829         {
1830           DBG ( "Stopping...\n" );
1831           PsTerminateSystemThread ( STATUS_SUCCESS );
1832         }
1833   
1834         KeQuerySystemTime ( &CurrentTime );
1835         /*
1836          * TODO: Make the below value a #defined constant 
1837          */
1838         if ( CurrentTime.QuadPart > ( ReportTime.QuadPart + 10000000LL ) )
1839         {
1840           DBG ( "Sends: %d  Resends: %d  ResendFails: %d  Fails: %d  "
1841                 "aoe__outstanding_tags_: %d  RequestTimeout: %d\n", Sends,
1842                 Resends, ResendFails, Fails, aoe__outstanding_tags_,
1843                 RequestTimeout );
1844           Sends = 0;
1845           Resends = 0;
1846           ResendFails = 0;
1847           Fails = 0;
1848           KeQuerySystemTime ( &ReportTime );
1849         }
1850   
1851         /*
1852          * TODO: Make the below value a #defined constant 
1853          */
1854         if ( CurrentTime.QuadPart >
1855            ( aoe__probe_tag_->SendTime.QuadPart + 100000000LL ) )
1856         {
1857           aoe__probe_tag_->Id = NextTagId++;
1858           if ( NextTagId == 0 )
1859             NextTagId++;
1860           aoe__probe_tag_->packet_data->Tag = aoe__probe_tag_->Id;
1861           Protocol_Send ( "\xff\xff\xff\xff\xff\xff",
1862                           "\xff\xff\xff\xff\xff\xff",
1863                           ( winvblock__uint8_ptr ) aoe__probe_tag_->
1864                           packet_data, aoe__probe_tag_->PacketSize,
1865                           NULL );
1866           KeQuerySystemTime ( &aoe__probe_tag_->SendTime );
1867         }
1868   
1869         KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
1870         if ( aoe__tag_list_ == NULL )
1871         {
1872           KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1873           continue;
1874         }
1875         tag = aoe__tag_list_;
1876         while ( tag != NULL )
1877         {
1878           /*
1879            * Establish pointers to the disk and AoE disk
1880            */
1881           disk_ptr = disk__get_ptr ( tag->device );
1882           aoe_disk_ptr = aoe__get_ ( tag->device );
1883   
1884           RequestTimeout = aoe_disk_ptr->Timeout;
1885           if ( tag->Id == 0 )
1886             {
1887               if ( aoe__outstanding_tags_ <= 64 )
1888                 {
1889                   /*
1890                    * if ( aoe__outstanding_tags_ <= 102400 ) { 
1891                    */
1892                   if ( aoe__outstanding_tags_ < 0 )
1893                     DBG ( "aoe__outstanding_tags_ < 0!!\n" );
1894                   tag->Id = NextTagId++;
1895                   if ( NextTagId == 0 )
1896                     NextTagId++;
1897                   tag->packet_data->Tag = tag->Id;
1898                   if ( Protocol_Send
1899                        ( aoe_disk_ptr->ClientMac, aoe_disk_ptr->ServerMac,
1900                          ( winvblock__uint8_ptr ) tag->packet_data,
1901                          tag->PacketSize, tag ) )
1902                     {
1903                       KeQuerySystemTime ( &tag->FirstSendTime );
1904                       KeQuerySystemTime ( &tag->SendTime );
1905                       aoe__outstanding_tags_++;
1906                       Sends++;
1907                     }
1908                   else
1909                     {
1910                       Fails++;
1911                       tag->Id = 0;
1912                       break;
1913                     }
1914                 }
1915             }
1916           else
1917             {
1918               KeQuerySystemTime ( &CurrentTime );
1919               if ( CurrentTime.QuadPart >
1920                    ( tag->SendTime.QuadPart +
1921                      ( LONGLONG ) ( aoe_disk_ptr->Timeout * 2 ) ) )
1922                 {
1923                   if ( Protocol_Send
1924                        ( aoe_disk_ptr->ClientMac, aoe_disk_ptr->ServerMac,
1925                          ( winvblock__uint8_ptr ) tag->packet_data,
1926                          tag->PacketSize, tag ) )
1927                     {
1928                       KeQuerySystemTime ( &tag->SendTime );
1929                       aoe_disk_ptr->Timeout += aoe_disk_ptr->Timeout / 1000;
1930                       if ( aoe_disk_ptr->Timeout > 100000000 )
1931                         aoe_disk_ptr->Timeout = 100000000;
1932                       Resends++;
1933                     }
1934                   else
1935                     {
1936                       ResendFails++;
1937                       break;
1938                     }
1939                 }
1940             }
1941           tag = tag->next;
1942           if ( tag == aoe__tag_list_ )
1943             {
1944               DBG ( "Taglist Cyclic!!\n" );
1945               break;
1946             }
1947         }
1948         KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1949       }
1950     DBG ( "Exit\n" );
1951   }
1952
1953 static disk__max_xfer_len_decl(max_xfer_len)
1954   {
1955     struct aoe__disk_type_ * aoe_disk_ptr = aoe__get_(disk_ptr->device);
1956   
1957     return disk_ptr->SectorSize * aoe_disk_ptr->MaxSectorsPerPacket;
1958   }
1959
1960 static disk__pnp_id_decl(query_id)
1961   {
1962     struct aoe__disk_type_ * aoe_disk_ptr = aoe__get_(disk_ptr->device);
1963   
1964     switch ( query_type )
1965       {
1966         case BusQueryDeviceID:
1967         return swprintf ( buf_512, winvblock__literal_w L"\\AoEHardDisk" ) + 1;
1968         case BusQueryInstanceID:
1969         return swprintf ( buf_512, L"AoE_at_Shelf_%d.Slot_%d",
1970                           aoe_disk_ptr->Major, aoe_disk_ptr->Minor ) + 1;
1971         case BusQueryHardwareIDs:
1972         {
1973           winvblock__uint32 tmp =
1974             swprintf ( buf_512, winvblock__literal_w L"\\AoEHardDisk" ) + 1;
1975           tmp += swprintf ( &buf_512[tmp], L"GenDisk" ) + 4;
1976           return tmp;
1977         }
1978         case BusQueryCompatibleIDs:
1979         return swprintf ( buf_512, L"GenDisk" ) + 4;
1980         default:
1981         return 0;
1982       }
1983   }
1984
1985 #ifdef _MSC_VER
1986 #  pragma pack(1)
1987 #endif
1988 winvblock__def_struct(abft)
1989   {
1990     winvblock__uint32 Signature;        /* 0x54464261 (aBFT) */
1991     winvblock__uint32 Length;
1992     winvblock__uint8 Revision;
1993     winvblock__uint8 Checksum;
1994     winvblock__uint8 OEMID[6];
1995     winvblock__uint8 OEMTableID[8];
1996     winvblock__uint8 Reserved1[12];
1997     winvblock__uint16 Major;
1998     winvblock__uint8 Minor;
1999     winvblock__uint8 Reserved2;
2000     winvblock__uint8 ClientMac[6];
2001   } __attribute__((__packed__));
2002 #ifdef _MSC_VER
2003 #  pragma pack()
2004 #endif
2005
2006 disk__close_decl(close)
2007   {
2008     return;
2009   }
2010
2011 static void aoe__process_abft_(void)
2012   {
2013     PHYSICAL_ADDRESS PhysicalAddress;
2014     winvblock__uint8_ptr PhysicalMemory;
2015     winvblock__uint32 Offset, Checksum, i;
2016     winvblock__bool FoundAbft = FALSE;
2017     abft AoEBootRecord;
2018     struct aoe__disk_type_ * aoe_disk_ptr;
2019   
2020     /* Find aBFT. */
2021     PhysicalAddress.QuadPart = 0LL;
2022     PhysicalMemory = MmMapIoSpace(PhysicalAddress, 0xa0000, MmNonCached);
2023     if (!PhysicalMemory)
2024       {
2025         DBG("Could not map low memory\n");
2026       }
2027       else
2028       {
2029         for (Offset = 0; Offset < 0xa0000; Offset += 0x10)
2030                 {
2031                   if (((abft_ptr) (PhysicalMemory + Offset))->Signature ==
2032                     0x54464261)
2033                     {
2034                       Checksum = 0;
2035                       for (i = 0;
2036                   i < ((abft_ptr) (PhysicalMemory + Offset))->Length;
2037                               i++)
2038                         Checksum += PhysicalMemory[Offset + i];
2039                       if (Checksum & 0xff)
2040                         continue;
2041                       if (((abft_ptr) (PhysicalMemory + Offset))->Revision != 1)
2042                         {
2043                           DBG(
2044                         "Found aBFT with mismatched revision v%d at "
2045                           "segment 0x%4x. want v1.\n",
2046                                           ((abft_ptr) (PhysicalMemory + Offset))->Revision,
2047                                           (Offset / 0x10)
2048                       );
2049                           continue;
2050                         }
2051                       DBG("Found aBFT at segment: 0x%04x\n", (Offset / 0x10 ));
2052                       RtlCopyMemory(
2053                     &AoEBootRecord,
2054                     PhysicalMemory + Offset,
2055                                       sizeof (abft)
2056                   );
2057                       FoundAbft = TRUE;
2058                       break;
2059                     }
2060                 }
2061         MmUnmapIoSpace(PhysicalMemory, 0xa0000);
2062       }
2063
2064     #ifdef RIS
2065     FoundAbft = TRUE;
2066     RtlCopyMemory(AoEBootRecord.ClientMac, "\x00\x0c\x29\x34\x69\x34", 6);
2067     AoEBootRecord.Major = 0;
2068     AoEBootRecord.Minor = 10;
2069     #endif
2070
2071     if (FoundAbft)
2072       {
2073         aoe_disk_ptr = aoe__create_disk_();
2074         if(aoe_disk_ptr == NULL)
2075                 {
2076                   DBG("Could not create AoE disk from aBFT!\n");
2077                   return;
2078                 }
2079         DBG(
2080             "Attaching AoE disk from client NIC "
2081                   "%02x:%02x:%02x:%02x:%02x:%02x to major: %d minor: %d\n",
2082                 AoEBootRecord.ClientMac[0],
2083             AoEBootRecord.ClientMac[1],
2084                 AoEBootRecord.ClientMac[2],
2085             AoEBootRecord.ClientMac[3],
2086                 AoEBootRecord.ClientMac[4],
2087             AoEBootRecord.ClientMac[5],
2088                 AoEBootRecord.Major,
2089             AoEBootRecord.Minor
2090           );
2091         RtlCopyMemory(aoe_disk_ptr->ClientMac, AoEBootRecord.ClientMac, 6);
2092         RtlFillMemory(aoe_disk_ptr->ServerMac, 6, 0xff);
2093         aoe_disk_ptr->Major = AoEBootRecord.Major;
2094         aoe_disk_ptr->Minor = AoEBootRecord.Minor;
2095         aoe_disk_ptr->MaxSectorsPerPacket = 1;
2096         aoe_disk_ptr->Timeout = 200000;         /* 20 ms. */
2097         aoe_disk_ptr->disk->BootDrive = TRUE;
2098         aoe_disk_ptr->disk->media = disk__media_hard;
2099         bus__add_child(bus__boot(), aoe_disk_ptr->disk->device);
2100       }
2101       else
2102       {
2103         DBG("No aBFT found\n");
2104       }
2105   }
2106
2107 static NTSTATUS STDCALL scan(
2108     IN PDEVICE_OBJECT DeviceObject,
2109     IN PIRP Irp,
2110     IN PIO_STACK_LOCATION Stack,
2111     IN struct _device__type * dev_ptr,
2112     OUT winvblock__bool_ptr completion_ptr
2113   )
2114   {
2115     KIRQL irql;
2116     winvblock__uint32 count;
2117     struct aoe__target_list_ * target_walker;
2118     aoe__mount_targets_ptr targets;
2119   
2120     DBG ( "Got IOCTL_AOE_SCAN...\n" );
2121     KeAcquireSpinLock ( &aoe__target_list_spinlock_, &irql );
2122   
2123     count = 0;
2124     target_walker = aoe__target_list_;
2125     while ( target_walker != NULL )
2126       {
2127         count++;
2128         target_walker = target_walker->next;
2129       }
2130   
2131     targets = wv_malloc(sizeof *targets + (count * sizeof targets->Target[0]));
2132     if ( targets == NULL )
2133       {
2134         DBG("wv_malloc targets\n");
2135         Irp->IoStatus.Information = 0;
2136         return STATUS_INSUFFICIENT_RESOURCES;
2137       }
2138     Irp->IoStatus.Information =
2139       sizeof ( aoe__mount_targets ) + ( count * sizeof ( aoe__mount_target ) );
2140     targets->Count = count;
2141   
2142     count = 0;
2143     target_walker = aoe__target_list_;
2144     while ( target_walker != NULL )
2145       {
2146         RtlCopyMemory ( &targets->Target[count], &target_walker->Target,
2147                       sizeof ( aoe__mount_target ) );
2148         count++;
2149         target_walker = target_walker->next;
2150       }
2151     RtlCopyMemory ( Irp->AssociatedIrp.SystemBuffer, targets,
2152                   ( Stack->Parameters.DeviceIoControl.OutputBufferLength <
2153                     ( sizeof ( aoe__mount_targets ) +
2154                       ( count *
2155                         sizeof ( aoe__mount_target ) ) ) ? Stack->
2156                     Parameters.DeviceIoControl.
2157                     OutputBufferLength : ( sizeof ( aoe__mount_targets ) +
2158                                            ( count *
2159                                              sizeof
2160                                              ( aoe__mount_target ) ) ) ) );
2161     wv_free(targets);
2162   
2163     KeReleaseSpinLock ( &aoe__target_list_spinlock_, irql );
2164     *completion_ptr = TRUE;
2165     return STATUS_SUCCESS;
2166   
2167   }
2168
2169 static NTSTATUS STDCALL show(
2170     IN PDEVICE_OBJECT DeviceObject,
2171     IN PIRP Irp,
2172     IN PIO_STACK_LOCATION Stack,
2173     IN struct _device__type * dev_ptr,
2174     OUT winvblock__bool_ptr completion_ptr
2175   )
2176   {
2177     winvblock__uint32 count;
2178     device__type_ptr dev_walker;
2179     bus__type_ptr bus_ptr;
2180     aoe__mount_disks_ptr disks;
2181   
2182     DBG ( "Got IOCTL_AOE_SHOW...\n" );
2183   
2184     bus_ptr = bus__get(dev_ptr);
2185     dev_walker = bus_ptr->first_child_ptr;
2186     count = 0;
2187     while ( dev_walker != NULL )
2188       {
2189         count++;
2190         dev_walker = dev_walker->next_sibling_ptr;
2191       }
2192   
2193     disks = wv_malloc(sizeof *disks + (count * sizeof disks->Disk[0]));
2194     if (disks == NULL ) {
2195         DBG("wv_malloc disks\n");
2196         Irp->IoStatus.Information = 0;
2197         return STATUS_INSUFFICIENT_RESOURCES;
2198       }
2199     Irp->IoStatus.Information =
2200       sizeof ( aoe__mount_disks ) + ( count * sizeof ( aoe__mount_disk ) );
2201     disks->Count = count;
2202   
2203     count = 0;
2204     dev_walker = bus_ptr->first_child_ptr;
2205     while ( dev_walker != NULL )
2206       {
2207         disk__type_ptr disk_ptr = disk__get_ptr ( dev_walker );
2208         struct aoe__disk_type_ * aoe_disk_ptr = aoe__get_(dev_walker);
2209   
2210         disks->Disk[count].Disk = disk_ptr->DiskNumber;
2211         RtlCopyMemory ( &disks->Disk[count].ClientMac, &aoe_disk_ptr->ClientMac,
2212                       6 );
2213         RtlCopyMemory ( &disks->Disk[count].ServerMac, &aoe_disk_ptr->ServerMac,
2214                       6 );
2215         disks->Disk[count].Major = aoe_disk_ptr->Major;
2216         disks->Disk[count].Minor = aoe_disk_ptr->Minor;
2217         disks->Disk[count].LBASize = disk_ptr->LBADiskSize;
2218         count++;
2219         dev_walker = dev_walker->next_sibling_ptr;
2220       }
2221     RtlCopyMemory ( Irp->AssociatedIrp.SystemBuffer, disks,
2222                   ( Stack->Parameters.DeviceIoControl.OutputBufferLength <
2223                     ( sizeof ( aoe__mount_disks ) +
2224                       ( count *
2225                         sizeof ( aoe__mount_disk ) ) ) ? Stack->
2226                     Parameters.DeviceIoControl.
2227                     OutputBufferLength : ( sizeof ( aoe__mount_disks ) +
2228                                            ( count *
2229                                              sizeof
2230                                              ( aoe__mount_disk ) ) ) ) );
2231     wv_free(disks);
2232     *completion_ptr = TRUE;
2233     return STATUS_SUCCESS;
2234   }
2235
2236 static NTSTATUS STDCALL mount(
2237     IN PDEVICE_OBJECT DeviceObject,
2238     IN PIRP Irp,
2239     IN PIO_STACK_LOCATION Stack,
2240     IN struct _device__type * dev_ptr,
2241     OUT winvblock__bool_ptr completion_ptr
2242   )
2243   {
2244     winvblock__uint8_ptr buffer = Irp->AssociatedIrp.SystemBuffer;
2245     struct aoe__disk_type_ * aoe_disk_ptr;
2246   
2247     DBG ( "Got IOCTL_AOE_MOUNT for client: %02x:%02x:%02x:%02x:%02x:%02x "
2248         "Major:%d Minor:%d\n", buffer[0], buffer[1], buffer[2], buffer[3],
2249         buffer[4], buffer[5], *( winvblock__uint16_ptr ) ( &buffer[6] ),
2250         ( winvblock__uint8 ) buffer[8] );
2251     aoe_disk_ptr = aoe__create_disk_();
2252     if ( aoe_disk_ptr == NULL )
2253       {
2254         DBG ( "Could not create AoE disk!\n" );
2255         Irp->IoStatus.Information = 0;
2256         *completion_ptr = TRUE;
2257         return STATUS_INSUFFICIENT_RESOURCES;
2258       }
2259     RtlCopyMemory ( aoe_disk_ptr->ClientMac, buffer, 6 );
2260     RtlFillMemory ( aoe_disk_ptr->ServerMac, 6, 0xff );
2261     aoe_disk_ptr->Major = *( winvblock__uint16_ptr ) ( &buffer[6] );
2262     aoe_disk_ptr->Minor = ( winvblock__uint8 ) buffer[8];
2263     aoe_disk_ptr->MaxSectorsPerPacket = 1;
2264     aoe_disk_ptr->Timeout = 200000;     /* 20 ms. */
2265     aoe_disk_ptr->disk->BootDrive = FALSE;
2266     aoe_disk_ptr->disk->media = disk__media_hard;
2267     bus__add_child ( bus__boot (  ), aoe_disk_ptr->disk->device );
2268     Irp->IoStatus.Information = 0;
2269     *completion_ptr = TRUE;
2270     return STATUS_SUCCESS;
2271   }
2272
2273 NTSTATUS STDCALL aoe__bus_dev_ctl_dispatch(
2274     IN PDEVICE_OBJECT DeviceObject,
2275     IN PIRP Irp,
2276     IN PIO_STACK_LOCATION Stack,
2277     IN struct _device__type * dev_ptr,
2278     OUT winvblock__bool_ptr completion_ptr
2279   )
2280   {
2281     NTSTATUS status = STATUS_NOT_SUPPORTED;
2282   
2283     switch ( Stack->Parameters.DeviceIoControl.IoControlCode )
2284       {
2285         case IOCTL_AOE_SCAN:
2286         status = scan ( DeviceObject, Irp, Stack, dev_ptr, completion_ptr );
2287         break;
2288         case IOCTL_AOE_SHOW:
2289         status = show ( DeviceObject, Irp, Stack, dev_ptr, completion_ptr );
2290         break;
2291         case IOCTL_AOE_MOUNT:
2292         status = mount ( DeviceObject, Irp, Stack, dev_ptr, completion_ptr );
2293         break;
2294         case IOCTL_AOE_UMOUNT:
2295         Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_FILE_DETACH;
2296         break;
2297       }
2298     if ( *completion_ptr )
2299       IoCompleteRequest ( Irp, IO_NO_INCREMENT );
2300     return status;
2301   }
2302
2303 /**
2304  * Create a new AoE disk.
2305  *
2306  * @ret aoe_disk_ptr    The address of a new AoE disk, or NULL for failure.
2307  *
2308  * This function should not be confused with a PDO creation routine, which is
2309  * actually implemented for each device type.  This routine will allocate a
2310  * aoe__disk_type_, track it in a global list, as well as populate the disk
2311  * with default values.
2312  */
2313 static struct aoe__disk_type_ * aoe__create_disk_(void)
2314   {
2315     disk__type_ptr disk_ptr;
2316     struct aoe__disk_type_ * aoe_disk_ptr;
2317   
2318     /* Try to create a disk. */
2319     disk_ptr = disk__create();
2320     if (disk_ptr == NULL)
2321       goto err_nodisk;
2322     /*
2323      * AoE disk devices might be used for booting and should
2324      * not be allocated from a paged memory pool.
2325      */
2326     aoe_disk_ptr = wv_mallocz(sizeof *aoe_disk_ptr);
2327     if (aoe_disk_ptr == NULL)
2328       goto err_noaoedisk;
2329     /* Track the new AoE disk in our global list. */
2330     ExInterlockedInsertTailList(
2331         &aoe__disk_list_,
2332         &aoe_disk_ptr->tracking,
2333                         &aoe__disk_list_lock_
2334       );
2335     /* Populate non-zero device defaults. */
2336     aoe_disk_ptr->disk = disk_ptr;
2337     aoe_disk_ptr->prev_free = disk_ptr->device->ops.free;
2338     disk_ptr->device->ops.free = aoe__free_disk_;
2339     disk_ptr->disk_ops.io = io;
2340     disk_ptr->disk_ops.max_xfer_len = max_xfer_len;
2341     disk_ptr->disk_ops.pnp_id = query_id;
2342     disk_ptr->disk_ops.init = init;
2343     disk_ptr->disk_ops.close = close;
2344     disk_ptr->ext = aoe_disk_ptr;
2345   
2346     return aoe_disk_ptr;
2347   
2348     err_noaoedisk:
2349   
2350     device__free(disk_ptr->device);
2351     err_nodisk:
2352   
2353     return NULL;
2354   }
2355
2356 /**
2357  * Default AoE disk deletion operation.
2358  *
2359  * @v dev_ptr           Points to the AoE disk device to delete.
2360  */
2361 static void STDCALL aoe__free_disk_(IN device__type_ptr dev_ptr)
2362   {
2363     disk__type_ptr disk_ptr = disk__get_ptr(dev_ptr);
2364     struct aoe__disk_type_ * aoe_disk_ptr = aoe__get_(dev_ptr);
2365     /* Free the "inherited class". */
2366     aoe_disk_ptr->prev_free(dev_ptr);
2367     /*
2368      * Track the AoE disk deletion in our global list.  Unfortunately,
2369      * for now we have faith that an AoE disk won't be deleted twice and
2370      * result in a race condition.  Something to keep in mind...
2371      */
2372     ExInterlockedRemoveHeadList(
2373         aoe_disk_ptr->tracking.Blink,
2374                         &aoe__disk_list_lock_
2375       );
2376   
2377     wv_free(aoe_disk_ptr);
2378   }