[bus] Initial test for mini IRP handling
[people/sha0/winvblock.git] / src / bus.c
1 /**
2  * Copyright (C) 2009, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  * Copyright 2006-2008, V.
4  * For WinAoE contact information, see http://winaoe.org/
5  *
6  * This file is part of WinVBlock, derived from WinAoE.
7  *
8  * WinVBlock is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * WinVBlock is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /**
23  * @file
24  *
25  * Bus specifics
26  *
27  */
28
29 #include <ntddk.h>
30
31 #include "winvblock.h"
32 #include "portable.h"
33 #include "irp.h"
34 #include "driver.h"
35 #include "disk.h"
36 #include "bus.h"
37 #include "aoe.h"
38 #include "mount.h"
39 #include "debug.h"
40 #include "mdi.h"
41 #include "protocol.h"
42 #include "probe.h"
43
44 /* in this file */
45 static irp__handler_decl (
46   Bus_DispatchNotSupported
47  );
48 static irp__handler_decl (
49   Bus_DispatchPower
50  );
51 winvblock__bool STDCALL Bus_AddChild (
52   IN PDEVICE_OBJECT BusDeviceObject,
53   IN disk__type Disk,
54   IN winvblock__bool Boot
55  );
56 static NTSTATUS STDCALL Bus_IoCompletionRoutine (
57   IN PDEVICE_OBJECT DeviceObject,
58   IN PIRP Irp,
59   IN PKEVENT Event
60  );
61
62 typedef struct _BUS_TARGETLIST
63 {
64   MOUNT_TARGET Target;
65   struct _BUS_TARGETLIST *Next;
66 } BUS_TARGETLIST,
67 *PBUS_TARGETLIST;
68
69 static PBUS_TARGETLIST Bus_Globals_TargetList = NULL;
70 static KSPIN_LOCK Bus_Globals_TargetListSpinLock;
71 static ULONG Bus_Globals_NextDisk = 0;
72 PDEVICE_OBJECT bus__fdo = NULL;
73
74 NTSTATUS STDCALL
75 Bus_Start (
76   void
77  )
78 {
79   DBG ( "Entry\n" );
80   KeInitializeSpinLock ( &Bus_Globals_TargetListSpinLock );
81   return STATUS_SUCCESS;
82 }
83
84 VOID STDCALL
85 Bus_Stop (
86   void
87  )
88 {
89   UNICODE_STRING DosDeviceName;
90   PBUS_TARGETLIST Walker,
91    Next;
92   KIRQL Irql;
93
94   DBG ( "Entry\n" );
95   KeAcquireSpinLock ( &Bus_Globals_TargetListSpinLock, &Irql );
96   Walker = Bus_Globals_TargetList;
97   while ( Walker != NULL )
98     {
99       Next = Walker->Next;
100       ExFreePool ( Walker );
101       Walker = Next;
102     }
103   KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
104   RtlInitUnicodeString ( &DosDeviceName, L"\\DosDevices\\AoE" );
105   IoDeleteSymbolicLink ( &DosDeviceName );
106   bus__fdo = NULL;
107 }
108
109 VOID STDCALL
110 Bus_AddTarget (
111   IN winvblock__uint8_ptr ClientMac,
112   IN winvblock__uint8_ptr ServerMac,
113   winvblock__uint16 Major,
114   winvblock__uint8 Minor,
115   LONGLONG LBASize
116  )
117 {
118   PBUS_TARGETLIST Walker,
119    Last;
120   KIRQL Irql;
121
122   KeAcquireSpinLock ( &Bus_Globals_TargetListSpinLock, &Irql );
123   Last = Bus_Globals_TargetList;
124   Walker = Bus_Globals_TargetList;
125   while ( Walker != NULL )
126     {
127       if ( ( RtlCompareMemory ( &Walker->Target.ClientMac, ClientMac, 6 ) ==
128              6 )
129            && ( RtlCompareMemory ( &Walker->Target.ServerMac, ServerMac, 6 ) ==
130                 6 ) && Walker->Target.Major == Major
131            && Walker->Target.Minor == Minor )
132         {
133           if ( Walker->Target.LBASize != LBASize )
134             {
135               DBG ( "LBASize changed for e%d.%d " "(%I64u->%I64u)\n", Major,
136                     Minor, Walker->Target.LBASize, LBASize );
137               Walker->Target.LBASize = LBASize;
138             }
139           KeQuerySystemTime ( &Walker->Target.ProbeTime );
140           KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
141           return;
142         }
143       Last = Walker;
144       Walker = Walker->Next;
145     }
146
147   if ( ( Walker =
148          ( PBUS_TARGETLIST ) ExAllocatePool ( NonPagedPool,
149                                               sizeof ( BUS_TARGETLIST ) ) ) ==
150        NULL )
151     {
152       DBG ( "ExAllocatePool Target\n" );
153       KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
154       return;
155     }
156   Walker->Next = NULL;
157   RtlCopyMemory ( Walker->Target.ClientMac, ClientMac, 6 );
158   RtlCopyMemory ( Walker->Target.ServerMac, ServerMac, 6 );
159   Walker->Target.Major = Major;
160   Walker->Target.Minor = Minor;
161   Walker->Target.LBASize = LBASize;
162   KeQuerySystemTime ( &Walker->Target.ProbeTime );
163
164   if ( Last == NULL )
165     {
166       Bus_Globals_TargetList = Walker;
167     }
168   else
169     {
170       Last->Next = Walker;
171     }
172   KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
173 }
174
175 VOID STDCALL
176 Bus_CleanupTargetList (
177   void
178  )
179 {
180 }
181
182 /*
183  * Establish a pointer into the bus device's extension space
184  */
185 bus__type_ptr STDCALL
186 get_bus_ptr (
187   driver__dev_ext_ptr dev_ext_ptr
188  )
189 {
190   winvblock__uint8_ptr tmp = ( winvblock__uint8_ptr ) dev_ext_ptr;
191   bus__type_ptr bus_ptr =
192     ( bus__type_ptr ) ( tmp + sizeof ( driver__dev_ext ) );
193   return bus_ptr;
194 }
195
196 /*
197  * Establish a pointer into the child disk device's extension space
198  */
199 disk__type_ptr STDCALL
200 get_disk_ptr (
201   driver__dev_ext_ptr dev_ext_ptr
202  )
203 {
204   winvblock__uint8_ptr tmp = ( winvblock__uint8_ptr ) dev_ext_ptr;
205   disk__type_ptr disk_ptr =
206     ( disk__type_ptr ) ( tmp + sizeof ( driver__dev_ext ) );
207   return disk_ptr;
208 }
209
210 /**
211  * Add a child node to the bus
212  *
213  * @v BusDeviceObject The bus to add the node to
214  * @v Disk            The disk to add
215  * @v Boot            Is this a boot device?
216  *
217  * Returns TRUE for success, FALSE for failure
218  */
219 winvblock__bool STDCALL
220 Bus_AddChild (
221   IN PDEVICE_OBJECT BusDeviceObject,
222   IN disk__type Disk,
223   IN winvblock__bool Boot
224  )
225 {
226         /**
227    * @v Status              Status of last operation
228    * @v BusDeviceExtension  Shortcut to the bus' device extension
229    * @v DeviceObject        The new node's device object
230    * @v DeviceExtension     The new node's device extension
231    * @v Walker              Walks the child nodes
232    */
233   NTSTATUS Status;
234   PDEVICE_OBJECT DeviceObject;
235   driver__dev_ext_ptr bus_dev_ext_ptr,
236    disk_dev_ext_ptr;
237   bus__type_ptr bus_ptr;
238   size_t new_dev_ext_size;
239   disk__type_ptr disk_ptr,
240    Walker;
241   DEVICE_TYPE DiskType =
242     Disk.DiskType == OpticalDisc ? FILE_DEVICE_CD_ROM : FILE_DEVICE_DISK;
243   ULONG DiskType2 =
244     Disk.DiskType ==
245     OpticalDisc ? FILE_READ_ONLY_DEVICE | FILE_REMOVABLE_MEDIA : Disk.DiskType
246     == FloppyDisk ? FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE : 0;
247
248   DBG ( "Entry\n" );
249   /*
250    * Establish pointers into the bus device's extension space
251    */
252   bus_dev_ext_ptr = ( driver__dev_ext_ptr ) BusDeviceObject->DeviceExtension;
253   bus_ptr = get_bus_ptr ( bus_dev_ext_ptr );
254   /*
255    * Create the child device
256    */
257   new_dev_ext_size =
258     sizeof ( driver__dev_ext ) + sizeof ( disk__type ) +
259     driver__handling_table_size;
260   if ( !NT_SUCCESS
261        ( Status =
262          IoCreateDevice ( bus_dev_ext_ptr->DriverObject, new_dev_ext_size,
263                           NULL, DiskType,
264                           FILE_AUTOGENERATED_DEVICE_NAME |
265                           FILE_DEVICE_SECURE_OPEN | DiskType2, FALSE,
266                           &DeviceObject ) ) )
267     {
268       Error ( "Bus_AddChild IoCreateDevice", Status );
269       return FALSE;
270     }
271   /*
272    * Establish pointers into the child disk device's extension space
273    */
274   disk_dev_ext_ptr = ( driver__dev_ext_ptr ) DeviceObject->DeviceExtension;
275   disk_ptr = get_disk_ptr ( disk_dev_ext_ptr );
276   /*
277    * Clear the extension space and establish parameters
278    */
279   RtlZeroMemory ( disk_dev_ext_ptr, new_dev_ext_size );
280   disk_dev_ext_ptr->IsBus = FALSE;
281   disk_dev_ext_ptr->dispatch = Disk_Dispatch;
282   disk_dev_ext_ptr->Self = DeviceObject;
283   disk_dev_ext_ptr->DriverObject = bus_dev_ext_ptr->DriverObject;
284   disk_dev_ext_ptr->State = NotStarted;
285   disk_dev_ext_ptr->OldState = NotStarted;
286   disk_dev_ext_ptr->irp_handler_stack_ptr =
287     ( winvblock__uint8 * ) disk_dev_ext_ptr + sizeof ( driver__dev_ext ) +
288     sizeof ( disk__type );
289   RtlCopyMemory ( disk_dev_ext_ptr->irp_handler_stack_ptr,
290                   driver__handling_table, driver__handling_table_size );
291   disk_dev_ext_ptr->irp_handler_stack_size =
292     driver__handling_table_size / sizeof ( irp__handling );
293   /*
294    * Copy the provided disk parameters into the disk extension space
295    */
296   RtlCopyMemory ( disk_ptr, &Disk, sizeof ( disk__type ) );
297   disk_ptr->dev_ext_ptr = disk_dev_ext_ptr;
298   disk_ptr->Parent = BusDeviceObject;
299   disk_ptr->next_sibling_ptr = NULL;
300   KeInitializeEvent ( &disk_ptr->SearchEvent, SynchronizationEvent, FALSE );
301   KeInitializeSpinLock ( &disk_ptr->SpinLock );
302   disk_ptr->BootDrive = Boot;
303   disk_ptr->Unmount = FALSE;
304   disk_ptr->DiskNumber = InterlockedIncrement ( &Bus_Globals_NextDisk ) - 1;
305   /*
306    * Some device parameters
307    */
308   DeviceObject->Flags |= DO_DIRECT_IO;  /* FIXME? */
309   DeviceObject->Flags |= DO_POWER_INRUSH;       /* FIXME? */
310   /*
311    * Determine the disk's geometry differently for AoE/MEMDISK
312    */
313   disk_ptr->Initialize ( disk_dev_ext_ptr );
314
315   DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
316   /*
317    * Add the new device's extension to the bus' list of children
318    */
319   if ( bus_ptr->first_child_ptr == NULL )
320     {
321       bus_ptr->first_child_ptr = disk_ptr;
322     }
323   else
324     {
325       Walker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
326       while ( Walker->next_sibling_ptr != NULL )
327         Walker = Walker->next_sibling_ptr;
328       Walker->next_sibling_ptr = disk_ptr;
329     }
330   bus_ptr->Children++;
331   return TRUE;
332 }
333
334 static
335 irp__handler_decl (
336   pnp_start_dev
337  )
338 {
339   NTSTATUS status;
340   KEVENT event;
341   bus__type_ptr bus_ptr;
342
343   bus_ptr = get_bus_ptr ( DeviceExtension );
344   KeInitializeEvent ( &event, NotificationEvent, FALSE );
345   IoCopyCurrentIrpStackLocationToNext ( Irp );
346   IoSetCompletionRoutine ( Irp,
347                            ( PIO_COMPLETION_ROUTINE ) Bus_IoCompletionRoutine,
348                            ( PVOID ) & event, TRUE, TRUE, TRUE );
349   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
350   if ( status == STATUS_PENDING )
351     {
352       DBG ( "Locked\n" );
353       KeWaitForSingleObject ( &event, Executive, KernelMode, FALSE, NULL );
354     }
355   if ( NT_SUCCESS ( status = Irp->IoStatus.Status ) )
356     {
357       DeviceExtension->OldState = DeviceExtension->State;
358       DeviceExtension->State = Started;
359     }
360   status = STATUS_SUCCESS;
361   Irp->IoStatus.Status = status;
362   IoCompleteRequest ( Irp, IO_NO_INCREMENT );
363   *completion_ptr = TRUE;
364   return status;
365 }
366
367 static
368 irp__handler_decl (
369   foo
370  )
371 {
372   DBG ( "BUS PNP test\n" );
373   return STATUS_SUCCESS;
374 }
375
376 irp__handling handling_table[] = {
377   /*
378    * Major, minor, any major?, any minor?, handler
379    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
380    * Note that the fall-through case must come FIRST!
381    * Why? It sets completion to true, so others won't be called
382    */
383   {IRP_MJ_PNP, IRP_MN_START_DEVICE, FALSE, FALSE, pnp_start_dev}
384   ,
385   {IRP_MJ_PNP, IRP_MN_QUERY_DEVICE_RELATIONS, FALSE, FALSE, foo}
386 };
387
388 size_t handling_table_size = sizeof ( handling_table );
389
390 irp__handler_decl ( Bus_DispatchPnP )
391 {
392   NTSTATUS Status;
393   KEVENT Event;
394   PDEVICE_RELATIONS DeviceRelations;
395   bus__type_ptr bus_ptr;
396   disk__type_ptr Walker,
397    Next;
398   ULONG Count;
399
400   /*
401    * Establish a pointer into the bus device's extension space
402    */
403   bus_ptr = get_bus_ptr ( DeviceExtension );
404
405   switch ( Stack->MinorFunction )
406     {
407       case IRP_MN_REMOVE_DEVICE:
408         DeviceExtension->OldState = DeviceExtension->State;
409         DeviceExtension->State = Deleted;
410         Irp->IoStatus.Information = 0;
411         Irp->IoStatus.Status = STATUS_SUCCESS;
412         IoSkipCurrentIrpStackLocation ( Irp );
413         Status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
414         Walker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
415         while ( Walker != NULL )
416           {
417             Next = Walker->next_sibling_ptr;
418             IoDeleteDevice ( Walker->dev_ext_ptr->Self );
419             Walker = Next;
420           }
421         bus_ptr->Children = 0;
422         bus_ptr->first_child_ptr = NULL;
423         IoDetachDevice ( bus_ptr->LowerDeviceObject );
424         IoDeleteDevice ( DeviceExtension->Self );
425         return Status;
426       case IRP_MN_QUERY_DEVICE_RELATIONS:
427         if ( Stack->Parameters.QueryDeviceRelations.Type != BusRelations
428              || Irp->IoStatus.Information )
429           {
430             Status = Irp->IoStatus.Status;
431             break;
432           }
433         Count = 0;
434         Walker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
435         while ( Walker != NULL )
436           {
437             Count++;
438             Walker = Walker->next_sibling_ptr;
439           }
440         DeviceRelations =
441           ( PDEVICE_RELATIONS ) ExAllocatePool ( NonPagedPool,
442                                                  sizeof ( DEVICE_RELATIONS ) +
443                                                  ( sizeof ( PDEVICE_OBJECT ) *
444                                                    Count ) );
445         if ( DeviceRelations == NULL )
446           {
447             Irp->IoStatus.Information = 0;
448             Status = STATUS_INSUFFICIENT_RESOURCES;
449             break;
450           }
451         DeviceRelations->Count = Count;
452
453         Count = 0;
454         Walker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
455         while ( Walker != NULL )
456           {
457             ObReferenceObject ( Walker->dev_ext_ptr->Self );
458             DeviceRelations->Objects[Count] = Walker->dev_ext_ptr->Self;
459             Count++;
460             Walker = Walker->next_sibling_ptr;
461           }
462         Irp->IoStatus.Information = ( ULONG_PTR ) DeviceRelations;
463         Status = STATUS_SUCCESS;
464         break;
465       case IRP_MN_QUERY_PNP_DEVICE_STATE:
466         Irp->IoStatus.Information = 0;
467         Status = STATUS_SUCCESS;
468         break;
469       case IRP_MN_QUERY_STOP_DEVICE:
470         DeviceExtension->OldState = DeviceExtension->State;
471         DeviceExtension->State = StopPending;
472         Status = STATUS_SUCCESS;
473         break;
474       case IRP_MN_CANCEL_STOP_DEVICE:
475         DeviceExtension->State = DeviceExtension->OldState;
476         Status = STATUS_SUCCESS;
477         break;
478       case IRP_MN_STOP_DEVICE:
479         DeviceExtension->OldState = DeviceExtension->State;
480         DeviceExtension->State = Stopped;
481         Status = STATUS_SUCCESS;
482         break;
483       case IRP_MN_QUERY_REMOVE_DEVICE:
484         DeviceExtension->OldState = DeviceExtension->State;
485         DeviceExtension->State = RemovePending;
486         Status = STATUS_SUCCESS;
487         break;
488       case IRP_MN_CANCEL_REMOVE_DEVICE:
489         DeviceExtension->State = DeviceExtension->OldState;
490         Status = STATUS_SUCCESS;
491         break;
492       case IRP_MN_SURPRISE_REMOVAL:
493         DeviceExtension->OldState = DeviceExtension->State;
494         DeviceExtension->State = SurpriseRemovePending;
495         Status = STATUS_SUCCESS;
496         break;
497       default:
498         Status = Irp->IoStatus.Status;
499     }
500
501   Irp->IoStatus.Status = Status;
502   IoSkipCurrentIrpStackLocation ( Irp );
503   Status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
504   return Status;
505 }
506
507 irp__handler_decl ( Bus_DispatchDeviceControl )
508 {
509   NTSTATUS Status;
510   winvblock__uint8_ptr Buffer;
511   ULONG Count;
512   PBUS_TARGETLIST TargetWalker;
513   bus__type_ptr bus_ptr;
514   disk__type_ptr DiskWalker,
515    DiskWalkerPrevious;
516   PMOUNT_TARGETS Targets;
517   PMOUNT_DISKS Disks;
518   KIRQL Irql;
519   disk__type Disk;
520
521   /*
522    * Establish a pointer into the bus device's extension space
523    */
524   bus_ptr = get_bus_ptr ( DeviceExtension );
525
526   switch ( Stack->Parameters.DeviceIoControl.IoControlCode )
527     {
528       case IOCTL_AOE_SCAN:
529         DBG ( "Got IOCTL_AOE_SCAN...\n" );
530         AoE_Start (  );
531         KeAcquireSpinLock ( &Bus_Globals_TargetListSpinLock, &Irql );
532
533         Count = 0;
534         TargetWalker = Bus_Globals_TargetList;
535         while ( TargetWalker != NULL )
536           {
537             Count++;
538             TargetWalker = TargetWalker->Next;
539           }
540
541         if ( ( Targets =
542                ( PMOUNT_TARGETS ) ExAllocatePool ( NonPagedPool,
543                                                    sizeof ( MOUNT_TARGETS ) +
544                                                    ( Count *
545                                                      sizeof
546                                                      ( MOUNT_TARGET ) ) ) ) ==
547              NULL )
548           {
549             DBG ( "ExAllocatePool Targets\n" );
550             Irp->IoStatus.Information = 0;
551             Status = STATUS_INSUFFICIENT_RESOURCES;
552             break;
553           }
554         Irp->IoStatus.Information =
555           sizeof ( MOUNT_TARGETS ) + ( Count * sizeof ( MOUNT_TARGET ) );
556         Targets->Count = Count;
557
558         Count = 0;
559         TargetWalker = Bus_Globals_TargetList;
560         while ( TargetWalker != NULL )
561           {
562             RtlCopyMemory ( &Targets->Target[Count], &TargetWalker->Target,
563                             sizeof ( MOUNT_TARGET ) );
564             Count++;
565             TargetWalker = TargetWalker->Next;
566           }
567         RtlCopyMemory ( Irp->AssociatedIrp.SystemBuffer, Targets,
568                         ( Stack->Parameters.
569                           DeviceIoControl.OutputBufferLength <
570                           ( sizeof ( MOUNT_TARGETS ) +
571                             ( Count *
572                               sizeof ( MOUNT_TARGET ) ) ) ? Stack->
573                           Parameters.DeviceIoControl.OutputBufferLength
574                           : ( sizeof ( MOUNT_TARGETS ) +
575                               ( Count * sizeof ( MOUNT_TARGET ) ) ) ) );
576         ExFreePool ( Targets );
577
578         KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
579         Status = STATUS_SUCCESS;
580         break;
581       case IOCTL_AOE_SHOW:
582         DBG ( "Got IOCTL_AOE_SHOW...\n" );
583
584         Count = 0;
585         DiskWalker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
586         while ( DiskWalker != NULL )
587           {
588             Count++;
589             DiskWalker = DiskWalker->next_sibling_ptr;
590           }
591
592         if ( ( Disks =
593                ( PMOUNT_DISKS ) ExAllocatePool ( NonPagedPool,
594                                                  sizeof ( MOUNT_DISKS ) +
595                                                  ( Count *
596                                                    sizeof ( MOUNT_DISK ) ) ) )
597              == NULL )
598           {
599             DBG ( "ExAllocatePool Disks\n" );
600             Irp->IoStatus.Information = 0;
601             Status = STATUS_INSUFFICIENT_RESOURCES;
602             break;
603           }
604         Irp->IoStatus.Information =
605           sizeof ( MOUNT_DISKS ) + ( Count * sizeof ( MOUNT_DISK ) );
606         Disks->Count = Count;
607
608         Count = 0;
609         DiskWalker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
610         while ( DiskWalker != NULL )
611           {
612             Disks->Disk[Count].Disk = DiskWalker->DiskNumber;
613             RtlCopyMemory ( &Disks->Disk[Count].ClientMac,
614                             &DiskWalker->AoE.ClientMac, 6 );
615             RtlCopyMemory ( &Disks->Disk[Count].ServerMac,
616                             &DiskWalker->AoE.ServerMac, 6 );
617             Disks->Disk[Count].Major = DiskWalker->AoE.Major;
618             Disks->Disk[Count].Minor = DiskWalker->AoE.Minor;
619             Disks->Disk[Count].LBASize = DiskWalker->LBADiskSize;
620             Count++;
621             DiskWalker = DiskWalker->next_sibling_ptr;
622           }
623         RtlCopyMemory ( Irp->AssociatedIrp.SystemBuffer, Disks,
624                         ( Stack->Parameters.
625                           DeviceIoControl.OutputBufferLength <
626                           ( sizeof ( MOUNT_DISKS ) +
627                             ( Count *
628                               sizeof ( MOUNT_DISK ) ) ) ? Stack->
629                           Parameters.DeviceIoControl.OutputBufferLength
630                           : ( sizeof ( MOUNT_DISKS ) +
631                               ( Count * sizeof ( MOUNT_DISK ) ) ) ) );
632         ExFreePool ( Disks );
633
634         Status = STATUS_SUCCESS;
635         break;
636       case IOCTL_AOE_MOUNT:
637         Buffer = Irp->AssociatedIrp.SystemBuffer;
638         DBG ( "Got IOCTL_AOE_MOUNT for client: %02x:%02x:%02x:%02x:%02x:%02x "
639               "Major:%d Minor:%d\n", Buffer[0], Buffer[1], Buffer[2],
640               Buffer[3], Buffer[4], Buffer[5],
641               *( winvblock__uint16_ptr ) ( &Buffer[6] ),
642               ( winvblock__uint8 ) Buffer[8] );
643         Disk.Initialize = AoE_SearchDrive;
644         RtlCopyMemory ( Disk.AoE.ClientMac, Buffer, 6 );
645         RtlFillMemory ( Disk.AoE.ServerMac, 6, 0xff );
646         Disk.AoE.Major = *( winvblock__uint16_ptr ) ( &Buffer[6] );
647         Disk.AoE.Minor = ( winvblock__uint8 ) Buffer[8];
648         Disk.AoE.MaxSectorsPerPacket = 1;
649         Disk.AoE.Timeout = 200000;      /* 20 ms. */
650         Disk.IsRamdisk = FALSE;
651         if ( !Bus_AddChild ( DeviceObject, Disk, FALSE ) )
652           {
653             DBG ( "Bus_AddChild() failed\n" );
654           }
655         else
656           {
657             if ( bus_ptr->PhysicalDeviceObject != NULL )
658               IoInvalidateDeviceRelations ( bus_ptr->PhysicalDeviceObject,
659                                             BusRelations );
660           }
661         Irp->IoStatus.Information = 0;
662         Status = STATUS_SUCCESS;
663         break;
664       case IOCTL_AOE_UMOUNT:
665         Buffer = Irp->AssociatedIrp.SystemBuffer;
666         DBG ( "Got IOCTL_AOE_UMOUNT for disk: %d\n", *( PULONG ) Buffer );
667         DiskWalker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
668         DiskWalkerPrevious = DiskWalker;
669         while ( ( DiskWalker != NULL )
670                 && ( DiskWalker->DiskNumber != *( PULONG ) Buffer ) )
671           {
672             DiskWalkerPrevious = DiskWalker;
673             DiskWalker = DiskWalker->next_sibling_ptr;
674           }
675         if ( DiskWalker != NULL )
676           {
677             if ( DiskWalker->BootDrive )
678               {
679                 DBG ( "Cannot unmount a boot drive.\n" );
680                 Irp->IoStatus.Information = 0;
681                 Status = STATUS_INVALID_DEVICE_REQUEST;
682                 break;
683               }
684             DBG ( "Deleting disk %d\n", DiskWalker->DiskNumber );
685             if ( DiskWalker == ( disk__type_ptr ) bus_ptr->first_child_ptr )
686               {
687                 bus_ptr->first_child_ptr =
688                   ( winvblock__uint8_ptr ) DiskWalker->next_sibling_ptr;
689               }
690             else
691               {
692                 DiskWalkerPrevious->next_sibling_ptr =
693                   DiskWalker->next_sibling_ptr;
694               }
695             DiskWalker->Unmount = TRUE;
696             DiskWalker->next_sibling_ptr = NULL;
697             if ( bus_ptr->PhysicalDeviceObject != NULL )
698               IoInvalidateDeviceRelations ( bus_ptr->PhysicalDeviceObject,
699                                             BusRelations );
700           }
701         bus_ptr->Children--;
702         Irp->IoStatus.Information = 0;
703         Status = STATUS_SUCCESS;
704         break;
705       default:
706         Irp->IoStatus.Information = 0;
707         Status = STATUS_INVALID_DEVICE_REQUEST;
708     }
709
710   Irp->IoStatus.Status = Status;
711   IoCompleteRequest ( Irp, IO_NO_INCREMENT );
712   return Status;
713 }
714
715 irp__handler_decl ( Bus_DispatchSystemControl )
716 {
717   bus__type_ptr bus_ptr = get_bus_ptr ( DeviceExtension );
718   DBG ( "...\n" );
719   IoSkipCurrentIrpStackLocation ( Irp );
720   return IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
721 }
722
723 irp__handler_decl ( Bus_Dispatch )
724 {
725   NTSTATUS Status;
726   bus__type_ptr bus_ptr = get_bus_ptr ( DeviceExtension );
727
728   switch ( Stack->MajorFunction )
729     {
730       case IRP_MJ_POWER:
731         PoStartNextPowerIrp ( Irp );
732         IoSkipCurrentIrpStackLocation ( Irp );
733         Status = PoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
734         break;
735       case IRP_MJ_PNP:
736         Status =
737           Bus_DispatchPnP ( DeviceObject, Irp, Stack, DeviceExtension,
738                             completion_ptr );
739         break;
740       case IRP_MJ_SYSTEM_CONTROL:
741         Status =
742           Bus_DispatchSystemControl ( DeviceObject, Irp, Stack,
743                                       DeviceExtension, completion_ptr );
744         break;
745       case IRP_MJ_DEVICE_CONTROL:
746         Status =
747           Bus_DispatchDeviceControl ( DeviceObject, Irp, Stack,
748                                       DeviceExtension, completion_ptr );
749         break;
750       default:
751         Status = STATUS_NOT_SUPPORTED;
752         Irp->IoStatus.Status = Status;
753         IoCompleteRequest ( Irp, IO_NO_INCREMENT );
754     }
755   return Status;
756 }
757
758 static NTSTATUS STDCALL
759 Bus_IoCompletionRoutine (
760   IN PDEVICE_OBJECT DeviceObject,
761   IN PIRP Irp,
762   IN PKEVENT Event
763  )
764 {
765   KeSetEvent ( Event, 0, FALSE );
766   return STATUS_MORE_PROCESSING_REQUIRED;
767 }
768
769 NTSTATUS STDCALL
770 Bus_GetDeviceCapabilities (
771   IN PDEVICE_OBJECT DeviceObject,
772   IN PDEVICE_CAPABILITIES DeviceCapabilities
773  )
774 {
775   IO_STATUS_BLOCK ioStatus;
776   KEVENT pnpEvent;
777   NTSTATUS status;
778   PDEVICE_OBJECT targetObject;
779   PIO_STACK_LOCATION irpStack;
780   PIRP pnpIrp;
781
782   RtlZeroMemory ( DeviceCapabilities, sizeof ( DEVICE_CAPABILITIES ) );
783   DeviceCapabilities->Size = sizeof ( DEVICE_CAPABILITIES );
784   DeviceCapabilities->Version = 1;
785   DeviceCapabilities->Address = -1;
786   DeviceCapabilities->UINumber = -1;
787
788   KeInitializeEvent ( &pnpEvent, NotificationEvent, FALSE );
789   targetObject = IoGetAttachedDeviceReference ( DeviceObject );
790   pnpIrp =
791     IoBuildSynchronousFsdRequest ( IRP_MJ_PNP, targetObject, NULL, 0, NULL,
792                                    &pnpEvent, &ioStatus );
793   if ( pnpIrp == NULL )
794     {
795       status = STATUS_INSUFFICIENT_RESOURCES;
796     }
797   else
798     {
799       pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
800       irpStack = IoGetNextIrpStackLocation ( pnpIrp );
801       RtlZeroMemory ( irpStack, sizeof ( IO_STACK_LOCATION ) );
802       irpStack->MajorFunction = IRP_MJ_PNP;
803       irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
804       irpStack->Parameters.DeviceCapabilities.Capabilities =
805         DeviceCapabilities;
806       status = IoCallDriver ( targetObject, pnpIrp );
807       if ( status == STATUS_PENDING )
808         {
809           KeWaitForSingleObject ( &pnpEvent, Executive, KernelMode, FALSE,
810                                   NULL );
811           status = ioStatus.Status;
812         }
813     }
814   ObDereferenceObject ( targetObject );
815   return status;
816 }
817
818 NTSTATUS STDCALL
819 Bus_AddDevice (
820   IN PDRIVER_OBJECT DriverObject,
821   IN PDEVICE_OBJECT PhysicalDeviceObject
822  )
823 {
824   NTSTATUS Status;
825   UNICODE_STRING DeviceName,
826    DosDeviceName;
827   size_t new_dev_ext_size;
828   driver__dev_ext_ptr bus_dev_ext_ptr;
829   bus__type_ptr bus_ptr;
830
831   DBG ( "Entry\n" );
832   if ( bus__fdo )
833     return STATUS_SUCCESS;
834   RtlInitUnicodeString ( &DeviceName, L"\\Device\\AoE" );
835   RtlInitUnicodeString ( &DosDeviceName, L"\\DosDevices\\AoE" );
836   new_dev_ext_size =
837     sizeof ( driver__dev_ext ) + sizeof ( bus__type ) +
838     driver__handling_table_size + handling_table_size;
839   if ( !NT_SUCCESS
840        ( Status =
841          IoCreateDevice ( DriverObject, new_dev_ext_size, &DeviceName,
842                           FILE_DEVICE_CONTROLLER, FILE_DEVICE_SECURE_OPEN,
843                           FALSE, &bus__fdo ) ) )
844     {
845       return Error ( "Bus_AddDevice IoCreateDevice", Status );
846     }
847   if ( !NT_SUCCESS
848        ( Status = IoCreateSymbolicLink ( &DosDeviceName, &DeviceName ) ) )
849     {
850       IoDeleteDevice ( bus__fdo );
851       return Error ( "Bus_AddDevice IoCreateSymbolicLink", Status );
852     }
853
854   bus_dev_ext_ptr = ( driver__dev_ext_ptr ) bus__fdo->DeviceExtension;
855   RtlZeroMemory ( bus_dev_ext_ptr, new_dev_ext_size );
856   bus_dev_ext_ptr->IsBus = TRUE;
857   bus_dev_ext_ptr->dispatch = Bus_Dispatch;
858   bus_dev_ext_ptr->DriverObject = DriverObject;
859   bus_dev_ext_ptr->Self = bus__fdo;
860   bus_dev_ext_ptr->State = NotStarted;
861   bus_dev_ext_ptr->OldState = NotStarted;
862   bus_dev_ext_ptr->irp_handler_stack_ptr =
863     ( winvblock__uint8 * ) bus_dev_ext_ptr + sizeof ( driver__dev_ext ) +
864     sizeof ( bus__type );
865   RtlCopyMemory ( bus_dev_ext_ptr->irp_handler_stack_ptr,
866                   driver__handling_table, driver__handling_table_size );
867   RtlCopyMemory ( ( winvblock__uint8 * ) bus_dev_ext_ptr->
868                   irp_handler_stack_ptr + driver__handling_table_size,
869                   handling_table, handling_table_size );
870   bus_dev_ext_ptr->irp_handler_stack_size =
871     ( driver__handling_table_size +
872       handling_table_size ) / sizeof ( irp__handling );
873   /*
874    * Establish a pointer into the bus device's extension space
875    */
876   bus_ptr = get_bus_ptr ( bus_dev_ext_ptr );
877   bus_ptr->PhysicalDeviceObject = PhysicalDeviceObject;
878   bus_ptr->Children = 0;
879   bus_ptr->first_child_ptr = NULL;
880   KeInitializeSpinLock ( &bus_ptr->SpinLock );
881   bus__fdo->Flags |= DO_DIRECT_IO;      /* FIXME? */
882   bus__fdo->Flags |= DO_POWER_INRUSH;   /* FIXME? */
883   /*
884    * Add the bus to the device tree
885    */
886   if ( PhysicalDeviceObject != NULL )
887     {
888       if ( ( bus_ptr->LowerDeviceObject =
889              IoAttachDeviceToDeviceStack ( bus__fdo,
890                                            PhysicalDeviceObject ) ) == NULL )
891         {
892           IoDeleteDevice ( bus__fdo );
893           bus__fdo = NULL;
894           return Error ( "AddDevice IoAttachDeviceToDeviceStack",
895                          STATUS_NO_SUCH_DEVICE );
896         }
897     }
898   bus__fdo->Flags &= ~DO_DEVICE_INITIALIZING;
899 #ifdef RIS
900   bus_dev_ext_ptr->State = Started;
901 #endif
902   return STATUS_SUCCESS;
903 }