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/
6 * This file is part of WinVBlock, derived from WinAoE.
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.
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.
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/>.
31 #include "winvblock.h"
32 #include "wv_stdlib.h"
33 #include "wv_string.h"
47 #define AOEPROTOCOLVER 1
49 extern NTSTATUS STDCALL ZwWaitForSingleObject(
51 IN winvblock__bool Alertable,
52 IN PLARGE_INTEGER Timeout OPTIONAL
55 /* Forward declarations. */
56 struct aoe__disk_type_;
57 static void STDCALL aoe__thread_(IN void *);
58 irp__handler aoe__bus_dev_ctl_dispatch;
59 static void aoe__process_abft_(void);
60 static void STDCALL aoe__unload_(IN PDRIVER_OBJECT);
61 static struct aoe__disk_type_ * aoe__create_disk_(void);
62 static device__free_func aoe__free_disk_;
68 aoe__tag_type_search_drive_
78 winvblock__uint8 ReservedFlag:2;
79 winvblock__uint8 ErrorFlag:1;
80 winvblock__uint8 ResponseFlag:1;
81 winvblock__uint8 Ver:4;
82 winvblock__uint8 Error;
83 winvblock__uint16 Major;
84 winvblock__uint8 Minor;
85 winvblock__uint8 Command;
86 winvblock__uint32 Tag;
88 winvblock__uint8 WriteAFlag:1;
89 winvblock__uint8 AsyncAFlag:1;
90 winvblock__uint8 Reserved1AFlag:2;
91 winvblock__uint8 DeviceHeadAFlag:1;
92 winvblock__uint8 Reserved2AFlag:1;
93 winvblock__uint8 ExtendedAFlag:1;
94 winvblock__uint8 Reserved3AFlag:1;
98 winvblock__uint8 Feature;
100 winvblock__uint8 Count;
103 winvblock__uint8 Cmd;
104 winvblock__uint8 Status;
107 winvblock__uint8 Lba0;
108 winvblock__uint8 Lba1;
109 winvblock__uint8 Lba2;
110 winvblock__uint8 Lba3;
111 winvblock__uint8 Lba4;
112 winvblock__uint8 Lba5;
113 winvblock__uint16 Reserved;
115 winvblock__uint8 Data[];
116 } __attribute__((__packed__));
122 /** An I/O request. */
126 winvblock__uint32 SectorCount;
127 winvblock__uint8_ptr Buffer;
129 winvblock__uint32 TagCount;
130 winvblock__uint32 TotalTags;
133 /** A work item "tag". */
134 struct aoe__work_tag_
136 enum aoe__tag_type_ type;
137 struct device__type * device;
138 struct aoe__io_req_ * request_ptr;
139 winvblock__uint32 Id;
140 struct aoe__packet_ * packet_data;
141 winvblock__uint32 PacketSize;
142 LARGE_INTEGER FirstSendTime;
143 LARGE_INTEGER SendTime;
144 winvblock__uint32 BufferOffset;
145 winvblock__uint32 SectorCount;
146 struct aoe__work_tag_ * next;
147 struct aoe__work_tag_ * previous;
150 /** A disk search. */
151 struct aoe__disk_search_
153 struct device__type * device;
154 struct aoe__work_tag_ * tag;
155 struct aoe__disk_search_ * next;
158 enum aoe__search_state_
160 aoe__search_state_search_nic_,
161 aoe__search_state_get_size_,
162 aoe__search_state_getting_size_,
163 aoe__search_state_get_geometry_,
164 aoe__search_state_getting_geometry_,
165 aoe__search_state_get_max_sectors_per_packet_,
166 aoe__search_state_getting_max_sectors_per_packet_,
167 aoe__search_state_done_
170 /** The AoE disk type. */
171 struct aoe__disk_type_
174 winvblock__uint32 MTU;
175 winvblock__uint8 ClientMac[6];
176 winvblock__uint8 ServerMac[6];
177 winvblock__uint32 Major;
178 winvblock__uint32 Minor;
179 winvblock__uint32 MaxSectorsPerPacket;
180 winvblock__uint32 Timeout;
181 enum aoe__search_state_ search_state;
182 device__free_func * prev_free;
186 struct aoe__target_list_
188 aoe__mount_target Target;
189 struct aoe__target_list_ * next;
192 /** Private globals. */
193 static struct aoe__target_list_ * aoe__target_list_ = NULL;
194 static KSPIN_LOCK aoe__target_list_spinlock_;
195 static winvblock__bool aoe__stop_ = FALSE;
196 static KSPIN_LOCK aoe__spinlock_;
197 static KEVENT aoe__thread_sig_evt_;
198 static struct aoe__work_tag_ * aoe__tag_list_ = NULL;
199 static struct aoe__work_tag_ * aoe__tag_list_last_ = NULL;
200 static struct aoe__work_tag_ * aoe__probe_tag_ = NULL;
201 static struct aoe__disk_search_ * aoe__disk_search_list_ = NULL;
202 static LONG aoe__outstanding_tags_ = 0;
203 static HANDLE aoe__thread_handle_;
204 static winvblock__bool aoe__started_ = FALSE;
205 static LIST_ENTRY aoe__disk_list_;
206 static KSPIN_LOCK aoe__disk_list_lock_;
208 static irp__handling handling_table[] =
210 /* Major, minor, any major?, any minor?, handler. */
211 { IRP_MJ_DEVICE_CONTROL, 0, FALSE, TRUE, aoe__bus_dev_ctl_dispatch }
214 /* Yield a pointer to the AoE disk. */
215 static struct aoe__disk_type_ * aoe__get_(struct device__type * dev_ptr)
217 return disk__get_ptr(dev_ptr)->ext;
220 static winvblock__bool STDCALL setup_reg(OUT PNTSTATUS status_out)
223 winvblock__bool Updated = FALSE;
224 WCHAR InterfacesPath[] = L"\\Ndi\\Interfaces\\";
225 WCHAR LinkagePath[] = L"\\Linkage\\";
226 WCHAR NdiPath[] = L"\\Ndi\\";
227 WCHAR DriverServiceNamePath[] =
228 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
229 OBJECT_ATTRIBUTES SubKeyObject;
231 ControlKeyHandle, NetworkClassKeyHandle, SubKeyHandle;
233 i, SubkeyIndex, ResultLength, InterfacesKeyStringLength,
234 LinkageKeyStringLength, NdiKeyStringLength, NewValueLength;
236 InterfacesKeyString, LinkageKeyString, NdiKeyString,
237 DriverServiceNameString, NewValue;
239 InterfacesKey, LinkageKey, NdiKey, LowerRange, UpperBind, Service,
241 PKEY_BASIC_INFORMATION KeyInformation;
242 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
243 winvblock__bool Update, Found;
247 RtlInitUnicodeString(&LowerRange, L"LowerRange");
248 RtlInitUnicodeString(&UpperBind, L"UpperBind");
249 RtlInitUnicodeString(&Service, L"Service");
251 /* Open the network adapter class key. */
252 status = registry__open_key(
253 (L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Class\\"
254 L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\"),
255 &NetworkClassKeyHandle
257 if (!NT_SUCCESS(status))
258 goto err_keyopennetworkclass;
260 /* Enumerate through subkeys. */
262 while ((status = ZwEnumerateKey(
263 NetworkClassKeyHandle,
269 )) != STATUS_NO_MORE_ENTRIES)
271 if ((status != STATUS_SUCCESS) &&
272 (status != STATUS_BUFFER_OVERFLOW) &&
273 (status != STATUS_BUFFER_TOO_SMALL)
276 DBG("ZwEnumerateKey 1 failed (%lx)\n", status);
279 if ((KeyInformation = wv_malloc(ResultLength)) == NULL)
281 DBG("wv_malloc KeyData failed\n");
283 registry__close_key(NetworkClassKeyHandle);
287 NetworkClassKeyHandle,
295 DBG ("ZwEnumerateKey 2 failed\n");
299 InterfacesKeyStringLength =
300 KeyInformation->NameLength + sizeof InterfacesPath;
301 InterfacesKeyString = wv_malloc(InterfacesKeyStringLength);
302 if (InterfacesKeyString == NULL)
304 DBG("wv_malloc InterfacesKeyString failed\n");
310 KeyInformation->Name,
311 KeyInformation->NameLength
314 InterfacesKeyString +
315 (KeyInformation->NameLength / sizeof (WCHAR)),
317 sizeof InterfacesPath
319 RtlInitUnicodeString(&InterfacesKey, InterfacesKeyString);
322 InitializeObjectAttributes(
325 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
326 NetworkClassKeyHandle,
329 if (NT_SUCCESS(ZwOpenKey(&SubKeyHandle, KEY_ALL_ACCESS, &SubKeyObject)))
331 if ((status = ZwQueryValueKey(
334 KeyValuePartialInformation,
338 )) != STATUS_OBJECT_NAME_NOT_FOUND )
340 if ((status != STATUS_SUCCESS) &&
341 (status != STATUS_BUFFER_OVERFLOW) &&
342 (status != STATUS_BUFFER_TOO_SMALL))
345 "ZwQueryValueKey InterfacesKey 1 failed (%lx)\n",
350 if ((KeyValueInformation = wv_malloc(ResultLength)) == NULL)
352 DBG("wv_malloc InterfacesKey KeyValueData failed\n");
355 if (!(NT_SUCCESS(ZwQueryValueKey(
358 KeyValuePartialInformation,
364 DBG("ZwQueryValueKey InterfacesKey 2 failed\n");
369 KeyValueInformation->Data,
373 wv_free(KeyValueInformation);
374 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
376 DBG("ZwClose InterfacesKey SubKeyHandle failed\n");
381 wv_free(InterfacesKeyString);
385 LinkageKeyStringLength =
386 KeyInformation->NameLength + sizeof LinkagePath;
387 if ((LinkageKeyString = wv_malloc(LinkageKeyStringLength)) == NULL)
389 DBG("wv_malloc LinkageKeyString failed\n");
394 KeyInformation->Name,
395 KeyInformation->NameLength
399 (KeyInformation->NameLength / sizeof (WCHAR)),
403 RtlInitUnicodeString(&LinkageKey, LinkageKeyString);
405 InitializeObjectAttributes(
408 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
409 NetworkClassKeyHandle,
412 if (!NT_SUCCESS(ZwCreateKey(
418 REG_OPTION_NON_VOLATILE,
422 DBG("ZwCreateKey failed (%lx)\n");
425 if ((status = ZwQueryValueKey(
428 KeyValuePartialInformation,
432 )) != STATUS_OBJECT_NAME_NOT_FOUND)
434 if ((status != STATUS_SUCCESS) &&
435 (status != STATUS_BUFFER_OVERFLOW) &&
436 (status != STATUS_BUFFER_TOO_SMALL))
438 DBG("ZwQueryValueKey LinkageKey 1 failed (%lx)\n", status);
441 if ((KeyValueInformation = wv_malloc(ResultLength)) == NULL)
443 DBG("wv_malloc LinkageKey KeyValueData failed\n");
446 if (!(NT_SUCCESS(ZwQueryValueKey(
449 KeyValuePartialInformation,
455 DBG("ZwQueryValueKey LinkageKey 2 failed\n");
461 i < (KeyValueInformation->DataLength -
462 sizeof winvblock__literal_w / sizeof (WCHAR));
466 winvblock__literal_w,
467 ((PWCHAR)KeyValueInformation->Data) + i,
468 sizeof winvblock__literal_w
473 } /* if wv_memcmpeq */
478 NewValueLength = KeyValueInformation->DataLength;
479 if ((NewValue = wv_malloc(NewValueLength)) == NULL)
481 DBG("wv_malloc NewValue 1 failed\n");
486 KeyValueInformation->Data,
487 KeyValueInformation->DataLength
493 NewValueLength = KeyValueInformation->DataLength +
494 sizeof winvblock__literal_w;
495 if ((NewValue = wv_malloc(NewValueLength)) == NULL)
497 DBG("wv_malloc NewValue 2 failed\n");
502 winvblock__literal_w,
503 sizeof winvblock__literal_w
507 (sizeof winvblock__literal_w / sizeof (WCHAR)),
508 KeyValueInformation->Data,
509 KeyValueInformation->DataLength
512 wv_free(KeyValueInformation);
517 NewValueLength = sizeof winvblock__literal_w + sizeof (WCHAR);
518 if ((NewValue = wv_mallocz(NewValueLength)) == NULL)
520 DBG("wv_mallocz NewValue 3 failed\n");
525 winvblock__literal_w,
526 sizeof winvblock__literal_w
529 if (!NT_SUCCESS(ZwSetValueKey(
538 DBG("ZwSetValueKey failed\n");
543 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
545 DBG("ZwClose LinkageKey SubKeyHandle failed\n");
548 wv_free(LinkageKeyString);
550 /* Not sure where this comes from. */
554 NdiKeyStringLength = KeyInformation->NameLength + sizeof NdiPath;
555 if ((NdiKeyString = wv_malloc(NdiKeyStringLength)) == NULL)
557 DBG("wv_malloc NdiKeyString failed\n");
562 KeyInformation->Name,
563 KeyInformation->NameLength
566 NdiKeyString + (KeyInformation->NameLength / sizeof (WCHAR)),
570 RtlInitUnicodeString(&NdiKey, NdiKeyString);
572 InitializeObjectAttributes(
575 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
576 NetworkClassKeyHandle,
579 if (NT_SUCCESS(ZwOpenKey(
585 if ((status = ZwQueryValueKey(
588 KeyValuePartialInformation,
592 )) != STATUS_OBJECT_NAME_NOT_FOUND)
594 if ((status != STATUS_SUCCESS) &&
595 (status != STATUS_BUFFER_OVERFLOW) &&
596 (status != STATUS_BUFFER_TOO_SMALL))
598 DBG("ZwQueryValueKey NdiKey 1 failed (%lx)\n", status);
601 if ((KeyValueInformation = wv_malloc(ResultLength)) == NULL)
603 DBG("wv_malloc NdiKey KeyValueData failed\n");
606 if (!(NT_SUCCESS(ZwQueryValueKey(
609 KeyValuePartialInformation,
615 DBG("ZwQueryValueKey NdiKey 2 failed\n");
616 wv_free(KeyValueInformation);
619 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
621 DBG("ZwClose NdiKey SubKeyHandle failed\n");
624 DriverServiceNameString = wv_malloc(
625 sizeof DriverServiceNamePath +
626 KeyValueInformation->DataLength -
627 sizeof *DriverServiceNamePath
629 if (DriverServiceNameString == NULL)
631 DBG("wv_malloc DriverServiceNameString failed\n");
636 DriverServiceNameString,
637 DriverServiceNamePath,
638 sizeof DriverServiceNamePath
641 DriverServiceNameString +
642 (sizeof DriverServiceNamePath / sizeof (WCHAR)) - 1,
643 KeyValueInformation->Data,
644 KeyValueInformation->DataLength
646 RtlInitUnicodeString(
648 DriverServiceNameString
652 "Starting driver %S -> %08x\n",
653 KeyValueInformation->Data,
654 ZwLoadDriver(&DriverServiceName)
657 wv_free(DriverServiceNameString);
658 wv_free(KeyValueInformation);
661 wv_free(NdiKeyString);
663 wv_free(KeyInformation);
666 registry__close_key ( NetworkClassKeyHandle );
667 *status_out = STATUS_SUCCESS;
672 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
673 DBG("ZwClose SubKeyHandle failed\n");
676 wv_free(NdiKeyString);
680 wv_free(KeyValueInformation);
683 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
684 DBG("ZwClose SubKeyHandle failed\n");
687 wv_free(LinkageKeyString);
691 wv_free(KeyValueInformation);
694 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
695 DBG("ZwClose SubKeyHandle failed\n");
698 wv_free(InterfacesKeyString);
702 wv_free(KeyInformation);
705 registry__close_key(NetworkClassKeyHandle);
706 err_keyopennetworkclass:
708 *status_out = STATUS_UNSUCCESSFUL;
713 * Start AoE operations.
715 * @ret Status Return status code.
717 NTSTATUS STDCALL DriverEntry(
718 IN PDRIVER_OBJECT DriverObject,
719 IN PUNICODE_STRING RegistryPath
722 OBJECT_ATTRIBUTES ObjectAttributes;
724 struct bus__type * bus_ptr;
729 return STATUS_SUCCESS;
730 /* Initialize the global list of AoE disks. */
731 InitializeListHead(&aoe__disk_list_);
732 KeInitializeSpinLock(&aoe__disk_list_lock_);
733 /* Setup the Registry. */
734 if (!NT_SUCCESS(setup_reg(&Status))) {
735 DBG("Could not update Registry!\n");
738 DBG("Registry updated\n");
740 /* Start up the protocol. */
741 if (!NT_SUCCESS(Status = Protocol_Start())) {
742 DBG("Protocol startup failure!\n");
745 /* Allocate and zero-fill the global probe tag. */
746 aoe__probe_tag_ = wv_mallocz(sizeof *aoe__probe_tag_);
747 if (aoe__probe_tag_ == NULL) {
748 DBG("Couldn't allocate probe tag; bye!\n");
749 return STATUS_INSUFFICIENT_RESOURCES;
752 /* Set up the probe tag's AoE packet reference. */
753 aoe__probe_tag_->PacketSize = sizeof (struct aoe__packet_);
754 /* Allocate and zero-fill the probe tag's packet reference. */
755 aoe__probe_tag_->packet_data = wv_mallocz(aoe__probe_tag_->PacketSize);
756 if (aoe__probe_tag_->packet_data == NULL) {
757 DBG("Couldn't allocate aoe__probe_tag_->packet_data\n");
758 wv_free(aoe__probe_tag_);
759 return STATUS_INSUFFICIENT_RESOURCES;
761 aoe__probe_tag_->SendTime.QuadPart = 0LL;
763 /* Initialize the probe tag's AoE packet. */
764 aoe__probe_tag_->packet_data->Ver = AOEPROTOCOLVER;
765 aoe__probe_tag_->packet_data->Major =
766 htons((winvblock__uint16) -1);
767 aoe__probe_tag_->packet_data->Minor = (winvblock__uint8) -1;
768 aoe__probe_tag_->packet_data->Cmd = 0xec; /* IDENTIFY DEVICE */
769 aoe__probe_tag_->packet_data->Count = 1;
771 /* Initialize global target-list spinlock. */
772 KeInitializeSpinLock(&aoe__target_list_spinlock_);
774 /* Initialize global spin-lock and global thread signal event. */
775 KeInitializeSpinLock(&aoe__spinlock_);
776 KeInitializeEvent(&aoe__thread_sig_evt_, SynchronizationEvent, FALSE);
778 /* Initialize object attributes for thread. */
779 InitializeObjectAttributes(
787 /* Create global thread. */
788 if (!NT_SUCCESS(Status = PsCreateSystemThread(
789 &aoe__thread_handle_,
797 return Error("PsCreateSystemThread", Status);
799 if (!NT_SUCCESS(Status = ObReferenceObjectByHandle(
807 ZwClose(aoe__thread_handle_);
808 Error("ObReferenceObjectByHandle", Status);
810 KeSetEvent(&aoe__thread_sig_evt_, 0, FALSE);
813 DriverObject->DriverUnload = aoe__unload_;
814 aoe__started_ = TRUE;
815 if (!aoe_bus__create()) {
816 DBG("Unable to create AoE bus!\n");
817 aoe__unload_(DriverObject);
818 return STATUS_INSUFFICIENT_RESOURCES;
820 aoe__process_abft_();
826 * Stop AoE operations.
828 static void STDCALL aoe__unload_(IN PDRIVER_OBJECT DriverObject) {
830 struct aoe__disk_search_ * disk_searcher, * previous_disk_searcher;
831 struct aoe__work_tag_ * tag;
833 struct aoe__target_list_ * Walker, * Next;
836 /* If we're not already started, there's nothing to do. */
839 /* Destroy the AoE bus. */
841 /* Stop the AoE protocol. */
843 /* If we're not already shutting down, signal the event. */
846 KeSetEvent(&aoe__thread_sig_evt_, 0, FALSE);
847 /* Wait until the event has been signalled. */
848 if (!NT_SUCCESS(Status = ZwWaitForSingleObject(
853 Error("AoE_Stop ZwWaitForSingleObject", Status);
854 ZwClose(aoe__thread_handle_);
857 /* Free the target list. */
858 KeAcquireSpinLock(&aoe__target_list_spinlock_, &Irql2);
859 Walker = aoe__target_list_;
860 while (Walker != NULL) {
865 KeReleaseSpinLock(&aoe__target_list_spinlock_, Irql2);
867 /* Wait until we have the global spin-lock. */
868 KeAcquireSpinLock(&aoe__spinlock_, &Irql);
870 /* Free disk searches in the global disk search list. */
871 disk_searcher = aoe__disk_search_list_;
872 while (disk_searcher != NULL) {
874 &(disk__get_ptr(disk_searcher->device)->SearchEvent),
878 previous_disk_searcher = disk_searcher;
879 disk_searcher = disk_searcher->next;
880 wv_free(previous_disk_searcher);
883 /* Cancel and free all tags in the global tag list. */
884 tag = aoe__tag_list_;
885 while (tag != NULL) {
886 if (tag->request_ptr != NULL && --tag->request_ptr->TagCount == 0) {
887 tag->request_ptr->Irp->IoStatus.Information = 0;
888 tag->request_ptr->Irp->IoStatus.Status = STATUS_CANCELLED;
889 IoCompleteRequest(tag->request_ptr->Irp, IO_NO_INCREMENT);
890 wv_free(tag->request_ptr);
892 if (tag->next == NULL) {
893 wv_free(tag->packet_data);
898 wv_free(tag->previous->packet_data);
899 wv_free(tag->previous);
902 aoe__tag_list_ = NULL;
903 aoe__tag_list_last_ = NULL;
905 /* Free the global probe tag and its AoE packet. */
906 wv_free(aoe__probe_tag_->packet_data);
907 wv_free(aoe__probe_tag_);
909 /* Release the global spin-lock. */
910 KeReleaseSpinLock(&aoe__spinlock_, Irql);
912 struct bus__type * bus_ptr = driver__bus();
915 DBG("Unable to un-register IOCTLs!\n");
918 &bus_ptr->device->irp_handler_chain,
923 aoe__started_ = FALSE;
928 * Search for disk parameters.
930 * @v dev_ptr The device extension for the disk.
932 * Returns TRUE if the disk could be matched, FALSE otherwise.
934 static disk__init_decl(init)
936 struct aoe__disk_search_
937 * disk_searcher, * disk_search_walker, * previous_disk_searcher;
938 LARGE_INTEGER Timeout, CurrentTime;
939 struct aoe__work_tag_ * tag, * tag_walker;
940 KIRQL Irql, InnerIrql;
941 LARGE_INTEGER MaxSectorsPerPacketSendTime;
942 winvblock__uint32 MTU;
943 struct aoe__disk_type_ * aoe_disk_ptr;
945 aoe_disk_ptr = aoe__get_ ( disk_ptr->device );
947 * Allocate our disk search
949 if ((disk_searcher = wv_malloc(sizeof *disk_searcher)) == NULL) {
950 DBG ( "Couldn't allocate for disk_searcher; bye!\n" );
955 * Initialize the disk search
957 disk_searcher->device = disk_ptr->device;
958 disk_searcher->next = NULL;
959 aoe_disk_ptr->search_state = aoe__search_state_search_nic_;
960 KeResetEvent ( &disk_ptr->SearchEvent );
963 * Wait until we have the global spin-lock
965 KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
968 * Add our disk search to the global list of disk searches
970 if ( aoe__disk_search_list_ == NULL )
972 aoe__disk_search_list_ = disk_searcher;
976 disk_search_walker = aoe__disk_search_list_;
977 while ( disk_search_walker->next )
978 disk_search_walker = disk_search_walker->next;
979 disk_search_walker->next = disk_searcher;
983 * Release the global spin-lock
985 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
988 * We go through all the states until the disk is ready for use
993 * Wait for our device's extension's search to be signalled
996 * TODO: Make the below value a #defined constant
999 * 500.000 * 100ns = 50.000.000 ns = 50ms
1001 Timeout.QuadPart = -500000LL;
1002 KeWaitForSingleObject ( &disk_ptr->SearchEvent, Executive, KernelMode,
1006 DBG ( "AoE is shutting down; bye!\n" );
1011 * Wait until we have the device extension's spin-lock
1013 KeAcquireSpinLock ( &disk_ptr->SpinLock, &Irql );
1015 if (aoe_disk_ptr->search_state == aoe__search_state_search_nic_)
1017 if ( !Protocol_SearchNIC ( aoe_disk_ptr->ClientMac ) )
1019 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1025 * We found the adapter to use, get MTU next
1027 aoe_disk_ptr->MTU = Protocol_GetMTU ( aoe_disk_ptr->ClientMac );
1028 aoe_disk_ptr->search_state = aoe__search_state_get_size_;
1032 if (aoe_disk_ptr->search_state == aoe__search_state_getting_size_)
1035 * Still getting the disk's size
1037 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1040 if (aoe_disk_ptr->search_state == aoe__search_state_getting_geometry_)
1043 * Still getting the disk's geometry
1045 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1048 if (aoe_disk_ptr->search_state ==
1049 aoe__search_state_getting_max_sectors_per_packet_)
1051 KeQuerySystemTime ( &CurrentTime );
1053 * TODO: Make the below value a #defined constant
1056 * 2.500.000 * 100ns = 250.000.000 ns = 250ms
1058 if ( CurrentTime.QuadPart >
1059 MaxSectorsPerPacketSendTime.QuadPart + 2500000LL )
1061 DBG ( "No reply after 250ms for MaxSectorsPerPacket %d, "
1062 "giving up\n", aoe_disk_ptr->MaxSectorsPerPacket );
1063 aoe_disk_ptr->MaxSectorsPerPacket--;
1064 aoe_disk_ptr->search_state = aoe__search_state_done_;
1069 * Still getting the maximum sectors per packet count
1071 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1076 if (aoe_disk_ptr->search_state == aoe__search_state_done_)
1079 * We've finished the disk search; perform clean-up
1081 KeAcquireSpinLock ( &aoe__spinlock_, &InnerIrql );
1084 * Tag clean-up: Find out if our tag is in the global tag list
1086 tag_walker = aoe__tag_list_;
1087 while ( tag_walker != NULL && tag_walker != tag )
1088 tag_walker = tag_walker->next;
1089 if ( tag_walker != NULL )
1092 * We found it. If it's at the beginning of the list, adjust
1093 * the list to point the the next tag
1095 if ( tag->previous == NULL )
1096 aoe__tag_list_ = tag->next;
1099 * Remove our tag from the list
1101 tag->previous->next = tag->next;
1103 * If we 're at the end of the list, adjust the list's end to
1104 * point to the penultimate tag
1106 if ( tag->next == NULL )
1107 aoe__tag_list_last_ = tag->previous;
1110 * Remove our tag from the list
1112 tag->next->previous = tag->previous;
1113 aoe__outstanding_tags_--;
1114 if ( aoe__outstanding_tags_ < 0 )
1115 DBG ( "aoe__outstanding_tags_ < 0!!\n" );
1117 * Free our tag and its AoE packet
1119 wv_free(tag->packet_data);
1124 * Disk search clean-up
1126 if ( aoe__disk_search_list_ == NULL )
1128 DBG ( "aoe__disk_search_list_ == NULL!!\n" );
1133 * Find our disk search in the global list of disk searches
1135 disk_search_walker = aoe__disk_search_list_;
1136 while ( disk_search_walker
1137 && disk_search_walker->device != disk_ptr->device )
1139 previous_disk_searcher = disk_search_walker;
1140 disk_search_walker = disk_search_walker->next;
1142 if ( disk_search_walker )
1145 * We found our disk search. If it's the first one in
1146 * the list, adjust the list and remove it
1148 if ( disk_search_walker == aoe__disk_search_list_ )
1149 aoe__disk_search_list_ = disk_search_walker->next;
1154 previous_disk_searcher->next = disk_search_walker->next;
1156 * Free our disk search
1158 wv_free(disk_search_walker);
1162 DBG ( "Disk not found in aoe__disk_search_list_!!\n" );
1167 * Release global and device extension spin-locks
1169 KeReleaseSpinLock ( &aoe__spinlock_, InnerIrql );
1170 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1172 DBG ( "Disk size: %I64uM cylinders: %I64u heads: %u "
1173 "sectors: %u sectors per packet: %u\n",
1174 disk_ptr->LBADiskSize / 2048, disk_ptr->Cylinders,
1175 disk_ptr->Heads, disk_ptr->Sectors,
1176 aoe_disk_ptr->MaxSectorsPerPacket );
1181 if ( aoe_disk_ptr->search_state == aoe__search_state_done_)
1186 if ((tag = wv_mallocz(sizeof *tag)) == NULL) {
1187 DBG ( "Couldn't allocate tag\n" );
1188 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1190 * Maybe next time around
1194 tag->type = aoe__tag_type_search_drive_;
1195 tag->device = disk_ptr->device;
1198 * Establish our tag's AoE packet
1200 tag->PacketSize = sizeof (struct aoe__packet_);
1201 if ((tag->packet_data = wv_mallocz(tag->PacketSize)) == NULL) {
1202 DBG ( "Couldn't allocate tag->packet_data\n" );
1205 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1207 * Maybe next time around
1211 tag->packet_data->Ver = AOEPROTOCOLVER;
1212 tag->packet_data->Major =
1213 htons ( ( winvblock__uint16 ) aoe_disk_ptr->Major );
1214 tag->packet_data->Minor = ( winvblock__uint8 ) aoe_disk_ptr->Minor;
1215 tag->packet_data->ExtendedAFlag = TRUE;
1218 * Initialize the packet appropriately based on our current phase
1220 switch ( aoe_disk_ptr->search_state )
1222 case aoe__search_state_get_size_:
1224 * TODO: Make the below value into a #defined constant
1226 tag->packet_data->Cmd = 0xec; /* IDENTIFY DEVICE */
1227 tag->packet_data->Count = 1;
1228 aoe_disk_ptr->search_state = aoe__search_state_getting_size_;
1230 case aoe__search_state_get_geometry_:
1232 * TODO: Make the below value into a #defined constant
1234 tag->packet_data->Cmd = 0x24; /* READ SECTOR */
1235 tag->packet_data->Count = 1;
1236 aoe_disk_ptr->search_state = aoe__search_state_getting_geometry_;
1238 case aoe__search_state_get_max_sectors_per_packet_:
1240 * TODO: Make the below value into a #defined constant
1242 tag->packet_data->Cmd = 0x24; /* READ SECTOR */
1243 tag->packet_data->Count =
1244 ( winvblock__uint8 ) ( ++aoe_disk_ptr->MaxSectorsPerPacket );
1245 KeQuerySystemTime ( &MaxSectorsPerPacketSendTime );
1246 aoe_disk_ptr->search_state =
1247 aoe__search_state_getting_max_sectors_per_packet_;
1249 * TODO: Make the below value into a #defined constant
1251 aoe_disk_ptr->Timeout = 200000;
1254 DBG ( "Undefined search_state!!\n" );
1255 wv_free(tag->packet_data);
1258 * TODO: Do we need to nullify tag here?
1260 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1269 KeAcquireSpinLock ( &aoe__spinlock_, &InnerIrql );
1270 if ( aoe__tag_list_ == NULL )
1272 aoe__tag_list_ = tag;
1273 tag->previous = NULL;
1277 aoe__tag_list_last_->next = tag;
1278 tag->previous = aoe__tag_list_last_;
1280 aoe__tag_list_last_ = tag;
1281 KeReleaseSpinLock ( &aoe__spinlock_, InnerIrql );
1282 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1286 static disk__io_decl(io)
1288 struct aoe__io_req_ * request_ptr;
1289 struct aoe__work_tag_ * tag, * new_tag_list = NULL, * previous_tag = NULL;
1291 winvblock__uint32 i;
1292 PHYSICAL_ADDRESS PhysicalAddress;
1293 winvblock__uint8_ptr PhysicalMemory;
1294 disk__type_ptr disk_ptr;
1295 struct aoe__disk_type_ * aoe_disk_ptr;
1298 * Establish pointers to the disk and AoE disk
1300 disk_ptr = disk__get_ptr ( dev_ptr );
1301 aoe_disk_ptr = aoe__get_ ( dev_ptr );
1306 * Shutting down AoE; we can't service this request
1308 irp->IoStatus.Information = 0;
1309 irp->IoStatus.Status = STATUS_CANCELLED;
1310 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1311 return STATUS_CANCELLED;
1314 if ( sector_count < 1 )
1319 DBG ( "sector_count < 1; cancelling\n" );
1320 irp->IoStatus.Information = 0;
1321 irp->IoStatus.Status = STATUS_CANCELLED;
1322 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1323 return STATUS_CANCELLED;
1327 * Allocate and zero-fill our request
1329 if ((request_ptr = wv_mallocz(sizeof *request_ptr)) == NULL) {
1330 DBG ( "Couldn't allocate for reques_ptr; bye!\n" );
1331 irp->IoStatus.Information = 0;
1332 irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1333 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1334 return STATUS_INSUFFICIENT_RESOURCES;
1338 * Initialize the request
1340 request_ptr->Mode = mode;
1341 request_ptr->SectorCount = sector_count;
1342 request_ptr->Buffer = buffer;
1343 request_ptr->Irp = irp;
1344 request_ptr->TagCount = 0;
1347 * Split the requested sectors into packets in tags
1349 for ( i = 0; i < sector_count; i += aoe_disk_ptr->MaxSectorsPerPacket )
1354 if ((tag = wv_mallocz(sizeof *tag)) == NULL) {
1355 DBG ( "Couldn't allocate tag; bye!\n" );
1357 * We failed while allocating tags; free the ones we built
1360 while ( tag != NULL )
1364 wv_free(previous_tag->packet_data);
1365 wv_free(previous_tag);
1367 wv_free(request_ptr);
1368 irp->IoStatus.Information = 0;
1369 irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1370 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1371 return STATUS_INSUFFICIENT_RESOURCES;
1375 * Initialize each tag
1377 tag->type = aoe__tag_type_io_;
1378 tag->request_ptr = request_ptr;
1379 tag->device = dev_ptr;
1380 request_ptr->TagCount++;
1382 tag->BufferOffset = i * disk_ptr->SectorSize;
1384 ( ( sector_count - i ) <
1385 aoe_disk_ptr->MaxSectorsPerPacket ? sector_count -
1386 i : aoe_disk_ptr->MaxSectorsPerPacket );
1389 * Allocate and initialize each tag's AoE packet
1391 tag->PacketSize = sizeof (struct aoe__packet_);
1392 if ( mode == disk__io_mode_write )
1393 tag->PacketSize += tag->SectorCount * disk_ptr->SectorSize;
1394 if ((tag->packet_data = wv_mallocz(tag->PacketSize)) == NULL) {
1395 DBG ( "Couldn't allocate tag->packet_data; bye!\n" );
1397 * We failed while allocating an AoE packet; free
1402 while ( tag != NULL )
1406 wv_free(previous_tag->packet_data);
1407 wv_free(previous_tag);
1409 wv_free(request_ptr);
1410 irp->IoStatus.Information = 0;
1411 irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1412 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1413 return STATUS_INSUFFICIENT_RESOURCES;
1415 tag->packet_data->Ver = AOEPROTOCOLVER;
1416 tag->packet_data->Major =
1417 htons ( ( winvblock__uint16 ) aoe_disk_ptr->Major );
1418 tag->packet_data->Minor = ( winvblock__uint8 ) aoe_disk_ptr->Minor;
1419 tag->packet_data->Tag = 0;
1420 tag->packet_data->Command = 0;
1421 tag->packet_data->ExtendedAFlag = TRUE;
1422 if ( mode == disk__io_mode_read )
1424 tag->packet_data->Cmd = 0x24; /* READ SECTOR */
1428 tag->packet_data->Cmd = 0x34; /* WRITE SECTOR */
1429 tag->packet_data->WriteAFlag = 1;
1431 tag->packet_data->Count = ( winvblock__uint8 ) tag->SectorCount;
1432 tag->packet_data->Lba0 =
1433 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 0 ) & 255 );
1434 tag->packet_data->Lba1 =
1435 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 8 ) & 255 );
1436 tag->packet_data->Lba2 =
1437 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 16 ) & 255 );
1438 tag->packet_data->Lba3 =
1439 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 24 ) & 255 );
1440 tag->packet_data->Lba4 =
1441 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 32 ) & 255 );
1442 tag->packet_data->Lba5 =
1443 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 40 ) & 255 );
1446 * For a write request, copy from the buffer into the AoE packet
1448 if ( mode == disk__io_mode_write )
1449 RtlCopyMemory ( tag->packet_data->Data, &buffer[tag->BufferOffset],
1450 tag->SectorCount * disk_ptr->SectorSize );
1453 * Add this tag to the request's tag list
1455 tag->previous = previous_tag;
1457 if ( new_tag_list == NULL )
1463 previous_tag->next = tag;
1468 * Split the requested sectors into packets in tags
1470 request_ptr->TotalTags = request_ptr->TagCount;
1473 * Wait until we have the global spin-lock
1475 KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
1478 * Enqueue our request's tag list to the global tag list
1480 if ( aoe__tag_list_last_ == NULL )
1482 aoe__tag_list_ = new_tag_list;
1486 aoe__tag_list_last_->next = new_tag_list;
1487 new_tag_list->previous = aoe__tag_list_last_;
1490 * Adjust the global list to reflect our last tag
1492 aoe__tag_list_last_ = tag;
1494 irp->IoStatus.Information = 0;
1495 irp->IoStatus.Status = STATUS_PENDING;
1496 IoMarkIrpPending ( irp );
1498 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1499 KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
1500 return STATUS_PENDING;
1503 static void STDCALL add_target(
1504 IN winvblock__uint8_ptr ClientMac,
1505 IN winvblock__uint8_ptr ServerMac,
1506 winvblock__uint16 Major,
1507 winvblock__uint8 Minor,
1511 struct aoe__target_list_ * Walker, * Last;
1514 KeAcquireSpinLock ( &aoe__target_list_spinlock_, &Irql );
1515 Walker = Last = aoe__target_list_;
1516 while ( Walker != NULL )
1518 if (wv_memcmpeq(&Walker->Target.ClientMac, ClientMac, 6) &&
1519 wv_memcmpeq(&Walker->Target.ServerMac, ServerMac, 6) &&
1520 Walker->Target.Major == Major
1521 && Walker->Target.Minor == Minor) {
1522 if ( Walker->Target.LBASize != LBASize )
1524 DBG ( "LBASize changed for e%d.%d " "(%I64u->%I64u)\n", Major,
1525 Minor, Walker->Target.LBASize, LBASize );
1526 Walker->Target.LBASize = LBASize;
1528 KeQuerySystemTime ( &Walker->Target.ProbeTime );
1529 KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql );
1533 Walker = Walker->next;
1536 if ((Walker = wv_malloc(sizeof *Walker)) == NULL) {
1537 DBG("wv_malloc Walker\n");
1538 KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql );
1541 Walker->next = NULL;
1542 RtlCopyMemory ( Walker->Target.ClientMac, ClientMac, 6 );
1543 RtlCopyMemory ( Walker->Target.ServerMac, ServerMac, 6 );
1544 Walker->Target.Major = Major;
1545 Walker->Target.Minor = Minor;
1546 Walker->Target.LBASize = LBASize;
1547 KeQuerySystemTime ( &Walker->Target.ProbeTime );
1551 aoe__target_list_ = Walker;
1555 Last->next = Walker;
1557 KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql );
1561 * Process an AoE reply.
1563 * @v SourceMac The AoE server's MAC address.
1564 * @v DestinationMac The AoE client's MAC address.
1565 * @v Data The AoE packet.
1566 * @v DataSize The AoE packet's size.
1568 NTSTATUS STDCALL aoe__reply(
1569 IN winvblock__uint8_ptr SourceMac,
1570 IN winvblock__uint8_ptr DestinationMac,
1571 IN winvblock__uint8_ptr Data,
1572 IN winvblock__uint32 DataSize
1575 struct aoe__packet_ * reply = (struct aoe__packet_ *) Data;
1577 struct aoe__work_tag_ * tag;
1579 winvblock__bool Found = FALSE;
1580 LARGE_INTEGER CurrentTime;
1581 disk__type_ptr disk_ptr;
1582 struct aoe__disk_type_ * aoe_disk_ptr;
1585 * Discard non-responses
1587 if ( !reply->ResponseFlag )
1588 return STATUS_SUCCESS;
1591 * If the response matches our probe, add the AoE disk device
1593 if ( aoe__probe_tag_->Id == reply->Tag )
1595 RtlCopyMemory ( &LBASize, &reply->Data[200], sizeof ( LONGLONG ) );
1596 add_target ( DestinationMac, SourceMac, ntohs ( reply->Major ),
1597 reply->Minor, LBASize );
1598 return STATUS_SUCCESS;
1602 * Wait until we have the global spin-lock
1604 KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
1607 * Search for request tag
1609 if ( aoe__tag_list_ == NULL )
1611 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1612 return STATUS_SUCCESS;
1614 tag = aoe__tag_list_;
1615 while ( tag != NULL )
1617 if ( ( tag->Id == reply->Tag )
1618 && ( tag->packet_data->Major == reply->Major )
1619 && ( tag->packet_data->Minor == reply->Minor ) )
1628 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1629 return STATUS_SUCCESS;
1634 * Remove the tag from the global tag list
1636 if ( tag->previous == NULL )
1637 aoe__tag_list_ = tag->next;
1639 tag->previous->next = tag->next;
1640 if ( tag->next == NULL )
1641 aoe__tag_list_last_ = tag->previous;
1643 tag->next->previous = tag->previous;
1644 aoe__outstanding_tags_--;
1645 if ( aoe__outstanding_tags_ < 0 )
1646 DBG ( "aoe__outstanding_tags_ < 0!!\n" );
1647 KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
1649 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1652 * Establish pointers to the disk device and AoE disk
1654 disk_ptr = disk__get_ptr ( tag->device );
1655 aoe_disk_ptr = aoe__get_ ( tag->device );
1658 * If our tag was a discovery request, note the server
1660 if (wv_memcmpeq(aoe_disk_ptr->ServerMac, "\xff\xff\xff\xff\xff\xff", 6)) {
1661 RtlCopyMemory ( aoe_disk_ptr->ServerMac, SourceMac, 6 );
1662 DBG ( "Major: %d minor: %d found on server "
1663 "%02x:%02x:%02x:%02x:%02x:%02x\n", aoe_disk_ptr->Major,
1664 aoe_disk_ptr->Minor, SourceMac[0], SourceMac[1], SourceMac[2],
1665 SourceMac[3], SourceMac[4], SourceMac[5] );
1668 KeQuerySystemTime ( &CurrentTime );
1669 aoe_disk_ptr->Timeout -=
1670 ( winvblock__uint32 ) ( ( aoe_disk_ptr->Timeout -
1671 ( CurrentTime.QuadPart -
1672 tag->FirstSendTime.QuadPart ) ) / 1024 );
1674 * TODO: Replace the values below with #defined constants
1676 if ( aoe_disk_ptr->Timeout > 100000000 )
1677 aoe_disk_ptr->Timeout = 100000000;
1679 switch ( tag->type )
1681 case aoe__tag_type_search_drive_:
1682 KeAcquireSpinLock ( &disk_ptr->SpinLock, &Irql );
1683 switch ( aoe_disk_ptr->search_state )
1685 case aoe__search_state_getting_size_:
1687 * The reply tells us the disk size
1689 RtlCopyMemory ( &disk_ptr->LBADiskSize, &reply->Data[200],
1690 sizeof ( LONGLONG ) );
1692 * Next we are concerned with the disk geometry
1694 aoe_disk_ptr->search_state = aoe__search_state_get_geometry_;
1696 case aoe__search_state_getting_geometry_:
1698 * FIXME: use real values from partition table.
1699 * We used to truncate a fractional end cylinder, but
1700 * now leave it be in the hopes everyone uses LBA
1702 disk_ptr->SectorSize = 512;
1703 disk_ptr->Heads = 255;
1704 disk_ptr->Sectors = 63;
1705 disk_ptr->Cylinders =
1706 disk_ptr->LBADiskSize / ( disk_ptr->Heads *
1707 disk_ptr->Sectors );
1709 * Next we are concerned with the maximum sectors per packet
1711 aoe_disk_ptr->search_state =
1712 aoe__search_state_get_max_sectors_per_packet_;
1714 case aoe__search_state_getting_max_sectors_per_packet_:
1715 DataSize -= sizeof (struct aoe__packet_);
1717 ( aoe_disk_ptr->MaxSectorsPerPacket *
1718 disk_ptr->SectorSize ) )
1720 DBG ( "Packet size too low while getting "
1721 "MaxSectorsPerPacket (tried %d, got size of %d)\n",
1722 aoe_disk_ptr->MaxSectorsPerPacket, DataSize );
1723 aoe_disk_ptr->MaxSectorsPerPacket--;
1724 aoe_disk_ptr->search_state = aoe__search_state_done_;
1726 else if ( aoe_disk_ptr->MTU <
1727 ( sizeof (struct aoe__packet_) +
1728 ( ( aoe_disk_ptr->MaxSectorsPerPacket +
1729 1 ) * disk_ptr->SectorSize ) ) )
1731 DBG ( "Got MaxSectorsPerPacket %d at size of %d. "
1732 "MTU of %d reached\n",
1733 aoe_disk_ptr->MaxSectorsPerPacket, DataSize,
1734 aoe_disk_ptr->MTU );
1735 aoe_disk_ptr->search_state = aoe__search_state_done_;
1739 DBG ( "Got MaxSectorsPerPacket %d at size of %d, "
1740 "trying next...\n", aoe_disk_ptr->MaxSectorsPerPacket,
1742 aoe_disk_ptr->search_state =
1743 aoe__search_state_get_max_sectors_per_packet_;
1747 DBG ( "Undefined search_state!\n" );
1750 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1751 KeSetEvent ( &disk_ptr->SearchEvent, 0, FALSE );
1753 case aoe__tag_type_io_:
1755 * If the reply is in response to a read request, get our data!
1757 if ( tag->request_ptr->Mode == disk__io_mode_read )
1758 RtlCopyMemory ( &tag->request_ptr->Buffer[tag->BufferOffset],
1760 tag->SectorCount * disk_ptr->SectorSize );
1762 * If this is the last reply expected for the read request,
1763 * complete the IRP and free the request
1765 if ( InterlockedDecrement ( &tag->request_ptr->TagCount ) == 0 )
1767 tag->request_ptr->Irp->IoStatus.Information =
1768 tag->request_ptr->SectorCount * disk_ptr->SectorSize;
1769 tag->request_ptr->Irp->IoStatus.Status = STATUS_SUCCESS;
1770 Driver_CompletePendingIrp ( tag->request_ptr->Irp );
1771 wv_free(tag->request_ptr);
1775 DBG ( "Unknown tag type!!\n" );
1779 KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
1780 wv_free(tag->packet_data);
1782 return STATUS_SUCCESS;
1785 void aoe__reset_probe(void)
1787 aoe__probe_tag_->SendTime.QuadPart = 0LL;
1790 static void STDCALL aoe__thread_(IN void *StartContext)
1792 LARGE_INTEGER Timeout, CurrentTime, ProbeTime, ReportTime;
1793 winvblock__uint32 NextTagId = 1;
1794 struct aoe__work_tag_ * tag;
1796 winvblock__uint32 Sends = 0;
1797 winvblock__uint32 Resends = 0;
1798 winvblock__uint32 ResendFails = 0;
1799 winvblock__uint32 Fails = 0;
1800 winvblock__uint32 RequestTimeout = 0;
1801 disk__type_ptr disk_ptr;
1802 struct aoe__disk_type_ * aoe_disk_ptr;
1805 ReportTime.QuadPart = 0LL;
1806 ProbeTime.QuadPart = 0LL;
1811 * TODO: Make the below value a #defined constant
1814 * 100.000 * 100ns = 10.000.000 ns = 10ms
1816 Timeout.QuadPart = -100000LL;
1817 KeWaitForSingleObject ( &aoe__thread_sig_evt_, Executive,
1818 KernelMode, FALSE, &Timeout );
1819 KeResetEvent ( &aoe__thread_sig_evt_ );
1822 DBG ( "Stopping...\n" );
1823 PsTerminateSystemThread ( STATUS_SUCCESS );
1826 KeQuerySystemTime ( &CurrentTime );
1828 * TODO: Make the below value a #defined constant
1830 if ( CurrentTime.QuadPart > ( ReportTime.QuadPart + 10000000LL ) )
1832 DBG ( "Sends: %d Resends: %d ResendFails: %d Fails: %d "
1833 "aoe__outstanding_tags_: %d RequestTimeout: %d\n", Sends,
1834 Resends, ResendFails, Fails, aoe__outstanding_tags_,
1840 KeQuerySystemTime ( &ReportTime );
1844 * TODO: Make the below value a #defined constant
1846 if ( CurrentTime.QuadPart >
1847 ( aoe__probe_tag_->SendTime.QuadPart + 100000000LL ) )
1849 aoe__probe_tag_->Id = NextTagId++;
1850 if ( NextTagId == 0 )
1852 aoe__probe_tag_->packet_data->Tag = aoe__probe_tag_->Id;
1853 Protocol_Send ( "\xff\xff\xff\xff\xff\xff",
1854 "\xff\xff\xff\xff\xff\xff",
1855 ( winvblock__uint8_ptr ) aoe__probe_tag_->
1856 packet_data, aoe__probe_tag_->PacketSize,
1858 KeQuerySystemTime ( &aoe__probe_tag_->SendTime );
1861 KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
1862 if ( aoe__tag_list_ == NULL )
1864 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1867 tag = aoe__tag_list_;
1868 while ( tag != NULL )
1871 * Establish pointers to the disk and AoE disk
1873 disk_ptr = disk__get_ptr ( tag->device );
1874 aoe_disk_ptr = aoe__get_ ( tag->device );
1876 RequestTimeout = aoe_disk_ptr->Timeout;
1879 if ( aoe__outstanding_tags_ <= 64 )
1882 * if ( aoe__outstanding_tags_ <= 102400 ) {
1884 if ( aoe__outstanding_tags_ < 0 )
1885 DBG ( "aoe__outstanding_tags_ < 0!!\n" );
1886 tag->Id = NextTagId++;
1887 if ( NextTagId == 0 )
1889 tag->packet_data->Tag = tag->Id;
1891 ( aoe_disk_ptr->ClientMac, aoe_disk_ptr->ServerMac,
1892 ( winvblock__uint8_ptr ) tag->packet_data,
1893 tag->PacketSize, tag ) )
1895 KeQuerySystemTime ( &tag->FirstSendTime );
1896 KeQuerySystemTime ( &tag->SendTime );
1897 aoe__outstanding_tags_++;
1910 KeQuerySystemTime ( &CurrentTime );
1911 if ( CurrentTime.QuadPart >
1912 ( tag->SendTime.QuadPart +
1913 ( LONGLONG ) ( aoe_disk_ptr->Timeout * 2 ) ) )
1916 ( aoe_disk_ptr->ClientMac, aoe_disk_ptr->ServerMac,
1917 ( winvblock__uint8_ptr ) tag->packet_data,
1918 tag->PacketSize, tag ) )
1920 KeQuerySystemTime ( &tag->SendTime );
1921 aoe_disk_ptr->Timeout += aoe_disk_ptr->Timeout / 1000;
1922 if ( aoe_disk_ptr->Timeout > 100000000 )
1923 aoe_disk_ptr->Timeout = 100000000;
1934 if ( tag == aoe__tag_list_ )
1936 DBG ( "Taglist Cyclic!!\n" );
1940 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1945 static disk__max_xfer_len_decl(max_xfer_len)
1947 struct aoe__disk_type_ * aoe_disk_ptr = aoe__get_(disk_ptr->device);
1949 return disk_ptr->SectorSize * aoe_disk_ptr->MaxSectorsPerPacket;
1952 static winvblock__uint32 STDCALL query_id(
1953 IN struct device__type * dev,
1954 IN BUS_QUERY_ID_TYPE query_type,
1955 IN OUT WCHAR (*buf)[512]
1957 struct aoe__disk_type_ * aoe_disk = aoe__get_(dev);
1959 switch (query_type) {
1960 case BusQueryDeviceID:
1961 return swprintf(*buf, winvblock__literal_w L"\\AoEHardDisk") + 1;
1963 case BusQueryInstanceID:
1966 L"AoE_at_Shelf_%d.Slot_%d",
1971 case BusQueryHardwareIDs: {
1972 winvblock__uint32 tmp;
1976 winvblock__literal_w L"\\AoEHardDisk"
1978 tmp += swprintf(*buf + tmp, L"GenDisk") + 4;
1982 case BusQueryCompatibleIDs:
1983 return swprintf(*buf, L"GenDisk") + 4;
1993 winvblock__def_struct(abft) {
1994 winvblock__uint32 Signature; /* 0x54464261 (aBFT) */
1995 winvblock__uint32 Length;
1996 winvblock__uint8 Revision;
1997 winvblock__uint8 Checksum;
1998 winvblock__uint8 OEMID[6];
1999 winvblock__uint8 OEMTableID[8];
2000 winvblock__uint8 Reserved1[12];
2001 winvblock__uint16 Major;
2002 winvblock__uint8 Minor;
2003 winvblock__uint8 Reserved2;
2004 winvblock__uint8 ClientMac[6];
2005 } __attribute__((__packed__));
2010 disk__close_decl(close) {
2014 static void aoe__process_abft_(void) {
2015 PHYSICAL_ADDRESS PhysicalAddress;
2016 winvblock__uint8_ptr PhysicalMemory;
2017 winvblock__uint32 Offset, Checksum, i;
2018 winvblock__bool FoundAbft = FALSE;
2020 struct aoe__disk_type_ * aoe_disk;
2023 PhysicalAddress.QuadPart = 0LL;
2024 PhysicalMemory = MmMapIoSpace(PhysicalAddress, 0xa0000, MmNonCached);
2025 if (!PhysicalMemory) {
2026 DBG("Could not map low memory\n");
2029 for (Offset = 0; Offset < 0xa0000; Offset += 0x10) {
2031 ((abft_ptr) (PhysicalMemory + Offset))->Signature ==
2038 i < ((abft_ptr) (PhysicalMemory + Offset))->Length;
2041 Checksum += PhysicalMemory[Offset + i];
2042 if (Checksum & 0xff)
2044 if (((abft_ptr) (PhysicalMemory + Offset))->Revision != 1) {
2046 "Found aBFT with mismatched revision v%d at "
2047 "segment 0x%4x. want v1.\n",
2048 ((abft_ptr) (PhysicalMemory + Offset))->Revision,
2053 DBG("Found aBFT at segment: 0x%04x\n", (Offset / 0x10));
2056 PhysicalMemory + Offset,
2062 MmUnmapIoSpace(PhysicalMemory, 0xa0000);
2066 RtlCopyMemory(AoEBootRecord.ClientMac, "\x00\x0c\x29\x34\x69\x34", 6);
2067 AoEBootRecord.Major = 0;
2068 AoEBootRecord.Minor = 10;
2073 aoe_disk = aoe__create_disk_();
2074 if(aoe_disk == NULL) {
2075 DBG("Could not create AoE disk from aBFT!\n");
2079 "Attaching AoE disk from client NIC "
2080 "%02x:%02x:%02x:%02x:%02x:%02x to major: %d minor: %d\n",
2081 AoEBootRecord.ClientMac[0],
2082 AoEBootRecord.ClientMac[1],
2083 AoEBootRecord.ClientMac[2],
2084 AoEBootRecord.ClientMac[3],
2085 AoEBootRecord.ClientMac[4],
2086 AoEBootRecord.ClientMac[5],
2087 AoEBootRecord.Major,
2090 RtlCopyMemory(aoe_disk->ClientMac, AoEBootRecord.ClientMac, 6);
2091 RtlFillMemory(aoe_disk->ServerMac, 6, 0xff);
2092 aoe_disk->Major = AoEBootRecord.Major;
2093 aoe_disk->Minor = AoEBootRecord.Minor;
2094 aoe_disk->MaxSectorsPerPacket = 1;
2095 aoe_disk->Timeout = 200000; /* 20 ms. */
2096 aoe_disk->disk->BootDrive = TRUE;
2097 aoe_disk->disk->media = disk__media_hard;
2098 bus__add_child(driver__bus(), aoe_disk->disk->device);
2102 DBG("No aBFT found\n");
2109 NTSTATUS STDCALL scan(
2110 IN PDEVICE_OBJECT dev_obj,
2112 IN PIO_STACK_LOCATION io_stack_loc,
2113 IN struct device__type * dev,
2114 OUT winvblock__bool_ptr completion
2117 winvblock__uint32 count;
2118 struct aoe__target_list_ * target_walker;
2119 aoe__mount_targets_ptr targets;
2121 DBG("Got IOCTL_AOE_SCAN...\n");
2122 KeAcquireSpinLock(&aoe__target_list_spinlock_, &irql);
2125 target_walker = aoe__target_list_;
2126 while (target_walker != NULL) {
2128 target_walker = target_walker->next;
2131 targets = wv_malloc(sizeof *targets + (count * sizeof targets->Target[0]));
2132 if ( targets == NULL ) {
2133 DBG("wv_malloc targets\n");
2134 irp->IoStatus.Information = 0;
2135 return STATUS_INSUFFICIENT_RESOURCES;
2137 irp->IoStatus.Information =
2138 sizeof (aoe__mount_targets) + (count * sizeof (aoe__mount_target));
2139 targets->Count = count;
2142 target_walker = aoe__target_list_;
2143 while (target_walker != NULL) {
2145 &targets->Target[count],
2146 &target_walker->Target,
2147 sizeof (aoe__mount_target)
2150 target_walker = target_walker->next;
2153 irp->AssociatedIrp.SystemBuffer,
2155 (io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength <
2156 (sizeof (aoe__mount_targets) + (count * sizeof (aoe__mount_target))) ?
2157 io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength :
2158 (sizeof (aoe__mount_targets) + (count * sizeof (aoe__mount_target)))
2163 KeReleaseSpinLock(&aoe__target_list_spinlock_, irql);
2165 return STATUS_SUCCESS;
2168 NTSTATUS STDCALL show(
2169 IN PDEVICE_OBJECT dev_obj,
2171 IN PIO_STACK_LOCATION io_stack_loc,
2172 IN struct device__type * dev,
2173 OUT winvblock__bool_ptr completion
2175 winvblock__uint32 count;
2176 struct device__type * dev_walker;
2177 struct bus__type * bus;
2178 aoe__mount_disks_ptr disks;
2180 DBG("Got IOCTL_AOE_SHOW...\n");
2182 bus = bus__get(dev);
2183 dev_walker = bus->first_child;
2185 while (dev_walker != NULL) {
2187 dev_walker = dev_walker->next_sibling_ptr;
2190 disks = wv_malloc(sizeof *disks + (count * sizeof disks->Disk[0]));
2191 if (disks == NULL) {
2192 DBG("wv_malloc disks\n");
2193 irp->IoStatus.Information = 0;
2194 return STATUS_INSUFFICIENT_RESOURCES;
2196 irp->IoStatus.Information =
2197 sizeof (aoe__mount_disks) + (count * sizeof (aoe__mount_disk ));
2198 disks->Count = count;
2201 dev_walker = bus->first_child;
2202 while (dev_walker != NULL) {
2203 disk__type_ptr disk = disk__get_ptr(dev_walker);
2204 struct aoe__disk_type_ * aoe_disk = aoe__get_(dev_walker);
2206 disks->Disk[count].Disk = dev_walker->dev_num;
2208 &disks->Disk[count].ClientMac,
2209 &aoe_disk->ClientMac,
2213 &disks->Disk[count].ServerMac,
2214 &aoe_disk->ServerMac,
2217 disks->Disk[count].Major = aoe_disk->Major;
2218 disks->Disk[count].Minor = aoe_disk->Minor;
2219 disks->Disk[count].LBASize = disk->LBADiskSize;
2221 dev_walker = dev_walker->next_sibling_ptr;
2224 irp->AssociatedIrp.SystemBuffer,
2226 (io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength <
2227 (sizeof (aoe__mount_disks) + (count * sizeof (aoe__mount_disk))) ?
2228 io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength :
2229 (sizeof (aoe__mount_disks) + (count * sizeof (aoe__mount_disk)))
2234 return STATUS_SUCCESS;
2237 NTSTATUS STDCALL mount(
2238 IN PDEVICE_OBJECT dev_obj,
2240 IN PIO_STACK_LOCATION io_stack_loc,
2241 IN struct device__type * dev,
2242 OUT winvblock__bool_ptr completion
2244 winvblock__uint8_ptr buffer = irp->AssociatedIrp.SystemBuffer;
2245 struct aoe__disk_type_ * aoe_disk;
2248 "Got IOCTL_AOE_MOUNT for client: %02x:%02x:%02x:%02x:%02x:%02x "
2249 "Major:%d Minor:%d\n",
2256 *(winvblock__uint16_ptr) (buffer + 6),
2257 (winvblock__uint8) buffer[8]
2259 aoe_disk = aoe__create_disk_();
2260 if (aoe_disk == NULL) {
2261 DBG("Could not create AoE disk!\n");
2262 irp->IoStatus.Information = 0;
2264 return STATUS_INSUFFICIENT_RESOURCES;
2266 RtlCopyMemory(aoe_disk->ClientMac, buffer, 6);
2267 RtlFillMemory(aoe_disk->ServerMac, 6, 0xff);
2268 aoe_disk->Major = *(winvblock__uint16_ptr) (buffer + 6);
2269 aoe_disk->Minor = (winvblock__uint8) buffer[8];
2270 aoe_disk->MaxSectorsPerPacket = 1;
2271 aoe_disk->Timeout = 200000; /* 20 ms. */
2272 aoe_disk->disk->BootDrive = FALSE;
2273 aoe_disk->disk->media = disk__media_hard;
2274 bus__add_child(driver__bus(), aoe_disk->disk->device);
2275 irp->IoStatus.Information = 0;
2277 return STATUS_SUCCESS;
2280 NTSTATUS STDCALL aoe__bus_dev_ctl_dispatch(
2281 IN PDEVICE_OBJECT dev_obj,
2283 IN PIO_STACK_LOCATION io_stack_loc,
2284 IN struct device__type * dev,
2285 OUT winvblock__bool_ptr completion
2287 NTSTATUS status = STATUS_NOT_SUPPORTED;
2289 switch (io_stack_loc->Parameters.DeviceIoControl.IoControlCode) {
2290 case IOCTL_AOE_SCAN:
2291 status = scan(dev_obj, irp, io_stack_loc, dev, completion);
2294 case IOCTL_AOE_SHOW:
2295 status = show(dev_obj, irp, io_stack_loc, dev, completion);
2298 case IOCTL_AOE_MOUNT:
2299 status = mount(dev_obj, irp, io_stack_loc, dev, completion);
2302 case IOCTL_AOE_UMOUNT:
2303 io_stack_loc->Parameters.DeviceIoControl.IoControlCode =
2308 IoCompleteRequest(irp, IO_NO_INCREMENT);
2313 * Create a new AoE disk.
2315 * @ret aoe_disk * The address of a new AoE disk, or NULL for failure.
2317 * This function should not be confused with a PDO creation routine, which is
2318 * actually implemented for each device type. This routine will allocate a
2319 * aoe__disk_type_, track it in a global list, as well as populate the disk
2320 * with default values.
2322 static struct aoe__disk_type_ * aoe__create_disk_(void) {
2323 disk__type_ptr disk;
2324 struct aoe__disk_type_ * aoe_disk;
2326 /* Try to create a disk. */
2327 disk = disk__create();
2331 * AoE disk devices might be used for booting and should
2332 * not be allocated from a paged memory pool.
2334 aoe_disk = wv_mallocz(sizeof *aoe_disk);
2335 if (aoe_disk == NULL)
2337 /* Track the new AoE disk in our global list. */
2338 ExInterlockedInsertTailList(
2340 &aoe_disk->tracking,
2341 &aoe__disk_list_lock_
2343 /* Populate non-zero device defaults. */
2344 aoe_disk->disk = disk;
2345 aoe_disk->prev_free = disk->device->ops.free;
2346 disk->device->ops.free = aoe__free_disk_;
2347 disk->device->ops.pnp_id = query_id;
2348 disk->disk_ops.io = io;
2349 disk->disk_ops.max_xfer_len = max_xfer_len;
2350 disk->disk_ops.init = init;
2351 disk->disk_ops.close = close;
2352 disk->ext = aoe_disk;
2358 device__free(disk->device);
2365 * Default AoE disk deletion operation.
2367 * @v dev Points to the AoE disk device to delete.
2369 static void STDCALL aoe__free_disk_(IN struct device__type * dev) {
2370 struct aoe__disk_type_ * aoe_disk = aoe__get_(dev);
2371 /* Free the "inherited class". */
2372 aoe_disk->prev_free(dev);
2374 * Track the AoE disk deletion in our global list. Unfortunately,
2375 * for now we have faith that an AoE disk won't be deleted twice and
2376 * result in a race condition. Something to keep in mind...
2378 ExInterlockedRemoveHeadList(
2379 aoe_disk->tracking.Blink,
2380 &aoe__disk_list_lock_