xref: /reactos/drivers/storage/class/disk/disk.c (revision 139a3d66)
1 /*
2  * PROJECT:         ReactOS Storage Stack
3  * LICENSE:         DDK - see license.txt in the root dir
4  * FILE:            drivers/storage/disk/disk.c
5  * PURPOSE:         Disk class driver
6  * PROGRAMMERS:     Based on a source code sample from Microsoft NT4 DDK
7  */
8 
9 #include <ntddk.h>
10 #include <ntdddisk.h>
11 #include <scsi.h>
12 #include <ntddscsi.h>
13 #include <mountdev.h>
14 #include <mountmgr.h>
15 #include <ntiologc.h>
16 #include <include/class2.h>
17 #include <stdio.h>
18 
19 #define NDEBUG
20 #include <debug.h>
21 
22 
23 #ifdef POOL_TAGGING
24 #ifdef ExAllocatePool
25 #undef ExAllocatePool
26 #endif
27 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
28 #endif
29 
30 typedef enum {
31     NotInitialized,
32     Initializing,
33     Initialized
34 } PARTITION_LIST_STATE;
35 
36 //
37 // Disk device data
38 //
39 
40 typedef struct _DISK_DATA {
41 
42     //
43     // Partition chain
44     //
45 
46     PDEVICE_EXTENSION NextPartition;
47 
48     //
49     // Disk signature (from MBR)
50     //
51 
52     ULONG Signature;
53 
54     //
55     // MBR checksum
56     //
57 
58     ULONG MbrCheckSum;
59 
60     //
61     // Number of hidden sectors for BPB.
62     //
63 
64     ULONG HiddenSectors;
65 
66     //
67     // Partition number of this device object
68     //
69     // This field is set during driver initialization or when the partition
70     // is created to identify a partition to the system.
71     //
72 
73     ULONG PartitionNumber;
74 
75     //
76     // This field is the ordinal of a partition as it appears on a disk.
77     //
78 
79     ULONG PartitionOrdinal;
80 
81     //
82     // Partition type of this device object
83     //
84     // This field is set by:
85     //
86     //     1)  Initially set according to the partition list entry partition
87     //         type returned by IoReadPartitionTable.
88     //
89     //     2)  Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
90     //         I/O control function when IoSetPartitionInformation function
91     //         successfully updates the partition type on the disk.
92     //
93 
94     UCHAR PartitionType;
95 
96     //
97     // Boot indicator - indicates whether this partition is a bootable (active)
98     // partition for this device
99     //
100     // This field is set according to the partition list entry boot indicator
101     // returned by IoReadPartitionTable.
102     //
103 
104     BOOLEAN BootIndicator;
105 
106     //
107     // DriveNotReady - indicates that the this device is currently not ready
108     // because there is no media in the device.
109     //
110 
111     BOOLEAN DriveNotReady;
112 
113     //
114     // State of PartitionList initialization
115     //
116 
117     PARTITION_LIST_STATE PartitionListState;
118 
119 #ifdef __REACTOS__
120     //
121     // HACK so that we can use NT5+ NTOS functions with this NT4 driver
122     // for removable devices and avoid an infinite recursive loop between
123     // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
124     //
125     ULONG UpdateRemovableGeometryCount;
126 #endif
127 
128 } DISK_DATA, *PDISK_DATA;
129 
130 //
131 // Define a general structure of identifying disk controllers with bad
132 // hardware.
133 //
134 
135 typedef struct _BAD_CONTROLLER_INFORMATION {
136     PCHAR InquiryString;
137     BOOLEAN DisableTaggedQueuing;
138     BOOLEAN DisableSynchronousTransfers;
139     BOOLEAN DisableDisconnects;
140     BOOLEAN DisableWriteCache;
141 }BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION;
142 
143 BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = {
144     { "TOSHIBA MK538FB         60",   TRUE,  FALSE, FALSE, FALSE },
145     { "CONNER  CP3500",               FALSE, TRUE,  FALSE, FALSE },
146     { "OLIVETTICP3500",               FALSE, TRUE,  FALSE, FALSE },
147     { "SyQuest SQ5110          CHC",  TRUE,  TRUE,  FALSE, FALSE },
148     { "SEAGATE ST41601N        0102", FALSE, TRUE,  FALSE, FALSE },
149     { "SEAGATE ST3655N",              FALSE, FALSE, FALSE, TRUE  },
150     { "SEAGATE ST3390N",              FALSE, FALSE, FALSE, TRUE  },
151     { "SEAGATE ST12550N",             FALSE, FALSE, FALSE, TRUE  },
152     { "SEAGATE ST32430N",             FALSE, FALSE, FALSE, TRUE  },
153     { "SEAGATE ST31230N",             FALSE, FALSE, FALSE, TRUE  },
154     { "SEAGATE ST15230N",             FALSE, FALSE, FALSE, TRUE  },
155     { "FUJITSU M2652S-512",           TRUE,  FALSE, FALSE, FALSE },
156     { "MAXTOR  MXT-540SL       I1.2", TRUE,  FALSE, FALSE, FALSE },
157     { "COMPAQ  PD-1",                 FALSE, TRUE,  FALSE, FALSE }
158 };
159 
160 
161 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
162 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
163 
164 #define MODE_DATA_SIZE      192
165 #define VALUE_BUFFER_SIZE  2048
166 #define SCSI_DISK_TIMEOUT    10
167 #define PARTITION0_LIST_SIZE  4
168 
169 
170 NTSTATUS
171 NTAPI
172 DriverEntry(
173     IN PDRIVER_OBJECT DriverObject,
174     IN PUNICODE_STRING RegistryPath
175     );
176 
177 BOOLEAN
178 NTAPI
179 ScsiDiskDeviceVerification(
180     IN PINQUIRYDATA InquiryData
181     );
182 
183 BOOLEAN
184 NTAPI
185 FindScsiDisks(
186     IN PDRIVER_OBJECT DriveObject,
187     IN PUNICODE_STRING RegistryPath,
188     IN PCLASS_INIT_DATA InitializationData,
189     IN PDEVICE_OBJECT PortDeviceObject,
190     IN ULONG PortNumber
191     );
192 
193 NTSTATUS
194 NTAPI
195 ScsiDiskCreateClose (
196     IN PDEVICE_OBJECT DeviceObject,
197     IN PIRP Irp
198     );
199 
200 NTSTATUS
201 NTAPI
202 ScsiDiskReadWriteVerification(
203     IN PDEVICE_OBJECT DeviceObject,
204     IN PIRP Irp
205     );
206 
207 NTSTATUS
208 NTAPI
209 ScsiDiskDeviceControl(
210     IN PDEVICE_OBJECT DeviceObject,
211     IN PIRP Irp
212     );
213 
214 VOID
215 NTAPI
216 ScsiDiskProcessError(
217     PDEVICE_OBJECT DeviceObject,
218     PSCSI_REQUEST_BLOCK Srb,
219     NTSTATUS *Status,
220     BOOLEAN *Retry
221     );
222 
223 NTSTATUS
224 NTAPI
225 ScsiDiskShutdownFlush(
226     IN PDEVICE_OBJECT DeviceObject,
227     IN PIRP Irp
228     );
229 
230 VOID
231 NTAPI
232 DisableWriteCache(
233     IN PDEVICE_OBJECT DeviceObject,
234     IN PSCSI_INQUIRY_DATA LunInfo
235     );
236 
237 BOOLEAN
238 NTAPI
239 ScsiDiskModeSelect(
240     IN PDEVICE_OBJECT DeviceObject,
241     IN PCHAR ModeSelectBuffer,
242     IN ULONG Length,
243     IN BOOLEAN SavePage
244     );
245 
246 BOOLEAN
247 NTAPI
248 IsFloppyDevice(
249     IN PDEVICE_OBJECT DeviceObject
250     );
251 
252 BOOLEAN
253 NTAPI
254 CalculateMbrCheckSum(
255     IN PDEVICE_EXTENSION DeviceExtension,
256     OUT PULONG Checksum
257     );
258 
259 BOOLEAN
260 NTAPI
261 EnumerateBusKey(
262     IN PDEVICE_EXTENSION DeviceExtension,
263     HANDLE BusKey,
264     PULONG DiskNumber
265     );
266 
267 VOID
268 NTAPI
269 UpdateGeometry(
270     IN PDEVICE_EXTENSION DeviceExtension
271     );
272 
273 NTSTATUS
274 NTAPI
275 UpdateRemovableGeometry (
276     IN PDEVICE_OBJECT DeviceObject,
277     IN PIRP Irp
278     );
279 
280 NTSTATUS
281 NTAPI
282 CreateDiskDeviceObject(
283     IN PDRIVER_OBJECT DriverObject,
284     IN PUNICODE_STRING RegistryPath,
285     IN PDEVICE_OBJECT PortDeviceObject,
286     IN ULONG PortNumber,
287     IN PULONG DeviceCount,
288     IN PIO_SCSI_CAPABILITIES PortCapabilities,
289     IN PSCSI_INQUIRY_DATA LunInfo,
290     IN PCLASS_INIT_DATA InitData
291     );
292 
293 NTSTATUS
294 NTAPI
295 CreatePartitionDeviceObjects(
296     IN PDEVICE_OBJECT PhysicalDeviceObject,
297     IN PUNICODE_STRING RegistryPath
298     );
299 
300 VOID
301 NTAPI
302 UpdateDeviceObjects(
303     IN PDEVICE_OBJECT DeviceObject,
304     IN PIRP Irp
305     );
306 
307 VOID
308 NTAPI
309 ScanForSpecial(
310     PDEVICE_OBJECT DeviceObject,
311     PSCSI_INQUIRY_DATA LunInfo,
312     PIO_SCSI_CAPABILITIES PortCapabilities
313     );
314 
315 VOID
316 NTAPI
317 ResetScsiBus(
318     IN PDEVICE_OBJECT DeviceObject
319     );
320 
321 NTSTATUS
322 NTAPI
323 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject,
324                           PIRP Irp);
325 
326 #ifdef ALLOC_PRAGMA
327 #pragma alloc_text(PAGE, DriverEntry)
328 #pragma alloc_text(PAGE, FindScsiDisks)
329 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
330 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
331 #pragma alloc_text(PAGE, EnumerateBusKey)
332 #pragma alloc_text(PAGE, UpdateGeometry)
333 #pragma alloc_text(PAGE, IsFloppyDevice)
334 #pragma alloc_text(PAGE, ScanForSpecial)
335 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
336 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
337 #endif
338 
339 
340 NTSTATUS
341 NTAPI
342 DriverEntry(
343     IN PDRIVER_OBJECT DriverObject,
344     IN PUNICODE_STRING RegistryPath
345     )
346 
347 /*++
348 
349 Routine Description:
350 
351     This routine initializes the SCSI hard disk class driver.
352 
353 Arguments:
354 
355     DriverObject - Pointer to driver object created by system.
356 
357     RegistryPath - Pointer to the name of the services node for this driver.
358 
359 Return Value:
360 
361     The function value is the final status from the initialization operation.
362 
363 --*/
364 
365 {
366     CLASS_INIT_DATA InitializationData;
367 
368     //
369     // Zero InitData
370     //
371 
372     RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
373 
374     //
375     // Set sizes
376     //
377 
378     InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
379     InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
380 
381     InitializationData.DeviceType = FILE_DEVICE_DISK;
382     InitializationData.DeviceCharacteristics = 0;
383 
384     //
385     // Set entry points
386     //
387 
388     InitializationData.ClassError = ScsiDiskProcessError;
389     InitializationData.ClassReadWriteVerification = ScsiDiskReadWriteVerification;
390     InitializationData.ClassFindDevices = FindScsiDisks;
391     InitializationData.ClassFindDeviceCallBack = ScsiDiskDeviceVerification;
392     InitializationData.ClassDeviceControl = ScsiDiskDeviceControl;
393     InitializationData.ClassShutdownFlush = ScsiDiskShutdownFlush;
394     InitializationData.ClassCreateClose = NULL;
395 
396     //
397     // Call the class init routine
398     //
399 
400     return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
401 
402 } // end DriverEntry()
403 
404 
405 
406 BOOLEAN
407 NTAPI
408 ScsiDiskDeviceVerification(
409     IN PINQUIRYDATA InquiryData
410     )
411 
412 /*++
413 
414 Routine Description:
415 
416     This routine checks InquiryData for the correct device type and qualifier.
417 
418 Arguments:
419 
420     InquiryData - Pointer to the inquiry data for the device in question.
421 
422 Return Value:
423 
424     True is returned if the correct device type is found.
425 
426 --*/
427 {
428 
429     if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
430         (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
431         InquiryData->DeviceTypeQualifier == 0) {
432 
433         return TRUE;
434 
435     } else {
436         return FALSE;
437     }
438 }
439 
440 
441 BOOLEAN
442 NTAPI
443 FindScsiDisks(
444     IN PDRIVER_OBJECT DriverObject,
445     IN PUNICODE_STRING RegistryPath,
446     IN PCLASS_INIT_DATA InitializationData,
447     IN PDEVICE_OBJECT PortDeviceObject,
448     IN ULONG PortNumber
449     )
450 
451 /*++
452 
453 Routine Description:
454 
455     This routine gets a port drivers capabilities, obtains the
456     inquiry data, searches the SCSI bus for the port driver and creates
457     the device objects for the disks found.
458 
459 Arguments:
460 
461     DriverObject - Pointer to driver object created by system.
462 
463     PortDeviceObject - Device object use to send requests to port driver.
464 
465     PortNumber - Number for port driver.  Used to pass on to
466                  CreateDiskDeviceObjects() and create device objects.
467 
468 Return Value:
469 
470     True is returned if one disk was found and successfully created.
471 
472 --*/
473 
474 {
475     PIO_SCSI_CAPABILITIES portCapabilities;
476     PULONG diskCount;
477     PCONFIGURATION_INFORMATION configurationInformation;
478     PCHAR buffer;
479     PSCSI_INQUIRY_DATA lunInfo;
480     PSCSI_ADAPTER_BUS_INFO  adapterInfo;
481     PINQUIRYDATA inquiryData;
482     ULONG scsiBus;
483     ULONG adapterDisk;
484     NTSTATUS status;
485     BOOLEAN foundOne = FALSE;
486 
487     PAGED_CODE();
488 
489     //
490     // Call port driver to get adapter capabilities.
491     //
492 
493     status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
494 
495     if (!NT_SUCCESS(status)) {
496         DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
497         return(FALSE);
498     }
499 
500     //
501     // Call port driver to get inquiry information to find disks.
502     //
503 
504     status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
505 
506     if (!NT_SUCCESS(status)) {
507         DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
508         return(FALSE);
509     }
510 
511     //
512     // Do a quick scan of the devices on this adapter to determine how many
513     // disks are on this adapter.  This is used to determine the number of
514     // SRB zone elements to allocate.
515     //
516 
517     adapterInfo = (PVOID) buffer;
518 
519     adapterDisk = ScsiClassFindUnclaimedDevices(InitializationData, adapterInfo);
520 
521     //
522     // Allocate a zone of SRB for disks on this adapter.
523     //
524 
525     if (adapterDisk == 0) {
526 
527         //
528         // No free disks were found.
529         //
530 
531         return(FALSE);
532     }
533 
534     //
535     // Get the number of disks already initialized.
536     //
537 
538     configurationInformation = IoGetConfigurationInformation();
539     diskCount = &configurationInformation->DiskCount;
540 
541     //
542     // For each SCSI bus this adapter supports ...
543     //
544 
545     for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
546 
547         //
548         // Get the SCSI bus scan data for this bus.
549         //
550 
551         lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
552 
553         //
554         // Search list for unclaimed disk devices.
555         //
556 
557         while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
558 
559             inquiryData = (PVOID)lunInfo->InquiryData;
560 
561             if (((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
562                 (inquiryData->DeviceType == OPTICAL_DEVICE)) &&
563                 inquiryData->DeviceTypeQualifier == 0 &&
564                 (!lunInfo->DeviceClaimed)) {
565 
566                 DebugPrint((1,
567                             "FindScsiDevices: Vendor string is %.24s\n",
568                             inquiryData->VendorId));
569 
570                 //
571                 // Create device objects for disk
572                 //
573 
574                 status = CreateDiskDeviceObject(DriverObject,
575                                                 RegistryPath,
576                                                 PortDeviceObject,
577                                                 PortNumber,
578                                                 diskCount,
579                                                 portCapabilities,
580                                                 lunInfo,
581                                                 InitializationData);
582 
583                 if (NT_SUCCESS(status)) {
584 
585                     //
586                     // Increment system disk device count.
587                     //
588 
589                     (*diskCount)++;
590                     foundOne = TRUE;
591 
592                 }
593             }
594 
595             //
596             // Get next LunInfo.
597             //
598 
599             if (lunInfo->NextInquiryDataOffset == 0) {
600                 break;
601             }
602 
603             lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
604 
605         }
606     }
607 
608     //
609     // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
610     //
611 
612     ExFreePool(buffer);
613 
614     return(foundOne);
615 
616 } // end FindScsiDisks()
617 
618 
619 NTSTATUS
620 NTAPI
621 CreateDiskDeviceObject(
622     IN PDRIVER_OBJECT DriverObject,
623     IN PUNICODE_STRING RegistryPath,
624     IN PDEVICE_OBJECT PortDeviceObject,
625     IN ULONG PortNumber,
626     IN PULONG DeviceCount,
627     IN PIO_SCSI_CAPABILITIES PortCapabilities,
628     IN PSCSI_INQUIRY_DATA LunInfo,
629     IN PCLASS_INIT_DATA InitData
630     )
631 
632 /*++
633 
634 Routine Description:
635 
636     This routine creates an object for the physical device and then searches
637     the device for partitions and creates an object for each partition.
638 
639 Arguments:
640 
641     DriverObject - Pointer to driver object created by system.
642 
643     PortDeviceObject - Miniport device object.
644 
645     PortNumber   - port number.  Used in creating disk objects.
646 
647     DeviceCount  - Number of previously installed devices.
648 
649     PortCapabilities - Capabilities of this SCSI port.
650 
651     LunInfo      - LUN specific information.
652 
653 Return Value:
654 
655     NTSTATUS
656 
657 --*/
658 {
659     CCHAR          ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
660     STRING         ntNameString;
661     UNICODE_STRING ntUnicodeString;
662     OBJECT_ATTRIBUTES objectAttributes;
663     HANDLE         handle;
664     NTSTATUS       status;
665     PDEVICE_OBJECT deviceObject = NULL;
666     //PDEVICE_OBJECT physicalDevice;
667     PDISK_GEOMETRY_EX diskGeometry = NULL;
668     PDEVICE_EXTENSION deviceExtension = NULL;
669     //PDEVICE_EXTENSION physicalDeviceExtension;
670     UCHAR          pathId = LunInfo->PathId;
671     UCHAR          targetId = LunInfo->TargetId;
672     UCHAR          lun = LunInfo->Lun;
673     //BOOLEAN        writeCache;
674     PVOID          senseData = NULL;
675     //ULONG          srbFlags;
676     ULONG          timeOut = 0;
677     BOOLEAN        srbListInitialized = FALSE;
678 
679 
680     PAGED_CODE();
681 
682     //
683     // Set up an object directory to contain the objects for this
684     // device and all its partitions.
685     //
686 
687     sprintf(ntNameBuffer,
688             "\\Device\\Harddisk%lu",
689             *DeviceCount);
690 
691     RtlInitString(&ntNameString,
692                   ntNameBuffer);
693 
694     status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
695                                           &ntNameString,
696                                           TRUE);
697 
698     if (!NT_SUCCESS(status)) {
699         return(status);
700     }
701 
702     InitializeObjectAttributes(&objectAttributes,
703                                &ntUnicodeString,
704                                OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
705                                NULL,
706                                NULL);
707 
708     status = ZwCreateDirectoryObject(&handle,
709                                      DIRECTORY_ALL_ACCESS,
710                                      &objectAttributes);
711 
712     RtlFreeUnicodeString(&ntUnicodeString);
713 
714     if (!NT_SUCCESS(status)) {
715 
716         DebugPrint((1,
717                     "CreateDiskDeviceObjects: Could not create directory %s\n",
718                     ntNameBuffer));
719 
720         return(status);
721     }
722 
723     //
724     // Claim the device.
725     //
726 
727     status = ScsiClassClaimDevice(PortDeviceObject,
728                                   LunInfo,
729                                   FALSE,
730                                   &PortDeviceObject);
731 
732     if (!NT_SUCCESS(status)) {
733         ZwMakeTemporaryObject(handle);
734         ZwClose(handle);
735         return status;
736     }
737 
738     //
739     // Create a device object for this device. Each physical disk will
740     // have at least one device object. The required device object
741     // describes the entire device. Its directory path is
742     // \Device\HarddiskN\Partition0, where N = device number.
743     //
744 
745     sprintf(ntNameBuffer,
746             "\\Device\\Harddisk%lu\\Partition0",
747             *DeviceCount);
748 
749 
750     status = ScsiClassCreateDeviceObject(DriverObject,
751                                          ntNameBuffer,
752                                          NULL,
753                                          &deviceObject,
754                                          InitData);
755 
756     if (!NT_SUCCESS(status)) {
757 
758         DebugPrint((1,
759                     "CreateDiskDeviceObjects: Can not create device object %s\n",
760                     ntNameBuffer));
761 
762         goto CreateDiskDeviceObjectsExit;
763     }
764 
765     //
766     // Indicate that IRPs should include MDLs for data transfers.
767     //
768 
769     deviceObject->Flags |= DO_DIRECT_IO;
770 
771     //
772     // Check if this is during initialization. If not indicate that
773     // system initialization already took place and this disk is ready
774     // to be accessed.
775     //
776 
777     if (!RegistryPath) {
778         deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
779     }
780 
781     //
782     // Check for removable media support.
783     //
784 
785     if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) {
786         deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
787     }
788 
789     //
790     // Set up required stack size in device object.
791     //
792 
793     deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
794 
795     deviceExtension = deviceObject->DeviceExtension;
796 
797     //
798     // Allocate spinlock for split request completion.
799     //
800 
801     KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
802 
803     //
804     // Initialize lock count to zero. The lock count is used to
805     // disable the ejection mechanism on devices that support
806     // removable media. Only the lock count in the physical
807     // device extension is used.
808     //
809 
810     deviceExtension->LockCount = 0;
811 
812     //
813     // Save system disk number.
814     //
815 
816     deviceExtension->DeviceNumber = *DeviceCount;
817 
818     //
819     // Copy port device object pointer to the device extension.
820     //
821 
822     deviceExtension->PortDeviceObject = PortDeviceObject;
823 
824     //
825     // Set the alignment requirements for the device based on the
826     // host adapter requirements
827     //
828 
829     if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
830         deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
831     }
832 
833     //
834     // This is the physical device object.
835     //
836 
837     //physicalDevice = deviceObject;
838     //physicalDeviceExtension = deviceExtension;
839 
840     //
841     // Save address of port driver capabilities.
842     //
843 
844     deviceExtension->PortCapabilities = PortCapabilities;
845 
846     //
847     // Build the lookaside list for srb's for the physical disk. Should only
848     // need a couple.
849     //
850 
851     ScsiClassInitializeSrbLookasideList(deviceExtension,
852                                         PARTITION0_LIST_SIZE);
853 
854     srbListInitialized = TRUE;
855 
856     //
857     // Initialize the srb flags.
858     //
859 
860     if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue &&
861         PortCapabilities->TaggedQueuing) {
862 
863         deviceExtension->SrbFlags  = SRB_FLAGS_QUEUE_ACTION_ENABLE;
864 
865     } else {
866 
867         deviceExtension->SrbFlags  = 0;
868 
869     }
870 
871     //
872     // Allow queued requests if this is not removable media.
873     //
874 
875     if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
876 
877         deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
878 
879     }
880 
881     //
882     // Look for controller that require special flags.
883     //
884 
885     ScanForSpecial(deviceObject,
886                     LunInfo,
887                     PortCapabilities);
888 
889     //srbFlags = deviceExtension->SrbFlags;
890 
891     //
892     // Allocate buffer for drive geometry.
893     //
894 
895     diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX));
896 
897     if (diskGeometry == NULL) {
898 
899         DebugPrint((1,
900            "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
901         status = STATUS_INSUFFICIENT_RESOURCES;
902         goto CreateDiskDeviceObjectsExit;
903     }
904 
905     deviceExtension->DiskGeometry = diskGeometry;
906 
907     //
908     // Allocate request sense buffer.
909     //
910 
911     senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
912 
913     if (senseData == NULL) {
914 
915         //
916         // The buffer can not be allocated.
917         //
918 
919         DebugPrint((1,
920            "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
921 
922         status = STATUS_INSUFFICIENT_RESOURCES;
923         goto CreateDiskDeviceObjectsExit;
924     }
925 
926     //
927     // Set the sense data pointer in the device extension.
928     //
929 
930     deviceExtension->SenseData = senseData;
931 
932     //
933     // Physical device object will describe the entire
934     // device, starting at byte offset 0.
935     //
936 
937     deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0);
938 
939     //
940     // TargetId/LUN describes a device location on the SCSI bus.
941     // This information comes from the inquiry buffer.
942     //
943 
944     deviceExtension->PortNumber = (UCHAR)PortNumber;
945     deviceExtension->PathId = pathId;
946     deviceExtension->TargetId = targetId;
947     deviceExtension->Lun = lun;
948 
949     //
950     // Set timeout value in seconds.
951     //
952 
953     timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
954     if (timeOut) {
955         deviceExtension->TimeOutValue = timeOut;
956     } else {
957         deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
958     }
959 
960     //
961     // Back pointer to device object.
962     //
963 
964     deviceExtension->DeviceObject = deviceObject;
965 
966     //
967     // If this is a removable device, then make sure it is not a floppy.
968     // Perform a mode sense command to determine the media type. Note
969     // IsFloppyDevice also checks for write cache enabled.
970     //
971 
972 #if 0
973     if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
974         (((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) {
975 
976         status = STATUS_NO_SUCH_DEVICE;
977         goto CreateDiskDeviceObjectsExit;
978     }
979 #endif
980 
981     DisableWriteCache(deviceObject,LunInfo);
982 
983     //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
984 
985     //
986     // NOTE: At this point one device object has been successfully created.
987     // from here on out return success.
988     //
989 
990     //
991     // Do READ CAPACITY. This SCSI command
992     // returns the number of bytes on a device.
993     // Device extension is updated with device size.
994     //
995 
996     status = ScsiClassReadDriveCapacity(deviceObject);
997 
998     //
999     // If the read capacity failed then just return, unless this is a
1000     // removable disk where a device object partition needs to be created.
1001     //
1002 
1003     if (!NT_SUCCESS(status) &&
1004         !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
1005 
1006         DebugPrint((1,
1007             "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
1008             ntNameBuffer));
1009 
1010         return(STATUS_SUCCESS);
1011 
1012     } else {
1013 
1014         //
1015         // Make sure the volume verification bit is off so that
1016         // IoReadPartitionTable will work.
1017         //
1018 
1019         deviceObject->Flags &= ~DO_VERIFY_VOLUME;
1020     }
1021 
1022     status = CreatePartitionDeviceObjects(deviceObject, RegistryPath);
1023 
1024     if (NT_SUCCESS(status))
1025         return STATUS_SUCCESS;
1026 
1027 
1028 CreateDiskDeviceObjectsExit:
1029 
1030     //
1031     // Release the device since an error occurred.
1032     //
1033 
1034     ScsiClassClaimDevice(PortDeviceObject,
1035                          LunInfo,
1036                          TRUE,
1037                          NULL);
1038 
1039     if (diskGeometry != NULL) {
1040         ExFreePool(diskGeometry);
1041     }
1042 
1043     if (senseData != NULL) {
1044         ExFreePool(senseData);
1045     }
1046 
1047     if (deviceObject != NULL) {
1048 
1049         if (srbListInitialized) {
1050             ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
1051         }
1052 
1053         IoDeleteDevice(deviceObject);
1054     }
1055 
1056     //
1057     // Delete directory and return.
1058     //
1059 
1060     if (!NT_SUCCESS(status)) {
1061         ZwMakeTemporaryObject(handle);
1062     }
1063 
1064     ZwClose(handle);
1065 
1066     return(status);
1067 
1068 } // end CreateDiskDeviceObjects()
1069 
1070 
1071 VOID
1072 NTAPI
1073 ReportToMountMgr(
1074     IN PDEVICE_OBJECT DiskDeviceObject
1075     )
1076 
1077 /*++
1078 
1079 Routine Description:
1080 
1081     This routine reports the creation of a disk device object to the
1082     MountMgr to fake PnP.
1083 
1084 Arguments:
1085 
1086     DiskDeviceObject - Pointer to the created disk device.
1087 
1088 Return Value:
1089 
1090     VOID
1091 
1092 --*/
1093 {
1094     NTSTATUS              status;
1095     UNICODE_STRING        mountMgrDevice;
1096     PDEVICE_OBJECT        deviceObject;
1097     PFILE_OBJECT          fileObject;
1098     PMOUNTMGR_TARGET_NAME mountTarget;
1099     ULONG                 diskLen;
1100     PDEVICE_EXTENSION     deviceExtension;
1101     PIRP                  irp;
1102     KEVENT                event;
1103     IO_STATUS_BLOCK       ioStatus;
1104 
1105     //
1106     // First, get MountMgr DeviceObject.
1107     //
1108 
1109     RtlInitUnicodeString(&mountMgrDevice, MOUNTMGR_DEVICE_NAME);
1110     status = IoGetDeviceObjectPointer(&mountMgrDevice, FILE_READ_ATTRIBUTES,
1111                                       &fileObject, &deviceObject);
1112 
1113     if (!NT_SUCCESS(status)) {
1114 
1115         DebugPrint((1,
1116                    "ReportToMountMgr: Can't get MountMgr pointers %lx\n",
1117                    status));
1118 
1119         return;
1120     }
1121 
1122     deviceExtension = DiskDeviceObject->DeviceExtension;
1123     diskLen = deviceExtension->DeviceName.Length;
1124 
1125     //
1126     // Allocate input buffer to report our partition device.
1127     //
1128 
1129     mountTarget = ExAllocatePool(NonPagedPool,
1130                                  sizeof(MOUNTMGR_TARGET_NAME) + diskLen);
1131 
1132     if (!mountTarget) {
1133 
1134         DebugPrint((1,
1135                    "ReportToMountMgr: Allocation of mountTarget failed\n"));
1136 
1137         ObDereferenceObject(fileObject);
1138         return;
1139     }
1140 
1141     mountTarget->DeviceNameLength = diskLen;
1142     RtlCopyMemory(mountTarget->DeviceName, deviceExtension->DeviceName.Buffer, diskLen);
1143 
1144     KeInitializeEvent(&event, NotificationEvent, FALSE);
1145 
1146     //
1147     // Build the IRP used to communicate with the MountMgr.
1148     //
1149 
1150     irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
1151                                         deviceObject,
1152                                         mountTarget,
1153                                         sizeof(MOUNTMGR_TARGET_NAME) + diskLen,
1154                                         NULL,
1155                                         0,
1156                                         FALSE,
1157                                         &event,
1158                                         &ioStatus);
1159 
1160     if (!irp) {
1161 
1162         DebugPrint((1,
1163                     "ReportToMountMgr: Allocation of irp failed\n"));
1164 
1165         ExFreePool(mountTarget);
1166         ObDereferenceObject(fileObject);
1167         return;
1168     }
1169 
1170     //
1171     // Call the MountMgr.
1172     //
1173 
1174     status = IoCallDriver(deviceObject, irp);
1175 
1176     if (status == STATUS_PENDING) {
1177         KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1178         status = ioStatus.Status;
1179     }
1180 
1181     //
1182     // We're done.
1183     //
1184 
1185     DPRINT1("Reported to the MountMgr: %lx\n", status);
1186 
1187     ExFreePool(mountTarget);
1188     ObDereferenceObject(fileObject);
1189 
1190     return;
1191 }
1192 
1193 
1194 NTSTATUS
1195 NTAPI
1196 CreatePartitionDeviceObjects(
1197     IN PDEVICE_OBJECT PhysicalDeviceObject,
1198     IN PUNICODE_STRING RegistryPath
1199     )
1200 {
1201     CCHAR          ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
1202     ULONG          partitionNumber = 0;
1203     NTSTATUS       status;
1204     PDEVICE_OBJECT deviceObject = NULL;
1205     PDISK_GEOMETRY_EX diskGeometry = NULL;
1206     PDRIVE_LAYOUT_INFORMATION partitionList = NULL;
1207     PDEVICE_EXTENSION deviceExtension;
1208     PDEVICE_EXTENSION physicalDeviceExtension;
1209     PCLASS_INIT_DATA initData = NULL;
1210     PDISK_DATA     diskData;
1211     PDISK_DATA     physicalDiskData;
1212     ULONG          bytesPerSector;
1213     UCHAR          sectorShift;
1214     ULONG          srbFlags;
1215     ULONG          dmByteSkew = 0;
1216     PULONG         dmSkew;
1217     BOOLEAN        dmActive = FALSE;
1218     ULONG          numberListElements = 0;
1219 
1220 
1221     //
1222     // Get physical device geometry information for partition table reads.
1223     //
1224 
1225     physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension;
1226     diskGeometry = physicalDeviceExtension->DiskGeometry;
1227     bytesPerSector = diskGeometry->Geometry.BytesPerSector;
1228 
1229     //
1230     // Make sure sector size is not zero.
1231     //
1232 
1233     if (bytesPerSector == 0) {
1234 
1235         //
1236         // Default sector size for disk is 512.
1237         //
1238 
1239         bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512;
1240     }
1241 
1242     sectorShift = physicalDeviceExtension->SectorShift;
1243 
1244     //
1245     // Set pointer to disk data area that follows device extension.
1246     //
1247 
1248     diskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1249     diskData->PartitionListState = Initializing;
1250 
1251     //
1252     // Determine is DM Driver is loaded on an IDE drive that is
1253     // under control of Atapi - this could be either a crashdump or
1254     // an Atapi device is sharing the controller with an IDE disk.
1255     //
1256 
1257     HalExamineMBR(PhysicalDeviceObject,
1258                   physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1259                   (ULONG)0x54,
1260                   (PVOID)&dmSkew);
1261 
1262     if (dmSkew) {
1263 
1264         //
1265         // Update the device extension, so that the call to IoReadPartitionTable
1266         // will get the correct information. Any I/O to this disk will have
1267         // to be skewed by *dmSkew sectors aka DMByteSkew.
1268         //
1269 
1270         physicalDeviceExtension->DMSkew = *dmSkew;
1271         physicalDeviceExtension->DMActive = TRUE;
1272         physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector;
1273 
1274         //
1275         // Save away the information that we need, since this deviceExtension will soon be
1276         // blown away.
1277         //
1278 
1279         dmActive = TRUE;
1280         dmByteSkew = physicalDeviceExtension->DMByteSkew;
1281 
1282     }
1283 
1284 #ifdef __REACTOS__
1285     //
1286     // HACK so that we can use NT5+ NTOS functions with this NT4 driver
1287     // for removable devices and avoid an infinite recursive loop between
1288     // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
1289     //
1290     diskData->UpdateRemovableGeometryCount = 0;
1291 #endif
1292 
1293     //
1294     // Create objects for all the partitions on the device.
1295     //
1296 
1297     status = IoReadPartitionTable(PhysicalDeviceObject,
1298                                   physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1299                                   TRUE,
1300                                   (PVOID)&partitionList);
1301 
1302     //
1303     // If the I/O read partition table failed and this is a removable device,
1304     // then fix up the partition list to make it look like there is one
1305     // zero length partition.
1306     //
1307     DPRINT("IoReadPartitionTable() status: 0x%08X\n", status);
1308     if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
1309         PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1310 
1311         if (!NT_SUCCESS(status)) {
1312 
1313             //
1314             // Remember this disk is not ready.
1315             //
1316 
1317             diskData->DriveNotReady = TRUE;
1318 
1319         } else {
1320 
1321             //
1322             // Free the partition list allocated by IoReadPartitionTable.
1323             //
1324 
1325             ExFreePool(partitionList);
1326         }
1327 
1328         //
1329         // Allocate and zero a partition list.
1330         //
1331 
1332         partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList));
1333 
1334 
1335         if (partitionList != NULL) {
1336 
1337             RtlZeroMemory( partitionList, sizeof( *partitionList ));
1338 
1339             //
1340             // Set the partition count to one and the status to success
1341             // so one device object will be created. Set the partition type
1342             // to a bogus value.
1343             //
1344 
1345             partitionList->PartitionCount = 1;
1346 
1347             status = STATUS_SUCCESS;
1348         }
1349     }
1350 
1351     if (NT_SUCCESS(status)) {
1352 
1353         //
1354         // Record disk signature.
1355         //
1356 
1357         diskData->Signature = partitionList->Signature;
1358 
1359         //
1360         // If disk signature is zero, then calculate the MBR checksum.
1361         //
1362 
1363         if (!diskData->Signature) {
1364 
1365             if (!CalculateMbrCheckSum(physicalDeviceExtension,
1366                                       &diskData->MbrCheckSum)) {
1367 
1368                 DebugPrint((1,
1369                             "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1370                             physicalDeviceExtension->DeviceNumber));
1371             } else {
1372 
1373                 DebugPrint((2,
1374                            "SCSIDISK: MBR checksum for disk %x is %x\n",
1375                            physicalDeviceExtension->DeviceNumber,
1376                            diskData->MbrCheckSum));
1377             }
1378         }
1379 
1380         //
1381         // Check the registry and determine if the BIOS knew about this drive.  If
1382         // it did then update the geometry with the BIOS information.
1383         //
1384 
1385         UpdateGeometry(physicalDeviceExtension);
1386 
1387         srbFlags = physicalDeviceExtension->SrbFlags;
1388 
1389         initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA));
1390         if (!initData)
1391         {
1392             DebugPrint((1,
1393                         "Disk.CreatePartitionDeviceObjects - Allocation of initData failed\n"));
1394 
1395             status = STATUS_INSUFFICIENT_RESOURCES;
1396             goto CreatePartitionDeviceObjectsExit;
1397         }
1398 
1399         RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA));
1400 
1401         initData->InitializationDataSize     = sizeof(CLASS_INIT_DATA);
1402         initData->DeviceExtensionSize        = DEVICE_EXTENSION_SIZE;
1403         initData->DeviceType                 = FILE_DEVICE_DISK;
1404         initData->DeviceCharacteristics      = PhysicalDeviceObject->Characteristics;
1405         initData->ClassError                 = physicalDeviceExtension->ClassError;
1406         initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification;
1407         initData->ClassFindDevices           = physicalDeviceExtension->ClassFindDevices;
1408         initData->ClassDeviceControl         = physicalDeviceExtension->ClassDeviceControl;
1409         initData->ClassShutdownFlush         = physicalDeviceExtension->ClassShutdownFlush;
1410         initData->ClassCreateClose           = physicalDeviceExtension->ClassCreateClose;
1411         initData->ClassStartIo               = physicalDeviceExtension->ClassStartIo;
1412 
1413         //
1414         // Create device objects for the device partitions (if any).
1415         // PartitionCount includes physical device partition 0,
1416         // so only one partition means no objects to create.
1417         //
1418 
1419         DebugPrint((2,
1420                     "CreateDiskDeviceObjects: Number of partitions is %d\n",
1421                     partitionList->PartitionCount));
1422 
1423         for (partitionNumber = 0; partitionNumber <
1424             partitionList->PartitionCount; partitionNumber++) {
1425 
1426             //
1427             // Create partition object and set up partition parameters.
1428             //
1429 
1430             sprintf(ntNameBuffer,
1431                     "\\Device\\Harddisk%lu\\Partition%lu",
1432                     physicalDeviceExtension->DeviceNumber,
1433                     partitionNumber + 1);
1434 
1435             DebugPrint((2,
1436                         "CreateDiskDeviceObjects: Create device object %s\n",
1437                         ntNameBuffer));
1438 
1439             status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject,
1440                                                  ntNameBuffer,
1441                                                  PhysicalDeviceObject,
1442                                                  &deviceObject,
1443                                                  initData);
1444 
1445             if (!NT_SUCCESS(status)) {
1446 
1447                 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer));
1448 
1449                 break;
1450             }
1451 
1452             //
1453             // Set up device object fields.
1454             //
1455 
1456             deviceObject->Flags |= DO_DIRECT_IO;
1457 
1458             //
1459             // Check if this is during initialization. If not indicate that
1460             // system initialization already took place and this disk is ready
1461             // to be accessed.
1462             //
1463 
1464             if (!RegistryPath) {
1465                 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1466             }
1467 
1468             deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1;
1469 
1470             //
1471             // Set up device extension fields.
1472             //
1473 
1474             deviceExtension = deviceObject->DeviceExtension;
1475 
1476             if (dmActive) {
1477 
1478                 //
1479                 // Restore any saved DM values.
1480                 //
1481 
1482                 deviceExtension->DMByteSkew = dmByteSkew;
1483                 deviceExtension->DMSkew     = *dmSkew;
1484                 deviceExtension->DMActive   = TRUE;
1485 
1486             }
1487 
1488             //
1489             // Link new device extension to previous disk data
1490             // to support dynamic partitioning.
1491             //
1492 
1493             diskData->NextPartition = deviceExtension;
1494 
1495             //
1496             // Get pointer to new disk data.
1497             //
1498 
1499             diskData = (PDISK_DATA)(deviceExtension + 1);
1500 
1501             //
1502             // Set next partition pointer to NULL in case this is the
1503             // last partition.
1504             //
1505 
1506             diskData->NextPartition = NULL;
1507 
1508             //
1509             // Allocate spinlock for zoning for split-request completion.
1510             //
1511 
1512             KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
1513 
1514             //
1515             // Copy port device object pointer to device extension.
1516             //
1517 
1518             deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject;
1519 
1520             //
1521             // Set the alignment requirements for the device based on the
1522             // host adapter requirements
1523             //
1524 
1525             if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
1526                 deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement;
1527             }
1528 
1529 
1530             if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
1531                 numberListElements = 30;
1532             } else {
1533                 numberListElements = 8;
1534             }
1535 
1536             //
1537             // Build the lookaside list for srb's for this partition based on
1538             // whether the adapter and disk can do tagged queueing.
1539             //
1540 
1541             ScsiClassInitializeSrbLookasideList(deviceExtension,
1542                                                 numberListElements);
1543 
1544             deviceExtension->SrbFlags = srbFlags;
1545 
1546             //
1547             // Set the sense-data pointer in the device extension.
1548             //
1549 
1550             deviceExtension->SenseData        = physicalDeviceExtension->SenseData;
1551             deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities;
1552             deviceExtension->DiskGeometry     = diskGeometry;
1553             diskData->PartitionOrdinal        = diskData->PartitionNumber = partitionNumber + 1;
1554             diskData->PartitionType           = partitionList->PartitionEntry[partitionNumber].PartitionType;
1555             diskData->BootIndicator           = partitionList->PartitionEntry[partitionNumber].BootIndicator;
1556 
1557             DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1558                 diskData->PartitionType));
1559 
1560             deviceExtension->StartingOffset  = partitionList->PartitionEntry[partitionNumber].StartingOffset;
1561             deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength;
1562             diskData->HiddenSectors          = partitionList->PartitionEntry[partitionNumber].HiddenSectors;
1563             deviceExtension->PortNumber      = physicalDeviceExtension->PortNumber;
1564             deviceExtension->PathId          = physicalDeviceExtension->PathId;
1565             deviceExtension->TargetId        = physicalDeviceExtension->TargetId;
1566             deviceExtension->Lun             = physicalDeviceExtension->Lun;
1567 
1568             //
1569             // Check for removable media support.
1570             //
1571 
1572             if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1573                 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
1574             }
1575 
1576             //
1577             // Set timeout value in seconds.
1578             //
1579 
1580             deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue;
1581             deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector;
1582             deviceExtension->SectorShift  = sectorShift;
1583             deviceExtension->DeviceObject = deviceObject;
1584             deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags;
1585 
1586             //
1587             // Now we're done, report to the MountMgr.
1588             // This is a HACK required to have the driver
1589             // handle the associated DosDevices.
1590             //
1591 
1592             ReportToMountMgr(deviceObject);
1593 
1594         } // end for (partitionNumber) ...
1595 
1596         //
1597         // Free the buffer allocated by reading the
1598         // partition table.
1599         //
1600 
1601         ExFreePool(partitionList);
1602 
1603         if (dmSkew) {
1604             ExFreePool(dmSkew);
1605         }
1606 
1607     } else {
1608 
1609 CreatePartitionDeviceObjectsExit:
1610 
1611         if (partitionList) {
1612             ExFreePool(partitionList);
1613         }
1614         if (initData) {
1615             ExFreePool(initData);
1616         }
1617 
1618         if (dmSkew) {
1619             ExFreePool(dmSkew);
1620         }
1621 
1622         return status;
1623 
1624     } // end if...else
1625 
1626 
1627     physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1628     physicalDiskData->PartitionListState = Initialized;
1629 
1630     return(STATUS_SUCCESS);
1631 
1632 
1633 } // end CreatePartitionDeviceObjects()
1634 
1635 
1636 NTSTATUS
1637 NTAPI
1638 ScsiDiskReadWriteVerification(
1639     IN PDEVICE_OBJECT DeviceObject,
1640     IN PIRP Irp
1641     )
1642 
1643 /*++
1644 
1645 Routine Description:
1646 
1647     I/O System entry for read and write requests to SCSI disks.
1648 
1649 Arguments:
1650 
1651     DeviceObject - Pointer to driver object created by system.
1652     Irp - IRP involved.
1653 
1654 Return Value:
1655 
1656     NT Status
1657 
1658 --*/
1659 
1660 {
1661     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1662     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1663     ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1664     LARGE_INTEGER startingOffset;
1665 
1666     //
1667     // HACK: How can we end here with null sector size?!
1668     //
1669 
1670     if (deviceExtension->DiskGeometry->Geometry.BytesPerSector == 0) {
1671         DPRINT1("Hack! Received invalid sector size\n");
1672         deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512;
1673     }
1674 
1675     //
1676     // Verify parameters of this request.
1677     // Check that ending sector is within partition and
1678     // that number of bytes to transfer is a multiple of
1679     // the sector size.
1680     //
1681 
1682     startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
1683                                transferByteCount);
1684 
1685     if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
1686         (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
1687 
1688         //
1689         // This error maybe caused by the fact that the drive is not ready.
1690         //
1691 
1692         if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) {
1693 
1694             //
1695             // Flag this as a user error so that a popup is generated.
1696             //
1697 
1698             Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
1699             IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1700 
1701         } else {
1702 
1703             //
1704             // Note fastfat depends on this parameter to determine when to
1705             // remount do to a sector size change.
1706             //
1707 
1708             Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1709         }
1710 
1711         if (startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) {
1712             DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset.QuadPart, deviceExtension->PartitionLength.QuadPart);
1713         }
1714 
1715         if (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1)) {
1716             DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount, deviceExtension->DiskGeometry->Geometry.BytesPerSector);
1717         }
1718 
1719         if (Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) {
1720             DPRINT1("Failing due to device not ready!\n");
1721         }
1722 
1723         return STATUS_INVALID_PARAMETER;
1724     }
1725 
1726     return STATUS_SUCCESS;
1727 
1728 } // end ScsiDiskReadWrite()
1729 
1730 
1731 NTSTATUS
1732 NTAPI
1733 ScsiDiskDeviceControl(
1734     PDEVICE_OBJECT DeviceObject,
1735     PIRP Irp
1736     )
1737 
1738 /*++
1739 
1740 Routine Description:
1741 
1742     I/O system entry for device controls to SCSI disks.
1743 
1744 Arguments:
1745 
1746     DeviceObject - Pointer to driver object created by system.
1747     Irp - IRP involved.
1748 
1749 Return Value:
1750 
1751     Status is returned.
1752 
1753 --*/
1754 
1755 {
1756     PIO_STACK_LOCATION     irpStack = IoGetCurrentIrpStackLocation(Irp);
1757     PDEVICE_EXTENSION      deviceExtension = DeviceObject->DeviceExtension;
1758     PDISK_DATA             diskData = (PDISK_DATA)(deviceExtension + 1);
1759     PSCSI_REQUEST_BLOCK    srb;
1760     PCDB                   cdb;
1761     PMODE_PARAMETER_HEADER modeData;
1762     PIRP                   irp2;
1763     ULONG                  length;
1764     NTSTATUS               status;
1765     KEVENT                 event;
1766     IO_STATUS_BLOCK        ioStatus;
1767 
1768     PAGED_CODE();
1769 
1770     srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
1771 
1772     if (srb == NULL) {
1773 
1774         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1775         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1776         return(STATUS_INSUFFICIENT_RESOURCES);
1777     }
1778 
1779     //
1780     // Write zeros to Srb.
1781     //
1782 
1783     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1784 
1785     cdb = (PCDB)srb->Cdb;
1786 
1787     switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1788 
1789     case SMART_GET_VERSION: {
1790 
1791         ULONG_PTR buffer;
1792         PSRB_IO_CONTROL  srbControl;
1793         PGETVERSIONINPARAMS versionParams;
1794 
1795         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1796             sizeof(GETVERSIONINPARAMS)) {
1797                 status = STATUS_INVALID_PARAMETER;
1798                 break;
1799         }
1800 
1801         //
1802         // Create notification event object to be used to signal the
1803         // request completion.
1804         //
1805 
1806         KeInitializeEvent(&event, NotificationEvent, FALSE);
1807 
1808         srbControl = ExAllocatePool(NonPagedPool,
1809                                     sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
1810 
1811         if (!srbControl) {
1812             status =  STATUS_INSUFFICIENT_RESOURCES;
1813             break;
1814         }
1815 
1816         //
1817         // fill in srbControl fields
1818         //
1819 
1820         srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1821         RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1822         srbControl->Timeout = deviceExtension->TimeOutValue;
1823         srbControl->Length = sizeof(GETVERSIONINPARAMS);
1824         srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
1825 
1826         //
1827         // Point to the 'buffer' portion of the SRB_CONTROL
1828         //
1829 
1830         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1831 
1832         //
1833         // Ensure correct target is set in the cmd parameters.
1834         //
1835 
1836         versionParams = (PGETVERSIONINPARAMS)buffer;
1837         versionParams->bIDEDeviceMap = deviceExtension->TargetId;
1838 
1839         //
1840         // Copy the IOCTL parameters to the srb control buffer area.
1841         //
1842 
1843         RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS));
1844 
1845 
1846         irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1847                                             deviceExtension->PortDeviceObject,
1848                                             srbControl,
1849                                             sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1850                                             srbControl,
1851                                             sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1852                                             FALSE,
1853                                             &event,
1854                                             &ioStatus);
1855 
1856         if (irp2 == NULL) {
1857             status = STATUS_INSUFFICIENT_RESOURCES;
1858             break;
1859         }
1860 
1861         //
1862         // Call the port driver with the request and wait for it to complete.
1863         //
1864 
1865         status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1866 
1867         if (status == STATUS_PENDING) {
1868             KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1869             status = ioStatus.Status;
1870         }
1871 
1872         //
1873         // If successful, copy the data received into the output buffer.
1874         // This should only fail in the event that the IDE driver is older than this driver.
1875         //
1876 
1877         if (NT_SUCCESS(status)) {
1878 
1879             buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1880 
1881             RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS));
1882             Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1883         }
1884 
1885         ExFreePool(srbControl);
1886         break;
1887     }
1888 
1889     case SMART_RCV_DRIVE_DATA: {
1890 
1891         PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1892         ULONG            controlCode = 0;
1893         PSRB_IO_CONTROL  srbControl;
1894         ULONG_PTR        buffer;
1895 
1896         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1897             (sizeof(SENDCMDINPARAMS) - 1)) {
1898                 status = STATUS_INVALID_PARAMETER;
1899                 break;
1900 
1901         } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1902             (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
1903                 status = STATUS_INVALID_PARAMETER;
1904                 break;
1905         }
1906 
1907         //
1908         // Create notification event object to be used to signal the
1909         // request completion.
1910         //
1911 
1912         KeInitializeEvent(&event, NotificationEvent, FALSE);
1913 
1914         if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
1915 
1916             length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1917             controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
1918 
1919         } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1920             switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1921                 case READ_ATTRIBUTES:
1922                     controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
1923                     length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1924                     break;
1925                 case READ_THRESHOLDS:
1926                     controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
1927                     length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1928                     break;
1929                 default:
1930                     status = STATUS_INVALID_PARAMETER;
1931                     break;
1932             }
1933         } else {
1934 
1935             status = STATUS_INVALID_PARAMETER;
1936         }
1937 
1938         if (controlCode == 0) {
1939             status = STATUS_INVALID_PARAMETER;
1940             break;
1941         }
1942 
1943         srbControl = ExAllocatePool(NonPagedPool,
1944                                     sizeof(SRB_IO_CONTROL) + length);
1945 
1946         if (!srbControl) {
1947             status =  STATUS_INSUFFICIENT_RESOURCES;
1948             break;
1949         }
1950 
1951         //
1952         // fill in srbControl fields
1953         //
1954 
1955         srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1956         RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1957         srbControl->Timeout = deviceExtension->TimeOutValue;
1958         srbControl->Length = length;
1959         srbControl->ControlCode = controlCode;
1960 
1961         //
1962         // Point to the 'buffer' portion of the SRB_CONTROL
1963         //
1964 
1965         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1966 
1967         //
1968         // Ensure correct target is set in the cmd parameters.
1969         //
1970 
1971         cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1972 
1973         //
1974         // Copy the IOCTL parameters to the srb control buffer area.
1975         //
1976 
1977         RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1978 
1979         irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1980                                             deviceExtension->PortDeviceObject,
1981                                             srbControl,
1982                                             sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1983                                             srbControl,
1984                                             sizeof(SRB_IO_CONTROL) + length,
1985                                             FALSE,
1986                                             &event,
1987                                             &ioStatus);
1988 
1989         if (irp2 == NULL) {
1990             status = STATUS_INSUFFICIENT_RESOURCES;
1991             break;
1992         }
1993 
1994         //
1995         // Call the port driver with the request and wait for it to complete.
1996         //
1997 
1998         status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1999 
2000         if (status == STATUS_PENDING) {
2001             KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
2002             status = ioStatus.Status;
2003         }
2004 
2005         //
2006         // If successful, copy the data received into the output buffer
2007         //
2008 
2009         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
2010 
2011         if (NT_SUCCESS(status)) {
2012 
2013             RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1);
2014             Irp->IoStatus.Information = length - 1;
2015 
2016         } else {
2017 
2018             RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
2019             Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
2020 
2021         }
2022 
2023         ExFreePool(srbControl);
2024         break;
2025 
2026     }
2027 
2028     case SMART_SEND_DRIVE_COMMAND: {
2029 
2030         PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
2031         PSRB_IO_CONTROL  srbControl;
2032         ULONG            controlCode = 0;
2033         ULONG_PTR        buffer;
2034 
2035         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2036                (sizeof(SENDCMDINPARAMS) - 1)) {
2037                 status = STATUS_INVALID_PARAMETER;
2038                 break;
2039 
2040         } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2041                       (sizeof(SENDCMDOUTPARAMS) - 1)) {
2042                 status = STATUS_INVALID_PARAMETER;
2043                 break;
2044         }
2045 
2046         //
2047         // Create notification event object to be used to signal the
2048         // request completion.
2049         //
2050 
2051         KeInitializeEvent(&event, NotificationEvent, FALSE);
2052 
2053         length = 0;
2054 
2055         if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
2056             switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
2057 
2058                 case ENABLE_SMART:
2059                     controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
2060                     break;
2061 
2062                 case DISABLE_SMART:
2063                     controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
2064                     break;
2065 
2066                 case  RETURN_SMART_STATUS:
2067 
2068                     //
2069                     // Ensure bBuffer is at least 2 bytes (to hold the values of
2070                     // cylinderLow and cylinderHigh).
2071                     //
2072 
2073                     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2074                         (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
2075 
2076                         status = STATUS_INVALID_PARAMETER;
2077                         break;
2078                     }
2079 
2080                     controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
2081                     length = sizeof(IDEREGS);
2082                     break;
2083 
2084                 case ENABLE_DISABLE_AUTOSAVE:
2085                     controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
2086                     break;
2087 
2088                 case SAVE_ATTRIBUTE_VALUES:
2089                     controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
2090                     break;
2091 
2092                 case EXECUTE_OFFLINE_DIAGS:
2093                     controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
2094                     break;
2095 
2096           default:
2097                     status = STATUS_INVALID_PARAMETER;
2098                     break;
2099             }
2100         } else {
2101 
2102             status = STATUS_INVALID_PARAMETER;
2103         }
2104 
2105         if (controlCode == 0) {
2106             status = STATUS_INVALID_PARAMETER;
2107             break;
2108         }
2109 
2110         length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);
2111         srbControl = ExAllocatePool(NonPagedPool,
2112                                     sizeof(SRB_IO_CONTROL) + length);
2113 
2114         if (!srbControl) {
2115             status =  STATUS_INSUFFICIENT_RESOURCES;
2116             break;
2117         }
2118 
2119         //
2120         // fill in srbControl fields
2121         //
2122 
2123         srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
2124         RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
2125         srbControl->Timeout = deviceExtension->TimeOutValue;
2126         srbControl->Length = length;
2127 
2128         //
2129         // Point to the 'buffer' portion of the SRB_CONTROL
2130         //
2131 
2132         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
2133 
2134         //
2135         // Ensure correct target is set in the cmd parameters.
2136         //
2137 
2138         cmdInParameters->bDriveNumber = deviceExtension->TargetId;
2139 
2140         //
2141         // Copy the IOCTL parameters to the srb control buffer area.
2142         //
2143 
2144         RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
2145 
2146         srbControl->ControlCode = controlCode;
2147 
2148         irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
2149                                             deviceExtension->PortDeviceObject,
2150                                             srbControl,
2151                                             sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
2152                                             srbControl,
2153                                             sizeof(SRB_IO_CONTROL) + length,
2154                                             FALSE,
2155                                             &event,
2156                                             &ioStatus);
2157 
2158         if (irp2 == NULL) {
2159             status = STATUS_INSUFFICIENT_RESOURCES;
2160             break;
2161         }
2162 
2163         //
2164         // Call the port driver with the request and wait for it to complete.
2165         //
2166 
2167         status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2168 
2169         if (status == STATUS_PENDING) {
2170             KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
2171             status = ioStatus.Status;
2172         }
2173 
2174         //
2175         // Copy the data received into the output buffer. Since the status buffer
2176         // contains error information also, always perform this copy. IO will will
2177         // either pass this back to the app, or zero it, in case of error.
2178         //
2179 
2180         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
2181 
2182         //
2183         // Update the return buffer size based on the sub-command.
2184         //
2185 
2186         if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
2187             length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
2188         } else {
2189             length = sizeof(SENDCMDOUTPARAMS) - 1;
2190         }
2191 
2192         RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length);
2193         Irp->IoStatus.Information = length;
2194 
2195         ExFreePool(srbControl);
2196         break;
2197 
2198     }
2199 
2200     case IOCTL_DISK_GET_DRIVE_GEOMETRY:
2201     case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
2202         {
2203 
2204         PDEVICE_EXTENSION physicalDeviceExtension;
2205         PDISK_DATA        physicalDiskData;
2206         BOOLEAN           removable = FALSE;
2207         BOOLEAN           listInitialized = FALSE;
2208         ULONG             copyLength;
2209 
2210         if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) {
2211             if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) {
2212                 status = STATUS_BUFFER_TOO_SMALL;
2213                 break;
2214             }
2215 
2216             copyLength = sizeof(DISK_GEOMETRY);
2217         } else {
2218             ASSERT(irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX);
2219             if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) {
2220                 status = STATUS_BUFFER_TOO_SMALL;
2221                 break;
2222             }
2223 
2224             if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(DISK_GEOMETRY_EX)) {
2225                 copyLength = sizeof(DISK_GEOMETRY_EX);
2226             } else {
2227                 copyLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data);
2228             }
2229         }
2230 
2231         status = STATUS_SUCCESS;
2232 
2233         physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2234         physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
2235 
2236         removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA;
2237         listInitialized = (physicalDiskData->PartitionListState == Initialized);
2238 
2239         if (removable || (!listInitialized))
2240         {
2241             //
2242             // Issue ReadCapacity to update device extension
2243             // with information for current media.
2244             //
2245 
2246             status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
2247 
2248         }
2249 
2250         if (removable) {
2251 
2252             if (!NT_SUCCESS(status)) {
2253 
2254                 //
2255                 // Note the drive is not ready.
2256                 //
2257 
2258                 diskData->DriveNotReady = TRUE;
2259 
2260                 break;
2261             }
2262 
2263             //
2264             // Note the drive is now ready.
2265             //
2266 
2267             diskData->DriveNotReady = FALSE;
2268 
2269         } else if (NT_SUCCESS(status)) {
2270 
2271             // ReadDriveCapacity was alright, create Partition Objects
2272 
2273             if (physicalDiskData->PartitionListState == NotInitialized) {
2274                     status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL);
2275             }
2276         }
2277 
2278         if (NT_SUCCESS(status)) {
2279 
2280             //
2281             // Copy drive geometry information from device extension.
2282             //
2283 
2284             RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2285                           deviceExtension->DiskGeometry,
2286                           copyLength);
2287 
2288             status = STATUS_SUCCESS;
2289             Irp->IoStatus.Information = copyLength;
2290         }
2291 
2292         break;
2293 
2294         }
2295 
2296     case IOCTL_DISK_VERIFY:
2297 
2298         {
2299 
2300         PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2301         LARGE_INTEGER byteOffset;
2302         ULONG         sectorOffset;
2303         USHORT        sectorCount;
2304 
2305         //
2306         // Validate buffer length.
2307         //
2308 
2309         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2310             sizeof(VERIFY_INFORMATION)) {
2311 
2312             status = STATUS_INFO_LENGTH_MISMATCH;
2313             break;
2314         }
2315 
2316         //
2317         // Verify sectors
2318         //
2319 
2320         srb->CdbLength = 10;
2321 
2322         cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2323 
2324         //
2325         // Add disk offset to starting sector.
2326         //
2327 
2328         byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart +
2329                                         verifyInfo->StartingOffset.QuadPart;
2330 
2331         //
2332         // Convert byte offset to sector offset.
2333         //
2334 
2335         sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift);
2336 
2337         //
2338         // Convert ULONG byte count to USHORT sector count.
2339         //
2340 
2341         sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift);
2342 
2343         //
2344         // Move little endian values into CDB in big endian format.
2345         //
2346 
2347         cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2348         cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2349         cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2350         cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2351 
2352         cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
2353         cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
2354 
2355         //
2356         // The verify command is used by the NT FORMAT utility and
2357         // requests are sent down for 5% of the volume size. The
2358         // request timeout value is calculated based on the number of
2359         // sectors verified.
2360         //
2361 
2362         srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
2363                                               deviceExtension->TimeOutValue;
2364 
2365         status = ScsiClassSendSrbAsynchronous(DeviceObject,
2366                                               srb,
2367                                               Irp,
2368                                               NULL,
2369                                               0,
2370                                               FALSE);
2371 
2372         return(status);
2373 
2374         }
2375 
2376     case IOCTL_DISK_GET_PARTITION_INFO:
2377 
2378         //
2379         // Return the information about the partition specified by the device
2380         // object.  Note that no information is ever returned about the size
2381         // or partition type of the physical disk, as this doesn't make any
2382         // sense.
2383         //
2384 
2385         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2386             sizeof(PARTITION_INFORMATION)) {
2387 
2388             status = STATUS_INFO_LENGTH_MISMATCH;
2389             break;
2390         }
2391 
2392         //
2393         // Update the geometry in case it has changed.
2394         //
2395 
2396         status = UpdateRemovableGeometry (DeviceObject, Irp);
2397 
2398         if (!NT_SUCCESS(status)) {
2399 
2400             //
2401             // Note the drive is not ready.
2402             //
2403 
2404             diskData->DriveNotReady = TRUE;
2405             break;
2406         }
2407 
2408         //
2409         // Note the drive is now ready.
2410         //
2411 
2412         diskData->DriveNotReady = FALSE;
2413 
2414         //
2415         // Handle the case were we query the whole disk
2416         //
2417 
2418         if (diskData->PartitionNumber == 0) {
2419 
2420             PPARTITION_INFORMATION outputBuffer;
2421 
2422             outputBuffer =
2423                     (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2424 
2425             outputBuffer->PartitionType = PARTITION_ENTRY_UNUSED;
2426             outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2427             outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2428             outputBuffer->HiddenSectors = 0;
2429             outputBuffer->PartitionNumber = diskData->PartitionNumber;
2430             outputBuffer->BootIndicator = FALSE;
2431             outputBuffer->RewritePartition = FALSE;
2432             outputBuffer->RecognizedPartition = FALSE;
2433 
2434             status = STATUS_SUCCESS;
2435             Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
2436 
2437         } else {
2438 
2439             PPARTITION_INFORMATION outputBuffer;
2440 
2441             //
2442             // We query a single partition here
2443             // FIXME: this can only work for MBR-based disks, check for this!
2444             //
2445 
2446             outputBuffer =
2447                     (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2448 
2449             outputBuffer->PartitionType = diskData->PartitionType;
2450             outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2451             outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2452             outputBuffer->HiddenSectors = diskData->HiddenSectors;
2453             outputBuffer->PartitionNumber = diskData->PartitionNumber;
2454             outputBuffer->BootIndicator = diskData->BootIndicator;
2455             outputBuffer->RewritePartition = FALSE;
2456             outputBuffer->RecognizedPartition =
2457                 IsRecognizedPartition(diskData->PartitionType);
2458 
2459             status = STATUS_SUCCESS;
2460             Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
2461         }
2462 
2463         break;
2464 
2465     case IOCTL_DISK_GET_PARTITION_INFO_EX:
2466 
2467         //
2468         // Return the information about the partition specified by the device
2469         // object.  Note that no information is ever returned about the size
2470         // or partition type of the physical disk, as this doesn't make any
2471         // sense.
2472         //
2473 
2474         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2475             sizeof(PARTITION_INFORMATION_EX)) {
2476 
2477             status = STATUS_INFO_LENGTH_MISMATCH;
2478 
2479         }
2480 #if 0 // HACK: ReactOS partition numbers must be wrong
2481         else if (diskData->PartitionNumber == 0) {
2482 
2483             //
2484             // Partition zero is not a partition so this is not a
2485             // reasonable request.
2486             //
2487 
2488             status = STATUS_INVALID_DEVICE_REQUEST;
2489 
2490         }
2491 #endif
2492         else {
2493 
2494             PPARTITION_INFORMATION_EX outputBuffer;
2495 
2496             if (diskData->PartitionNumber == 0) {
2497                 DPRINT1("HACK: Handling partition 0 request!\n");
2498                 //ASSERT(FALSE);
2499             }
2500 
2501             //
2502             // Update the geometry in case it has changed.
2503             //
2504 
2505             status = UpdateRemovableGeometry (DeviceObject, Irp);
2506 
2507             if (!NT_SUCCESS(status)) {
2508 
2509                 //
2510                 // Note the drive is not ready.
2511                 //
2512 
2513                 diskData->DriveNotReady = TRUE;
2514                 break;
2515             }
2516 
2517             //
2518             // Note the drive is now ready.
2519             //
2520 
2521             diskData->DriveNotReady = FALSE;
2522 
2523             if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2524 
2525                 status = STATUS_INVALID_DEVICE_REQUEST;
2526                 break;
2527             }
2528 
2529             outputBuffer =
2530                     (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
2531 
2532             //
2533             // FIXME: hack of the year, assume that partition is MBR
2534             // Thing that can obviously be wrong...
2535             //
2536 
2537             outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
2538             outputBuffer->Mbr.PartitionType = diskData->PartitionType;
2539             outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2540             outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2541             outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors;
2542             outputBuffer->PartitionNumber = diskData->PartitionNumber;
2543             outputBuffer->Mbr.BootIndicator = diskData->BootIndicator;
2544             outputBuffer->RewritePartition = FALSE;
2545             outputBuffer->Mbr.RecognizedPartition =
2546                 IsRecognizedPartition(diskData->PartitionType);
2547 
2548             status = STATUS_SUCCESS;
2549             Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
2550         }
2551 
2552         break;
2553 
2554     case IOCTL_DISK_SET_PARTITION_INFO:
2555 
2556         if (diskData->PartitionNumber == 0) {
2557 
2558             status = STATUS_UNSUCCESSFUL;
2559 
2560         } else {
2561 
2562             PSET_PARTITION_INFORMATION inputBuffer =
2563                 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2564 
2565             //
2566             // Validate buffer length.
2567             //
2568 
2569             if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2570                 sizeof(SET_PARTITION_INFORMATION)) {
2571 
2572                 status = STATUS_INFO_LENGTH_MISMATCH;
2573                 break;
2574             }
2575 
2576             //
2577             // The HAL routines IoGet- and IoSetPartitionInformation were
2578             // developed before support of dynamic partitioning and therefore
2579             // don't distinguish between partition ordinal (that is the order
2580             // of a partition on a disk) and the partition number. (The
2581             // partition number is assigned to a partition to identify it to
2582             // the system.) Use partition ordinals for these legacy calls.
2583             //
2584 
2585             status = IoSetPartitionInformation(
2586                           deviceExtension->PhysicalDevice,
2587                           deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2588                           diskData->PartitionOrdinal,
2589                           inputBuffer->PartitionType);
2590 
2591             if (NT_SUCCESS(status)) {
2592 
2593                 diskData->PartitionType = inputBuffer->PartitionType;
2594             }
2595         }
2596 
2597         break;
2598 
2599     case IOCTL_DISK_GET_DRIVE_LAYOUT:
2600 
2601         //
2602         // Return the partition layout for the physical drive.  Note that
2603         // the layout is returned for the actual physical drive, regardless
2604         // of which partition was specified for the request.
2605         //
2606 
2607         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2608             sizeof(DRIVE_LAYOUT_INFORMATION)) {
2609             status = STATUS_INFO_LENGTH_MISMATCH;
2610 
2611         } else {
2612 
2613             PDRIVE_LAYOUT_INFORMATION partitionList;
2614             PDEVICE_EXTENSION         physicalExtension = deviceExtension;
2615             PPARTITION_INFORMATION    partitionEntry;
2616             PDISK_DATA                diskData;
2617             ULONG                     tempSize;
2618             ULONG                     i;
2619 
2620             //
2621             // Read partition information.
2622             //
2623 
2624             status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
2625                               deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2626                               FALSE,
2627                               &partitionList);
2628 
2629             if (!NT_SUCCESS(status)) {
2630                 break;
2631             }
2632 
2633             //
2634             // The disk layout has been returned in the partitionList
2635             // buffer.  Determine its size and, if the data will fit
2636             // into the intermediary buffer, return it.
2637             //
2638 
2639             tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
2640             tempSize += partitionList->PartitionCount *
2641                         sizeof(PARTITION_INFORMATION);
2642 
2643             if (tempSize >
2644                irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
2645 
2646                 status = STATUS_BUFFER_TOO_SMALL;
2647                 ExFreePool(partitionList);
2648                 break;
2649             }
2650 
2651             //
2652             // Walk partition list to associate partition numbers with
2653             // partition entries.
2654             //
2655 
2656             for (i = 0; i < partitionList->PartitionCount; i++) {
2657 
2658                 //
2659                 // Walk partition chain anchored at physical disk extension.
2660                 //
2661 
2662                 deviceExtension = physicalExtension;
2663                 diskData = (PDISK_DATA)(deviceExtension + 1);
2664 
2665                 do {
2666 
2667                     deviceExtension = diskData->NextPartition;
2668 
2669                     //
2670                     // Check if this is the last partition in the chain.
2671                     //
2672 
2673                     if (!deviceExtension) {
2674                        break;
2675                     }
2676 
2677                     //
2678                     // Get the partition device extension from disk data.
2679                     //
2680 
2681                     diskData = (PDISK_DATA)(deviceExtension + 1);
2682 
2683                     //
2684                     // Check if this partition is not currently being used.
2685                     //
2686 
2687                     if (!deviceExtension->PartitionLength.QuadPart) {
2688                        continue;
2689                     }
2690 
2691                     partitionEntry = &partitionList->PartitionEntry[i];
2692 
2693                     //
2694                     // Check if empty, or describes extended partition or hasn't changed.
2695                     //
2696 
2697                     if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2698                         IsContainerPartition(partitionEntry->PartitionType)) {
2699                         continue;
2700                     }
2701 
2702                     //
2703                     // Check if new partition starts where this partition starts.
2704                     //
2705 
2706                     if (partitionEntry->StartingOffset.QuadPart !=
2707                               deviceExtension->StartingOffset.QuadPart) {
2708                         continue;
2709                     }
2710 
2711                     //
2712                     // Check if partition length is the same.
2713                     //
2714 
2715                     if (partitionEntry->PartitionLength.QuadPart ==
2716                               deviceExtension->PartitionLength.QuadPart) {
2717 
2718                         //
2719                         // Partitions match. Update partition number.
2720                         //
2721 
2722                         partitionEntry->PartitionNumber =
2723                             diskData->PartitionNumber;
2724                         break;
2725                     }
2726 
2727                 } while (TRUE);
2728             }
2729 
2730             //
2731             // Copy partition information to system buffer.
2732             //
2733 
2734             RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2735                           partitionList,
2736                           tempSize);
2737             status = STATUS_SUCCESS;
2738             Irp->IoStatus.Information = tempSize;
2739 
2740             //
2741             // Finally, free the buffer allocated by reading the
2742             // partition table.
2743             //
2744 
2745             ExFreePool(partitionList);
2746         }
2747 
2748         break;
2749 
2750     case IOCTL_DISK_SET_DRIVE_LAYOUT:
2751 
2752         {
2753 
2754         //
2755         // Update the disk with new partition information.
2756         //
2757 
2758         PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
2759 
2760         //
2761         // Validate buffer length.
2762         //
2763 
2764         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2765             sizeof(DRIVE_LAYOUT_INFORMATION)) {
2766 
2767             status = STATUS_INFO_LENGTH_MISMATCH;
2768             break;
2769         }
2770 
2771         length = sizeof(DRIVE_LAYOUT_INFORMATION) +
2772             (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
2773 
2774 
2775         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2776             length) {
2777 
2778             status = STATUS_BUFFER_TOO_SMALL;
2779             break;
2780         }
2781 
2782         //
2783         // Verify that device object is for physical disk.
2784         //
2785 
2786         if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
2787             status = STATUS_INVALID_PARAMETER;
2788             break;
2789         }
2790 
2791         //
2792         // Walk through partition table comparing partitions to
2793         // existing partitions to create, delete and change
2794         // device objects as necessary.
2795         //
2796 
2797         UpdateDeviceObjects(DeviceObject,
2798                             Irp);
2799 
2800         //
2801         // Write changes to disk.
2802         //
2803 
2804         status = IoWritePartitionTable(
2805                            deviceExtension->DeviceObject,
2806                            deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2807                            deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
2808                            deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
2809                            partitionList);
2810         }
2811 
2812         //
2813         // Update IRP with bytes returned.
2814         //
2815 
2816         if (NT_SUCCESS(status)) {
2817             Irp->IoStatus.Information = length;
2818         }
2819 
2820         break;
2821 
2822     case IOCTL_DISK_REASSIGN_BLOCKS:
2823 
2824         //
2825         // Map defective blocks to new location on disk.
2826         //
2827 
2828         {
2829 
2830         PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2831         ULONG bufferSize;
2832         ULONG blockNumber;
2833         ULONG blockCount;
2834 
2835         //
2836         // Validate buffer length.
2837         //
2838 
2839         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2840             sizeof(REASSIGN_BLOCKS)) {
2841 
2842             status = STATUS_INFO_LENGTH_MISMATCH;
2843             break;
2844         }
2845 
2846         bufferSize = sizeof(REASSIGN_BLOCKS) +
2847             (badBlocks->Count - 1) * sizeof(ULONG);
2848 
2849         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2850             bufferSize) {
2851 
2852             status = STATUS_INFO_LENGTH_MISMATCH;
2853             break;
2854         }
2855 
2856         //
2857         // Build the data buffer to be transferred in the input buffer.
2858         // The format of the data to the device is:
2859         //
2860         //      2 bytes Reserved
2861         //      2 bytes Length
2862         //      x * 4 btyes Block Address
2863         //
2864         // All values are big endian.
2865         //
2866 
2867         badBlocks->Reserved = 0;
2868         blockCount = badBlocks->Count;
2869 
2870         //
2871         // Convert # of entries to # of bytes.
2872         //
2873 
2874         blockCount *= 4;
2875         badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2876         badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2877 
2878         //
2879         // Convert back to number of entries.
2880         //
2881 
2882         blockCount /= 4;
2883 
2884         for (; blockCount > 0; blockCount--) {
2885 
2886             blockNumber = badBlocks->BlockNumber[blockCount-1];
2887 
2888             REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2889                           (PFOUR_BYTE) &blockNumber);
2890         }
2891 
2892         srb->CdbLength = 6;
2893 
2894         cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2895 
2896         //
2897         // Set timeout value.
2898         //
2899 
2900         srb->TimeOutValue = deviceExtension->TimeOutValue;
2901 
2902         status = ScsiClassSendSrbSynchronous(DeviceObject,
2903                                              srb,
2904                                              badBlocks,
2905                                              bufferSize,
2906                                              TRUE);
2907 
2908         Irp->IoStatus.Status = status;
2909         Irp->IoStatus.Information = 0;
2910         ExFreePool(srb);
2911         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2912         }
2913 
2914         return(status);
2915 
2916     case IOCTL_DISK_IS_WRITABLE:
2917 
2918         //
2919         // Determine if the device is writable.
2920         //
2921 
2922         modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
2923 
2924         if (modeData == NULL) {
2925             status = STATUS_INSUFFICIENT_RESOURCES;
2926             break;
2927         }
2928 
2929         RtlZeroMemory(modeData, MODE_DATA_SIZE);
2930 
2931         length = ScsiClassModeSense(DeviceObject,
2932                                     (PCHAR) modeData,
2933                                     MODE_DATA_SIZE,
2934                                     MODE_SENSE_RETURN_ALL);
2935 
2936         if (length < sizeof(MODE_PARAMETER_HEADER)) {
2937 
2938             //
2939             // Retry the request in case of a check condition.
2940             //
2941 
2942             length = ScsiClassModeSense(DeviceObject,
2943                                         (PCHAR) modeData,
2944                                         MODE_DATA_SIZE,
2945                                         MODE_SENSE_RETURN_ALL);
2946 
2947             if (length < sizeof(MODE_PARAMETER_HEADER)) {
2948                 status = STATUS_IO_DEVICE_ERROR;
2949                 ExFreePool(modeData);
2950                 break;
2951             }
2952         }
2953 
2954         if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
2955             status = STATUS_MEDIA_WRITE_PROTECTED;
2956         } else {
2957             status = STATUS_SUCCESS;
2958         }
2959 
2960         ExFreePool(modeData);
2961         break;
2962 
2963     case IOCTL_DISK_INTERNAL_SET_VERIFY:
2964 
2965         //
2966         // If the caller is kernel mode, set the verify bit.
2967         //
2968 
2969         if (Irp->RequestorMode == KernelMode) {
2970             DeviceObject->Flags |= DO_VERIFY_VOLUME;
2971         }
2972         status = STATUS_SUCCESS;
2973         break;
2974 
2975     case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
2976 
2977         //
2978         // If the caller is kernel mode, clear the verify bit.
2979         //
2980 
2981         if (Irp->RequestorMode == KernelMode) {
2982             DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
2983         }
2984         status = STATUS_SUCCESS;
2985         break;
2986 
2987     case IOCTL_DISK_FIND_NEW_DEVICES:
2988 
2989         //
2990         // Search for devices that have been powered on since the last
2991         // device search or system initialization.
2992         //
2993 
2994         DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2995         status = DriverEntry(DeviceObject->DriverObject,
2996                              NULL);
2997 
2998         Irp->IoStatus.Status = status;
2999         ExFreePool(srb);
3000         IoCompleteRequest(Irp, IO_NO_INCREMENT);
3001         return status;
3002 
3003     case IOCTL_DISK_MEDIA_REMOVAL:
3004 
3005         //
3006         // If the disk is not removable then don't allow this command.
3007         //
3008 
3009         if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
3010             status = STATUS_INVALID_DEVICE_REQUEST;
3011             break;
3012         }
3013 
3014         //
3015         // Fall through and let the class driver process the request.
3016         //
3017 
3018     case IOCTL_DISK_GET_LENGTH_INFO:
3019 
3020         //
3021         // Validate buffer length.
3022         //
3023 
3024         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
3025             sizeof(GET_LENGTH_INFORMATION)) {
3026             status = STATUS_BUFFER_TOO_SMALL;
3027 
3028         } else {
3029 
3030             PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer;
3031 
3032             //
3033             // Update the geometry in case it has changed.
3034             //
3035 
3036             status = UpdateRemovableGeometry (DeviceObject, Irp);
3037 
3038             if (!NT_SUCCESS(status)) {
3039 
3040                 //
3041                 // Note the drive is not ready.
3042                 //
3043 
3044                 diskData->DriveNotReady = TRUE;
3045                 break;
3046             }
3047 
3048             //
3049             // Note the drive is now ready.
3050             //
3051 
3052             diskData->DriveNotReady = FALSE;
3053 
3054             //
3055             // Output data, and return
3056             //
3057 
3058             lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart;
3059             status = STATUS_SUCCESS;
3060             Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
3061         }
3062 
3063         break;
3064 
3065     default:
3066 
3067         //
3068         // Free the Srb, since it is not needed.
3069         //
3070 
3071         ExFreePool(srb);
3072 
3073         //
3074         // Pass the request to the common device control routine.
3075         //
3076 
3077         return(ScsiClassDeviceControl(DeviceObject, Irp));
3078 
3079         break;
3080 
3081     } // end switch( ...
3082 
3083     Irp->IoStatus.Status = status;
3084 
3085     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3086 
3087         IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
3088     }
3089 
3090     IoCompleteRequest(Irp, IO_NO_INCREMENT);
3091     ExFreePool(srb);
3092     return(status);
3093 
3094 } // end ScsiDiskDeviceControl()
3095 
3096 NTSTATUS
3097 NTAPI
3098 ScsiDiskShutdownFlush (
3099     IN PDEVICE_OBJECT DeviceObject,
3100     IN PIRP Irp
3101     )
3102 
3103 /*++
3104 
3105 Routine Description:
3106 
3107     This routine is called for a shutdown and flush IRPs.  These are sent by the
3108     system before it actually shuts down or when the file system does a flush.
3109     A synchronize cache command is sent to the device if it is write caching.
3110     If the device is removable an unlock command will be sent. This routine
3111     will sent a shutdown or flush Srb to the port driver.
3112 
3113 Arguments:
3114 
3115     DriverObject - Pointer to device object to being shutdown by system.
3116 
3117     Irp - IRP involved.
3118 
3119 Return Value:
3120 
3121     NT Status
3122 
3123 --*/
3124 
3125 {
3126     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3127     PIO_STACK_LOCATION irpStack;
3128     PSCSI_REQUEST_BLOCK srb;
3129     NTSTATUS status;
3130     PCDB cdb;
3131 
3132     //
3133     // Allocate SCSI request block.
3134     //
3135 
3136     srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
3137 
3138     if (srb == NULL) {
3139 
3140         //
3141         // Set the status and complete the request.
3142         //
3143 
3144         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3145         IoCompleteRequest(Irp, IO_NO_INCREMENT);
3146         return(STATUS_INSUFFICIENT_RESOURCES);
3147     }
3148 
3149     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
3150 
3151     //
3152     // Write length to SRB.
3153     //
3154 
3155     srb->Length = SCSI_REQUEST_BLOCK_SIZE;
3156 
3157     //
3158     // Set SCSI bus address.
3159     //
3160 
3161     srb->PathId = deviceExtension->PathId;
3162     srb->TargetId = deviceExtension->TargetId;
3163     srb->Lun = deviceExtension->Lun;
3164 
3165     //
3166     // Set timeout value and mark the request as not being a tagged request.
3167     //
3168 
3169     srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
3170     srb->QueueTag = SP_UNTAGGED;
3171     srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
3172     srb->SrbFlags = deviceExtension->SrbFlags;
3173 
3174     //
3175     // If the write cache is enabled then send a synchronize cache request.
3176     //
3177 
3178     if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
3179 
3180         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3181         srb->CdbLength = 10;
3182 
3183         srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
3184 
3185         status = ScsiClassSendSrbSynchronous(DeviceObject,
3186                                              srb,
3187                                              NULL,
3188                                              0,
3189                                              TRUE);
3190 
3191         DebugPrint((1, "ScsiDiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status ));
3192     }
3193 
3194     //
3195     // Unlock the device if it is removable and this is a shutdown.
3196     //
3197 
3198     irpStack = IoGetCurrentIrpStackLocation(Irp);
3199 
3200     if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
3201         irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
3202 
3203         srb->CdbLength = 6;
3204         cdb = (PVOID) srb->Cdb;
3205         cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3206         cdb->MEDIA_REMOVAL.Prevent = FALSE;
3207 
3208         //
3209         // Set timeout value.
3210         //
3211 
3212         srb->TimeOutValue = deviceExtension->TimeOutValue;
3213         status = ScsiClassSendSrbSynchronous(DeviceObject,
3214                                              srb,
3215                                              NULL,
3216                                              0,
3217                                              TRUE);
3218 
3219         DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
3220     }
3221 
3222     srb->CdbLength = 0;
3223 
3224     //
3225     // Save a few parameters in the current stack location.
3226     //
3227 
3228     srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
3229         SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
3230 
3231     //
3232     // Set the retry count to zero.
3233     //
3234 
3235     irpStack->Parameters.Others.Argument4 = (PVOID) 0;
3236 
3237     //
3238     // Set up IoCompletion routine address.
3239     //
3240 
3241     IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
3242 
3243     //
3244     // Get next stack location and
3245     // set major function code.
3246     //
3247 
3248     irpStack = IoGetNextIrpStackLocation(Irp);
3249 
3250     irpStack->MajorFunction = IRP_MJ_SCSI;
3251 
3252     //
3253     // Set up SRB for execute scsi request.
3254     // Save SRB address in next stack for port driver.
3255     //
3256 
3257     irpStack->Parameters.Scsi.Srb = srb;
3258 
3259     //
3260     // Set up Irp Address.
3261     //
3262 
3263     srb->OriginalRequest = Irp;
3264 
3265     //
3266     // Call the port driver to process the request.
3267     //
3268 
3269     return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3270 
3271 } // end ScsiDiskShutdown()
3272 
3273 
3274 BOOLEAN
3275 NTAPI
3276 IsFloppyDevice(
3277     PDEVICE_OBJECT DeviceObject
3278     )
3279 /*++
3280 
3281 Routine Description:
3282 
3283     The routine performs the necessary functions to determine if a device is
3284     really a floppy rather than a harddisk.  This is done by a mode sense
3285     command.  First, a check is made to see if the media type is set.  Second
3286     a check is made for the flexible parameters mode page.  Also a check is
3287     made to see if the write cache is enabled.
3288 
3289 Arguments:
3290 
3291     DeviceObject - Supplies the device object to be tested.
3292 
3293 Return Value:
3294 
3295     Return TRUE if the indicated device is a floppy.
3296 
3297 --*/
3298 {
3299     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3300     PVOID modeData;
3301     PUCHAR pageData;
3302     ULONG length;
3303 
3304     PAGED_CODE();
3305 
3306     modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3307 
3308     if (modeData == NULL) {
3309         return(FALSE);
3310     }
3311 
3312     RtlZeroMemory(modeData, MODE_DATA_SIZE);
3313 
3314     length = ScsiClassModeSense(DeviceObject,
3315                                 modeData,
3316                                 MODE_DATA_SIZE,
3317                                 MODE_SENSE_RETURN_ALL);
3318 
3319     if (length < sizeof(MODE_PARAMETER_HEADER)) {
3320 
3321         //
3322         // Retry the request in case of a check condition.
3323         //
3324 
3325         length = ScsiClassModeSense(DeviceObject,
3326                                 modeData,
3327                                 MODE_DATA_SIZE,
3328                                 MODE_SENSE_RETURN_ALL);
3329 
3330         if (length < sizeof(MODE_PARAMETER_HEADER)) {
3331 
3332             ExFreePool(modeData);
3333             return(FALSE);
3334 
3335         }
3336     }
3337 
3338     //
3339     // If the length is greater than length indicated by the mode data reset
3340     // the data to the mode data.
3341     //
3342 
3343     if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3344         length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3345     }
3346 
3347     //
3348     // Look for the flexible disk mode page.
3349     //
3350 
3351     pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
3352 
3353     if (pageData != NULL) {
3354 
3355         DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3356         ExFreePool(modeData);
3357         return(TRUE);
3358     }
3359 
3360     //
3361     // Check to see if the write cache is enabled.
3362     //
3363 
3364     pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3365 
3366     //
3367     // Assume that write cache is disabled or not supported.
3368     //
3369 
3370     deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3371 
3372     //
3373     // Check if valid caching page exists.
3374     //
3375 
3376     if (pageData != NULL) {
3377 
3378         //
3379         // Check if write cache is disabled.
3380         //
3381 
3382         if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3383 
3384             DebugPrint((1,
3385                        "SCSIDISK: Disk write cache enabled\n"));
3386 
3387             //
3388             // Check if forced unit access (FUA) is supported.
3389             //
3390 
3391             if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
3392 
3393                 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3394 
3395             } else {
3396 
3397                 DebugPrint((1,
3398                            "SCSIDISK: Disk does not support FUA or DPO\n"));
3399 
3400                 //
3401                 // TODO: Log this.
3402                 //
3403 
3404             }
3405         }
3406     }
3407 
3408     ExFreePool(modeData);
3409     return(FALSE);
3410 
3411 } // end IsFloppyDevice()
3412 
3413 
3414 BOOLEAN
3415 NTAPI
3416 ScsiDiskModeSelect(
3417     IN PDEVICE_OBJECT DeviceObject,
3418     IN PCHAR ModeSelectBuffer,
3419     IN ULONG Length,
3420     IN BOOLEAN SavePage
3421     )
3422 
3423 /*++
3424 
3425 Routine Description:
3426 
3427     This routine sends a mode select command.
3428 
3429 Arguments:
3430 
3431     DeviceObject - Supplies the device object associated with this request.
3432 
3433     ModeSelectBuffer - Supplies a buffer containing the page data.
3434 
3435     Length - Supplies the length in bytes of the mode select buffer.
3436 
3437     SavePage - Indicates that parameters should be written to disk.
3438 
3439 Return Value:
3440 
3441     Length of the transferred data is returned.
3442 
3443 --*/
3444 {
3445     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3446     PCDB cdb;
3447     SCSI_REQUEST_BLOCK srb;
3448     ULONG retries = 1;
3449     ULONG length2;
3450     NTSTATUS status;
3451     ULONG_PTR buffer;
3452     PMODE_PARAMETER_BLOCK blockDescriptor;
3453 
3454     PAGED_CODE();
3455 
3456     length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
3457 
3458     //
3459     // Allocate buffer for mode select header, block descriptor, and mode page.
3460     //
3461 
3462     buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
3463 
3464     RtlZeroMemory((PVOID)buffer, length2);
3465 
3466     //
3467     // Set length in header to size of mode page.
3468     //
3469 
3470     ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
3471 
3472     blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
3473 
3474     //
3475     // Set size
3476     //
3477 
3478     blockDescriptor->BlockLength[1]=0x02;
3479 
3480     //
3481     // Copy mode page to buffer.
3482     //
3483 
3484     RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
3485 
3486     //
3487     // Zero SRB.
3488     //
3489 
3490     RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3491 
3492     //
3493     // Build the MODE SELECT CDB.
3494     //
3495 
3496     srb.CdbLength = 6;
3497     cdb = (PCDB)srb.Cdb;
3498 
3499     //
3500     // Set timeout value from device extension.
3501     //
3502 
3503     srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
3504 
3505     cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3506     cdb->MODE_SELECT.SPBit = SavePage;
3507     cdb->MODE_SELECT.PFBit = 1;
3508     cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
3509 
3510 Retry:
3511 
3512     status = ScsiClassSendSrbSynchronous(DeviceObject,
3513                                          &srb,
3514                                          (PVOID)buffer,
3515                                          length2,
3516                                          TRUE);
3517 
3518 
3519     if (status == STATUS_VERIFY_REQUIRED) {
3520 
3521         //
3522         // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3523         // this status.
3524         //
3525 
3526         if (retries--) {
3527 
3528             //
3529             // Retry request.
3530             //
3531 
3532             goto Retry;
3533         }
3534 
3535     } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3536         status = STATUS_SUCCESS;
3537     }
3538 
3539     ExFreePool((PVOID)buffer);
3540 
3541     if (NT_SUCCESS(status)) {
3542         return(TRUE);
3543     } else {
3544         return(FALSE);
3545     }
3546 
3547 } // end SciDiskModeSelect()
3548 
3549 
3550 VOID
3551 NTAPI
3552 DisableWriteCache(
3553     IN PDEVICE_OBJECT DeviceObject,
3554     IN PSCSI_INQUIRY_DATA LunInfo
3555     )
3556 
3557 {
3558     PDEVICE_EXTENSION          deviceExtension = DeviceObject->DeviceExtension;
3559     PINQUIRYDATA               InquiryData     = (PINQUIRYDATA)LunInfo->InquiryData;
3560     BAD_CONTROLLER_INFORMATION const *controller;
3561     ULONG                      j,length;
3562     PVOID                      modeData;
3563     PUCHAR                     pageData;
3564 
3565     for (j = 0; j <  NUMBER_OF_BAD_CONTROLLERS; j++) {
3566 
3567         controller = &ScsiDiskBadControllers[j];
3568 
3569         if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
3570             continue;
3571         }
3572 
3573         DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
3574 
3575         modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3576 
3577         if (modeData == NULL) {
3578 
3579             DebugPrint((1,
3580                         "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3581             return;
3582         }
3583 
3584         RtlZeroMemory(modeData, MODE_DATA_SIZE);
3585 
3586         length = ScsiClassModeSense(DeviceObject,
3587                                     modeData,
3588                                     MODE_DATA_SIZE,
3589                                     MODE_SENSE_RETURN_ALL);
3590 
3591         if (length < sizeof(MODE_PARAMETER_HEADER)) {
3592 
3593             //
3594             // Retry the request in case of a check condition.
3595             //
3596 
3597             length = ScsiClassModeSense(DeviceObject,
3598                                     modeData,
3599                                     MODE_DATA_SIZE,
3600                                     MODE_SENSE_RETURN_ALL);
3601 
3602             if (length < sizeof(MODE_PARAMETER_HEADER)) {
3603 
3604 
3605                 DebugPrint((1,
3606                             "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3607 
3608                 ExFreePool(modeData);
3609                 return;
3610 
3611             }
3612         }
3613 
3614         //
3615         // If the length is greater than length indicated by the mode data reset
3616         // the data to the mode data.
3617         //
3618 
3619         if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3620             length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3621         }
3622 
3623         //
3624         // Check to see if the write cache is enabled.
3625         //
3626 
3627         pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3628 
3629         //
3630         // Assume that write cache is disabled or not supported.
3631         //
3632 
3633         deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3634 
3635         //
3636         // Check if valid caching page exists.
3637         //
3638 
3639         if (pageData != NULL) {
3640 
3641             BOOLEAN savePage = FALSE;
3642 
3643             savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
3644 
3645             //
3646             // Check if write cache is disabled.
3647             //
3648 
3649             if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3650 
3651                 PIO_ERROR_LOG_PACKET errorLogEntry;
3652                 LONG                 errorCode;
3653 
3654 
3655                 //
3656                 // Disable write cache and ensure necessary fields are zeroed.
3657                 //
3658 
3659                 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
3660                 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
3661                 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
3662                 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
3663 
3664                 //
3665                 // Extract length from caching page.
3666                 //
3667 
3668                 length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
3669 
3670                 //
3671                 // Compensate for page code and page length.
3672                 //
3673 
3674                 length += 2;
3675 
3676                 //
3677                 // Issue mode select to set the parameter.
3678                 //
3679 
3680                 if (ScsiDiskModeSelect(DeviceObject,
3681                                        (PCHAR)pageData,
3682                                        length,
3683                                        savePage)) {
3684 
3685                     DebugPrint((1,
3686                                "SCSIDISK: Disk write cache disabled\n"));
3687 
3688                     deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3689                     errorCode = IO_WRITE_CACHE_DISABLED;
3690 
3691                 } else {
3692                     if (ScsiDiskModeSelect(DeviceObject,
3693                                            (PCHAR)pageData,
3694                                            length,
3695                                            savePage)) {
3696 
3697                         DebugPrint((1,
3698                                    "SCSIDISK: Disk write cache disabled\n"));
3699 
3700 
3701                         deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3702                         errorCode = IO_WRITE_CACHE_DISABLED;
3703 
3704                     } else {
3705 
3706                             DebugPrint((1,
3707                                        "SCSIDISK: Mode select to disable write cache failed\n"));
3708 
3709                             deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3710                             errorCode = IO_WRITE_CACHE_ENABLED;
3711                     }
3712                 }
3713 
3714                 //
3715                 // Log the appropriate informational or error entry.
3716                 //
3717 
3718                 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3719                                                          DeviceObject,
3720                                                          sizeof(IO_ERROR_LOG_PACKET) + 3
3721                                                              * sizeof(ULONG));
3722 
3723                 if (errorLogEntry != NULL) {
3724 
3725                     errorLogEntry->FinalStatus     = STATUS_SUCCESS;
3726                     errorLogEntry->ErrorCode       = errorCode;
3727                     errorLogEntry->SequenceNumber  = 0;
3728                     errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
3729                     errorLogEntry->IoControlCode   = 0;
3730                     errorLogEntry->RetryCount      = 0;
3731                     errorLogEntry->UniqueErrorValue = 0x1;
3732                     errorLogEntry->DumpDataSize    = 3 * sizeof(ULONG);
3733                     errorLogEntry->DumpData[0]     = LunInfo->PathId;
3734                     errorLogEntry->DumpData[1]     = LunInfo->TargetId;
3735                     errorLogEntry->DumpData[2]     = LunInfo->Lun;
3736 
3737                     //
3738                     // Write the error log packet.
3739                     //
3740 
3741                     IoWriteErrorLogEntry(errorLogEntry);
3742                 }
3743             }
3744         }
3745 
3746         //
3747         // Found device so exit the loop and return.
3748         //
3749 
3750         break;
3751     }
3752 
3753     return;
3754 }
3755 
3756 
3757 BOOLEAN
3758 NTAPI
3759 CalculateMbrCheckSum(
3760     IN PDEVICE_EXTENSION DeviceExtension,
3761     OUT PULONG Checksum
3762     )
3763 
3764 /*++
3765 
3766 Routine Description:
3767 
3768     Read MBR and calculate checksum.
3769 
3770 Arguments:
3771 
3772     DeviceExtension - Supplies a pointer to the device information for disk.
3773     Checksum - Memory location to return MBR checksum.
3774 
3775 Return Value:
3776 
3777     Returns TRUE if checksum is valid.
3778 
3779 --*/
3780 {
3781     LARGE_INTEGER   sectorZero;
3782     PIRP            irp;
3783     IO_STATUS_BLOCK ioStatus;
3784     KEVENT          event;
3785     NTSTATUS        status;
3786     ULONG           sectorSize;
3787     PULONG          mbr;
3788     ULONG           i;
3789 
3790     PAGED_CODE();
3791     sectorZero.QuadPart = (LONGLONG) 0;
3792 
3793     //
3794     // Create notification event object to be used to signal the inquiry
3795     // request completion.
3796     //
3797 
3798     KeInitializeEvent(&event, NotificationEvent, FALSE);
3799 
3800     //
3801     // Get sector size.
3802     //
3803 
3804     sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
3805 
3806     //
3807     // Make sure sector size is at least 512 bytes.
3808     //
3809 
3810     if (sectorSize < 512) {
3811         sectorSize = 512;
3812     }
3813 
3814     //
3815     // Allocate buffer for sector read.
3816     //
3817 
3818     mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize);
3819 
3820     if (!mbr) {
3821         return FALSE;
3822     }
3823 
3824     //
3825     // Build IRP to read MBR.
3826     //
3827 
3828     irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
3829                                        DeviceExtension->DeviceObject,
3830                                        mbr,
3831                                        sectorSize,
3832                                        &sectorZero,
3833                                        &event,
3834                                        &ioStatus );
3835 
3836     if (!irp) {
3837         ExFreePool(mbr);
3838         return FALSE;
3839     }
3840 
3841     //
3842     // Pass request to port driver and wait for request to complete.
3843     //
3844 
3845     status = IoCallDriver(DeviceExtension->DeviceObject,
3846                           irp);
3847 
3848     if (status == STATUS_PENDING) {
3849         KeWaitForSingleObject(&event,
3850                               Suspended,
3851                               KernelMode,
3852                               FALSE,
3853                               NULL);
3854         status = ioStatus.Status;
3855     }
3856 
3857     if (!NT_SUCCESS(status)) {
3858         ExFreePool(mbr);
3859         return FALSE;
3860     }
3861 
3862     //
3863     // Calculate MBR checksum.
3864     //
3865 
3866     *Checksum = 0;
3867 
3868     for (i = 0; i < 128; i++) {
3869         *Checksum += mbr[i];
3870     }
3871 
3872     *Checksum = ~*Checksum + 1;
3873 
3874     ExFreePool(mbr);
3875     return TRUE;
3876 }
3877 
3878 
3879 BOOLEAN
3880 NTAPI
3881 EnumerateBusKey(
3882     IN PDEVICE_EXTENSION DeviceExtension,
3883     HANDLE BusKey,
3884     PULONG DiskNumber
3885     )
3886 
3887 /*++
3888 
3889 Routine Description:
3890 
3891     The routine queries the registry to determine if this disk is visible to
3892     the BIOS.  If the disk is visible to the BIOS, then the geometry information
3893     is updated.
3894 
3895 Arguments:
3896 
3897     DeviceExtension - Supplies a pointer to the device information for disk.
3898     Signature - Unique identifier recorded in MBR.
3899     BusKey - Handle of bus key.
3900     DiskNumber - Returns ordinal of disk as BIOS sees it.
3901 
3902 Return Value:
3903 
3904     TRUE is disk signature matched.
3905 
3906 --*/
3907 {
3908     PDISK_DATA        diskData = (PDISK_DATA)(DeviceExtension + 1);
3909     BOOLEAN           diskFound = FALSE;
3910     OBJECT_ATTRIBUTES objectAttributes;
3911     UNICODE_STRING    unicodeString;
3912     UNICODE_STRING    identifier;
3913     ULONG             busNumber;
3914     ULONG             adapterNumber;
3915     ULONG             diskNumber;
3916     HANDLE            adapterKey;
3917     HANDLE            spareKey;
3918     HANDLE            diskKey;
3919     HANDLE            targetKey;
3920     NTSTATUS          status;
3921     STRING            string;
3922     STRING            anotherString;
3923     ULONG             length;
3924     UCHAR             buffer[20];
3925     PKEY_VALUE_FULL_INFORMATION keyData;
3926 
3927     PAGED_CODE();
3928 
3929     for (busNumber = 0; ; busNumber++) {
3930 
3931         //
3932         // Open controller name key.
3933         //
3934 
3935         sprintf((PCHAR)buffer,
3936                 "%lu",
3937                 busNumber);
3938 
3939         RtlInitString(&string,
3940                       (PCSZ)buffer);
3941 
3942         status = RtlAnsiStringToUnicodeString(&unicodeString,
3943                                               &string,
3944                                               TRUE);
3945 
3946         if (!NT_SUCCESS(status)){
3947             break;
3948         }
3949 
3950         InitializeObjectAttributes(&objectAttributes,
3951                                    &unicodeString,
3952                                    OBJ_CASE_INSENSITIVE,
3953                                    BusKey,
3954                                    (PSECURITY_DESCRIPTOR)NULL);
3955 
3956         status = ZwOpenKey(&spareKey,
3957                            KEY_READ,
3958                            &objectAttributes);
3959 
3960         RtlFreeUnicodeString(&unicodeString);
3961 
3962         if (!NT_SUCCESS(status)) {
3963             break;
3964         }
3965 
3966         //
3967         // Open up controller ordinal key.
3968         //
3969 
3970         RtlInitUnicodeString(&unicodeString, L"DiskController");
3971         InitializeObjectAttributes(&objectAttributes,
3972                                    &unicodeString,
3973                                    OBJ_CASE_INSENSITIVE,
3974                                    spareKey,
3975                                    (PSECURITY_DESCRIPTOR)NULL);
3976 
3977         status = ZwOpenKey(&adapterKey,
3978                            KEY_READ,
3979                            &objectAttributes);
3980 
3981         //
3982         // This could fail even with additional adapters of this type
3983         // to search.
3984         //
3985 
3986         if (!NT_SUCCESS(status)) {
3987             continue;
3988         }
3989 
3990         for (adapterNumber = 0; ; adapterNumber++) {
3991 
3992             //
3993             // Open disk key.
3994             //
3995 
3996             sprintf((PCHAR)buffer,
3997                     "%lu\\DiskPeripheral",
3998                     adapterNumber);
3999 
4000             RtlInitString(&string,
4001                           (PCSZ)buffer);
4002 
4003             status = RtlAnsiStringToUnicodeString(&unicodeString,
4004                                                   &string,
4005                                                   TRUE);
4006 
4007             if (!NT_SUCCESS(status)){
4008                 break;
4009             }
4010 
4011             InitializeObjectAttributes(&objectAttributes,
4012                                        &unicodeString,
4013                                        OBJ_CASE_INSENSITIVE,
4014                                        adapterKey,
4015                                        (PSECURITY_DESCRIPTOR)NULL);
4016 
4017             status = ZwOpenKey(&diskKey,
4018                                KEY_READ,
4019                                &objectAttributes);
4020 
4021             RtlFreeUnicodeString(&unicodeString);
4022 
4023             if (!NT_SUCCESS(status)) {
4024                 break;
4025             }
4026 
4027             for (diskNumber = 0; ; diskNumber++) {
4028 
4029                 sprintf((PCHAR)buffer,
4030                         "%lu",
4031                         diskNumber);
4032 
4033                 RtlInitString(&string,
4034                               (PCSZ)buffer);
4035 
4036                 status = RtlAnsiStringToUnicodeString(&unicodeString,
4037                                                       &string,
4038                                                       TRUE);
4039 
4040                 if (!NT_SUCCESS(status)){
4041                     break;
4042                 }
4043 
4044                 InitializeObjectAttributes(&objectAttributes,
4045                                            &unicodeString,
4046                                            OBJ_CASE_INSENSITIVE,
4047                                            diskKey,
4048                                            (PSECURITY_DESCRIPTOR)NULL);
4049 
4050                 status = ZwOpenKey(&targetKey,
4051                                    KEY_READ,
4052                                    &objectAttributes);
4053 
4054                 RtlFreeUnicodeString(&unicodeString);
4055 
4056                 if (!NT_SUCCESS(status)) {
4057                     break;
4058                 }
4059 
4060                 //
4061                 // Allocate buffer for registry query.
4062                 //
4063 
4064                 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
4065 
4066                 if (keyData == NULL) {
4067                     ZwClose(targetKey);
4068                     continue;
4069                 }
4070 
4071                 //
4072                 // Get disk peripheral identifier.
4073                 //
4074 
4075                 RtlInitUnicodeString(&unicodeString, L"Identifier");
4076                 status = ZwQueryValueKey(targetKey,
4077                                          &unicodeString,
4078                                          KeyValueFullInformation,
4079                                          keyData,
4080                                          VALUE_BUFFER_SIZE,
4081                                          &length);
4082 
4083                 ZwClose(targetKey);
4084 
4085                 if (!NT_SUCCESS(status)) {
4086                     ExFreePool(keyData);
4087                     continue;
4088                 }
4089 
4090                 if (keyData->DataLength < 9*sizeof(WCHAR)) {
4091                     //
4092                     // the data is too short to use (we subtract 9 chars in normal path)
4093                     //
4094                     DebugPrint((1, "EnumerateBusKey: Saved data was invalid, "
4095                                 "not enough data in registry!\n"));
4096                     ExFreePool(keyData);
4097                     continue;
4098                 }
4099 
4100                 //
4101                 // Complete unicode string.
4102                 //
4103 
4104                 identifier.Buffer =
4105                     (PWSTR)((PUCHAR)keyData + keyData->DataOffset);
4106                 identifier.Length = (USHORT)keyData->DataLength;
4107                 identifier.MaximumLength = (USHORT)keyData->DataLength;
4108 
4109                 //
4110                 // Convert unicode identifier to ansi string.
4111                 //
4112 
4113                 status =
4114                     RtlUnicodeStringToAnsiString(&anotherString,
4115                                                  &identifier,
4116                                                  TRUE);
4117 
4118                 if (!NT_SUCCESS(status)) {
4119                     ExFreePool(keyData);
4120                     continue;
4121                 }
4122 
4123                 //
4124                 // If checksum is zero, then the MBR is valid and
4125                 // the signature is meaningful.
4126                 //
4127 
4128                 if (diskData->MbrCheckSum) {
4129 
4130                     //
4131                     // Convert checksum to ansi string.
4132                     //
4133 
4134                     sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum);
4135 
4136                 } else {
4137 
4138                     //
4139                     // Convert signature to ansi string.
4140                     //
4141 
4142                     sprintf((PCHAR)buffer, "%08lx", diskData->Signature);
4143 
4144                     //
4145                     // Make string point at signature. Can't use scan
4146                     // functions because they are not exported for driver use.
4147                     //
4148 
4149                     anotherString.Buffer+=9;
4150                 }
4151 
4152                 //
4153                 // Convert to ansi string.
4154                 //
4155 
4156                 RtlInitString(&string,
4157                               (PCSZ)buffer);
4158 
4159 
4160                 //
4161                 // Make string lengths equal.
4162                 //
4163 
4164                 anotherString.Length = string.Length;
4165 
4166                 //
4167                 // Check if strings match.
4168                 //
4169 
4170                 if (RtlCompareString(&string,
4171                                      &anotherString,
4172                                      TRUE) == 0)  {
4173 
4174                     diskFound = TRUE;
4175                     *DiskNumber = diskNumber;
4176                 }
4177 
4178                 ExFreePool(keyData);
4179 
4180                 //
4181                 // Readjust identifier string if necessary.
4182                 //
4183 
4184                 if (!diskData->MbrCheckSum) {
4185                     anotherString.Buffer-=9;
4186                 }
4187 
4188                 RtlFreeAnsiString(&anotherString);
4189 
4190                 if (diskFound) {
4191                     break;
4192                 }
4193             }
4194 
4195             ZwClose(diskKey);
4196         }
4197 
4198         ZwClose(adapterKey);
4199     }
4200 
4201     ZwClose(BusKey);
4202     return diskFound;
4203 
4204 } // end EnumerateBusKey()
4205 
4206 
4207 VOID
4208 NTAPI
4209 UpdateGeometry(
4210     IN PDEVICE_EXTENSION DeviceExtension
4211     )
4212 /*++
4213 
4214 Routine Description:
4215 
4216     The routine queries the registry to determine if this disk is visible to
4217     the BIOS.  If the disk is visible to the BIOS, then the geometry information
4218     is updated.
4219 
4220 Arguments:
4221 
4222     DeviceExtension - Supplies a pointer to the device information for disk.
4223 
4224 Return Value:
4225 
4226     None.
4227 
4228 --*/
4229 
4230 {
4231     OBJECT_ATTRIBUTES objectAttributes;
4232     UNICODE_STRING unicodeString;
4233     NTSTATUS status;
4234     HANDLE hardwareKey;
4235     HANDLE busKey;
4236     PCM_INT13_DRIVE_PARAMETER driveParameters;
4237     PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
4238     PKEY_VALUE_FULL_INFORMATION keyData;
4239     ULONG diskNumber;
4240     PUCHAR buffer;
4241     ULONG length;
4242     ULONG numberOfDrives;
4243     ULONG cylinders;
4244     ULONG sectors;
4245     ULONG sectorsPerTrack;
4246     ULONG tracksPerCylinder;
4247     BOOLEAN foundEZHooker;
4248     PVOID tmpPtr;
4249 
4250     PAGED_CODE();
4251 
4252     //
4253     // Initialize the object for the key.
4254     //
4255 
4256     InitializeObjectAttributes(&objectAttributes,
4257                                DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
4258                                OBJ_CASE_INSENSITIVE,
4259                                NULL,
4260                                (PSECURITY_DESCRIPTOR) NULL);
4261 
4262     //
4263     // Create the hardware base key.
4264     //
4265 
4266     status =  ZwOpenKey(&hardwareKey,
4267                         KEY_READ,
4268                         &objectAttributes);
4269 
4270 
4271     if (!NT_SUCCESS(status)) {
4272         DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase));
4273         return;
4274     }
4275 
4276 
4277     //
4278     // Get disk BIOS geometry information.
4279     //
4280 
4281     RtlInitUnicodeString(&unicodeString, L"Configuration Data");
4282 
4283     keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
4284 
4285     if (keyData == NULL) {
4286         ZwClose(hardwareKey);
4287         return;
4288     }
4289 
4290     status = ZwQueryValueKey(hardwareKey,
4291                              &unicodeString,
4292                              KeyValueFullInformation,
4293                              keyData,
4294                              VALUE_BUFFER_SIZE,
4295                              &length);
4296 
4297     if (!NT_SUCCESS(status)) {
4298         DebugPrint((1,
4299                    "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4300                    status));
4301         ZwClose(hardwareKey);
4302         ExFreePool(keyData);
4303         return;
4304     }
4305 
4306     //
4307     // Open EISA bus key.
4308     //
4309 
4310     RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
4311 
4312     InitializeObjectAttributes(&objectAttributes,
4313                                &unicodeString,
4314                                OBJ_CASE_INSENSITIVE,
4315                                hardwareKey,
4316                                (PSECURITY_DESCRIPTOR)NULL);
4317 
4318     status = ZwOpenKey(&busKey,
4319                        KEY_READ,
4320                        &objectAttributes);
4321 
4322     if (!NT_SUCCESS(status)) {
4323         goto openMultiKey;
4324     }
4325 
4326     DebugPrint((3,
4327                "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4328     if (EnumerateBusKey(DeviceExtension,
4329                         busKey,
4330                         &diskNumber)) {
4331 
4332         ZwClose(hardwareKey);
4333         goto diskMatched;
4334     }
4335 
4336 openMultiKey:
4337 
4338     //
4339     // Open Multifunction bus key.
4340     //
4341 
4342     RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
4343 
4344     InitializeObjectAttributes(&objectAttributes,
4345                                &unicodeString,
4346                                OBJ_CASE_INSENSITIVE,
4347                                hardwareKey,
4348                                (PSECURITY_DESCRIPTOR)NULL);
4349 
4350     status = ZwOpenKey(&busKey,
4351                        KEY_READ,
4352                        &objectAttributes);
4353 
4354     ZwClose(hardwareKey);
4355     if (NT_SUCCESS(status)) {
4356         DebugPrint((3,
4357                    "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4358         if (EnumerateBusKey(DeviceExtension,
4359                             busKey,
4360                             &diskNumber)) {
4361 
4362             goto diskMatched;
4363         }
4364     }
4365 
4366     ExFreePool(keyData);
4367     return;
4368 
4369 diskMatched:
4370 
4371     resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData +
4372         keyData->DataOffset);
4373 
4374     //
4375     // Check that the data is long enough to hold a full resource descriptor,
4376     // and that the last resource list is device-specific and long enough.
4377     //
4378 
4379     if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) ||
4380         resourceDescriptor->PartialResourceList.Count == 0 ||
4381         resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type !=
4382         CmResourceTypeDeviceSpecific ||
4383         resourceDescriptor->PartialResourceList.PartialDescriptors[0]
4384             .u.DeviceSpecificData.DataSize < sizeof(ULONG)) {
4385 
4386         DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4387         ExFreePool(keyData);
4388         return;
4389     }
4390 
4391     length =
4392         resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize;
4393 
4394     //
4395     // Point to the BIOS data. The BIOS data is located after the first
4396     // partial Resource list which should be device specific data.
4397     //
4398 
4399     buffer = (PUCHAR) keyData + keyData->DataOffset +
4400         sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
4401 
4402 
4403     numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
4404 
4405     //
4406     // Use the defaults if the drive number is greater than the
4407     // number of drives detected by the BIOS.
4408     //
4409 
4410     if (numberOfDrives <= diskNumber) {
4411         ExFreePool(keyData);
4412         return;
4413     }
4414 
4415     //
4416     // Point to the array of drive parameters.
4417     //
4418 
4419     driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber;
4420     cylinders = driveParameters->MaxCylinders + 1;
4421     sectorsPerTrack = driveParameters->SectorsPerTrack;
4422     tracksPerCylinder = driveParameters->MaxHeads +1;
4423 
4424     //
4425     // Calculate the actual number of sectors.
4426     //
4427 
4428     sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >>
4429                                      DeviceExtension->SectorShift);
4430 
4431 #if DBG
4432     if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) {
4433         DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4434             "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4435             sectors, cylinders, tracksPerCylinder, sectorsPerTrack));
4436     }
4437 #endif
4438 
4439     //
4440     // Since the BIOS may not report the full drive, recalculate the drive
4441     // size based on the volume size and the BIOS values for tracks per
4442     // cylinder and sectors per track..
4443     //
4444 
4445     length = tracksPerCylinder * sectorsPerTrack;
4446 
4447     if (length == 0) {
4448 
4449         //
4450         // The BIOS information is bogus.
4451         //
4452 
4453         DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4454         ExFreePool(keyData);
4455         return;
4456     }
4457 
4458     cylinders = sectors / length;
4459 
4460     //
4461     // Update the actual geometry information.
4462     //
4463 
4464     DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack;
4465     DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder;
4466     DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders;
4467     DeviceExtension->DiskGeometry->DiskSize.QuadPart = (LONGLONG)cylinders * tracksPerCylinder * sectorsPerTrack *
4468                                                        DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4469 
4470     DebugPrint((3,
4471                "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4472                sectorsPerTrack,
4473                tracksPerCylinder,
4474                cylinders));
4475 
4476     ExFreePool(keyData);
4477 
4478     foundEZHooker = FALSE;
4479 
4480     if (!DeviceExtension->DMActive) {
4481 
4482         HalExamineMBR(DeviceExtension->DeviceObject,
4483                       DeviceExtension->DiskGeometry->Geometry.BytesPerSector,
4484                       (ULONG)0x55,
4485                       &tmpPtr
4486                       );
4487 
4488         if (tmpPtr) {
4489 
4490             ExFreePool(tmpPtr);
4491             foundEZHooker = TRUE;
4492 
4493         }
4494 
4495     }
4496 
4497     if (DeviceExtension->DMActive || foundEZHooker) {
4498 
4499         while (cylinders > 1024) {
4500 
4501             tracksPerCylinder = tracksPerCylinder*2;
4502             cylinders = cylinders/2;
4503 
4504         }
4505 
4506         //
4507         // int 13 values are always 1 less.
4508         //
4509 
4510         tracksPerCylinder -= 1;
4511         cylinders -= 1;
4512 
4513         //
4514         // DM reserves the CE cylinder
4515         //
4516 
4517         cylinders -= 1;
4518 
4519         DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1;
4520         DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1;
4521 
4522         DeviceExtension->PartitionLength.QuadPart =
4523         DeviceExtension->DiskGeometry->DiskSize.QuadPart =
4524             DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart *
4525                 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack *
4526                 DeviceExtension->DiskGeometry->Geometry.BytesPerSector *
4527                 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder;
4528 
4529         if (DeviceExtension->DMActive) {
4530 
4531             DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4532 
4533         }
4534 
4535     } else {
4536 
4537         DeviceExtension->DMByteSkew = 0;
4538 
4539     }
4540 
4541     return;
4542 
4543 } // end UpdateGeometry()
4544 
4545 
4546 
4547 NTSTATUS
4548 NTAPI
4549 UpdateRemovableGeometry (
4550     IN PDEVICE_OBJECT DeviceObject,
4551     IN PIRP Irp
4552     )
4553 
4554 /*++
4555 
4556 Routine Description:
4557 
4558     This routines updates the size and starting offset of the device.  This is
4559     used when the media on the device may have changed thereby changing the
4560     size of the device.  If this is the physical device then a
4561     ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4562 
4563 Arguments:
4564 
4565     DeviceObject - Supplies the device object whos size needs to be updated.
4566 
4567     Irp - Supplies a reference where the status can be updated.
4568 
4569 Return Value:
4570 
4571     Returns the status of the operation.
4572 
4573 --*/
4574 {
4575 
4576     PDEVICE_EXTENSION         deviceExtension = DeviceObject->DeviceExtension;
4577     PDRIVE_LAYOUT_INFORMATION partitionList;
4578     NTSTATUS                  status;
4579     PDISK_DATA                diskData;
4580     ULONG                     partitionNumber;
4581 
4582     //
4583     // Determine if the size of the partition may have changed because
4584     // the media has changed.
4585     //
4586 
4587     if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
4588 
4589         return(STATUS_SUCCESS);
4590 
4591     }
4592 
4593     //
4594     // If this request is for partition zero then do a read drive
4595     // capacity otherwise do a I/O read partition table.
4596     //
4597 
4598     diskData = (PDISK_DATA) (deviceExtension + 1);
4599 
4600     //
4601     // Read the drive capacity.  If that fails, give up.
4602     //
4603 
4604     status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
4605 
4606     if (!NT_SUCCESS(status)) {
4607         return(status);
4608     }
4609 
4610 #ifdef __REACTOS__
4611     //
4612     // HACK so that we can use NT5+ NTOS functions with this NT4 driver
4613     // for removable devices and avoid an infinite recursive loop between
4614     // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
4615     //
4616     // Check whether the update-count is greater or equal than one
4617     // (and increase it) and if so, reset it and return success.
4618     if (diskData->UpdateRemovableGeometryCount++ >= 1)
4619     {
4620         diskData->UpdateRemovableGeometryCount = 0;
4621         return(STATUS_SUCCESS);
4622     }
4623 #endif
4624 
4625     //
4626     // Read the partition table again.
4627     //
4628 
4629     status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
4630                       deviceExtension->DiskGeometry->Geometry.BytesPerSector,
4631                       TRUE,
4632                       &partitionList);
4633 
4634 #ifdef __REACTOS__
4635     //
4636     // HACK so that we can use NT5+ NTOS functions with this NT4 driver
4637     // for removable devices and avoid an infinite recursive loop between
4638     // disk!UpdateRemovableGeometry() and ntos!IoReadPartitionTable().
4639     //
4640     // Inconditionally reset the update-count.
4641     diskData->UpdateRemovableGeometryCount = 0;
4642 #endif
4643 
4644     if (!NT_SUCCESS(status)) {
4645 
4646         //
4647         // Fail the request.
4648         //
4649 
4650         return(status);
4651     }
4652 
4653     if (diskData->PartitionNumber != 0 &&
4654         diskData->PartitionNumber <= partitionList->PartitionCount ) {
4655 
4656         partitionNumber = diskData->PartitionNumber - 1;
4657 
4658         //
4659         // Update the partition information for this partition.
4660         //
4661 
4662         diskData->PartitionType =
4663             partitionList->PartitionEntry[partitionNumber].PartitionType;
4664 
4665         diskData->BootIndicator =
4666             partitionList->PartitionEntry[partitionNumber].BootIndicator;
4667 
4668         deviceExtension->StartingOffset =
4669             partitionList->PartitionEntry[partitionNumber].StartingOffset;
4670 
4671         deviceExtension->PartitionLength =
4672             partitionList->PartitionEntry[partitionNumber].PartitionLength;
4673 
4674         diskData->HiddenSectors =
4675             partitionList->PartitionEntry[partitionNumber].HiddenSectors;
4676 
4677         deviceExtension->SectorShift = ((PDEVICE_EXTENSION)
4678             deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift;
4679 
4680     } else if (diskData->PartitionNumber != 0) {
4681 
4682         //
4683         // The partition does not exist.  Zero all the data.
4684         //
4685 
4686         diskData->PartitionType = 0;
4687         diskData->BootIndicator = 0;
4688         diskData->HiddenSectors = 0;
4689         deviceExtension->StartingOffset.QuadPart  = (LONGLONG)0;
4690         deviceExtension->PartitionLength.QuadPart = (LONGLONG)0;
4691     }
4692 
4693     //
4694     // Free the partition list allocate by I/O read partition table.
4695     //
4696 
4697     ExFreePool(partitionList);
4698 
4699 
4700     return(STATUS_SUCCESS);
4701 }
4702 
4703 
4704 VOID
4705 NTAPI
4706 ScsiDiskProcessError(
4707     PDEVICE_OBJECT DeviceObject,
4708     PSCSI_REQUEST_BLOCK Srb,
4709     NTSTATUS *Status,
4710     BOOLEAN *Retry
4711     )
4712 /*++
4713 
4714 Routine Description:
4715 
4716    This routine checks the type of error.  If the error indicates an underrun
4717    then indicate the request should be retried.
4718 
4719 Arguments:
4720 
4721     DeviceObject - Supplies a pointer to the device object.
4722 
4723     Srb - Supplies a pointer to the failing Srb.
4724 
4725     Status - Status with which the IRP will be completed.
4726 
4727     Retry - Indication of whether the request will be retried.
4728 
4729 Return Value:
4730 
4731     None.
4732 
4733 --*/
4734 
4735 {
4736     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4737 
4738     if (*Status == STATUS_DATA_OVERRUN &&
4739         ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) {
4740 
4741             *Retry = TRUE;
4742 
4743             //
4744             // Update the error count for the device.
4745             //
4746 
4747             deviceExtension->ErrorCount++;
4748     }
4749 
4750     if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
4751         Srb->ScsiStatus == SCSISTAT_BUSY) {
4752 
4753         //
4754         // The disk drive should never be busy this long. Reset the scsi bus
4755         // maybe this will clear the condition.
4756         //
4757 
4758         ResetScsiBus(DeviceObject);
4759 
4760         //
4761         // Update the error count for the device.
4762         //
4763 
4764         deviceExtension->ErrorCount++;
4765     }
4766 }
4767 
4768 VOID
4769 NTAPI
4770 ScanForSpecial(
4771     PDEVICE_OBJECT DeviceObject,
4772     PSCSI_INQUIRY_DATA LunInfo,
4773     PIO_SCSI_CAPABILITIES PortCapabilities
4774     )
4775 
4776 /*++
4777 
4778 Routine Description:
4779 
4780     This function checks to see if an SCSI logical unit requires special
4781     flags to be set.
4782 
4783 Arguments:
4784 
4785     DeviceObject - Supplies the device object to be tested.
4786 
4787     InquiryData - Supplies the inquiry data returned by the device of interest.
4788 
4789     PortCapabilities - Supplies the capabilities of the device object.
4790 
4791 Return Value:
4792 
4793     None.
4794 
4795 --*/
4796 
4797 {
4798     PDEVICE_EXTENSION          deviceExtension = DeviceObject->DeviceExtension;
4799     PINQUIRYDATA               InquiryData     = (PINQUIRYDATA)LunInfo->InquiryData;
4800     BAD_CONTROLLER_INFORMATION const *controller;
4801     ULONG                      j;
4802 
4803     for (j = 0; j <  NUMBER_OF_BAD_CONTROLLERS; j++) {
4804 
4805         controller = &ScsiDiskBadControllers[j];
4806 
4807         if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
4808             continue;
4809         }
4810 
4811         DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString));
4812 
4813         //
4814         // Found a listed controller.  Determine what must be done.
4815         //
4816 
4817         if (controller->DisableTaggedQueuing) {
4818 
4819             //
4820             // Disable tagged queuing.
4821             //
4822 
4823             deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
4824         }
4825 
4826         if (controller->DisableSynchronousTransfers) {
4827 
4828             //
4829             // Disable synchronous data transfers.
4830             //
4831 
4832             deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
4833 
4834         }
4835 
4836         if (controller->DisableDisconnects) {
4837 
4838             //
4839             // Disable disconnects.
4840             //
4841 
4842             deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
4843 
4844         }
4845 
4846         //
4847         // Found device so exit the loop and return.
4848         //
4849 
4850         break;
4851     }
4852 
4853     //
4854     // Set the StartUnit flag appropriately.
4855     //
4856 
4857     if (DeviceObject->DeviceType == FILE_DEVICE_DISK) {
4858         deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT;
4859 
4860         if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
4861             if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) {
4862                 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT;
4863             }
4864         }
4865     }
4866 
4867     return;
4868 }
4869 
4870 VOID
4871 NTAPI
4872 ResetScsiBus(
4873     IN PDEVICE_OBJECT DeviceObject
4874     )
4875 
4876 /*++
4877 
4878 Routine Description:
4879 
4880     This command sends a reset bus command to the SCSI port driver.
4881 
4882 Arguments:
4883 
4884     DeviceObject - The device object for the logical unit with
4885         hardware problem.
4886 
4887 Return Value:
4888 
4889     None.
4890 
4891 --*/
4892 {
4893     PIO_STACK_LOCATION irpStack;
4894     PIRP irp;
4895     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4896     PSCSI_REQUEST_BLOCK srb;
4897     PCOMPLETION_CONTEXT context;
4898 
4899     DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4900 
4901     //
4902     // Allocate Srb from nonpaged pool.
4903     //
4904 
4905     context = ExAllocatePool(NonPagedPoolMustSucceed,
4906                              sizeof(COMPLETION_CONTEXT));
4907 
4908     //
4909     // Save the device object in the context for use by the completion
4910     // routine.
4911     //
4912 
4913     context->DeviceObject = DeviceObject;
4914     srb = &context->Srb;
4915 
4916     //
4917     // Zero out srb.
4918     //
4919 
4920     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
4921 
4922     //
4923     // Write length to SRB.
4924     //
4925 
4926     srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4927 
4928     //
4929     // Set up SCSI bus address.
4930     //
4931 
4932     srb->PathId = deviceExtension->PathId;
4933     srb->TargetId = deviceExtension->TargetId;
4934     srb->Lun = deviceExtension->Lun;
4935 
4936     srb->Function = SRB_FUNCTION_RESET_BUS;
4937 
4938     //
4939     // Build the asynchronous request to be sent to the port driver.
4940     // Since this routine is called from a DPC the IRP should always be
4941     // available.
4942     //
4943 
4944     irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4945 
4946     IoSetCompletionRoutine(irp,
4947                            (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
4948                            context,
4949                            TRUE,
4950                            TRUE,
4951                            TRUE);
4952 
4953     irpStack = IoGetNextIrpStackLocation(irp);
4954 
4955     irpStack->MajorFunction = IRP_MJ_SCSI;
4956 
4957     srb->OriginalRequest = irp;
4958 
4959     //
4960     // Store the SRB address in next stack for port driver.
4961     //
4962 
4963     irpStack->Parameters.Scsi.Srb = srb;
4964 
4965     //
4966     // Call the port driver with the IRP.
4967     //
4968 
4969     IoCallDriver(deviceExtension->PortDeviceObject, irp);
4970 
4971     return;
4972 
4973 } // end ResetScsiBus()
4974 
4975 
4976 VOID
4977 NTAPI
4978 UpdateDeviceObjects(
4979     IN PDEVICE_OBJECT PhysicalDisk,
4980     IN PIRP Irp
4981     )
4982 
4983 /*++
4984 
4985 Routine Description:
4986 
4987     This routine creates, deletes and changes device objects when
4988     the IOCTL_SET_DRIVE_LAYOUT is called.  This routine also updates
4989     the drive layout information for the user.  It is possible to
4990     call this routine even in the GET_LAYOUT case because RewritePartition
4991     will be false.
4992 
4993 Arguments:
4994 
4995     DeviceObject - Device object for physical disk.
4996     Irp - IO Request Packet (IRP).
4997 
4998 Return Value:
4999 
5000     None.
5001 
5002 --*/
5003 {
5004     PDEVICE_EXTENSION         physicalExtension = PhysicalDisk->DeviceExtension;
5005     PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
5006     ULONG                     partition;
5007     ULONG                     partitionNumber;
5008     ULONG                     partitionCount;
5009     ULONG                     lastPartition;
5010     ULONG                     partitionOrdinal;
5011     PPARTITION_INFORMATION    partitionEntry;
5012     CCHAR                     ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
5013     STRING                    ntNameString;
5014     UNICODE_STRING            ntUnicodeString;
5015     PDEVICE_OBJECT            deviceObject;
5016     PDEVICE_EXTENSION         deviceExtension;
5017     PDISK_DATA                diskData;
5018     NTSTATUS                  status;
5019     ULONG                     numberListElements;
5020     BOOLEAN                   found;
5021 
5022     partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4;
5023 
5024     //
5025     // Zero all of the partition numbers.
5026     //
5027 
5028     for (partition = 0; partition < partitionCount; partition++) {
5029         partitionEntry = &partitionList->PartitionEntry[partition];
5030         partitionEntry->PartitionNumber = 0;
5031     }
5032 
5033     //
5034     // Walk through chain of partitions for this disk to determine
5035     // which existing partitions have no match.
5036     //
5037 
5038     deviceExtension = physicalExtension;
5039     diskData = (PDISK_DATA)(deviceExtension + 1);
5040     lastPartition = 0;
5041 
5042     do {
5043 
5044         deviceExtension = diskData->NextPartition;
5045 
5046         //
5047         // Check if this is the last partition in the chain.
5048         //
5049 
5050         if (!deviceExtension) {
5051            break;
5052         }
5053 
5054         //
5055         // Get the partition device extension from disk data.
5056         //
5057 
5058         diskData = (PDISK_DATA)(deviceExtension + 1);
5059 
5060         //
5061         // Check for highest partition number this far.
5062         //
5063 
5064         if (diskData->PartitionNumber > lastPartition) {
5065            lastPartition = diskData->PartitionNumber;
5066         }
5067 
5068         //
5069         // Check if this partition is not currently being used.
5070         //
5071 
5072         if (!deviceExtension->PartitionLength.QuadPart) {
5073            continue;
5074         }
5075 
5076         //
5077         // Loop through partition information to look for match.
5078         //
5079 
5080         found = FALSE;
5081         partitionOrdinal = 0;
5082 
5083         for (partition = 0; partition < partitionCount; partition++) {
5084 
5085             //
5086             // Get partition descriptor.
5087             //
5088 
5089             partitionEntry = &partitionList->PartitionEntry[partition];
5090 
5091             //
5092             // Check if empty, or describes extended partition or hasn't changed.
5093             //
5094 
5095             if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
5096                 IsContainerPartition(partitionEntry->PartitionType)) {
5097                 continue;
5098             }
5099 
5100             //
5101             // Advance partition ordinal.
5102             //
5103 
5104             partitionOrdinal++;
5105 
5106             //
5107             // Check if new partition starts where this partition starts.
5108             //
5109 
5110             if (partitionEntry->StartingOffset.QuadPart !=
5111                       deviceExtension->StartingOffset.QuadPart) {
5112                 continue;
5113             }
5114 
5115             //
5116             // Check if partition length is the same.
5117             //
5118 
5119             if (partitionEntry->PartitionLength.QuadPart ==
5120                       deviceExtension->PartitionLength.QuadPart) {
5121 
5122                 DebugPrint((3,
5123                            "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
5124                            physicalExtension->DeviceNumber,
5125                            diskData->PartitionNumber));
5126 
5127                 //
5128                 // Indicate match is found and set partition number
5129                 // in user buffer.
5130                 //
5131 
5132                 found = TRUE;
5133                 partitionEntry->PartitionNumber = diskData->PartitionNumber;
5134                 break;
5135             }
5136         }
5137 
5138         if (found) {
5139 
5140             //
5141             // A match is found.
5142             //
5143 
5144             diskData = (PDISK_DATA)(deviceExtension + 1);
5145 
5146             //
5147             // If this partition is marked for update then update partition type.
5148             //
5149 
5150             if (partitionEntry->RewritePartition) {
5151                 diskData->PartitionType = partitionEntry->PartitionType;
5152             }
5153 
5154             //
5155             // Update partitional ordinal for calls to HAL routine
5156             // IoSetPartitionInformation.
5157             //
5158 
5159             diskData->PartitionOrdinal = partitionOrdinal;
5160 
5161             DebugPrint((1,
5162                        "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
5163                        physicalExtension->DeviceNumber,
5164                        diskData->PartitionOrdinal,
5165                        diskData->PartitionNumber));
5166 
5167         } else {
5168 
5169             //
5170             // no match was found, indicate this partition is gone.
5171             //
5172 
5173             DebugPrint((1,
5174                        "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
5175                        physicalExtension->DeviceNumber,
5176                        diskData->PartitionNumber));
5177 
5178             deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
5179         }
5180 
5181     } while (TRUE);
5182 
5183     //
5184     // Walk through partition loop to find new partitions and set up
5185     // device extensions to describe them. In some cases new device
5186     // objects will be created.
5187     //
5188 
5189     partitionOrdinal = 0;
5190 
5191     for (partition = 0;
5192          partition < partitionCount;
5193          partition++) {
5194 
5195         //
5196         // Get partition descriptor.
5197         //
5198 
5199         partitionEntry = &partitionList->PartitionEntry[partition];
5200 
5201         //
5202         // Check if empty, or describes an extended partition.
5203         //
5204 
5205         if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
5206             IsContainerPartition(partitionEntry->PartitionType)) {
5207             continue;
5208         }
5209 
5210         //
5211         // Keep track of position on the disk for calls to IoSetPartitionInformation.
5212         //
5213 
5214         partitionOrdinal++;
5215 
5216         //
5217         // Check if this entry should be rewritten.
5218         //
5219 
5220         if (!partitionEntry->RewritePartition) {
5221             continue;
5222         }
5223 
5224         if (partitionEntry->PartitionNumber) {
5225 
5226             //
5227             // Partition is an exact match with an existing partition, but is
5228             // being written anyway.
5229             //
5230 
5231             continue;
5232         }
5233 
5234         //
5235         // Check first if existing device object is available by
5236         // walking partition extension list.
5237         //
5238 
5239         partitionNumber = 0;
5240         deviceExtension = physicalExtension;
5241         diskData = (PDISK_DATA)(deviceExtension + 1);
5242 
5243         do {
5244 
5245             //
5246             // Get next partition device extension from disk data.
5247             //
5248 
5249             deviceExtension = diskData->NextPartition;
5250 
5251             if (!deviceExtension) {
5252                break;
5253             }
5254 
5255             diskData = (PDISK_DATA)(deviceExtension + 1);
5256 
5257             //
5258             // A device object is free if the partition length is set to zero.
5259             //
5260 
5261             if (!deviceExtension->PartitionLength.QuadPart) {
5262                partitionNumber = diskData->PartitionNumber;
5263                break;
5264             }
5265 
5266         } while (TRUE);
5267 
5268         //
5269         // If partition number is still zero then a new device object
5270         // must be created.
5271         //
5272 
5273         if (partitionNumber == 0) {
5274 
5275             lastPartition++;
5276             partitionNumber = lastPartition;
5277 
5278             //
5279             // Get or create partition object and set up partition parameters.
5280             //
5281 
5282             sprintf(ntNameBuffer,
5283                     "\\Device\\Harddisk%lu\\Partition%lu",
5284                     physicalExtension->DeviceNumber,
5285                     partitionNumber);
5286 
5287             RtlInitString(&ntNameString,
5288                           ntNameBuffer);
5289 
5290             status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
5291                                                   &ntNameString,
5292                                                   TRUE);
5293 
5294             if (!NT_SUCCESS(status)) {
5295                 continue;
5296             }
5297 
5298             DebugPrint((3,
5299                         "UpdateDeviceObjects: Create device object %s\n",
5300                         ntNameBuffer));
5301 
5302             //
5303             // This is a new name. Create the device object to represent it.
5304             //
5305 
5306             status = IoCreateDevice(PhysicalDisk->DriverObject,
5307                                     DEVICE_EXTENSION_SIZE,
5308                                     &ntUnicodeString,
5309                                     FILE_DEVICE_DISK,
5310                                     0,
5311                                     FALSE,
5312                                     &deviceObject);
5313 
5314             if (!NT_SUCCESS(status)) {
5315                 DebugPrint((1,
5316                             "UpdateDeviceObjects: Can't create device %s\n",
5317                             ntNameBuffer));
5318                 RtlFreeUnicodeString(&ntUnicodeString);
5319                 continue;
5320             }
5321 
5322             //
5323             // Set up device object fields.
5324             //
5325 
5326             deviceObject->Flags |= DO_DIRECT_IO;
5327             deviceObject->StackSize = PhysicalDisk->StackSize;
5328 
5329             //
5330             // Set up device extension fields.
5331             //
5332 
5333             deviceExtension = deviceObject->DeviceExtension;
5334 
5335             //
5336             // Copy physical disk extension to partition extension.
5337             //
5338 
5339             RtlMoveMemory(deviceExtension,
5340                           physicalExtension,
5341                           sizeof(DEVICE_EXTENSION));
5342 
5343             //
5344             // Initialize the new S-List.
5345             //
5346 
5347             if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
5348                 numberListElements = 30;
5349             } else {
5350                 numberListElements = 8;
5351             }
5352 
5353             //
5354             // Build the lookaside list for srb's for this partition based on
5355             // whether the adapter and disk can do tagged queueing.
5356             //
5357 
5358             ScsiClassInitializeSrbLookasideList(deviceExtension,
5359                                                 numberListElements);
5360 
5361             //
5362             // Allocate spinlock for zoning for split-request completion.
5363             //
5364 
5365             KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
5366 
5367             //
5368             // Write back partition number used in creating object name.
5369             //
5370 
5371             partitionEntry->PartitionNumber = partitionNumber;
5372 
5373             //
5374             // Clear flags initializing bit.
5375             //
5376 
5377             deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
5378 
5379             //
5380             // Point back at device object.
5381             //
5382 
5383             deviceExtension->DeviceObject = deviceObject;
5384 
5385             RtlFreeUnicodeString(&ntUnicodeString);
5386 
5387             //
5388             // Link to end of partition chain using previous disk data.
5389             //
5390 
5391             diskData->NextPartition = deviceExtension;
5392 
5393             //
5394             // Get new disk data and zero next partition pointer.
5395             //
5396 
5397             diskData = (PDISK_DATA)(deviceExtension + 1);
5398             diskData->NextPartition = NULL;
5399 
5400         } else {
5401 
5402             //
5403             // Set pointer to disk data area that follows device extension.
5404             //
5405 
5406             diskData = (PDISK_DATA)(deviceExtension + 1);
5407 
5408             DebugPrint((1,
5409                         "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5410                         physicalExtension->DeviceNumber,
5411                         partitionNumber));
5412         }
5413 
5414         //
5415         // Update partition information in partition device extension.
5416         //
5417 
5418         diskData->PartitionNumber = partitionNumber;
5419         diskData->PartitionType = partitionEntry->PartitionType;
5420         diskData->BootIndicator = partitionEntry->BootIndicator;
5421         deviceExtension->StartingOffset = partitionEntry->StartingOffset;
5422         deviceExtension->PartitionLength = partitionEntry->PartitionLength;
5423         diskData->HiddenSectors = partitionEntry->HiddenSectors;
5424         diskData->PartitionOrdinal = partitionOrdinal;
5425 
5426         DebugPrint((1,
5427                    "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5428                    diskData->PartitionOrdinal,
5429                    diskData->PartitionNumber));
5430 
5431         //
5432         // Update partition number passed in to indicate the
5433         // device name for this partition.
5434         //
5435 
5436         partitionEntry->PartitionNumber = partitionNumber;
5437     }
5438 
5439 } // end UpdateDeviceObjects()
5440 
5441