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"
45 #define AOEPROTOCOLVER 1
47 extern NTSTATUS STDCALL ZwWaitForSingleObject(
49 IN winvblock__bool Alertable,
50 IN PLARGE_INTEGER Timeout OPTIONAL
54 extern WV_SP_BUS_T aoe_bus;
55 extern winvblock__bool aoe_bus__create(void);
56 extern void aoe_bus__free(void);
58 /* Forward declarations. */
59 struct aoe__disk_type_;
60 static void STDCALL aoe__thread_(IN void *);
61 static void aoe__process_abft_(void);
62 static void STDCALL aoe__unload_(IN PDRIVER_OBJECT);
63 static struct aoe__disk_type_ * aoe__create_disk_(void);
64 static WV_F_DEV_FREE aoe__free_disk_;
70 aoe__tag_type_search_drive_
80 winvblock__uint8 ReservedFlag:2;
81 winvblock__uint8 ErrorFlag:1;
82 winvblock__uint8 ResponseFlag:1;
83 winvblock__uint8 Ver:4;
84 winvblock__uint8 Error;
85 winvblock__uint16 Major;
86 winvblock__uint8 Minor;
87 winvblock__uint8 Command;
88 winvblock__uint32 Tag;
90 winvblock__uint8 WriteAFlag:1;
91 winvblock__uint8 AsyncAFlag:1;
92 winvblock__uint8 Reserved1AFlag:2;
93 winvblock__uint8 DeviceHeadAFlag:1;
94 winvblock__uint8 Reserved2AFlag:1;
95 winvblock__uint8 ExtendedAFlag:1;
96 winvblock__uint8 Reserved3AFlag:1;
100 winvblock__uint8 Feature;
102 winvblock__uint8 Count;
105 winvblock__uint8 Cmd;
106 winvblock__uint8 Status;
109 winvblock__uint8 Lba0;
110 winvblock__uint8 Lba1;
111 winvblock__uint8 Lba2;
112 winvblock__uint8 Lba3;
113 winvblock__uint8 Lba4;
114 winvblock__uint8 Lba5;
115 winvblock__uint16 Reserved;
117 winvblock__uint8 Data[];
118 } __attribute__((__packed__));
124 /** An I/O request. */
128 winvblock__uint32 SectorCount;
129 winvblock__uint8_ptr Buffer;
131 winvblock__uint32 TagCount;
132 winvblock__uint32 TotalTags;
135 /** A work item "tag". */
136 struct aoe__work_tag_
138 enum aoe__tag_type_ type;
140 struct aoe__io_req_ * request_ptr;
141 winvblock__uint32 Id;
142 struct aoe__packet_ * packet_data;
143 winvblock__uint32 PacketSize;
144 LARGE_INTEGER FirstSendTime;
145 LARGE_INTEGER SendTime;
146 winvblock__uint32 BufferOffset;
147 winvblock__uint32 SectorCount;
148 struct aoe__work_tag_ * next;
149 struct aoe__work_tag_ * previous;
152 /** A disk search. */
153 struct aoe__disk_search_
156 struct aoe__work_tag_ * tag;
157 struct aoe__disk_search_ * next;
160 enum aoe__search_state_
162 aoe__search_state_search_nic_,
163 aoe__search_state_get_size_,
164 aoe__search_state_getting_size_,
165 aoe__search_state_get_geometry_,
166 aoe__search_state_getting_geometry_,
167 aoe__search_state_get_max_sectors_per_packet_,
168 aoe__search_state_getting_max_sectors_per_packet_,
169 aoe__search_state_done_
172 /** The AoE disk type. */
173 struct aoe__disk_type_
176 winvblock__uint32 MTU;
177 winvblock__uint8 ClientMac[6];
178 winvblock__uint8 ServerMac[6];
179 winvblock__uint32 Major;
180 winvblock__uint32 Minor;
181 winvblock__uint32 MaxSectorsPerPacket;
182 winvblock__uint32 Timeout;
183 enum aoe__search_state_ search_state;
184 WV_FP_DEV_FREE prev_free;
188 struct aoe__target_list_
190 aoe__mount_target Target;
191 struct aoe__target_list_ * next;
194 /** Private globals. */
195 static struct aoe__target_list_ * aoe__target_list_ = NULL;
196 static KSPIN_LOCK aoe__target_list_spinlock_;
197 static winvblock__bool aoe__stop_ = FALSE;
198 static KSPIN_LOCK aoe__spinlock_;
199 static KEVENT aoe__thread_sig_evt_;
200 static struct aoe__work_tag_ * aoe__tag_list_ = NULL;
201 static struct aoe__work_tag_ * aoe__tag_list_last_ = NULL;
202 static struct aoe__work_tag_ * aoe__probe_tag_ = NULL;
203 static struct aoe__disk_search_ * aoe__disk_search_list_ = NULL;
204 static LONG aoe__outstanding_tags_ = 0;
205 static HANDLE aoe__thread_handle_;
206 static winvblock__bool aoe__started_ = FALSE;
207 static LIST_ENTRY aoe__disk_list_;
208 static KSPIN_LOCK aoe__disk_list_lock_;
210 /* Yield a pointer to the AoE disk. */
211 static struct aoe__disk_type_ * aoe__get_(WV_SP_DEV_T dev_ptr)
213 return disk__get_ptr(dev_ptr)->ext;
216 static winvblock__bool STDCALL setup_reg(OUT PNTSTATUS status_out)
219 winvblock__bool Updated = FALSE;
220 WCHAR InterfacesPath[] = L"\\Ndi\\Interfaces\\";
221 WCHAR LinkagePath[] = L"\\Linkage\\";
222 WCHAR NdiPath[] = L"\\Ndi\\";
223 WCHAR DriverServiceNamePath[] =
224 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
225 OBJECT_ATTRIBUTES SubKeyObject;
227 ControlKeyHandle, NetworkClassKeyHandle, SubKeyHandle;
229 i, SubkeyIndex, ResultLength, InterfacesKeyStringLength,
230 LinkageKeyStringLength, NdiKeyStringLength, NewValueLength;
232 InterfacesKeyString, LinkageKeyString, NdiKeyString,
233 DriverServiceNameString, NewValue;
235 InterfacesKey, LinkageKey, NdiKey, LowerRange, UpperBind, Service,
237 PKEY_BASIC_INFORMATION KeyInformation;
238 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
239 winvblock__bool Update, Found;
243 RtlInitUnicodeString(&LowerRange, L"LowerRange");
244 RtlInitUnicodeString(&UpperBind, L"UpperBind");
245 RtlInitUnicodeString(&Service, L"Service");
247 /* Open the network adapter class key. */
248 status = registry__open_key(
249 (L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Class\\"
250 L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\"),
251 &NetworkClassKeyHandle
253 if (!NT_SUCCESS(status))
254 goto err_keyopennetworkclass;
256 /* Enumerate through subkeys. */
258 while ((status = ZwEnumerateKey(
259 NetworkClassKeyHandle,
265 )) != STATUS_NO_MORE_ENTRIES)
267 if ((status != STATUS_SUCCESS) &&
268 (status != STATUS_BUFFER_OVERFLOW) &&
269 (status != STATUS_BUFFER_TOO_SMALL)
272 DBG("ZwEnumerateKey 1 failed (%lx)\n", status);
275 if ((KeyInformation = wv_malloc(ResultLength)) == NULL)
277 DBG("wv_malloc KeyData failed\n");
279 registry__close_key(NetworkClassKeyHandle);
283 NetworkClassKeyHandle,
291 DBG ("ZwEnumerateKey 2 failed\n");
295 InterfacesKeyStringLength =
296 KeyInformation->NameLength + sizeof InterfacesPath;
297 InterfacesKeyString = wv_malloc(InterfacesKeyStringLength);
298 if (InterfacesKeyString == NULL)
300 DBG("wv_malloc InterfacesKeyString failed\n");
306 KeyInformation->Name,
307 KeyInformation->NameLength
310 InterfacesKeyString +
311 (KeyInformation->NameLength / sizeof (WCHAR)),
313 sizeof InterfacesPath
315 RtlInitUnicodeString(&InterfacesKey, InterfacesKeyString);
318 InitializeObjectAttributes(
321 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
322 NetworkClassKeyHandle,
325 if (NT_SUCCESS(ZwOpenKey(&SubKeyHandle, KEY_ALL_ACCESS, &SubKeyObject)))
327 if ((status = ZwQueryValueKey(
330 KeyValuePartialInformation,
334 )) != STATUS_OBJECT_NAME_NOT_FOUND )
336 if ((status != STATUS_SUCCESS) &&
337 (status != STATUS_BUFFER_OVERFLOW) &&
338 (status != STATUS_BUFFER_TOO_SMALL))
341 "ZwQueryValueKey InterfacesKey 1 failed (%lx)\n",
346 if ((KeyValueInformation = wv_malloc(ResultLength)) == NULL)
348 DBG("wv_malloc InterfacesKey KeyValueData failed\n");
351 if (!(NT_SUCCESS(ZwQueryValueKey(
354 KeyValuePartialInformation,
360 DBG("ZwQueryValueKey InterfacesKey 2 failed\n");
365 KeyValueInformation->Data,
369 wv_free(KeyValueInformation);
370 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
372 DBG("ZwClose InterfacesKey SubKeyHandle failed\n");
377 wv_free(InterfacesKeyString);
381 LinkageKeyStringLength =
382 KeyInformation->NameLength + sizeof LinkagePath;
383 if ((LinkageKeyString = wv_malloc(LinkageKeyStringLength)) == NULL)
385 DBG("wv_malloc LinkageKeyString failed\n");
390 KeyInformation->Name,
391 KeyInformation->NameLength
395 (KeyInformation->NameLength / sizeof (WCHAR)),
399 RtlInitUnicodeString(&LinkageKey, LinkageKeyString);
401 InitializeObjectAttributes(
404 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
405 NetworkClassKeyHandle,
408 if (!NT_SUCCESS(ZwCreateKey(
414 REG_OPTION_NON_VOLATILE,
418 DBG("ZwCreateKey failed (%lx)\n");
421 if ((status = ZwQueryValueKey(
424 KeyValuePartialInformation,
428 )) != STATUS_OBJECT_NAME_NOT_FOUND)
430 if ((status != STATUS_SUCCESS) &&
431 (status != STATUS_BUFFER_OVERFLOW) &&
432 (status != STATUS_BUFFER_TOO_SMALL))
434 DBG("ZwQueryValueKey LinkageKey 1 failed (%lx)\n", status);
437 if ((KeyValueInformation = wv_malloc(ResultLength)) == NULL)
439 DBG("wv_malloc LinkageKey KeyValueData failed\n");
442 if (!(NT_SUCCESS(ZwQueryValueKey(
445 KeyValuePartialInformation,
451 DBG("ZwQueryValueKey LinkageKey 2 failed\n");
457 i < (KeyValueInformation->DataLength -
458 sizeof winvblock__literal_w / sizeof (WCHAR));
462 winvblock__literal_w,
463 ((PWCHAR)KeyValueInformation->Data) + i,
464 sizeof winvblock__literal_w
469 } /* if wv_memcmpeq */
474 NewValueLength = KeyValueInformation->DataLength;
475 if ((NewValue = wv_malloc(NewValueLength)) == NULL)
477 DBG("wv_malloc NewValue 1 failed\n");
482 KeyValueInformation->Data,
483 KeyValueInformation->DataLength
489 NewValueLength = KeyValueInformation->DataLength +
490 sizeof winvblock__literal_w;
491 if ((NewValue = wv_malloc(NewValueLength)) == NULL)
493 DBG("wv_malloc NewValue 2 failed\n");
498 winvblock__literal_w,
499 sizeof winvblock__literal_w
503 (sizeof winvblock__literal_w / sizeof (WCHAR)),
504 KeyValueInformation->Data,
505 KeyValueInformation->DataLength
508 wv_free(KeyValueInformation);
513 NewValueLength = sizeof winvblock__literal_w + sizeof (WCHAR);
514 if ((NewValue = wv_mallocz(NewValueLength)) == NULL)
516 DBG("wv_mallocz NewValue 3 failed\n");
521 winvblock__literal_w,
522 sizeof winvblock__literal_w
525 if (!NT_SUCCESS(ZwSetValueKey(
534 DBG("ZwSetValueKey failed\n");
539 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
541 DBG("ZwClose LinkageKey SubKeyHandle failed\n");
544 wv_free(LinkageKeyString);
546 /* Not sure where this comes from. */
550 NdiKeyStringLength = KeyInformation->NameLength + sizeof NdiPath;
551 if ((NdiKeyString = wv_malloc(NdiKeyStringLength)) == NULL)
553 DBG("wv_malloc NdiKeyString failed\n");
558 KeyInformation->Name,
559 KeyInformation->NameLength
562 NdiKeyString + (KeyInformation->NameLength / sizeof (WCHAR)),
566 RtlInitUnicodeString(&NdiKey, NdiKeyString);
568 InitializeObjectAttributes(
571 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
572 NetworkClassKeyHandle,
575 if (NT_SUCCESS(ZwOpenKey(
581 if ((status = ZwQueryValueKey(
584 KeyValuePartialInformation,
588 )) != STATUS_OBJECT_NAME_NOT_FOUND)
590 if ((status != STATUS_SUCCESS) &&
591 (status != STATUS_BUFFER_OVERFLOW) &&
592 (status != STATUS_BUFFER_TOO_SMALL))
594 DBG("ZwQueryValueKey NdiKey 1 failed (%lx)\n", status);
597 if ((KeyValueInformation = wv_malloc(ResultLength)) == NULL)
599 DBG("wv_malloc NdiKey KeyValueData failed\n");
602 if (!(NT_SUCCESS(ZwQueryValueKey(
605 KeyValuePartialInformation,
611 DBG("ZwQueryValueKey NdiKey 2 failed\n");
612 wv_free(KeyValueInformation);
615 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
617 DBG("ZwClose NdiKey SubKeyHandle failed\n");
620 DriverServiceNameString = wv_malloc(
621 sizeof DriverServiceNamePath +
622 KeyValueInformation->DataLength -
623 sizeof *DriverServiceNamePath
625 if (DriverServiceNameString == NULL)
627 DBG("wv_malloc DriverServiceNameString failed\n");
632 DriverServiceNameString,
633 DriverServiceNamePath,
634 sizeof DriverServiceNamePath
637 DriverServiceNameString +
638 (sizeof DriverServiceNamePath / sizeof (WCHAR)) - 1,
639 KeyValueInformation->Data,
640 KeyValueInformation->DataLength
642 RtlInitUnicodeString(
644 DriverServiceNameString
648 "Starting driver %S -> %08x\n",
649 KeyValueInformation->Data,
650 ZwLoadDriver(&DriverServiceName)
653 wv_free(DriverServiceNameString);
654 wv_free(KeyValueInformation);
657 wv_free(NdiKeyString);
659 wv_free(KeyInformation);
662 registry__close_key ( NetworkClassKeyHandle );
663 *status_out = STATUS_SUCCESS;
668 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
669 DBG("ZwClose SubKeyHandle failed\n");
672 wv_free(NdiKeyString);
676 wv_free(KeyValueInformation);
679 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
680 DBG("ZwClose SubKeyHandle failed\n");
683 wv_free(LinkageKeyString);
687 wv_free(KeyValueInformation);
690 if (!NT_SUCCESS(ZwClose(SubKeyHandle)))
691 DBG("ZwClose SubKeyHandle failed\n");
694 wv_free(InterfacesKeyString);
698 wv_free(KeyInformation);
701 registry__close_key(NetworkClassKeyHandle);
702 err_keyopennetworkclass:
704 *status_out = STATUS_UNSUCCESSFUL;
709 * Start AoE operations.
711 * @ret Status Return status code.
713 NTSTATUS STDCALL DriverEntry(
714 IN PDRIVER_OBJECT DriverObject,
715 IN PUNICODE_STRING RegistryPath
718 OBJECT_ATTRIBUTES ObjectAttributes;
725 return STATUS_SUCCESS;
726 /* Initialize the global list of AoE disks. */
727 InitializeListHead(&aoe__disk_list_);
728 KeInitializeSpinLock(&aoe__disk_list_lock_);
729 /* Setup the Registry. */
730 if (!NT_SUCCESS(setup_reg(&Status))) {
731 DBG("Could not update Registry!\n");
734 DBG("Registry updated\n");
736 /* Start up the protocol. */
737 if (!NT_SUCCESS(Status = Protocol_Start())) {
738 DBG("Protocol startup failure!\n");
741 /* Allocate and zero-fill the global probe tag. */
742 aoe__probe_tag_ = wv_mallocz(sizeof *aoe__probe_tag_);
743 if (aoe__probe_tag_ == NULL) {
744 DBG("Couldn't allocate probe tag; bye!\n");
745 return STATUS_INSUFFICIENT_RESOURCES;
748 /* Set up the probe tag's AoE packet reference. */
749 aoe__probe_tag_->PacketSize = sizeof (struct aoe__packet_);
750 /* Allocate and zero-fill the probe tag's packet reference. */
751 aoe__probe_tag_->packet_data = wv_mallocz(aoe__probe_tag_->PacketSize);
752 if (aoe__probe_tag_->packet_data == NULL) {
753 DBG("Couldn't allocate aoe__probe_tag_->packet_data\n");
754 wv_free(aoe__probe_tag_);
755 return STATUS_INSUFFICIENT_RESOURCES;
757 aoe__probe_tag_->SendTime.QuadPart = 0LL;
759 /* Initialize the probe tag's AoE packet. */
760 aoe__probe_tag_->packet_data->Ver = AOEPROTOCOLVER;
761 aoe__probe_tag_->packet_data->Major =
762 htons((winvblock__uint16) -1);
763 aoe__probe_tag_->packet_data->Minor = (winvblock__uint8) -1;
764 aoe__probe_tag_->packet_data->Cmd = 0xec; /* IDENTIFY DEVICE */
765 aoe__probe_tag_->packet_data->Count = 1;
767 /* Initialize global target-list spinlock. */
768 KeInitializeSpinLock(&aoe__target_list_spinlock_);
770 /* Initialize global spin-lock and global thread signal event. */
771 KeInitializeSpinLock(&aoe__spinlock_);
772 KeInitializeEvent(&aoe__thread_sig_evt_, SynchronizationEvent, FALSE);
774 /* Initialize object attributes for thread. */
775 InitializeObjectAttributes(
783 /* Create global thread. */
784 if (!NT_SUCCESS(Status = PsCreateSystemThread(
785 &aoe__thread_handle_,
793 return Error("PsCreateSystemThread", Status);
795 if (!NT_SUCCESS(Status = ObReferenceObjectByHandle(
803 ZwClose(aoe__thread_handle_);
804 Error("ObReferenceObjectByHandle", Status);
806 KeSetEvent(&aoe__thread_sig_evt_, 0, FALSE);
809 DriverObject->DriverUnload = aoe__unload_;
810 aoe__started_ = TRUE;
811 if (!aoe_bus__create()) {
812 DBG("Unable to create AoE bus!\n");
813 aoe__unload_(DriverObject);
814 return STATUS_INSUFFICIENT_RESOURCES;
816 aoe__process_abft_();
822 * Stop AoE operations.
824 static void STDCALL aoe__unload_(IN PDRIVER_OBJECT DriverObject) {
826 struct aoe__disk_search_ * disk_searcher, * previous_disk_searcher;
827 struct aoe__work_tag_ * tag;
829 struct aoe__target_list_ * Walker, * Next;
832 /* If we're not already started, there's nothing to do. */
835 /* Destroy the AoE bus. */
837 /* Stop the AoE protocol. */
839 /* If we're not already shutting down, signal the event. */
842 KeSetEvent(&aoe__thread_sig_evt_, 0, FALSE);
843 /* Wait until the event has been signalled. */
844 if (!NT_SUCCESS(Status = ZwWaitForSingleObject(
849 Error("AoE_Stop ZwWaitForSingleObject", Status);
850 ZwClose(aoe__thread_handle_);
853 /* Free the target list. */
854 KeAcquireSpinLock(&aoe__target_list_spinlock_, &Irql2);
855 Walker = aoe__target_list_;
856 while (Walker != NULL) {
861 KeReleaseSpinLock(&aoe__target_list_spinlock_, Irql2);
863 /* Wait until we have the global spin-lock. */
864 KeAcquireSpinLock(&aoe__spinlock_, &Irql);
866 /* Free disk searches in the global disk search list. */
867 disk_searcher = aoe__disk_search_list_;
868 while (disk_searcher != NULL) {
870 &(disk__get_ptr(disk_searcher->device)->SearchEvent),
874 previous_disk_searcher = disk_searcher;
875 disk_searcher = disk_searcher->next;
876 wv_free(previous_disk_searcher);
879 /* Cancel and free all tags in the global tag list. */
880 tag = aoe__tag_list_;
881 while (tag != NULL) {
882 if (tag->request_ptr != NULL && --tag->request_ptr->TagCount == 0) {
883 tag->request_ptr->Irp->IoStatus.Information = 0;
884 tag->request_ptr->Irp->IoStatus.Status = STATUS_CANCELLED;
885 IoCompleteRequest(tag->request_ptr->Irp, IO_NO_INCREMENT);
886 wv_free(tag->request_ptr);
888 if (tag->next == NULL) {
889 wv_free(tag->packet_data);
894 wv_free(tag->previous->packet_data);
895 wv_free(tag->previous);
898 aoe__tag_list_ = NULL;
899 aoe__tag_list_last_ = NULL;
901 /* Free the global probe tag and its AoE packet. */
902 wv_free(aoe__probe_tag_->packet_data);
903 wv_free(aoe__probe_tag_);
905 /* Release the global spin-lock. */
906 KeReleaseSpinLock(&aoe__spinlock_, Irql);
908 aoe__started_ = FALSE;
913 * Search for disk parameters.
915 * @v dev_ptr The device extension for the disk.
917 * Returns TRUE if the disk could be matched, FALSE otherwise.
919 static disk__init_decl(init)
921 struct aoe__disk_search_
922 * disk_searcher, * disk_search_walker, * previous_disk_searcher;
923 LARGE_INTEGER Timeout, CurrentTime;
924 struct aoe__work_tag_ * tag, * tag_walker;
925 KIRQL Irql, InnerIrql;
926 LARGE_INTEGER MaxSectorsPerPacketSendTime;
927 winvblock__uint32 MTU;
928 struct aoe__disk_type_ * aoe_disk_ptr;
930 aoe_disk_ptr = aoe__get_ ( disk_ptr->device );
932 * Allocate our disk search
934 if ((disk_searcher = wv_malloc(sizeof *disk_searcher)) == NULL) {
935 DBG ( "Couldn't allocate for disk_searcher; bye!\n" );
940 * Initialize the disk search
942 disk_searcher->device = disk_ptr->device;
943 disk_searcher->next = NULL;
944 aoe_disk_ptr->search_state = aoe__search_state_search_nic_;
945 KeResetEvent ( &disk_ptr->SearchEvent );
948 * Wait until we have the global spin-lock
950 KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
953 * Add our disk search to the global list of disk searches
955 if ( aoe__disk_search_list_ == NULL )
957 aoe__disk_search_list_ = disk_searcher;
961 disk_search_walker = aoe__disk_search_list_;
962 while ( disk_search_walker->next )
963 disk_search_walker = disk_search_walker->next;
964 disk_search_walker->next = disk_searcher;
968 * Release the global spin-lock
970 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
973 * We go through all the states until the disk is ready for use
978 * Wait for our device's extension's search to be signalled
981 * TODO: Make the below value a #defined constant
984 * 500.000 * 100ns = 50.000.000 ns = 50ms
986 Timeout.QuadPart = -500000LL;
987 KeWaitForSingleObject ( &disk_ptr->SearchEvent, Executive, KernelMode,
991 DBG ( "AoE is shutting down; bye!\n" );
996 * Wait until we have the device extension's spin-lock
998 KeAcquireSpinLock ( &disk_ptr->SpinLock, &Irql );
1000 if (aoe_disk_ptr->search_state == aoe__search_state_search_nic_)
1002 if ( !Protocol_SearchNIC ( aoe_disk_ptr->ClientMac ) )
1004 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1010 * We found the adapter to use, get MTU next
1012 aoe_disk_ptr->MTU = Protocol_GetMTU ( aoe_disk_ptr->ClientMac );
1013 aoe_disk_ptr->search_state = aoe__search_state_get_size_;
1017 if (aoe_disk_ptr->search_state == aoe__search_state_getting_size_)
1020 * Still getting the disk's size
1022 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1025 if (aoe_disk_ptr->search_state == aoe__search_state_getting_geometry_)
1028 * Still getting the disk's geometry
1030 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1033 if (aoe_disk_ptr->search_state ==
1034 aoe__search_state_getting_max_sectors_per_packet_)
1036 KeQuerySystemTime ( &CurrentTime );
1038 * TODO: Make the below value a #defined constant
1041 * 2.500.000 * 100ns = 250.000.000 ns = 250ms
1043 if ( CurrentTime.QuadPart >
1044 MaxSectorsPerPacketSendTime.QuadPart + 2500000LL )
1046 DBG ( "No reply after 250ms for MaxSectorsPerPacket %d, "
1047 "giving up\n", aoe_disk_ptr->MaxSectorsPerPacket );
1048 aoe_disk_ptr->MaxSectorsPerPacket--;
1049 aoe_disk_ptr->search_state = aoe__search_state_done_;
1054 * Still getting the maximum sectors per packet count
1056 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1061 if (aoe_disk_ptr->search_state == aoe__search_state_done_)
1064 * We've finished the disk search; perform clean-up
1066 KeAcquireSpinLock ( &aoe__spinlock_, &InnerIrql );
1069 * Tag clean-up: Find out if our tag is in the global tag list
1071 tag_walker = aoe__tag_list_;
1072 while ( tag_walker != NULL && tag_walker != tag )
1073 tag_walker = tag_walker->next;
1074 if ( tag_walker != NULL )
1077 * We found it. If it's at the beginning of the list, adjust
1078 * the list to point the the next tag
1080 if ( tag->previous == NULL )
1081 aoe__tag_list_ = tag->next;
1084 * Remove our tag from the list
1086 tag->previous->next = tag->next;
1088 * If we 're at the end of the list, adjust the list's end to
1089 * point to the penultimate tag
1091 if ( tag->next == NULL )
1092 aoe__tag_list_last_ = tag->previous;
1095 * Remove our tag from the list
1097 tag->next->previous = tag->previous;
1098 aoe__outstanding_tags_--;
1099 if ( aoe__outstanding_tags_ < 0 )
1100 DBG ( "aoe__outstanding_tags_ < 0!!\n" );
1102 * Free our tag and its AoE packet
1104 wv_free(tag->packet_data);
1109 * Disk search clean-up
1111 if ( aoe__disk_search_list_ == NULL )
1113 DBG ( "aoe__disk_search_list_ == NULL!!\n" );
1118 * Find our disk search in the global list of disk searches
1120 disk_search_walker = aoe__disk_search_list_;
1121 while ( disk_search_walker
1122 && disk_search_walker->device != disk_ptr->device )
1124 previous_disk_searcher = disk_search_walker;
1125 disk_search_walker = disk_search_walker->next;
1127 if ( disk_search_walker )
1130 * We found our disk search. If it's the first one in
1131 * the list, adjust the list and remove it
1133 if ( disk_search_walker == aoe__disk_search_list_ )
1134 aoe__disk_search_list_ = disk_search_walker->next;
1139 previous_disk_searcher->next = disk_search_walker->next;
1141 * Free our disk search
1143 wv_free(disk_search_walker);
1147 DBG ( "Disk not found in aoe__disk_search_list_!!\n" );
1152 * Release global and device extension spin-locks
1154 KeReleaseSpinLock ( &aoe__spinlock_, InnerIrql );
1155 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1157 DBG ( "Disk size: %I64uM cylinders: %I64u heads: %u "
1158 "sectors: %u sectors per packet: %u\n",
1159 disk_ptr->LBADiskSize / 2048, disk_ptr->Cylinders,
1160 disk_ptr->Heads, disk_ptr->Sectors,
1161 aoe_disk_ptr->MaxSectorsPerPacket );
1166 if ( aoe_disk_ptr->search_state == aoe__search_state_done_)
1171 if ((tag = wv_mallocz(sizeof *tag)) == NULL) {
1172 DBG ( "Couldn't allocate tag\n" );
1173 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1175 * Maybe next time around
1179 tag->type = aoe__tag_type_search_drive_;
1180 tag->device = disk_ptr->device;
1183 * Establish our tag's AoE packet
1185 tag->PacketSize = sizeof (struct aoe__packet_);
1186 if ((tag->packet_data = wv_mallocz(tag->PacketSize)) == NULL) {
1187 DBG ( "Couldn't allocate tag->packet_data\n" );
1190 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1192 * Maybe next time around
1196 tag->packet_data->Ver = AOEPROTOCOLVER;
1197 tag->packet_data->Major =
1198 htons ( ( winvblock__uint16 ) aoe_disk_ptr->Major );
1199 tag->packet_data->Minor = ( winvblock__uint8 ) aoe_disk_ptr->Minor;
1200 tag->packet_data->ExtendedAFlag = TRUE;
1203 * Initialize the packet appropriately based on our current phase
1205 switch ( aoe_disk_ptr->search_state )
1207 case aoe__search_state_get_size_:
1209 * TODO: Make the below value into a #defined constant
1211 tag->packet_data->Cmd = 0xec; /* IDENTIFY DEVICE */
1212 tag->packet_data->Count = 1;
1213 aoe_disk_ptr->search_state = aoe__search_state_getting_size_;
1215 case aoe__search_state_get_geometry_:
1217 * TODO: Make the below value into a #defined constant
1219 tag->packet_data->Cmd = 0x24; /* READ SECTOR */
1220 tag->packet_data->Count = 1;
1221 aoe_disk_ptr->search_state = aoe__search_state_getting_geometry_;
1223 case aoe__search_state_get_max_sectors_per_packet_:
1225 * TODO: Make the below value into a #defined constant
1227 tag->packet_data->Cmd = 0x24; /* READ SECTOR */
1228 tag->packet_data->Count =
1229 ( winvblock__uint8 ) ( ++aoe_disk_ptr->MaxSectorsPerPacket );
1230 KeQuerySystemTime ( &MaxSectorsPerPacketSendTime );
1231 aoe_disk_ptr->search_state =
1232 aoe__search_state_getting_max_sectors_per_packet_;
1234 * TODO: Make the below value into a #defined constant
1236 aoe_disk_ptr->Timeout = 200000;
1239 DBG ( "Undefined search_state!!\n" );
1240 wv_free(tag->packet_data);
1243 * TODO: Do we need to nullify tag here?
1245 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1254 KeAcquireSpinLock ( &aoe__spinlock_, &InnerIrql );
1255 if ( aoe__tag_list_ == NULL )
1257 aoe__tag_list_ = tag;
1258 tag->previous = NULL;
1262 aoe__tag_list_last_->next = tag;
1263 tag->previous = aoe__tag_list_last_;
1265 aoe__tag_list_last_ = tag;
1266 KeReleaseSpinLock ( &aoe__spinlock_, InnerIrql );
1267 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1271 static disk__io_decl(io)
1273 struct aoe__io_req_ * request_ptr;
1274 struct aoe__work_tag_ * tag, * new_tag_list = NULL, * previous_tag = NULL;
1276 winvblock__uint32 i;
1277 PHYSICAL_ADDRESS PhysicalAddress;
1278 winvblock__uint8_ptr PhysicalMemory;
1279 disk__type_ptr disk_ptr;
1280 struct aoe__disk_type_ * aoe_disk_ptr;
1283 * Establish pointers to the disk and AoE disk
1285 disk_ptr = disk__get_ptr ( dev_ptr );
1286 aoe_disk_ptr = aoe__get_ ( dev_ptr );
1291 * Shutting down AoE; we can't service this request
1293 irp->IoStatus.Information = 0;
1294 irp->IoStatus.Status = STATUS_CANCELLED;
1295 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1296 return STATUS_CANCELLED;
1299 if ( sector_count < 1 )
1304 DBG ( "sector_count < 1; cancelling\n" );
1305 irp->IoStatus.Information = 0;
1306 irp->IoStatus.Status = STATUS_CANCELLED;
1307 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1308 return STATUS_CANCELLED;
1312 * Allocate and zero-fill our request
1314 if ((request_ptr = wv_mallocz(sizeof *request_ptr)) == NULL) {
1315 DBG ( "Couldn't allocate for reques_ptr; bye!\n" );
1316 irp->IoStatus.Information = 0;
1317 irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1318 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1319 return STATUS_INSUFFICIENT_RESOURCES;
1323 * Initialize the request
1325 request_ptr->Mode = mode;
1326 request_ptr->SectorCount = sector_count;
1327 request_ptr->Buffer = buffer;
1328 request_ptr->Irp = irp;
1329 request_ptr->TagCount = 0;
1332 * Split the requested sectors into packets in tags
1334 for ( i = 0; i < sector_count; i += aoe_disk_ptr->MaxSectorsPerPacket )
1339 if ((tag = wv_mallocz(sizeof *tag)) == NULL) {
1340 DBG ( "Couldn't allocate tag; bye!\n" );
1342 * We failed while allocating tags; free the ones we built
1345 while ( tag != NULL )
1349 wv_free(previous_tag->packet_data);
1350 wv_free(previous_tag);
1352 wv_free(request_ptr);
1353 irp->IoStatus.Information = 0;
1354 irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1355 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1356 return STATUS_INSUFFICIENT_RESOURCES;
1360 * Initialize each tag
1362 tag->type = aoe__tag_type_io_;
1363 tag->request_ptr = request_ptr;
1364 tag->device = dev_ptr;
1365 request_ptr->TagCount++;
1367 tag->BufferOffset = i * disk_ptr->SectorSize;
1369 ( ( sector_count - i ) <
1370 aoe_disk_ptr->MaxSectorsPerPacket ? sector_count -
1371 i : aoe_disk_ptr->MaxSectorsPerPacket );
1374 * Allocate and initialize each tag's AoE packet
1376 tag->PacketSize = sizeof (struct aoe__packet_);
1377 if ( mode == disk__io_mode_write )
1378 tag->PacketSize += tag->SectorCount * disk_ptr->SectorSize;
1379 if ((tag->packet_data = wv_mallocz(tag->PacketSize)) == NULL) {
1380 DBG ( "Couldn't allocate tag->packet_data; bye!\n" );
1382 * We failed while allocating an AoE packet; free
1387 while ( tag != NULL )
1391 wv_free(previous_tag->packet_data);
1392 wv_free(previous_tag);
1394 wv_free(request_ptr);
1395 irp->IoStatus.Information = 0;
1396 irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1397 IoCompleteRequest ( irp, IO_NO_INCREMENT );
1398 return STATUS_INSUFFICIENT_RESOURCES;
1400 tag->packet_data->Ver = AOEPROTOCOLVER;
1401 tag->packet_data->Major =
1402 htons ( ( winvblock__uint16 ) aoe_disk_ptr->Major );
1403 tag->packet_data->Minor = ( winvblock__uint8 ) aoe_disk_ptr->Minor;
1404 tag->packet_data->Tag = 0;
1405 tag->packet_data->Command = 0;
1406 tag->packet_data->ExtendedAFlag = TRUE;
1407 if ( mode == disk__io_mode_read )
1409 tag->packet_data->Cmd = 0x24; /* READ SECTOR */
1413 tag->packet_data->Cmd = 0x34; /* WRITE SECTOR */
1414 tag->packet_data->WriteAFlag = 1;
1416 tag->packet_data->Count = ( winvblock__uint8 ) tag->SectorCount;
1417 tag->packet_data->Lba0 =
1418 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 0 ) & 255 );
1419 tag->packet_data->Lba1 =
1420 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 8 ) & 255 );
1421 tag->packet_data->Lba2 =
1422 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 16 ) & 255 );
1423 tag->packet_data->Lba3 =
1424 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 24 ) & 255 );
1425 tag->packet_data->Lba4 =
1426 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 32 ) & 255 );
1427 tag->packet_data->Lba5 =
1428 ( winvblock__uint8 ) ( ( ( start_sector + i ) >> 40 ) & 255 );
1431 * For a write request, copy from the buffer into the AoE packet
1433 if ( mode == disk__io_mode_write )
1434 RtlCopyMemory ( tag->packet_data->Data, &buffer[tag->BufferOffset],
1435 tag->SectorCount * disk_ptr->SectorSize );
1438 * Add this tag to the request's tag list
1440 tag->previous = previous_tag;
1442 if ( new_tag_list == NULL )
1448 previous_tag->next = tag;
1453 * Split the requested sectors into packets in tags
1455 request_ptr->TotalTags = request_ptr->TagCount;
1458 * Wait until we have the global spin-lock
1460 KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
1463 * Enqueue our request's tag list to the global tag list
1465 if ( aoe__tag_list_last_ == NULL )
1467 aoe__tag_list_ = new_tag_list;
1471 aoe__tag_list_last_->next = new_tag_list;
1472 new_tag_list->previous = aoe__tag_list_last_;
1475 * Adjust the global list to reflect our last tag
1477 aoe__tag_list_last_ = tag;
1479 irp->IoStatus.Information = 0;
1480 irp->IoStatus.Status = STATUS_PENDING;
1481 IoMarkIrpPending ( irp );
1483 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1484 KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
1485 return STATUS_PENDING;
1488 static void STDCALL add_target(
1489 IN winvblock__uint8_ptr ClientMac,
1490 IN winvblock__uint8_ptr ServerMac,
1491 winvblock__uint16 Major,
1492 winvblock__uint8 Minor,
1496 struct aoe__target_list_ * Walker, * Last;
1499 KeAcquireSpinLock ( &aoe__target_list_spinlock_, &Irql );
1500 Walker = Last = aoe__target_list_;
1501 while ( Walker != NULL )
1503 if (wv_memcmpeq(&Walker->Target.ClientMac, ClientMac, 6) &&
1504 wv_memcmpeq(&Walker->Target.ServerMac, ServerMac, 6) &&
1505 Walker->Target.Major == Major
1506 && Walker->Target.Minor == Minor) {
1507 if ( Walker->Target.LBASize != LBASize )
1509 DBG ( "LBASize changed for e%d.%d " "(%I64u->%I64u)\n", Major,
1510 Minor, Walker->Target.LBASize, LBASize );
1511 Walker->Target.LBASize = LBASize;
1513 KeQuerySystemTime ( &Walker->Target.ProbeTime );
1514 KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql );
1518 Walker = Walker->next;
1521 if ((Walker = wv_malloc(sizeof *Walker)) == NULL) {
1522 DBG("wv_malloc Walker\n");
1523 KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql );
1526 Walker->next = NULL;
1527 RtlCopyMemory ( Walker->Target.ClientMac, ClientMac, 6 );
1528 RtlCopyMemory ( Walker->Target.ServerMac, ServerMac, 6 );
1529 Walker->Target.Major = Major;
1530 Walker->Target.Minor = Minor;
1531 Walker->Target.LBASize = LBASize;
1532 KeQuerySystemTime ( &Walker->Target.ProbeTime );
1536 aoe__target_list_ = Walker;
1540 Last->next = Walker;
1542 KeReleaseSpinLock ( &aoe__target_list_spinlock_, Irql );
1546 * Process an AoE reply.
1548 * @v SourceMac The AoE server's MAC address.
1549 * @v DestinationMac The AoE client's MAC address.
1550 * @v Data The AoE packet.
1551 * @v DataSize The AoE packet's size.
1553 NTSTATUS STDCALL aoe__reply(
1554 IN winvblock__uint8_ptr SourceMac,
1555 IN winvblock__uint8_ptr DestinationMac,
1556 IN winvblock__uint8_ptr Data,
1557 IN winvblock__uint32 DataSize
1560 struct aoe__packet_ * reply = (struct aoe__packet_ *) Data;
1562 struct aoe__work_tag_ * tag;
1564 winvblock__bool Found = FALSE;
1565 LARGE_INTEGER CurrentTime;
1566 disk__type_ptr disk_ptr;
1567 struct aoe__disk_type_ * aoe_disk_ptr;
1570 * Discard non-responses
1572 if ( !reply->ResponseFlag )
1573 return STATUS_SUCCESS;
1576 * If the response matches our probe, add the AoE disk device
1578 if ( aoe__probe_tag_->Id == reply->Tag )
1580 RtlCopyMemory ( &LBASize, &reply->Data[200], sizeof ( LONGLONG ) );
1581 add_target ( DestinationMac, SourceMac, ntohs ( reply->Major ),
1582 reply->Minor, LBASize );
1583 return STATUS_SUCCESS;
1587 * Wait until we have the global spin-lock
1589 KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
1592 * Search for request tag
1594 if ( aoe__tag_list_ == NULL )
1596 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1597 return STATUS_SUCCESS;
1599 tag = aoe__tag_list_;
1600 while ( tag != NULL )
1602 if ( ( tag->Id == reply->Tag )
1603 && ( tag->packet_data->Major == reply->Major )
1604 && ( tag->packet_data->Minor == reply->Minor ) )
1613 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1614 return STATUS_SUCCESS;
1619 * Remove the tag from the global tag list
1621 if ( tag->previous == NULL )
1622 aoe__tag_list_ = tag->next;
1624 tag->previous->next = tag->next;
1625 if ( tag->next == NULL )
1626 aoe__tag_list_last_ = tag->previous;
1628 tag->next->previous = tag->previous;
1629 aoe__outstanding_tags_--;
1630 if ( aoe__outstanding_tags_ < 0 )
1631 DBG ( "aoe__outstanding_tags_ < 0!!\n" );
1632 KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
1634 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1637 * Establish pointers to the disk device and AoE disk
1639 disk_ptr = disk__get_ptr ( tag->device );
1640 aoe_disk_ptr = aoe__get_ ( tag->device );
1643 * If our tag was a discovery request, note the server
1645 if (wv_memcmpeq(aoe_disk_ptr->ServerMac, "\xff\xff\xff\xff\xff\xff", 6)) {
1646 RtlCopyMemory ( aoe_disk_ptr->ServerMac, SourceMac, 6 );
1647 DBG ( "Major: %d minor: %d found on server "
1648 "%02x:%02x:%02x:%02x:%02x:%02x\n", aoe_disk_ptr->Major,
1649 aoe_disk_ptr->Minor, SourceMac[0], SourceMac[1], SourceMac[2],
1650 SourceMac[3], SourceMac[4], SourceMac[5] );
1653 KeQuerySystemTime ( &CurrentTime );
1654 aoe_disk_ptr->Timeout -=
1655 ( winvblock__uint32 ) ( ( aoe_disk_ptr->Timeout -
1656 ( CurrentTime.QuadPart -
1657 tag->FirstSendTime.QuadPart ) ) / 1024 );
1659 * TODO: Replace the values below with #defined constants
1661 if ( aoe_disk_ptr->Timeout > 100000000 )
1662 aoe_disk_ptr->Timeout = 100000000;
1664 switch ( tag->type )
1666 case aoe__tag_type_search_drive_:
1667 KeAcquireSpinLock ( &disk_ptr->SpinLock, &Irql );
1668 switch ( aoe_disk_ptr->search_state )
1670 case aoe__search_state_getting_size_:
1672 * The reply tells us the disk size
1674 RtlCopyMemory ( &disk_ptr->LBADiskSize, &reply->Data[200],
1675 sizeof ( LONGLONG ) );
1677 * Next we are concerned with the disk geometry
1679 aoe_disk_ptr->search_state = aoe__search_state_get_geometry_;
1681 case aoe__search_state_getting_geometry_:
1683 * FIXME: use real values from partition table.
1684 * We used to truncate a fractional end cylinder, but
1685 * now leave it be in the hopes everyone uses LBA
1687 disk_ptr->SectorSize = 512;
1688 disk_ptr->Heads = 255;
1689 disk_ptr->Sectors = 63;
1690 disk_ptr->Cylinders =
1691 disk_ptr->LBADiskSize / ( disk_ptr->Heads *
1692 disk_ptr->Sectors );
1694 * Next we are concerned with the maximum sectors per packet
1696 aoe_disk_ptr->search_state =
1697 aoe__search_state_get_max_sectors_per_packet_;
1699 case aoe__search_state_getting_max_sectors_per_packet_:
1700 DataSize -= sizeof (struct aoe__packet_);
1702 ( aoe_disk_ptr->MaxSectorsPerPacket *
1703 disk_ptr->SectorSize ) )
1705 DBG ( "Packet size too low while getting "
1706 "MaxSectorsPerPacket (tried %d, got size of %d)\n",
1707 aoe_disk_ptr->MaxSectorsPerPacket, DataSize );
1708 aoe_disk_ptr->MaxSectorsPerPacket--;
1709 aoe_disk_ptr->search_state = aoe__search_state_done_;
1711 else if ( aoe_disk_ptr->MTU <
1712 ( sizeof (struct aoe__packet_) +
1713 ( ( aoe_disk_ptr->MaxSectorsPerPacket +
1714 1 ) * disk_ptr->SectorSize ) ) )
1716 DBG ( "Got MaxSectorsPerPacket %d at size of %d. "
1717 "MTU of %d reached\n",
1718 aoe_disk_ptr->MaxSectorsPerPacket, DataSize,
1719 aoe_disk_ptr->MTU );
1720 aoe_disk_ptr->search_state = aoe__search_state_done_;
1724 DBG ( "Got MaxSectorsPerPacket %d at size of %d, "
1725 "trying next...\n", aoe_disk_ptr->MaxSectorsPerPacket,
1727 aoe_disk_ptr->search_state =
1728 aoe__search_state_get_max_sectors_per_packet_;
1732 DBG ( "Undefined search_state!\n" );
1735 KeReleaseSpinLock ( &disk_ptr->SpinLock, Irql );
1736 KeSetEvent ( &disk_ptr->SearchEvent, 0, FALSE );
1738 case aoe__tag_type_io_:
1740 * If the reply is in response to a read request, get our data!
1742 if ( tag->request_ptr->Mode == disk__io_mode_read )
1743 RtlCopyMemory ( &tag->request_ptr->Buffer[tag->BufferOffset],
1745 tag->SectorCount * disk_ptr->SectorSize );
1747 * If this is the last reply expected for the read request,
1748 * complete the IRP and free the request
1750 if ( InterlockedDecrement ( &tag->request_ptr->TagCount ) == 0 )
1752 tag->request_ptr->Irp->IoStatus.Information =
1753 tag->request_ptr->SectorCount * disk_ptr->SectorSize;
1754 tag->request_ptr->Irp->IoStatus.Status = STATUS_SUCCESS;
1755 Driver_CompletePendingIrp ( tag->request_ptr->Irp );
1756 wv_free(tag->request_ptr);
1760 DBG ( "Unknown tag type!!\n" );
1764 KeSetEvent ( &aoe__thread_sig_evt_, 0, FALSE );
1765 wv_free(tag->packet_data);
1767 return STATUS_SUCCESS;
1770 void aoe__reset_probe(void)
1772 aoe__probe_tag_->SendTime.QuadPart = 0LL;
1775 static void STDCALL aoe__thread_(IN void *StartContext)
1777 LARGE_INTEGER Timeout, CurrentTime, ProbeTime, ReportTime;
1778 winvblock__uint32 NextTagId = 1;
1779 struct aoe__work_tag_ * tag;
1781 winvblock__uint32 Sends = 0;
1782 winvblock__uint32 Resends = 0;
1783 winvblock__uint32 ResendFails = 0;
1784 winvblock__uint32 Fails = 0;
1785 winvblock__uint32 RequestTimeout = 0;
1786 disk__type_ptr disk_ptr;
1787 struct aoe__disk_type_ * aoe_disk_ptr;
1790 ReportTime.QuadPart = 0LL;
1791 ProbeTime.QuadPart = 0LL;
1796 * TODO: Make the below value a #defined constant
1799 * 100.000 * 100ns = 10.000.000 ns = 10ms
1801 Timeout.QuadPart = -100000LL;
1802 KeWaitForSingleObject ( &aoe__thread_sig_evt_, Executive,
1803 KernelMode, FALSE, &Timeout );
1804 KeResetEvent ( &aoe__thread_sig_evt_ );
1807 DBG ( "Stopping...\n" );
1808 PsTerminateSystemThread ( STATUS_SUCCESS );
1811 KeQuerySystemTime ( &CurrentTime );
1813 * TODO: Make the below value a #defined constant
1815 if ( CurrentTime.QuadPart > ( ReportTime.QuadPart + 10000000LL ) )
1817 DBG ( "Sends: %d Resends: %d ResendFails: %d Fails: %d "
1818 "aoe__outstanding_tags_: %d RequestTimeout: %d\n", Sends,
1819 Resends, ResendFails, Fails, aoe__outstanding_tags_,
1825 KeQuerySystemTime ( &ReportTime );
1829 * TODO: Make the below value a #defined constant
1831 if ( CurrentTime.QuadPart >
1832 ( aoe__probe_tag_->SendTime.QuadPart + 100000000LL ) )
1834 aoe__probe_tag_->Id = NextTagId++;
1835 if ( NextTagId == 0 )
1837 aoe__probe_tag_->packet_data->Tag = aoe__probe_tag_->Id;
1838 Protocol_Send ( "\xff\xff\xff\xff\xff\xff",
1839 "\xff\xff\xff\xff\xff\xff",
1840 ( winvblock__uint8_ptr ) aoe__probe_tag_->
1841 packet_data, aoe__probe_tag_->PacketSize,
1843 KeQuerySystemTime ( &aoe__probe_tag_->SendTime );
1846 KeAcquireSpinLock ( &aoe__spinlock_, &Irql );
1847 if ( aoe__tag_list_ == NULL )
1849 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1852 tag = aoe__tag_list_;
1853 while ( tag != NULL )
1856 * Establish pointers to the disk and AoE disk
1858 disk_ptr = disk__get_ptr ( tag->device );
1859 aoe_disk_ptr = aoe__get_ ( tag->device );
1861 RequestTimeout = aoe_disk_ptr->Timeout;
1864 if ( aoe__outstanding_tags_ <= 64 )
1867 * if ( aoe__outstanding_tags_ <= 102400 ) {
1869 if ( aoe__outstanding_tags_ < 0 )
1870 DBG ( "aoe__outstanding_tags_ < 0!!\n" );
1871 tag->Id = NextTagId++;
1872 if ( NextTagId == 0 )
1874 tag->packet_data->Tag = tag->Id;
1876 ( aoe_disk_ptr->ClientMac, aoe_disk_ptr->ServerMac,
1877 ( winvblock__uint8_ptr ) tag->packet_data,
1878 tag->PacketSize, tag ) )
1880 KeQuerySystemTime ( &tag->FirstSendTime );
1881 KeQuerySystemTime ( &tag->SendTime );
1882 aoe__outstanding_tags_++;
1895 KeQuerySystemTime ( &CurrentTime );
1896 if ( CurrentTime.QuadPart >
1897 ( tag->SendTime.QuadPart +
1898 ( LONGLONG ) ( aoe_disk_ptr->Timeout * 2 ) ) )
1901 ( aoe_disk_ptr->ClientMac, aoe_disk_ptr->ServerMac,
1902 ( winvblock__uint8_ptr ) tag->packet_data,
1903 tag->PacketSize, tag ) )
1905 KeQuerySystemTime ( &tag->SendTime );
1906 aoe_disk_ptr->Timeout += aoe_disk_ptr->Timeout / 1000;
1907 if ( aoe_disk_ptr->Timeout > 100000000 )
1908 aoe_disk_ptr->Timeout = 100000000;
1919 if ( tag == aoe__tag_list_ )
1921 DBG ( "Taglist Cyclic!!\n" );
1925 KeReleaseSpinLock ( &aoe__spinlock_, Irql );
1930 static disk__max_xfer_len_decl(max_xfer_len)
1932 struct aoe__disk_type_ * aoe_disk_ptr = aoe__get_(disk_ptr->device);
1934 return disk_ptr->SectorSize * aoe_disk_ptr->MaxSectorsPerPacket;
1937 static winvblock__uint32 STDCALL query_id(
1939 IN BUS_QUERY_ID_TYPE query_type,
1940 IN OUT WCHAR (*buf)[512]
1942 struct aoe__disk_type_ * aoe_disk = aoe__get_(dev);
1944 switch (query_type) {
1945 case BusQueryDeviceID:
1946 return swprintf(*buf, winvblock__literal_w L"\\AoEHardDisk") + 1;
1948 case BusQueryInstanceID:
1951 L"AoE_at_Shelf_%d.Slot_%d",
1956 case BusQueryHardwareIDs: {
1957 winvblock__uint32 tmp;
1961 winvblock__literal_w L"\\AoEHardDisk"
1963 tmp += swprintf(*buf + tmp, L"GenDisk") + 4;
1967 case BusQueryCompatibleIDs:
1968 return swprintf(*buf, L"GenDisk") + 4;
1978 winvblock__def_struct(abft) {
1979 winvblock__uint32 Signature; /* 0x54464261 (aBFT) */
1980 winvblock__uint32 Length;
1981 winvblock__uint8 Revision;
1982 winvblock__uint8 Checksum;
1983 winvblock__uint8 OEMID[6];
1984 winvblock__uint8 OEMTableID[8];
1985 winvblock__uint8 Reserved1[12];
1986 winvblock__uint16 Major;
1987 winvblock__uint8 Minor;
1988 winvblock__uint8 Reserved2;
1989 winvblock__uint8 ClientMac[6];
1990 } __attribute__((__packed__));
1995 disk__close_decl(close) {
1999 static void aoe__process_abft_(void) {
2000 PHYSICAL_ADDRESS PhysicalAddress;
2001 winvblock__uint8_ptr PhysicalMemory;
2002 winvblock__uint32 Offset, Checksum, i;
2003 winvblock__bool FoundAbft = FALSE;
2005 struct aoe__disk_type_ * aoe_disk;
2008 PhysicalAddress.QuadPart = 0LL;
2009 PhysicalMemory = MmMapIoSpace(PhysicalAddress, 0xa0000, MmNonCached);
2010 if (!PhysicalMemory) {
2011 DBG("Could not map low memory\n");
2014 for (Offset = 0; Offset < 0xa0000; Offset += 0x10) {
2016 ((abft_ptr) (PhysicalMemory + Offset))->Signature ==
2023 i < ((abft_ptr) (PhysicalMemory + Offset))->Length;
2026 Checksum += PhysicalMemory[Offset + i];
2027 if (Checksum & 0xff)
2029 if (((abft_ptr) (PhysicalMemory + Offset))->Revision != 1) {
2031 "Found aBFT with mismatched revision v%d at "
2032 "segment 0x%4x. want v1.\n",
2033 ((abft_ptr) (PhysicalMemory + Offset))->Revision,
2038 DBG("Found aBFT at segment: 0x%04x\n", (Offset / 0x10));
2041 PhysicalMemory + Offset,
2047 MmUnmapIoSpace(PhysicalMemory, 0xa0000);
2051 RtlCopyMemory(AoEBootRecord.ClientMac, "\x00\x0c\x29\x34\x69\x34", 6);
2052 AoEBootRecord.Major = 0;
2053 AoEBootRecord.Minor = 10;
2058 aoe_disk = aoe__create_disk_();
2059 if(aoe_disk == NULL) {
2060 DBG("Could not create AoE disk from aBFT!\n");
2064 "Attaching AoE disk from client NIC "
2065 "%02x:%02x:%02x:%02x:%02x:%02x to major: %d minor: %d\n",
2066 AoEBootRecord.ClientMac[0],
2067 AoEBootRecord.ClientMac[1],
2068 AoEBootRecord.ClientMac[2],
2069 AoEBootRecord.ClientMac[3],
2070 AoEBootRecord.ClientMac[4],
2071 AoEBootRecord.ClientMac[5],
2072 AoEBootRecord.Major,
2075 RtlCopyMemory(aoe_disk->ClientMac, AoEBootRecord.ClientMac, 6);
2076 RtlFillMemory(aoe_disk->ServerMac, 6, 0xff);
2077 aoe_disk->Major = AoEBootRecord.Major;
2078 aoe_disk->Minor = AoEBootRecord.Minor;
2079 aoe_disk->MaxSectorsPerPacket = 1;
2080 aoe_disk->Timeout = 200000; /* 20 ms. */
2081 aoe_disk->disk->BootDrive = TRUE;
2082 aoe_disk->disk->Media = WvDiskMediaTypeHard;
2083 WvBusAddChild(driver__bus(), aoe_disk->disk->device);
2087 DBG("No aBFT found\n");
2094 NTSTATUS STDCALL aoe__scan(
2099 winvblock__uint32 count;
2100 struct aoe__target_list_ * target_walker;
2101 aoe__mount_targets_ptr targets;
2102 PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
2104 DBG("Got IOCTL_AOE_SCAN...\n");
2105 KeAcquireSpinLock(&aoe__target_list_spinlock_, &irql);
2108 target_walker = aoe__target_list_;
2109 while (target_walker != NULL) {
2111 target_walker = target_walker->next;
2114 targets = wv_malloc(sizeof *targets + (count * sizeof targets->Target[0]));
2115 if (targets == NULL) {
2116 DBG("wv_malloc targets\n");
2117 return driver__complete_irp(
2120 STATUS_INSUFFICIENT_RESOURCES
2123 irp->IoStatus.Information =
2124 sizeof (aoe__mount_targets) + (count * sizeof (aoe__mount_target));
2125 targets->Count = count;
2128 target_walker = aoe__target_list_;
2129 while (target_walker != NULL) {
2131 &targets->Target[count],
2132 &target_walker->Target,
2133 sizeof (aoe__mount_target)
2136 target_walker = target_walker->next;
2139 irp->AssociatedIrp.SystemBuffer,
2141 (io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength <
2142 (sizeof (aoe__mount_targets) + (count * sizeof (aoe__mount_target))) ?
2143 io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength :
2144 (sizeof (aoe__mount_targets) + (count * sizeof (aoe__mount_target)))
2149 KeReleaseSpinLock(&aoe__target_list_spinlock_, irql);
2150 return driver__complete_irp(irp, irp->IoStatus.Information, STATUS_SUCCESS);
2153 NTSTATUS STDCALL aoe__show(
2157 winvblock__uint32 count;
2158 WV_SP_DEV_T dev_walker;
2160 aoe__mount_disks_ptr disks;
2161 PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
2163 DBG("Got IOCTL_AOE_SHOW...\n");
2165 bus = WvBusFromDev(dev);
2166 dev_walker = bus->first_child;
2168 while (dev_walker != NULL) {
2170 dev_walker = dev_walker->next_sibling_ptr;
2173 disks = wv_malloc(sizeof *disks + (count * sizeof disks->Disk[0]));
2174 if (disks == NULL) {
2175 DBG("wv_malloc disks\n");
2176 return driver__complete_irp(
2179 STATUS_INSUFFICIENT_RESOURCES
2182 irp->IoStatus.Information =
2183 sizeof (aoe__mount_disks) + (count * sizeof (aoe__mount_disk));
2184 disks->Count = count;
2187 dev_walker = bus->first_child;
2188 while (dev_walker != NULL) {
2189 disk__type_ptr disk = disk__get_ptr(dev_walker);
2190 struct aoe__disk_type_ * aoe_disk = aoe__get_(dev_walker);
2192 disks->Disk[count].Disk = dev_walker->DevNum;
2194 &disks->Disk[count].ClientMac,
2195 &aoe_disk->ClientMac,
2199 &disks->Disk[count].ServerMac,
2200 &aoe_disk->ServerMac,
2203 disks->Disk[count].Major = aoe_disk->Major;
2204 disks->Disk[count].Minor = aoe_disk->Minor;
2205 disks->Disk[count].LBASize = disk->LBADiskSize;
2207 dev_walker = dev_walker->next_sibling_ptr;
2210 irp->AssociatedIrp.SystemBuffer,
2212 (io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength <
2213 (sizeof (aoe__mount_disks) + (count * sizeof (aoe__mount_disk))) ?
2214 io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength :
2215 (sizeof (aoe__mount_disks) + (count * sizeof (aoe__mount_disk)))
2219 return driver__complete_irp(irp, irp->IoStatus.Information, STATUS_SUCCESS);
2222 NTSTATUS STDCALL aoe__mount(
2226 winvblock__uint8_ptr buffer = irp->AssociatedIrp.SystemBuffer;
2227 struct aoe__disk_type_ * aoe_disk;
2230 "Got IOCTL_AOE_MOUNT for client: %02x:%02x:%02x:%02x:%02x:%02x "
2231 "Major:%d Minor:%d\n",
2238 *(winvblock__uint16_ptr) (buffer + 6),
2239 (winvblock__uint8) buffer[8]
2241 aoe_disk = aoe__create_disk_();
2242 if (aoe_disk == NULL) {
2243 DBG("Could not create AoE disk!\n");
2244 return driver__complete_irp(
2247 STATUS_INSUFFICIENT_RESOURCES
2250 RtlCopyMemory(aoe_disk->ClientMac, buffer, 6);
2251 RtlFillMemory(aoe_disk->ServerMac, 6, 0xff);
2252 aoe_disk->Major = *(winvblock__uint16_ptr) (buffer + 6);
2253 aoe_disk->Minor = (winvblock__uint8) buffer[8];
2254 aoe_disk->MaxSectorsPerPacket = 1;
2255 aoe_disk->Timeout = 200000; /* 20 ms. */
2256 aoe_disk->disk->BootDrive = FALSE;
2257 aoe_disk->disk->Media = WvDiskMediaTypeHard;
2258 WvBusAddChild(driver__bus(), aoe_disk->disk->device);
2260 return driver__complete_irp(irp, 0, STATUS_SUCCESS);
2264 * Create a new AoE disk.
2266 * @ret aoe_disk * The address of a new AoE disk, or NULL for failure.
2268 * This function should not be confused with a PDO creation routine, which is
2269 * actually implemented for each device type. This routine will allocate a
2270 * aoe__disk_type_, track it in a global list, as well as populate the disk
2271 * with default values.
2273 static struct aoe__disk_type_ * aoe__create_disk_(void) {
2274 disk__type_ptr disk;
2275 struct aoe__disk_type_ * aoe_disk;
2277 /* Try to create a disk. */
2278 disk = disk__create();
2282 * AoE disk devices might be used for booting and should
2283 * not be allocated from a paged memory pool.
2285 aoe_disk = wv_mallocz(sizeof *aoe_disk);
2286 if (aoe_disk == NULL)
2288 /* Track the new AoE disk in our global list. */
2289 ExInterlockedInsertTailList(
2291 &aoe_disk->tracking,
2292 &aoe__disk_list_lock_
2294 /* Populate non-zero device defaults. */
2295 aoe_disk->disk = disk;
2296 aoe_disk->prev_free = disk->device->Ops.Free;
2297 disk->device->Ops.Free = aoe__free_disk_;
2298 disk->device->Ops.PnpId = query_id;
2299 disk->disk_ops.io = io;
2300 disk->disk_ops.max_xfer_len = max_xfer_len;
2301 disk->disk_ops.init = init;
2302 disk->disk_ops.close = close;
2303 disk->ext = aoe_disk;
2309 WvDevFree(disk->device);
2316 * Default AoE disk deletion operation.
2318 * @v dev Points to the AoE disk device to delete.
2320 static void STDCALL aoe__free_disk_(IN WV_SP_DEV_T dev) {
2321 struct aoe__disk_type_ * aoe_disk = aoe__get_(dev);
2322 /* Free the "inherited class". */
2323 aoe_disk->prev_free(dev);
2325 * Track the AoE disk deletion in our global list. Unfortunately,
2326 * for now we have faith that an AoE disk won't be deleted twice and
2327 * result in a race condition. Something to keep in mind...
2329 ExInterlockedRemoveHeadList(
2330 aoe_disk->tracking.Blink,
2331 &aoe__disk_list_lock_