8d20fad2964df6a6f94cdd0fbc9e91cf25cd322e
[reactos.git] / reactos / drivers / storage / class / disk / disk.c
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 parition 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 - inidicates that the this device is currenly 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 } DISK_DATA, *PDISK_DATA;
120
121 //
122 // Define a general structure of identfing disk controllers with bad
123 // hardware.
124 //
125
126 typedef struct _BAD_CONTROLLER_INFORMATION {
127 PCHAR InquiryString;
128 BOOLEAN DisableTaggedQueuing;
129 BOOLEAN DisableSynchronousTransfers;
130 BOOLEAN DisableDisconnects;
131 BOOLEAN DisableWriteCache;
132 }BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION;
133
134 BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = {
135 { "TOSHIBA MK538FB 60", TRUE, FALSE, FALSE, FALSE },
136 { "CONNER CP3500", FALSE, TRUE, FALSE, FALSE },
137 { "OLIVETTICP3500", FALSE, TRUE, FALSE, FALSE },
138 { "SyQuest SQ5110 CHC", TRUE, TRUE, FALSE, FALSE },
139 { "SEAGATE ST41601N 0102", FALSE, TRUE, FALSE, FALSE },
140 { "SEAGATE ST3655N", FALSE, FALSE, FALSE, TRUE },
141 { "SEAGATE ST3390N", FALSE, FALSE, FALSE, TRUE },
142 { "SEAGATE ST12550N", FALSE, FALSE, FALSE, TRUE },
143 { "SEAGATE ST32430N", FALSE, FALSE, FALSE, TRUE },
144 { "SEAGATE ST31230N", FALSE, FALSE, FALSE, TRUE },
145 { "SEAGATE ST15230N", FALSE, FALSE, FALSE, TRUE },
146 { "FUJITSU M2652S-512", TRUE, FALSE, FALSE, FALSE },
147 { "MAXTOR MXT-540SL I1.2", TRUE, FALSE, FALSE, FALSE },
148 { "COMPAQ PD-1", FALSE, TRUE, FALSE, FALSE }
149 };
150
151
152 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
153 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
154
155 #define MODE_DATA_SIZE 192
156 #define VALUE_BUFFER_SIZE 2048
157 #define SCSI_DISK_TIMEOUT 10
158 #define PARTITION0_LIST_SIZE 4
159
160 \f
161 NTSTATUS
162 NTAPI
163 DriverEntry(
164 IN PDRIVER_OBJECT DriverObject,
165 IN PUNICODE_STRING RegistryPath
166 );
167
168 BOOLEAN
169 NTAPI
170 ScsiDiskDeviceVerification(
171 IN PINQUIRYDATA InquiryData
172 );
173
174 BOOLEAN
175 NTAPI
176 FindScsiDisks(
177 IN PDRIVER_OBJECT DriveObject,
178 IN PUNICODE_STRING RegistryPath,
179 IN PCLASS_INIT_DATA InitializationData,
180 IN PDEVICE_OBJECT PortDeviceObject,
181 IN ULONG PortNumber
182 );
183
184 NTSTATUS
185 NTAPI
186 ScsiDiskCreateClose (
187 IN PDEVICE_OBJECT DeviceObject,
188 IN PIRP Irp
189 );
190
191 NTSTATUS
192 NTAPI
193 ScsiDiskReadWriteVerification(
194 IN PDEVICE_OBJECT DeviceObject,
195 IN PIRP Irp
196 );
197
198 NTSTATUS
199 NTAPI
200 ScsiDiskDeviceControl(
201 IN PDEVICE_OBJECT DeviceObject,
202 IN PIRP Irp
203 );
204
205 VOID
206 NTAPI
207 ScsiDiskProcessError(
208 PDEVICE_OBJECT DeviceObject,
209 PSCSI_REQUEST_BLOCK Srb,
210 NTSTATUS *Status,
211 BOOLEAN *Retry
212 );
213
214 NTSTATUS
215 NTAPI
216 ScsiDiskShutdownFlush(
217 IN PDEVICE_OBJECT DeviceObject,
218 IN PIRP Irp
219 );
220
221 VOID
222 NTAPI
223 DisableWriteCache(
224 IN PDEVICE_OBJECT DeviceObject,
225 IN PSCSI_INQUIRY_DATA LunInfo
226 );
227
228 BOOLEAN
229 NTAPI
230 ScsiDiskModeSelect(
231 IN PDEVICE_OBJECT DeviceObject,
232 IN PCHAR ModeSelectBuffer,
233 IN ULONG Length,
234 IN BOOLEAN SavePage
235 );
236
237 BOOLEAN
238 NTAPI
239 IsFloppyDevice(
240 IN PDEVICE_OBJECT DeviceObject
241 );
242
243 BOOLEAN
244 NTAPI
245 CalculateMbrCheckSum(
246 IN PDEVICE_EXTENSION DeviceExtension,
247 OUT PULONG Checksum
248 );
249
250 BOOLEAN
251 NTAPI
252 EnumerateBusKey(
253 IN PDEVICE_EXTENSION DeviceExtension,
254 HANDLE BusKey,
255 PULONG DiskNumber
256 );
257
258 VOID
259 NTAPI
260 UpdateGeometry(
261 IN PDEVICE_EXTENSION DeviceExtension
262 );
263
264 NTSTATUS
265 NTAPI
266 UpdateRemovableGeometry (
267 IN PDEVICE_OBJECT DeviceObject,
268 IN PIRP Irp
269 );
270
271 NTSTATUS
272 NTAPI
273 CreateDiskDeviceObject(
274 IN PDRIVER_OBJECT DriverObject,
275 IN PUNICODE_STRING RegistryPath,
276 IN PDEVICE_OBJECT PortDeviceObject,
277 IN ULONG PortNumber,
278 IN PULONG DeviceCount,
279 IN PIO_SCSI_CAPABILITIES PortCapabilities,
280 IN PSCSI_INQUIRY_DATA LunInfo,
281 IN PCLASS_INIT_DATA InitData
282 );
283
284 NTSTATUS
285 NTAPI
286 CreatePartitionDeviceObjects(
287 IN PDEVICE_OBJECT PhysicalDeviceObject,
288 IN PUNICODE_STRING RegistryPath
289 );
290
291 VOID
292 NTAPI
293 UpdateDeviceObjects(
294 IN PDEVICE_OBJECT DeviceObject,
295 IN PIRP Irp
296 );
297
298 VOID
299 NTAPI
300 ScanForSpecial(
301 PDEVICE_OBJECT DeviceObject,
302 PSCSI_INQUIRY_DATA LunInfo,
303 PIO_SCSI_CAPABILITIES PortCapabilities
304 );
305
306 VOID
307 NTAPI
308 ResetScsiBus(
309 IN PDEVICE_OBJECT DeviceObject
310 );
311
312 NTSTATUS
313 NTAPI
314 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject,
315 PIRP Irp);
316
317 #ifdef ALLOC_PRAGMA
318 #pragma alloc_text(PAGE, DriverEntry)
319 #pragma alloc_text(PAGE, FindScsiDisks)
320 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
321 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
322 #pragma alloc_text(PAGE, EnumerateBusKey)
323 #pragma alloc_text(PAGE, UpdateGeometry)
324 #pragma alloc_text(PAGE, IsFloppyDevice)
325 #pragma alloc_text(PAGE, ScanForSpecial)
326 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
327 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
328 #endif
329
330 \f
331 NTSTATUS
332 NTAPI
333 DriverEntry(
334 IN PDRIVER_OBJECT DriverObject,
335 IN PUNICODE_STRING RegistryPath
336 )
337
338 /*++
339
340 Routine Description:
341
342 This routine initializes the SCSI hard disk class driver.
343
344 Arguments:
345
346 DriverObject - Pointer to driver object created by system.
347
348 RegistryPath - Pointer to the name of the services node for this driver.
349
350 Return Value:
351
352 The function value is the final status from the initialization operation.
353
354 --*/
355
356 {
357 CLASS_INIT_DATA InitializationData;
358
359 //
360 // Zero InitData
361 //
362
363 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
364
365 //
366 // Set sizes
367 //
368
369 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
370 InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
371
372 InitializationData.DeviceType = FILE_DEVICE_DISK;
373 InitializationData.DeviceCharacteristics = 0;
374
375 //
376 // Set entry points
377 //
378
379 InitializationData.ClassError = ScsiDiskProcessError;
380 InitializationData.ClassReadWriteVerification = ScsiDiskReadWriteVerification;
381 InitializationData.ClassFindDevices = FindScsiDisks;
382 InitializationData.ClassFindDeviceCallBack = ScsiDiskDeviceVerification;
383 InitializationData.ClassDeviceControl = ScsiDiskDeviceControl;
384 InitializationData.ClassShutdownFlush = ScsiDiskShutdownFlush;
385 InitializationData.ClassCreateClose = NULL;
386
387 //
388 // Call the class init routine
389 //
390
391 return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
392
393 } // end DriverEntry()
394
395
396 \f
397 BOOLEAN
398 NTAPI
399 ScsiDiskDeviceVerification(
400 IN PINQUIRYDATA InquiryData
401 )
402
403 /*++
404
405 Routine Description:
406
407 This routine checks InquiryData for the correct device type and qualifier.
408
409 Arguments:
410
411 InquiryData - Pointer to the inquiry data for the device in question.
412
413 Return Value:
414
415 True is returned if the correct device type is found.
416
417 --*/
418 {
419
420 if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
421 (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
422 InquiryData->DeviceTypeQualifier == 0) {
423
424 return TRUE;
425
426 } else {
427 return FALSE;
428 }
429 }
430
431 \f
432 BOOLEAN
433 NTAPI
434 FindScsiDisks(
435 IN PDRIVER_OBJECT DriverObject,
436 IN PUNICODE_STRING RegistryPath,
437 IN PCLASS_INIT_DATA InitializationData,
438 IN PDEVICE_OBJECT PortDeviceObject,
439 IN ULONG PortNumber
440 )
441
442 /*++
443
444 Routine Description:
445
446 This routine gets a port drivers capabilities, obtains the
447 inquiry data, searches the SCSI bus for the port driver and creates
448 the device objects for the disks found.
449
450 Arguments:
451
452 DriverObject - Pointer to driver object created by system.
453
454 PortDeviceObject - Device object use to send requests to port driver.
455
456 PortNumber - Number for port driver. Used to pass on to
457 CreateDiskDeviceObjects() and create device objects.
458
459 Return Value:
460
461 True is returned if one disk was found and successfully created.
462
463 --*/
464
465 {
466 PIO_SCSI_CAPABILITIES portCapabilities;
467 PULONG diskCount;
468 PCONFIGURATION_INFORMATION configurationInformation;
469 PCHAR buffer;
470 PSCSI_INQUIRY_DATA lunInfo;
471 PSCSI_ADAPTER_BUS_INFO adapterInfo;
472 PINQUIRYDATA inquiryData;
473 ULONG scsiBus;
474 ULONG adapterDisk;
475 NTSTATUS status;
476 BOOLEAN foundOne = FALSE;
477
478 PAGED_CODE();
479
480 //
481 // Call port driver to get adapter capabilities.
482 //
483
484 status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
485
486 if (!NT_SUCCESS(status)) {
487 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
488 return(FALSE);
489 }
490
491 //
492 // Call port driver to get inquiry information to find disks.
493 //
494
495 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
496
497 if (!NT_SUCCESS(status)) {
498 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
499 return(FALSE);
500 }
501
502 //
503 // Do a quick scan of the devices on this adapter to determine how many
504 // disks are on this adapter. This is used to determine the number of
505 // SRB zone elements to allocate.
506 //
507
508 adapterDisk = 0;
509 adapterInfo = (PVOID) buffer;
510
511 adapterDisk = ScsiClassFindUnclaimedDevices(InitializationData, adapterInfo);
512
513 //
514 // Allocate a zone of SRB for disks on this adapter.
515 //
516
517 if (adapterDisk == 0) {
518
519 //
520 // No free disks were found.
521 //
522
523 return(FALSE);
524 }
525
526 //
527 // Get the number of disks already initialized.
528 //
529
530 configurationInformation = IoGetConfigurationInformation();
531 diskCount = &configurationInformation->DiskCount;
532
533 //
534 // For each SCSI bus this adapter supports ...
535 //
536
537 for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
538
539 //
540 // Get the SCSI bus scan data for this bus.
541 //
542
543 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
544
545 //
546 // Search list for unclaimed disk devices.
547 //
548
549 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
550
551 inquiryData = (PVOID)lunInfo->InquiryData;
552
553 if (((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
554 (inquiryData->DeviceType == OPTICAL_DEVICE)) &&
555 inquiryData->DeviceTypeQualifier == 0 &&
556 (!lunInfo->DeviceClaimed)) {
557
558 DebugPrint((1,
559 "FindScsiDevices: Vendor string is %.24s\n",
560 inquiryData->VendorId));
561
562 //
563 // Create device objects for disk
564 //
565
566 status = CreateDiskDeviceObject(DriverObject,
567 RegistryPath,
568 PortDeviceObject,
569 PortNumber,
570 diskCount,
571 portCapabilities,
572 lunInfo,
573 InitializationData);
574
575 if (NT_SUCCESS(status)) {
576
577 //
578 // Increment system disk device count.
579 //
580
581 (*diskCount)++;
582 foundOne = TRUE;
583
584 }
585 }
586
587 //
588 // Get next LunInfo.
589 //
590
591 if (lunInfo->NextInquiryDataOffset == 0) {
592 break;
593 }
594
595 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
596
597 }
598 }
599
600 //
601 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
602 //
603
604 ExFreePool(buffer);
605
606 return(foundOne);
607
608 } // end FindScsiDisks()
609
610 \f
611 NTSTATUS
612 NTAPI
613 CreateDiskDeviceObject(
614 IN PDRIVER_OBJECT DriverObject,
615 IN PUNICODE_STRING RegistryPath,
616 IN PDEVICE_OBJECT PortDeviceObject,
617 IN ULONG PortNumber,
618 IN PULONG DeviceCount,
619 IN PIO_SCSI_CAPABILITIES PortCapabilities,
620 IN PSCSI_INQUIRY_DATA LunInfo,
621 IN PCLASS_INIT_DATA InitData
622 )
623
624 /*++
625
626 Routine Description:
627
628 This routine creates an object for the physical device and then searches
629 the device for partitions and creates an object for each partition.
630
631 Arguments:
632
633 DriverObject - Pointer to driver object created by system.
634
635 PortDeviceObject - Miniport device object.
636
637 PortNumber - port number. Used in creating disk objects.
638
639 DeviceCount - Number of previously installed devices.
640
641 PortCapabilities - Capabilities of this SCSI port.
642
643 LunInfo - LUN specific information.
644
645 Return Value:
646
647 NTSTATUS
648
649 --*/
650 {
651 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
652 STRING ntNameString;
653 UNICODE_STRING ntUnicodeString;
654 OBJECT_ATTRIBUTES objectAttributes;
655 HANDLE handle;
656 NTSTATUS status;
657 PDEVICE_OBJECT deviceObject = NULL;
658 //PDEVICE_OBJECT physicalDevice;
659 PDISK_GEOMETRY_EX diskGeometry = NULL;
660 PDEVICE_EXTENSION deviceExtension = NULL;
661 //PDEVICE_EXTENSION physicalDeviceExtension;
662 UCHAR pathId = LunInfo->PathId;
663 UCHAR targetId = LunInfo->TargetId;
664 UCHAR lun = LunInfo->Lun;
665 //BOOLEAN writeCache;
666 PVOID senseData = NULL;
667 //ULONG srbFlags;
668 ULONG timeOut = 0;
669 BOOLEAN srbListInitialized = FALSE;
670
671
672 PAGED_CODE();
673
674 //
675 // Set up an object directory to contain the objects for this
676 // device and all its partitions.
677 //
678
679 sprintf(ntNameBuffer,
680 "\\Device\\Harddisk%lu",
681 *DeviceCount);
682
683 RtlInitString(&ntNameString,
684 ntNameBuffer);
685
686 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
687 &ntNameString,
688 TRUE);
689
690 if (!NT_SUCCESS(status)) {
691 return(status);
692 }
693
694 InitializeObjectAttributes(&objectAttributes,
695 &ntUnicodeString,
696 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
697 NULL,
698 NULL);
699
700 status = ZwCreateDirectoryObject(&handle,
701 DIRECTORY_ALL_ACCESS,
702 &objectAttributes);
703
704 RtlFreeUnicodeString(&ntUnicodeString);
705
706 if (!NT_SUCCESS(status)) {
707
708 DebugPrint((1,
709 "CreateDiskDeviceObjects: Could not create directory %s\n",
710 ntNameBuffer));
711
712 return(status);
713 }
714
715 //
716 // Claim the device.
717 //
718
719 status = ScsiClassClaimDevice(PortDeviceObject,
720 LunInfo,
721 FALSE,
722 &PortDeviceObject);
723
724 if (!NT_SUCCESS(status)) {
725 ZwMakeTemporaryObject(handle);
726 ZwClose(handle);
727 return status;
728 }
729
730 //
731 // Create a device object for this device. Each physical disk will
732 // have at least one device object. The required device object
733 // describes the entire device. Its directory path is
734 // \Device\HarddiskN\Partition0, where N = device number.
735 //
736
737 sprintf(ntNameBuffer,
738 "\\Device\\Harddisk%lu\\Partition0",
739 *DeviceCount);
740
741
742 status = ScsiClassCreateDeviceObject(DriverObject,
743 ntNameBuffer,
744 NULL,
745 &deviceObject,
746 InitData);
747
748 if (!NT_SUCCESS(status)) {
749
750 DebugPrint((1,
751 "CreateDiskDeviceObjects: Can not create device object %s\n",
752 ntNameBuffer));
753
754 goto CreateDiskDeviceObjectsExit;
755 }
756
757 //
758 // Indicate that IRPs should include MDLs for data transfers.
759 //
760
761 deviceObject->Flags |= DO_DIRECT_IO;
762
763 //
764 // Check if this is during initialization. If not indicate that
765 // system initialization already took place and this disk is ready
766 // to be accessed.
767 //
768
769 if (!RegistryPath) {
770 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
771 }
772
773 //
774 // Check for removable media support.
775 //
776
777 if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) {
778 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
779 }
780
781 //
782 // Set up required stack size in device object.
783 //
784
785 deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
786
787 deviceExtension = deviceObject->DeviceExtension;
788
789 //
790 // Allocate spinlock for split request completion.
791 //
792
793 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
794
795 //
796 // Initialize lock count to zero. The lock count is used to
797 // disable the ejection mechanism on devices that support
798 // removable media. Only the lock count in the physical
799 // device extension is used.
800 //
801
802 deviceExtension->LockCount = 0;
803
804 //
805 // Save system disk number.
806 //
807
808 deviceExtension->DeviceNumber = *DeviceCount;
809
810 //
811 // Copy port device object pointer to the device extension.
812 //
813
814 deviceExtension->PortDeviceObject = PortDeviceObject;
815
816 //
817 // Set the alignment requirements for the device based on the
818 // host adapter requirements
819 //
820
821 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
822 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
823 }
824
825 //
826 // This is the physical device object.
827 //
828
829 //physicalDevice = deviceObject;
830 //physicalDeviceExtension = deviceExtension;
831
832 //
833 // Save address of port driver capabilities.
834 //
835
836 deviceExtension->PortCapabilities = PortCapabilities;
837
838 //
839 // Build the lookaside list for srb's for the physical disk. Should only
840 // need a couple.
841 //
842
843 ScsiClassInitializeSrbLookasideList(deviceExtension,
844 PARTITION0_LIST_SIZE);
845
846 srbListInitialized = TRUE;
847
848 //
849 // Initialize the srb flags.
850 //
851
852 if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue &&
853 PortCapabilities->TaggedQueuing) {
854
855 deviceExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE;
856
857 } else {
858
859 deviceExtension->SrbFlags = 0;
860
861 }
862
863 //
864 // Allow queued requests if this is not removable media.
865 //
866
867 if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
868
869 deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
870
871 }
872
873 //
874 // Look for controller that require special flags.
875 //
876
877 ScanForSpecial(deviceObject,
878 LunInfo,
879 PortCapabilities);
880
881 //srbFlags = deviceExtension->SrbFlags;
882
883 //
884 // Allocate buffer for drive geometry.
885 //
886
887 diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX));
888
889 if (diskGeometry == NULL) {
890
891 DebugPrint((1,
892 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
893 status = STATUS_INSUFFICIENT_RESOURCES;
894 goto CreateDiskDeviceObjectsExit;
895 }
896
897 deviceExtension->DiskGeometry = diskGeometry;
898
899 //
900 // Allocate request sense buffer.
901 //
902
903 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
904
905 if (senseData == NULL) {
906
907 //
908 // The buffer can not be allocated.
909 //
910
911 DebugPrint((1,
912 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
913
914 status = STATUS_INSUFFICIENT_RESOURCES;
915 goto CreateDiskDeviceObjectsExit;
916 }
917
918 //
919 // Set the sense data pointer in the device extension.
920 //
921
922 deviceExtension->SenseData = senseData;
923
924 //
925 // Physical device object will describe the entire
926 // device, starting at byte offset 0.
927 //
928
929 deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0);
930
931 //
932 // TargetId/LUN describes a device location on the SCSI bus.
933 // This information comes from the inquiry buffer.
934 //
935
936 deviceExtension->PortNumber = (UCHAR)PortNumber;
937 deviceExtension->PathId = pathId;
938 deviceExtension->TargetId = targetId;
939 deviceExtension->Lun = lun;
940
941 //
942 // Set timeout value in seconds.
943 //
944
945 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
946 if (timeOut) {
947 deviceExtension->TimeOutValue = timeOut;
948 } else {
949 deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
950 }
951
952 //
953 // Back pointer to device object.
954 //
955
956 deviceExtension->DeviceObject = deviceObject;
957
958 //
959 // If this is a removable device, then make sure it is not a floppy.
960 // Perform a mode sense command to determine the media type. Note
961 // IsFloppyDevice also checks for write cache enabled.
962 //
963
964 if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
965 (((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) {
966
967 status = STATUS_NO_SUCH_DEVICE;
968 goto CreateDiskDeviceObjectsExit;
969 }
970
971 DisableWriteCache(deviceObject,LunInfo);
972
973 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
974
975 //
976 // NOTE: At this point one device object has been successfully created.
977 // from here on out return success.
978 //
979
980 //
981 // Do READ CAPACITY. This SCSI command
982 // returns the number of bytes on a device.
983 // Device extension is updated with device size.
984 //
985
986 status = ScsiClassReadDriveCapacity(deviceObject);
987
988 //
989 // If the read capcity failed then just return, unless this is a
990 // removable disk where a device object partition needs to be created.
991 //
992
993 if (!NT_SUCCESS(status) &&
994 !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
995
996 DebugPrint((1,
997 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
998 ntNameBuffer));
999
1000 return(STATUS_SUCCESS);
1001
1002 } else {
1003
1004 //
1005 // Make sure the volume verification bit is off so that
1006 // IoReadPartitionTable will work.
1007 //
1008
1009 deviceObject->Flags &= ~DO_VERIFY_VOLUME;
1010 }
1011
1012 status = CreatePartitionDeviceObjects(deviceObject, RegistryPath);
1013
1014 if (NT_SUCCESS(status))
1015 return STATUS_SUCCESS;
1016
1017
1018 CreateDiskDeviceObjectsExit:
1019
1020 //
1021 // Release the device since an error occurred.
1022 //
1023
1024 ScsiClassClaimDevice(PortDeviceObject,
1025 LunInfo,
1026 TRUE,
1027 NULL);
1028
1029 if (diskGeometry != NULL) {
1030 ExFreePool(diskGeometry);
1031 }
1032
1033 if (senseData != NULL) {
1034 ExFreePool(senseData);
1035 }
1036
1037 if (deviceObject != NULL) {
1038
1039 if (srbListInitialized) {
1040 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
1041 }
1042
1043 IoDeleteDevice(deviceObject);
1044 }
1045
1046 //
1047 // Delete directory and return.
1048 //
1049
1050 if (!NT_SUCCESS(status)) {
1051 ZwMakeTemporaryObject(handle);
1052 }
1053
1054 ZwClose(handle);
1055
1056 return(status);
1057
1058 } // end CreateDiskDeviceObjects()
1059
1060 \f
1061 NTSTATUS
1062 NTAPI
1063 CreatePartitionDeviceObjects(
1064 IN PDEVICE_OBJECT PhysicalDeviceObject,
1065 IN PUNICODE_STRING RegistryPath
1066 )
1067 {
1068 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
1069 ULONG partitionNumber = 0;
1070 NTSTATUS status;
1071 PDEVICE_OBJECT deviceObject = NULL;
1072 PDISK_GEOMETRY_EX diskGeometry = NULL;
1073 PDRIVE_LAYOUT_INFORMATION partitionList = NULL;
1074 PDEVICE_EXTENSION deviceExtension;
1075 PDEVICE_EXTENSION physicalDeviceExtension;
1076 PCLASS_INIT_DATA initData = NULL;
1077 PDISK_DATA diskData;
1078 PDISK_DATA physicalDiskData;
1079 ULONG bytesPerSector;
1080 UCHAR sectorShift;
1081 ULONG srbFlags;
1082 ULONG dmByteSkew = 0;
1083 PULONG dmSkew;
1084 BOOLEAN dmActive = FALSE;
1085 ULONG numberListElements = 0;
1086
1087
1088 //
1089 // Get physical device geometry information for partition table reads.
1090 //
1091
1092 physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension;
1093 diskGeometry = physicalDeviceExtension->DiskGeometry;
1094 bytesPerSector = diskGeometry->Geometry.BytesPerSector;
1095
1096 //
1097 // Make sure sector size is not zero.
1098 //
1099
1100 if (bytesPerSector == 0) {
1101
1102 //
1103 // Default sector size for disk is 512.
1104 //
1105
1106 bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512;
1107 }
1108
1109 sectorShift = physicalDeviceExtension->SectorShift;
1110
1111 //
1112 // Set pointer to disk data area that follows device extension.
1113 //
1114
1115 diskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1116 diskData->PartitionListState = Initializing;
1117
1118 //
1119 // Determine is DM Driver is loaded on an IDE drive that is
1120 // under control of Atapi - this could be either a crashdump or
1121 // an Atapi device is sharing the controller with an IDE disk.
1122 //
1123
1124 HalExamineMBR(PhysicalDeviceObject,
1125 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1126 (ULONG)0x54,
1127 (PVOID)&dmSkew);
1128
1129 if (dmSkew) {
1130
1131 //
1132 // Update the device extension, so that the call to IoReadPartitionTable
1133 // will get the correct information. Any I/O to this disk will have
1134 // to be skewed by *dmSkew sectors aka DMByteSkew.
1135 //
1136
1137 physicalDeviceExtension->DMSkew = *dmSkew;
1138 physicalDeviceExtension->DMActive = TRUE;
1139 physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector;
1140
1141 //
1142 // Save away the infomation that we need, since this deviceExtension will soon be
1143 // blown away.
1144 //
1145
1146 dmActive = TRUE;
1147 dmByteSkew = physicalDeviceExtension->DMByteSkew;
1148
1149 }
1150
1151 //
1152 // Create objects for all the partitions on the device.
1153 //
1154
1155 status = IoReadPartitionTable(PhysicalDeviceObject,
1156 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1157 TRUE,
1158 (PVOID)&partitionList);
1159
1160 //
1161 // If the I/O read partition table failed and this is a removable device,
1162 // then fix up the partition list to make it look like there is one
1163 // zero length partition.
1164 //
1165 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status);
1166 if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
1167 PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1168
1169 if (!NT_SUCCESS(status)) {
1170
1171 //
1172 // Remember this disk is not ready.
1173 //
1174
1175 diskData->DriveNotReady = TRUE;
1176
1177 } else {
1178
1179 //
1180 // Free the partition list allocated by IoReadPartitionTable.
1181 //
1182
1183 ExFreePool(partitionList);
1184 }
1185
1186 //
1187 // Allocate and zero a partition list.
1188 //
1189
1190 partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList));
1191
1192
1193 if (partitionList != NULL) {
1194
1195 RtlZeroMemory( partitionList, sizeof( *partitionList ));
1196
1197 //
1198 // Set the partition count to one and the status to success
1199 // so one device object will be created. Set the partition type
1200 // to a bogus value.
1201 //
1202
1203 partitionList->PartitionCount = 1;
1204
1205 status = STATUS_SUCCESS;
1206 }
1207 }
1208
1209 if (NT_SUCCESS(status)) {
1210
1211 //
1212 // Record disk signature.
1213 //
1214
1215 diskData->Signature = partitionList->Signature;
1216
1217 //
1218 // If disk signature is zero, then calculate the MBR checksum.
1219 //
1220
1221 if (!diskData->Signature) {
1222
1223 if (!CalculateMbrCheckSum(physicalDeviceExtension,
1224 &diskData->MbrCheckSum)) {
1225
1226 DebugPrint((1,
1227 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1228 physicalDeviceExtension->DeviceNumber));
1229 } else {
1230
1231 DebugPrint((2,
1232 "SCSIDISK: MBR checksum for disk %x is %x\n",
1233 physicalDeviceExtension->DeviceNumber,
1234 diskData->MbrCheckSum));
1235 }
1236 }
1237
1238 //
1239 // Check the registry and determine if the BIOS knew about this drive. If
1240 // it did then update the geometry with the BIOS information.
1241 //
1242
1243 UpdateGeometry(physicalDeviceExtension);
1244
1245 srbFlags = physicalDeviceExtension->SrbFlags;
1246
1247 initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA));
1248 if (!initData)
1249 {
1250 DebugPrint((1,
1251 "Disk.CreatePartionDeviceObjects - Allocation of initData failed\n"));
1252
1253 status = STATUS_INSUFFICIENT_RESOURCES;
1254 goto CreatePartitionDeviceObjectsExit;
1255 }
1256
1257 RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA));
1258
1259 initData->InitializationDataSize = sizeof(CLASS_INIT_DATA);
1260 initData->DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
1261 initData->DeviceType = FILE_DEVICE_DISK;
1262 initData->DeviceCharacteristics = PhysicalDeviceObject->Characteristics;
1263 initData->ClassError = physicalDeviceExtension->ClassError;
1264 initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification;
1265 initData->ClassFindDevices = physicalDeviceExtension->ClassFindDevices;
1266 initData->ClassDeviceControl = physicalDeviceExtension->ClassDeviceControl;
1267 initData->ClassShutdownFlush = physicalDeviceExtension->ClassShutdownFlush;
1268 initData->ClassCreateClose = physicalDeviceExtension->ClassCreateClose;
1269 initData->ClassStartIo = physicalDeviceExtension->ClassStartIo;
1270
1271 //
1272 // Create device objects for the device partitions (if any).
1273 // PartitionCount includes physical device partition 0,
1274 // so only one partition means no objects to create.
1275 //
1276
1277 DebugPrint((2,
1278 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1279 partitionList->PartitionCount));
1280
1281 for (partitionNumber = 0; partitionNumber <
1282 partitionList->PartitionCount; partitionNumber++) {
1283
1284 //
1285 // Create partition object and set up partition parameters.
1286 //
1287
1288 sprintf(ntNameBuffer,
1289 "\\Device\\Harddisk%lu\\Partition%lu",
1290 physicalDeviceExtension->DeviceNumber,
1291 partitionNumber + 1);
1292
1293 DebugPrint((2,
1294 "CreateDiskDeviceObjects: Create device object %s\n",
1295 ntNameBuffer));
1296
1297 status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject,
1298 ntNameBuffer,
1299 PhysicalDeviceObject,
1300 &deviceObject,
1301 initData);
1302
1303 if (!NT_SUCCESS(status)) {
1304
1305 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer));
1306
1307 break;
1308 }
1309
1310 //
1311 // Set up device object fields.
1312 //
1313
1314 deviceObject->Flags |= DO_DIRECT_IO;
1315
1316 //
1317 // Check if this is during initialization. If not indicate that
1318 // system initialization already took place and this disk is ready
1319 // to be accessed.
1320 //
1321
1322 if (!RegistryPath) {
1323 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1324 }
1325
1326 deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1;
1327
1328 //
1329 // Set up device extension fields.
1330 //
1331
1332 deviceExtension = deviceObject->DeviceExtension;
1333
1334 if (dmActive) {
1335
1336 //
1337 // Restore any saved DM values.
1338 //
1339
1340 deviceExtension->DMByteSkew = dmByteSkew;
1341 deviceExtension->DMSkew = *dmSkew;
1342 deviceExtension->DMActive = TRUE;
1343
1344 }
1345
1346 //
1347 // Link new device extension to previous disk data
1348 // to support dynamic partitioning.
1349 //
1350
1351 diskData->NextPartition = deviceExtension;
1352
1353 //
1354 // Get pointer to new disk data.
1355 //
1356
1357 diskData = (PDISK_DATA)(deviceExtension + 1);
1358
1359 //
1360 // Set next partition pointer to NULL in case this is the
1361 // last partition.
1362 //
1363
1364 diskData->NextPartition = NULL;
1365
1366 //
1367 // Allocate spinlock for zoning for split-request completion.
1368 //
1369
1370 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
1371
1372 //
1373 // Copy port device object pointer to device extension.
1374 //
1375
1376 deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject;
1377
1378 //
1379 // Set the alignment requirements for the device based on the
1380 // host adapter requirements
1381 //
1382
1383 if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
1384 deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement;
1385 }
1386
1387
1388 if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
1389 numberListElements = 30;
1390 } else {
1391 numberListElements = 8;
1392 }
1393
1394 //
1395 // Build the lookaside list for srb's for this partition based on
1396 // whether the adapter and disk can do tagged queueing.
1397 //
1398
1399 ScsiClassInitializeSrbLookasideList(deviceExtension,
1400 numberListElements);
1401
1402 deviceExtension->SrbFlags = srbFlags;
1403
1404 //
1405 // Set the sense-data pointer in the device extension.
1406 //
1407
1408 deviceExtension->SenseData = physicalDeviceExtension->SenseData;
1409 deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities;
1410 deviceExtension->DiskGeometry = diskGeometry;
1411 diskData->PartitionOrdinal = diskData->PartitionNumber = partitionNumber + 1;
1412 diskData->PartitionType = partitionList->PartitionEntry[partitionNumber].PartitionType;
1413 diskData->BootIndicator = partitionList->PartitionEntry[partitionNumber].BootIndicator;
1414
1415 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1416 diskData->PartitionType));
1417
1418 deviceExtension->StartingOffset = partitionList->PartitionEntry[partitionNumber].StartingOffset;
1419 deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength;
1420 diskData->HiddenSectors = partitionList->PartitionEntry[partitionNumber].HiddenSectors;
1421 deviceExtension->PortNumber = physicalDeviceExtension->PortNumber;
1422 deviceExtension->PathId = physicalDeviceExtension->PathId;
1423 deviceExtension->TargetId = physicalDeviceExtension->TargetId;
1424 deviceExtension->Lun = physicalDeviceExtension->Lun;
1425
1426 //
1427 // Check for removable media support.
1428 //
1429
1430 if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1431 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
1432 }
1433
1434 //
1435 // Set timeout value in seconds.
1436 //
1437
1438 deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue;
1439 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector;
1440 deviceExtension->SectorShift = sectorShift;
1441 deviceExtension->DeviceObject = deviceObject;
1442 deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags;
1443
1444 } // end for (partitionNumber) ...
1445
1446 //
1447 // Free the buffer allocated by reading the
1448 // partition table.
1449 //
1450
1451 ExFreePool(partitionList);
1452
1453 if (dmSkew) {
1454 ExFreePool(dmSkew);
1455 }
1456
1457 } else {
1458
1459 CreatePartitionDeviceObjectsExit:
1460
1461 if (partitionList) {
1462 ExFreePool(partitionList);
1463 }
1464 if (initData) {
1465 ExFreePool(initData);
1466 }
1467
1468 if (dmSkew) {
1469 ExFreePool(dmSkew);
1470 }
1471
1472 return status;
1473
1474 } // end if...else
1475
1476
1477 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1478 physicalDiskData->PartitionListState = Initialized;
1479
1480 return(STATUS_SUCCESS);
1481
1482
1483 } // end CreatePartitionDeviceObjects()
1484
1485 \f
1486 NTSTATUS
1487 NTAPI
1488 ScsiDiskReadWriteVerification(
1489 IN PDEVICE_OBJECT DeviceObject,
1490 IN PIRP Irp
1491 )
1492
1493 /*++
1494
1495 Routine Description:
1496
1497 I/O System entry for read and write requests to SCSI disks.
1498
1499 Arguments:
1500
1501 DeviceObject - Pointer to driver object created by system.
1502 Irp - IRP involved.
1503
1504 Return Value:
1505
1506 NT Status
1507
1508 --*/
1509
1510 {
1511 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1512 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1513 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1514 LARGE_INTEGER startingOffset;
1515
1516 //
1517 // HACK: How can we end here with null sector size?!
1518 //
1519
1520 if (deviceExtension->DiskGeometry->Geometry.BytesPerSector == 0) {
1521 DPRINT1("Hack! Received invalid sector size\n");
1522 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512;
1523 }
1524
1525 //
1526 // Verify parameters of this request.
1527 // Check that ending sector is within partition and
1528 // that number of bytes to transfer is a multiple of
1529 // the sector size.
1530 //
1531
1532 startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
1533 transferByteCount);
1534
1535 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
1536 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
1537
1538 //
1539 // This error maybe caused by the fact that the drive is not ready.
1540 //
1541
1542 if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) {
1543
1544 //
1545 // Flag this as a user errror so that a popup is generated.
1546 //
1547
1548 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
1549 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1550
1551 } else {
1552
1553 //
1554 // Note fastfat depends on this parameter to determine when to
1555 // remount do to a sector size change.
1556 //
1557
1558 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1559 }
1560
1561 if (startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) {
1562 DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset.QuadPart, deviceExtension->PartitionLength.QuadPart);
1563 }
1564
1565 if (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1)) {
1566 DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount, deviceExtension->DiskGeometry->Geometry.BytesPerSector);
1567 }
1568
1569 if (Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) {
1570 DPRINT1("Failing due to device not ready!\n");
1571 }
1572
1573 return STATUS_INVALID_PARAMETER;
1574 }
1575
1576 return STATUS_SUCCESS;
1577
1578 } // end ScsiDiskReadWrite()
1579
1580 \f
1581 NTSTATUS
1582 NTAPI
1583 ScsiDiskDeviceControl(
1584 PDEVICE_OBJECT DeviceObject,
1585 PIRP Irp
1586 )
1587
1588 /*++
1589
1590 Routine Description:
1591
1592 I/O system entry for device controls to SCSI disks.
1593
1594 Arguments:
1595
1596 DeviceObject - Pointer to driver object created by system.
1597 Irp - IRP involved.
1598
1599 Return Value:
1600
1601 Status is returned.
1602
1603 --*/
1604
1605 {
1606 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1607 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1608 PDISK_DATA diskData = (PDISK_DATA)(deviceExtension + 1);
1609 PSCSI_REQUEST_BLOCK srb;
1610 PCDB cdb;
1611 PMODE_PARAMETER_HEADER modeData;
1612 PIRP irp2;
1613 ULONG length;
1614 NTSTATUS status;
1615 KEVENT event;
1616 IO_STATUS_BLOCK ioStatus;
1617
1618 PAGED_CODE();
1619
1620 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
1621
1622 if (srb == NULL) {
1623
1624 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1625 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1626 return(STATUS_INSUFFICIENT_RESOURCES);
1627 }
1628
1629 //
1630 // Write zeros to Srb.
1631 //
1632
1633 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1634
1635 cdb = (PCDB)srb->Cdb;
1636
1637 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1638
1639 case SMART_GET_VERSION: {
1640
1641 ULONG_PTR buffer;
1642 PSRB_IO_CONTROL srbControl;
1643 PGETVERSIONINPARAMS versionParams;
1644
1645 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1646 sizeof(GETVERSIONINPARAMS)) {
1647 status = STATUS_INVALID_PARAMETER;
1648 break;
1649 }
1650
1651 //
1652 // Create notification event object to be used to signal the
1653 // request completion.
1654 //
1655
1656 KeInitializeEvent(&event, NotificationEvent, FALSE);
1657
1658 srbControl = ExAllocatePool(NonPagedPool,
1659 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
1660
1661 if (!srbControl) {
1662 status = STATUS_INSUFFICIENT_RESOURCES;
1663 break;
1664 }
1665
1666 //
1667 // fill in srbControl fields
1668 //
1669
1670 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1671 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1672 srbControl->Timeout = deviceExtension->TimeOutValue;
1673 srbControl->Length = sizeof(GETVERSIONINPARAMS);
1674 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
1675
1676 //
1677 // Point to the 'buffer' portion of the SRB_CONTROL
1678 //
1679
1680 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1681
1682 //
1683 // Ensure correct target is set in the cmd parameters.
1684 //
1685
1686 versionParams = (PGETVERSIONINPARAMS)buffer;
1687 versionParams->bIDEDeviceMap = deviceExtension->TargetId;
1688
1689 //
1690 // Copy the IOCTL parameters to the srb control buffer area.
1691 //
1692
1693 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS));
1694
1695
1696 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1697 deviceExtension->PortDeviceObject,
1698 srbControl,
1699 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1700 srbControl,
1701 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1702 FALSE,
1703 &event,
1704 &ioStatus);
1705
1706 if (irp2 == NULL) {
1707 status = STATUS_INSUFFICIENT_RESOURCES;
1708 break;
1709 }
1710
1711 //
1712 // Call the port driver with the request and wait for it to complete.
1713 //
1714
1715 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1716
1717 if (status == STATUS_PENDING) {
1718 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1719 status = ioStatus.Status;
1720 }
1721
1722 //
1723 // If successful, copy the data received into the output buffer.
1724 // This should only fail in the event that the IDE driver is older than this driver.
1725 //
1726
1727 if (NT_SUCCESS(status)) {
1728
1729 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1730
1731 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS));
1732 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1733 }
1734
1735 ExFreePool(srbControl);
1736 break;
1737 }
1738
1739 case SMART_RCV_DRIVE_DATA: {
1740
1741 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1742 ULONG controlCode = 0;
1743 PSRB_IO_CONTROL srbControl;
1744 ULONG_PTR buffer;
1745
1746 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1747 (sizeof(SENDCMDINPARAMS) - 1)) {
1748 status = STATUS_INVALID_PARAMETER;
1749 break;
1750
1751 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1752 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
1753 status = STATUS_INVALID_PARAMETER;
1754 break;
1755 }
1756
1757 //
1758 // Create notification event object to be used to signal the
1759 // request completion.
1760 //
1761
1762 KeInitializeEvent(&event, NotificationEvent, FALSE);
1763
1764 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
1765
1766 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1767 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
1768
1769 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1770 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1771 case READ_ATTRIBUTES:
1772 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
1773 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1774 break;
1775 case READ_THRESHOLDS:
1776 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
1777 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1778 break;
1779 default:
1780 status = STATUS_INVALID_PARAMETER;
1781 break;
1782 }
1783 } else {
1784
1785 status = STATUS_INVALID_PARAMETER;
1786 }
1787
1788 if (controlCode == 0) {
1789 status = STATUS_INVALID_PARAMETER;
1790 break;
1791 }
1792
1793 srbControl = ExAllocatePool(NonPagedPool,
1794 sizeof(SRB_IO_CONTROL) + length);
1795
1796 if (!srbControl) {
1797 status = STATUS_INSUFFICIENT_RESOURCES;
1798 break;
1799 }
1800
1801 //
1802 // fill in srbControl fields
1803 //
1804
1805 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1806 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1807 srbControl->Timeout = deviceExtension->TimeOutValue;
1808 srbControl->Length = length;
1809 srbControl->ControlCode = controlCode;
1810
1811 //
1812 // Point to the 'buffer' portion of the SRB_CONTROL
1813 //
1814
1815 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1816
1817 //
1818 // Ensure correct target is set in the cmd parameters.
1819 //
1820
1821 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1822
1823 //
1824 // Copy the IOCTL parameters to the srb control buffer area.
1825 //
1826
1827 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1828
1829 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1830 deviceExtension->PortDeviceObject,
1831 srbControl,
1832 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1833 srbControl,
1834 sizeof(SRB_IO_CONTROL) + length,
1835 FALSE,
1836 &event,
1837 &ioStatus);
1838
1839 if (irp2 == NULL) {
1840 status = STATUS_INSUFFICIENT_RESOURCES;
1841 break;
1842 }
1843
1844 //
1845 // Call the port driver with the request and wait for it to complete.
1846 //
1847
1848 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1849
1850 if (status == STATUS_PENDING) {
1851 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1852 status = ioStatus.Status;
1853 }
1854
1855 //
1856 // If successful, copy the data received into the output buffer
1857 //
1858
1859 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1860
1861 if (NT_SUCCESS(status)) {
1862
1863 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1);
1864 Irp->IoStatus.Information = length - 1;
1865
1866 } else {
1867
1868 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
1869 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
1870
1871 }
1872
1873 ExFreePool(srbControl);
1874 break;
1875
1876 }
1877
1878 case SMART_SEND_DRIVE_COMMAND: {
1879
1880 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1881 PSRB_IO_CONTROL srbControl;
1882 ULONG controlCode = 0;
1883 ULONG_PTR buffer;
1884
1885 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1886 (sizeof(SENDCMDINPARAMS) - 1)) {
1887 status = STATUS_INVALID_PARAMETER;
1888 break;
1889
1890 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1891 (sizeof(SENDCMDOUTPARAMS) - 1)) {
1892 status = STATUS_INVALID_PARAMETER;
1893 break;
1894 }
1895
1896 //
1897 // Create notification event object to be used to signal the
1898 // request completion.
1899 //
1900
1901 KeInitializeEvent(&event, NotificationEvent, FALSE);
1902
1903 length = 0;
1904
1905 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1906 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1907
1908 case ENABLE_SMART:
1909 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
1910 break;
1911
1912 case DISABLE_SMART:
1913 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
1914 break;
1915
1916 case RETURN_SMART_STATUS:
1917
1918 //
1919 // Ensure bBuffer is at least 2 bytes (to hold the values of
1920 // cylinderLow and cylinderHigh).
1921 //
1922
1923 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1924 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
1925
1926 status = STATUS_INVALID_PARAMETER;
1927 break;
1928 }
1929
1930 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
1931 length = sizeof(IDEREGS);
1932 break;
1933
1934 case ENABLE_DISABLE_AUTOSAVE:
1935 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
1936 break;
1937
1938 case SAVE_ATTRIBUTE_VALUES:
1939 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
1940 break;
1941
1942 case EXECUTE_OFFLINE_DIAGS:
1943 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
1944 break;
1945
1946 default:
1947 status = STATUS_INVALID_PARAMETER;
1948 break;
1949 }
1950 } else {
1951
1952 status = STATUS_INVALID_PARAMETER;
1953 }
1954
1955 if (controlCode == 0) {
1956 status = STATUS_INVALID_PARAMETER;
1957 break;
1958 }
1959
1960 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);
1961 srbControl = ExAllocatePool(NonPagedPool,
1962 sizeof(SRB_IO_CONTROL) + length);
1963
1964 if (!srbControl) {
1965 status = STATUS_INSUFFICIENT_RESOURCES;
1966 break;
1967 }
1968
1969 //
1970 // fill in srbControl fields
1971 //
1972
1973 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1974 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1975 srbControl->Timeout = deviceExtension->TimeOutValue;
1976 srbControl->Length = length;
1977
1978 //
1979 // Point to the 'buffer' portion of the SRB_CONTROL
1980 //
1981
1982 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1983
1984 //
1985 // Ensure correct target is set in the cmd parameters.
1986 //
1987
1988 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1989
1990 //
1991 // Copy the IOCTL parameters to the srb control buffer area.
1992 //
1993
1994 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1995
1996 srbControl->ControlCode = controlCode;
1997
1998 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1999 deviceExtension->PortDeviceObject,
2000 srbControl,
2001 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
2002 srbControl,
2003 sizeof(SRB_IO_CONTROL) + length,
2004 FALSE,
2005 &event,
2006 &ioStatus);
2007
2008 if (irp2 == NULL) {
2009 status = STATUS_INSUFFICIENT_RESOURCES;
2010 break;
2011 }
2012
2013 //
2014 // Call the port driver with the request and wait for it to complete.
2015 //
2016
2017 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2018
2019 if (status == STATUS_PENDING) {
2020 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
2021 status = ioStatus.Status;
2022 }
2023
2024 //
2025 // Copy the data received into the output buffer. Since the status buffer
2026 // contains error information also, always perform this copy. IO will will
2027 // either pass this back to the app, or zero it, in case of error.
2028 //
2029
2030 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
2031
2032 //
2033 // Update the return buffer size based on the sub-command.
2034 //
2035
2036 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
2037 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
2038 } else {
2039 length = sizeof(SENDCMDOUTPARAMS) - 1;
2040 }
2041
2042 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length);
2043 Irp->IoStatus.Information = length;
2044
2045 ExFreePool(srbControl);
2046 break;
2047
2048 }
2049
2050 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
2051 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
2052 {
2053
2054 PDEVICE_EXTENSION physicalDeviceExtension;
2055 PDISK_DATA physicalDiskData;
2056 BOOLEAN removable = FALSE;
2057 BOOLEAN listInitialized = FALSE;
2058
2059 if ((irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY &&
2060 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2061 sizeof(DISK_GEOMETRY)) ||
2062 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX &&
2063 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2064 sizeof(DISK_GEOMETRY_EX))) {
2065
2066 status = STATUS_INFO_LENGTH_MISMATCH;
2067 break;
2068 }
2069
2070 status = STATUS_SUCCESS;
2071
2072 physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2073 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
2074
2075 removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA;
2076 listInitialized = (physicalDiskData->PartitionListState == Initialized);
2077
2078 if (removable || (!listInitialized))
2079 {
2080 //
2081 // Issue ReadCapacity to update device extension
2082 // with information for current media.
2083 //
2084
2085 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
2086
2087 }
2088
2089 if (removable) {
2090
2091 if (!NT_SUCCESS(status)) {
2092
2093 //
2094 // Note the drive is not ready.
2095 //
2096
2097 diskData->DriveNotReady = TRUE;
2098
2099 break;
2100 }
2101
2102 //
2103 // Note the drive is now ready.
2104 //
2105
2106 diskData->DriveNotReady = FALSE;
2107
2108 } else if (NT_SUCCESS(status)) {
2109
2110 // ReadDriveCapacity was allright, create Partition Objects
2111
2112 if (physicalDiskData->PartitionListState == NotInitialized) {
2113 status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL);
2114 }
2115 }
2116
2117 if (NT_SUCCESS(status)) {
2118
2119 //
2120 // Copy drive geometry information from device extension.
2121 //
2122
2123 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2124 deviceExtension->DiskGeometry,
2125 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2126 sizeof(DISK_GEOMETRY) :
2127 sizeof(DISK_GEOMETRY_EX));
2128
2129 status = STATUS_SUCCESS;
2130 Irp->IoStatus.Information =
2131 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2132 sizeof(DISK_GEOMETRY) :
2133 sizeof(DISK_GEOMETRY_EX);
2134 }
2135
2136 break;
2137
2138 }
2139
2140 case IOCTL_DISK_VERIFY:
2141
2142 {
2143
2144 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2145 LARGE_INTEGER byteOffset;
2146 ULONG sectorOffset;
2147 USHORT sectorCount;
2148
2149 //
2150 // Validate buffer length.
2151 //
2152
2153 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2154 sizeof(VERIFY_INFORMATION)) {
2155
2156 status = STATUS_INFO_LENGTH_MISMATCH;
2157 break;
2158 }
2159
2160 //
2161 // Verify sectors
2162 //
2163
2164 srb->CdbLength = 10;
2165
2166 cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2167
2168 //
2169 // Add disk offset to starting sector.
2170 //
2171
2172 byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart +
2173 verifyInfo->StartingOffset.QuadPart;
2174
2175 //
2176 // Convert byte offset to sector offset.
2177 //
2178
2179 sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift);
2180
2181 //
2182 // Convert ULONG byte count to USHORT sector count.
2183 //
2184
2185 sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift);
2186
2187 //
2188 // Move little endian values into CDB in big endian format.
2189 //
2190
2191 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2192 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2193 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2194 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2195
2196 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
2197 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
2198
2199 //
2200 // The verify command is used by the NT FORMAT utility and
2201 // requests are sent down for 5% of the volume size. The
2202 // request timeout value is calculated based on the number of
2203 // sectors verified.
2204 //
2205
2206 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
2207 deviceExtension->TimeOutValue;
2208
2209 status = ScsiClassSendSrbAsynchronous(DeviceObject,
2210 srb,
2211 Irp,
2212 NULL,
2213 0,
2214 FALSE);
2215
2216 return(status);
2217
2218 }
2219
2220 case IOCTL_DISK_GET_PARTITION_INFO:
2221
2222 //
2223 // Return the information about the partition specified by the device
2224 // object. Note that no information is ever returned about the size
2225 // or partition type of the physical disk, as this doesn't make any
2226 // sense.
2227 //
2228
2229 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2230 sizeof(PARTITION_INFORMATION)) {
2231
2232 status = STATUS_INFO_LENGTH_MISMATCH;
2233
2234 }
2235 #if 0 // HACK: ReactOS partition numbers must be wrong
2236 else if (diskData->PartitionNumber == 0) {
2237
2238 //
2239 // Paritition zero is not a partition so this is not a
2240 // reasonable request.
2241 //
2242
2243 status = STATUS_INVALID_DEVICE_REQUEST;
2244
2245 }
2246 #endif
2247 else {
2248
2249 PPARTITION_INFORMATION outputBuffer;
2250
2251 //
2252 // Update the geometry in case it has changed.
2253 //
2254
2255 status = UpdateRemovableGeometry (DeviceObject, Irp);
2256
2257 if (!NT_SUCCESS(status)) {
2258
2259 //
2260 // Note the drive is not ready.
2261 //
2262
2263 diskData->DriveNotReady = TRUE;
2264 break;
2265 }
2266
2267 //
2268 // Note the drive is now ready.
2269 //
2270
2271 diskData->DriveNotReady = FALSE;
2272 // HACK: ReactOS partition numbers must be wrong (>0 part)
2273 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2274
2275 status = STATUS_INVALID_DEVICE_REQUEST;
2276 break;
2277 }
2278
2279 outputBuffer =
2280 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2281
2282 outputBuffer->PartitionType = diskData->PartitionType;
2283 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2284 outputBuffer->PartitionLength.QuadPart = (diskData->PartitionNumber) ?
2285 deviceExtension->PartitionLength.QuadPart : 2305843009213693951LL; // HACK
2286 outputBuffer->HiddenSectors = diskData->HiddenSectors;
2287 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2288 outputBuffer->BootIndicator = diskData->BootIndicator;
2289 outputBuffer->RewritePartition = FALSE;
2290 outputBuffer->RecognizedPartition =
2291 IsRecognizedPartition(diskData->PartitionType);
2292
2293 status = STATUS_SUCCESS;
2294 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
2295 }
2296
2297 break;
2298
2299 case IOCTL_DISK_GET_PARTITION_INFO_EX:
2300
2301 //
2302 // Return the information about the partition specified by the device
2303 // object. Note that no information is ever returned about the size
2304 // or partition type of the physical disk, as this doesn't make any
2305 // sense.
2306 //
2307
2308 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2309 sizeof(PARTITION_INFORMATION_EX)) {
2310
2311 status = STATUS_INFO_LENGTH_MISMATCH;
2312
2313 }
2314 else if (diskData->PartitionNumber == 0) {
2315
2316 //
2317 // Paritition zero is not a partition so this is not a
2318 // reasonable request.
2319 //
2320
2321 status = STATUS_INVALID_DEVICE_REQUEST;
2322
2323 }
2324 else {
2325
2326 PPARTITION_INFORMATION_EX outputBuffer;
2327
2328 //
2329 // Update the geometry in case it has changed.
2330 //
2331
2332 status = UpdateRemovableGeometry (DeviceObject, Irp);
2333
2334 if (!NT_SUCCESS(status)) {
2335
2336 //
2337 // Note the drive is not ready.
2338 //
2339
2340 diskData->DriveNotReady = TRUE;
2341 break;
2342 }
2343
2344 //
2345 // Note the drive is now ready.
2346 //
2347
2348 diskData->DriveNotReady = FALSE;
2349
2350 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2351
2352 status = STATUS_INVALID_DEVICE_REQUEST;
2353 break;
2354 }
2355
2356 outputBuffer =
2357 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
2358
2359 //
2360 // FIXME: hack of the year, assume that partition is MBR
2361 // Thing that can obviously be wrong...
2362 //
2363
2364 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
2365 outputBuffer->Mbr.PartitionType = diskData->PartitionType;
2366 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2367 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2368 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors;
2369 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2370 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator;
2371 outputBuffer->RewritePartition = FALSE;
2372 outputBuffer->Mbr.RecognizedPartition =
2373 IsRecognizedPartition(diskData->PartitionType);
2374
2375 status = STATUS_SUCCESS;
2376 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
2377 }
2378
2379 break;
2380
2381 case IOCTL_DISK_SET_PARTITION_INFO:
2382
2383 if (diskData->PartitionNumber == 0) {
2384
2385 status = STATUS_UNSUCCESSFUL;
2386
2387 } else {
2388
2389 PSET_PARTITION_INFORMATION inputBuffer =
2390 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2391
2392 //
2393 // Validate buffer length.
2394 //
2395
2396 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2397 sizeof(SET_PARTITION_INFORMATION)) {
2398
2399 status = STATUS_INFO_LENGTH_MISMATCH;
2400 break;
2401 }
2402
2403 //
2404 // The HAL routines IoGet- and IoSetPartitionInformation were
2405 // developed before support of dynamic partitioning and therefore
2406 // don't distinguish between partition ordinal (that is the order
2407 // of a partition on a disk) and the partition number. (The
2408 // partition number is assigned to a partition to identify it to
2409 // the system.) Use partition ordinals for these legacy calls.
2410 //
2411
2412 status = IoSetPartitionInformation(
2413 deviceExtension->PhysicalDevice,
2414 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2415 diskData->PartitionOrdinal,
2416 inputBuffer->PartitionType);
2417
2418 if (NT_SUCCESS(status)) {
2419
2420 diskData->PartitionType = inputBuffer->PartitionType;
2421 }
2422 }
2423
2424 break;
2425
2426 case IOCTL_DISK_GET_DRIVE_LAYOUT:
2427
2428 //
2429 // Return the partition layout for the physical drive. Note that
2430 // the layout is returned for the actual physical drive, regardless
2431 // of which partition was specified for the request.
2432 //
2433
2434 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2435 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2436 status = STATUS_INFO_LENGTH_MISMATCH;
2437
2438 } else {
2439
2440 PDRIVE_LAYOUT_INFORMATION partitionList;
2441 PDEVICE_EXTENSION physicalExtension = deviceExtension;
2442 PPARTITION_INFORMATION partitionEntry;
2443 PDISK_DATA diskData;
2444 ULONG tempSize;
2445 ULONG i;
2446
2447 //
2448 // Read partition information.
2449 //
2450
2451 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
2452 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2453 FALSE,
2454 &partitionList);
2455
2456 if (!NT_SUCCESS(status)) {
2457 break;
2458 }
2459
2460 //
2461 // The disk layout has been returned in the partitionList
2462 // buffer. Determine its size and, if the data will fit
2463 // into the intermediatery buffer, return it.
2464 //
2465
2466 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
2467 tempSize += partitionList->PartitionCount *
2468 sizeof(PARTITION_INFORMATION);
2469
2470 if (tempSize >
2471 irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
2472
2473 status = STATUS_BUFFER_TOO_SMALL;
2474 ExFreePool(partitionList);
2475 break;
2476 }
2477
2478 //
2479 // Walk partition list to associate partition numbers with
2480 // partition entries.
2481 //
2482
2483 for (i = 0; i < partitionList->PartitionCount; i++) {
2484
2485 //
2486 // Walk partition chain anchored at physical disk extension.
2487 //
2488
2489 deviceExtension = physicalExtension;
2490 diskData = (PDISK_DATA)(deviceExtension + 1);
2491
2492 do {
2493
2494 deviceExtension = diskData->NextPartition;
2495
2496 //
2497 // Check if this is the last partition in the chain.
2498 //
2499
2500 if (!deviceExtension) {
2501 break;
2502 }
2503
2504 //
2505 // Get the partition device extension from disk data.
2506 //
2507
2508 diskData = (PDISK_DATA)(deviceExtension + 1);
2509
2510 //
2511 // Check if this partition is not currently being used.
2512 //
2513
2514 if (!deviceExtension->PartitionLength.QuadPart) {
2515 continue;
2516 }
2517
2518 partitionEntry = &partitionList->PartitionEntry[i];
2519
2520 //
2521 // Check if empty, or describes extended partiton or hasn't changed.
2522 //
2523
2524 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2525 IsContainerPartition(partitionEntry->PartitionType)) {
2526 continue;
2527 }
2528
2529 //
2530 // Check if new partition starts where this partition starts.
2531 //
2532
2533 if (partitionEntry->StartingOffset.QuadPart !=
2534 deviceExtension->StartingOffset.QuadPart) {
2535 continue;
2536 }
2537
2538 //
2539 // Check if partition length is the same.
2540 //
2541
2542 if (partitionEntry->PartitionLength.QuadPart ==
2543 deviceExtension->PartitionLength.QuadPart) {
2544
2545 //
2546 // Partitions match. Update partition number.
2547 //
2548
2549 partitionEntry->PartitionNumber =
2550 diskData->PartitionNumber;
2551 break;
2552 }
2553
2554 } while (TRUE);
2555 }
2556
2557 //
2558 // Copy partition information to system buffer.
2559 //
2560
2561 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2562 partitionList,
2563 tempSize);
2564 status = STATUS_SUCCESS;
2565 Irp->IoStatus.Information = tempSize;
2566
2567 //
2568 // Finally, free the buffer allocated by reading the
2569 // partition table.
2570 //
2571
2572 ExFreePool(partitionList);
2573 }
2574
2575 break;
2576
2577 case IOCTL_DISK_SET_DRIVE_LAYOUT:
2578
2579 {
2580
2581 //
2582 // Update the disk with new partition information.
2583 //
2584
2585 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
2586
2587 //
2588 // Validate buffer length.
2589 //
2590
2591 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2592 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2593
2594 status = STATUS_INFO_LENGTH_MISMATCH;
2595 break;
2596 }
2597
2598 length = sizeof(DRIVE_LAYOUT_INFORMATION) +
2599 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
2600
2601
2602 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2603 length) {
2604
2605 status = STATUS_BUFFER_TOO_SMALL;
2606 break;
2607 }
2608
2609 //
2610 // Verify that device object is for physical disk.
2611 //
2612
2613 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
2614 status = STATUS_INVALID_PARAMETER;
2615 break;
2616 }
2617
2618 //
2619 // Walk through partition table comparing partitions to
2620 // existing partitions to create, delete and change
2621 // device objects as necessary.
2622 //
2623
2624 UpdateDeviceObjects(DeviceObject,
2625 Irp);
2626
2627 //
2628 // Write changes to disk.
2629 //
2630
2631 status = IoWritePartitionTable(
2632 deviceExtension->DeviceObject,
2633 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2634 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
2635 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
2636 partitionList);
2637 }
2638
2639 //
2640 // Update IRP with bytes returned.
2641 //
2642
2643 if (NT_SUCCESS(status)) {
2644 Irp->IoStatus.Information = length;
2645 }
2646
2647 break;
2648
2649 case IOCTL_DISK_REASSIGN_BLOCKS:
2650
2651 //
2652 // Map defective blocks to new location on disk.
2653 //
2654
2655 {
2656
2657 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2658 ULONG bufferSize;
2659 ULONG blockNumber;
2660 ULONG blockCount;
2661
2662 //
2663 // Validate buffer length.
2664 //
2665
2666 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2667 sizeof(REASSIGN_BLOCKS)) {
2668
2669 status = STATUS_INFO_LENGTH_MISMATCH;
2670 break;
2671 }
2672
2673 bufferSize = sizeof(REASSIGN_BLOCKS) +
2674 (badBlocks->Count - 1) * sizeof(ULONG);
2675
2676 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2677 bufferSize) {
2678
2679 status = STATUS_INFO_LENGTH_MISMATCH;
2680 break;
2681 }
2682
2683 //
2684 // Build the data buffer to be transferred in the input buffer.
2685 // The format of the data to the device is:
2686 //
2687 // 2 bytes Reserved
2688 // 2 bytes Length
2689 // x * 4 btyes Block Address
2690 //
2691 // All values are big endian.
2692 //
2693
2694 badBlocks->Reserved = 0;
2695 blockCount = badBlocks->Count;
2696
2697 //
2698 // Convert # of entries to # of bytes.
2699 //
2700
2701 blockCount *= 4;
2702 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2703 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2704
2705 //
2706 // Convert back to number of entries.
2707 //
2708
2709 blockCount /= 4;
2710
2711 for (; blockCount > 0; blockCount--) {
2712
2713 blockNumber = badBlocks->BlockNumber[blockCount-1];
2714
2715 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2716 (PFOUR_BYTE) &blockNumber);
2717 }
2718
2719 srb->CdbLength = 6;
2720
2721 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2722
2723 //
2724 // Set timeout value.
2725 //
2726
2727 srb->TimeOutValue = deviceExtension->TimeOutValue;
2728
2729 status = ScsiClassSendSrbSynchronous(DeviceObject,
2730 srb,
2731 badBlocks,
2732 bufferSize,
2733 TRUE);
2734
2735 Irp->IoStatus.Status = status;
2736 Irp->IoStatus.Information = 0;
2737 ExFreePool(srb);
2738 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2739 }
2740
2741 return(status);
2742
2743 case IOCTL_DISK_IS_WRITABLE:
2744
2745 //
2746 // Determine if the device is writable.
2747 //
2748
2749 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
2750
2751 if (modeData == NULL) {
2752 status = STATUS_INSUFFICIENT_RESOURCES;
2753 break;
2754 }
2755
2756 RtlZeroMemory(modeData, MODE_DATA_SIZE);
2757
2758 length = ScsiClassModeSense(DeviceObject,
2759 (PCHAR) modeData,
2760 MODE_DATA_SIZE,
2761 MODE_SENSE_RETURN_ALL);
2762
2763 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2764
2765 //
2766 // Retry the request in case of a check condition.
2767 //
2768
2769 length = ScsiClassModeSense(DeviceObject,
2770 (PCHAR) modeData,
2771 MODE_DATA_SIZE,
2772 MODE_SENSE_RETURN_ALL);
2773
2774 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2775 status = STATUS_IO_DEVICE_ERROR;
2776 ExFreePool(modeData);
2777 break;
2778 }
2779 }
2780
2781 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
2782 status = STATUS_MEDIA_WRITE_PROTECTED;
2783 } else {
2784 status = STATUS_SUCCESS;
2785 }
2786
2787 ExFreePool(modeData);
2788 break;
2789
2790 case IOCTL_DISK_INTERNAL_SET_VERIFY:
2791
2792 //
2793 // If the caller is kernel mode, set the verify bit.
2794 //
2795
2796 if (Irp->RequestorMode == KernelMode) {
2797 DeviceObject->Flags |= DO_VERIFY_VOLUME;
2798 }
2799 status = STATUS_SUCCESS;
2800 break;
2801
2802 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
2803
2804 //
2805 // If the caller is kernel mode, clear the verify bit.
2806 //
2807
2808 if (Irp->RequestorMode == KernelMode) {
2809 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
2810 }
2811 status = STATUS_SUCCESS;
2812 break;
2813
2814 case IOCTL_DISK_FIND_NEW_DEVICES:
2815
2816 //
2817 // Search for devices that have been powered on since the last
2818 // device search or system initialization.
2819 //
2820
2821 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2822 status = DriverEntry(DeviceObject->DriverObject,
2823 NULL);
2824
2825 Irp->IoStatus.Status = status;
2826 ExFreePool(srb);
2827 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2828 return status;
2829
2830 case IOCTL_DISK_MEDIA_REMOVAL:
2831
2832 //
2833 // If the disk is not removable then don't allow this command.
2834 //
2835
2836 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
2837 status = STATUS_INVALID_DEVICE_REQUEST;
2838 break;
2839 }
2840
2841 //
2842 // Fall through and let the class driver process the request.
2843 //
2844
2845 case IOCTL_DISK_GET_LENGTH_INFO:
2846
2847 //
2848 // Validate buffer length.
2849 //
2850
2851 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2852 sizeof(GET_LENGTH_INFORMATION)) {
2853 status = STATUS_BUFFER_TOO_SMALL;
2854
2855 } else {
2856
2857 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer;
2858
2859 //
2860 // Update the geometry in case it has changed.
2861 //
2862
2863 status = UpdateRemovableGeometry (DeviceObject, Irp);
2864
2865 if (!NT_SUCCESS(status)) {
2866
2867 //
2868 // Note the drive is not ready.
2869 //
2870
2871 diskData->DriveNotReady = TRUE;
2872 break;
2873 }
2874
2875 //
2876 // Note the drive is now ready.
2877 //
2878
2879 diskData->DriveNotReady = FALSE;
2880
2881 //
2882 // Output data, and return
2883 //
2884
2885 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart;
2886 status = STATUS_SUCCESS;
2887 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
2888 }
2889
2890 break;
2891
2892 default:
2893
2894 //
2895 // Free the Srb, since it is not needed.
2896 //
2897
2898 ExFreePool(srb);
2899
2900 //
2901 // Pass the request to the common device control routine.
2902 //
2903
2904 return(ScsiClassDeviceControl(DeviceObject, Irp));
2905
2906 break;
2907
2908 } // end switch( ...
2909
2910 Irp->IoStatus.Status = status;
2911
2912 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
2913
2914 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
2915 }
2916
2917 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2918 ExFreePool(srb);
2919 return(status);
2920
2921 } // end ScsiDiskDeviceControl()
2922 \f
2923 NTSTATUS
2924 NTAPI
2925 ScsiDiskShutdownFlush (
2926 IN PDEVICE_OBJECT DeviceObject,
2927 IN PIRP Irp
2928 )
2929
2930 /*++
2931
2932 Routine Description:
2933
2934 This routine is called for a shutdown and flush IRPs. These are sent by the
2935 system before it actually shuts down or when the file system does a flush.
2936 A synchronize cache command is sent to the device if it is write caching.
2937 If the device is removable an unlock command will be sent. This routine
2938 will sent a shutdown or flush Srb to the port driver.
2939
2940 Arguments:
2941
2942 DriverObject - Pointer to device object to being shutdown by system.
2943
2944 Irp - IRP involved.
2945
2946 Return Value:
2947
2948 NT Status
2949
2950 --*/
2951
2952 {
2953 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2954 PIO_STACK_LOCATION irpStack;
2955 PSCSI_REQUEST_BLOCK srb;
2956 NTSTATUS status;
2957 PCDB cdb;
2958
2959 //
2960 // Allocate SCSI request block.
2961 //
2962
2963 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
2964
2965 if (srb == NULL) {
2966
2967 //
2968 // Set the status and complete the request.
2969 //
2970
2971 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2972 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2973 return(STATUS_INSUFFICIENT_RESOURCES);
2974 }
2975
2976 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2977
2978 //
2979 // Write length to SRB.
2980 //
2981
2982 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2983
2984 //
2985 // Set SCSI bus address.
2986 //
2987
2988 srb->PathId = deviceExtension->PathId;
2989 srb->TargetId = deviceExtension->TargetId;
2990 srb->Lun = deviceExtension->Lun;
2991
2992 //
2993 // Set timeout value and mark the request as not being a tagged request.
2994 //
2995
2996 srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
2997 srb->QueueTag = SP_UNTAGGED;
2998 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
2999 srb->SrbFlags = deviceExtension->SrbFlags;
3000
3001 //
3002 // If the write cache is enabled then send a synchronize cache request.
3003 //
3004
3005 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
3006
3007 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3008 srb->CdbLength = 10;
3009
3010 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
3011
3012 status = ScsiClassSendSrbSynchronous(DeviceObject,
3013 srb,
3014 NULL,
3015 0,
3016 TRUE);
3017
3018 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status ));
3019 }
3020
3021 //
3022 // Unlock the device if it is removable and this is a shutdown.
3023 //
3024
3025 irpStack = IoGetCurrentIrpStackLocation(Irp);
3026
3027 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
3028 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
3029
3030 srb->CdbLength = 6;
3031 cdb = (PVOID) srb->Cdb;
3032 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3033 cdb->MEDIA_REMOVAL.Prevent = FALSE;
3034
3035 //
3036 // Set timeout value.
3037 //
3038
3039 srb->TimeOutValue = deviceExtension->TimeOutValue;
3040 status = ScsiClassSendSrbSynchronous(DeviceObject,
3041 srb,
3042 NULL,
3043 0,
3044 TRUE);
3045
3046 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
3047 }
3048
3049 srb->CdbLength = 0;
3050
3051 //
3052 // Save a few parameters in the current stack location.
3053 //
3054
3055 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
3056 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
3057
3058 //
3059 // Set the retry count to zero.
3060 //
3061
3062 irpStack->Parameters.Others.Argument4 = (PVOID) 0;
3063
3064 //
3065 // Set up IoCompletion routine address.
3066 //
3067
3068 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
3069
3070 //
3071 // Get next stack location and
3072 // set major function code.
3073 //
3074
3075 irpStack = IoGetNextIrpStackLocation(Irp);
3076
3077 irpStack->MajorFunction = IRP_MJ_SCSI;
3078
3079 //
3080 // Set up SRB for execute scsi request.
3081 // Save SRB address in next stack for port driver.
3082 //
3083
3084 irpStack->Parameters.Scsi.Srb = srb;
3085
3086 //
3087 // Set up Irp Address.
3088 //
3089
3090 srb->OriginalRequest = Irp;
3091
3092 //
3093 // Call the port driver to process the request.
3094 //
3095
3096 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3097
3098 } // end ScsiDiskShutdown()
3099
3100 \f
3101 BOOLEAN
3102 NTAPI
3103 IsFloppyDevice(
3104 PDEVICE_OBJECT DeviceObject
3105 )
3106 /*++
3107
3108 Routine Description:
3109
3110 The routine performs the necessary functions to determine if a device is
3111 really a floppy rather than a harddisk. This is done by a mode sense
3112 command. First, a check is made to see if the medimum type is set. Second
3113 a check is made for the flexible parameters mode page. Also a check is
3114 made to see if the write cache is enabled.
3115
3116 Arguments:
3117
3118 DeviceObject - Supplies the device object to be tested.
3119
3120 Return Value:
3121
3122 Return TRUE if the indicated device is a floppy.
3123
3124 --*/
3125 {
3126 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3127 PVOID modeData;
3128 PUCHAR pageData;
3129 ULONG length;
3130
3131 PAGED_CODE();
3132
3133 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3134
3135 if (modeData == NULL) {
3136 return(FALSE);
3137 }
3138
3139 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3140
3141 length = ScsiClassModeSense(DeviceObject,
3142 modeData,
3143 MODE_DATA_SIZE,
3144 MODE_SENSE_RETURN_ALL);
3145
3146 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3147
3148 //
3149 // Retry the request in case of a check condition.
3150 //
3151
3152 length = ScsiClassModeSense(DeviceObject,
3153 modeData,
3154 MODE_DATA_SIZE,
3155 MODE_SENSE_RETURN_ALL);
3156
3157 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3158
3159 ExFreePool(modeData);
3160 return(FALSE);
3161
3162 }
3163 }
3164
3165 //
3166 // If the length is greater than length indicated by the mode data reset
3167 // the data to the mode data.
3168 //
3169
3170 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3171 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3172 }
3173
3174 //
3175 // Look for the flexible disk mode page.
3176 //
3177
3178 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
3179
3180 if (pageData != NULL) {
3181
3182 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3183 ExFreePool(modeData);
3184 return(TRUE);
3185 }
3186
3187 //
3188 // Check to see if the write cache is enabled.
3189 //
3190
3191 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3192
3193 //
3194 // Assume that write cache is disabled or not supported.
3195 //
3196
3197 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3198
3199 //
3200 // Check if valid caching page exists.
3201 //
3202
3203 if (pageData != NULL) {
3204
3205 //
3206 // Check if write cache is disabled.
3207 //
3208
3209 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3210
3211 DebugPrint((1,
3212 "SCSIDISK: Disk write cache enabled\n"));
3213
3214 //
3215 // Check if forced unit access (FUA) is supported.
3216 //
3217
3218 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
3219
3220 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3221
3222 } else {
3223
3224 DebugPrint((1,
3225 "SCSIDISK: Disk does not support FUA or DPO\n"));
3226
3227 //
3228 // TODO: Log this.
3229 //
3230
3231 }
3232 }
3233 }
3234
3235 ExFreePool(modeData);
3236 return(FALSE);
3237
3238 } // end IsFloppyDevice()
3239
3240 \f
3241 BOOLEAN
3242 NTAPI
3243 ScsiDiskModeSelect(
3244 IN PDEVICE_OBJECT DeviceObject,
3245 IN PCHAR ModeSelectBuffer,
3246 IN ULONG Length,
3247 IN BOOLEAN SavePage
3248 )
3249
3250 /*++
3251
3252 Routine Description:
3253
3254 This routine sends a mode select command.
3255
3256 Arguments:
3257
3258 DeviceObject - Supplies the device object associated with this request.
3259
3260 ModeSelectBuffer - Supplies a buffer containing the page data.
3261
3262 Length - Supplies the length in bytes of the mode select buffer.
3263
3264 SavePage - Indicates that parameters should be written to disk.
3265
3266 Return Value:
3267
3268 Length of the transferred data is returned.
3269
3270 --*/
3271 {
3272 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3273 PCDB cdb;
3274 SCSI_REQUEST_BLOCK srb;
3275 ULONG retries = 1;
3276 ULONG length2;
3277 NTSTATUS status;
3278 ULONG_PTR buffer;
3279 PMODE_PARAMETER_BLOCK blockDescriptor;
3280
3281 PAGED_CODE();
3282
3283 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
3284
3285 //
3286 // Allocate buffer for mode select header, block descriptor, and mode page.
3287 //
3288
3289 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
3290
3291 RtlZeroMemory((PVOID)buffer, length2);
3292
3293 //
3294 // Set length in header to size of mode page.
3295 //
3296
3297 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
3298
3299 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
3300
3301 //
3302 // Set size
3303 //
3304
3305 blockDescriptor->BlockLength[1]=0x02;
3306
3307 //
3308 // Copy mode page to buffer.
3309 //
3310
3311 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
3312
3313 //
3314 // Zero SRB.
3315 //
3316
3317 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3318
3319 //
3320 // Build the MODE SELECT CDB.
3321 //
3322
3323 srb.CdbLength = 6;
3324 cdb = (PCDB)srb.Cdb;
3325
3326 //
3327 // Set timeout value from device extension.
3328 //
3329
3330 srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
3331
3332 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3333 cdb->MODE_SELECT.SPBit = SavePage;
3334 cdb->MODE_SELECT.PFBit = 1;
3335 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
3336
3337 Retry:
3338
3339 status = ScsiClassSendSrbSynchronous(DeviceObject,
3340 &srb,
3341 (PVOID)buffer,
3342 length2,
3343 TRUE);
3344
3345
3346 if (status == STATUS_VERIFY_REQUIRED) {
3347
3348 //
3349 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3350 // this status.
3351 //
3352
3353 if (retries--) {
3354
3355 //
3356 // Retry request.
3357 //
3358
3359 goto Retry;
3360 }
3361
3362 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3363 status = STATUS_SUCCESS;
3364 }
3365
3366 ExFreePool((PVOID)buffer);
3367
3368 if (NT_SUCCESS(status)) {
3369 return(TRUE);
3370 } else {
3371 return(FALSE);
3372 }
3373
3374 } // end SciDiskModeSelect()
3375
3376 \f
3377 VOID
3378 NTAPI
3379 DisableWriteCache(
3380 IN PDEVICE_OBJECT DeviceObject,
3381 IN PSCSI_INQUIRY_DATA LunInfo
3382 )
3383
3384 {
3385 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3386 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3387 BAD_CONTROLLER_INFORMATION const *controller;
3388 ULONG j,length;
3389 PVOID modeData;
3390 PUCHAR pageData;
3391
3392 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
3393
3394 controller = &ScsiDiskBadControllers[j];
3395
3396 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
3397 continue;
3398 }
3399
3400 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
3401
3402 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3403
3404 if (modeData == NULL) {
3405
3406 DebugPrint((1,
3407 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3408 return;
3409 }
3410
3411 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3412
3413 length = ScsiClassModeSense(DeviceObject,
3414 modeData,
3415 MODE_DATA_SIZE,
3416 MODE_SENSE_RETURN_ALL);
3417
3418 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3419
3420 //
3421 // Retry the request in case of a check condition.
3422 //
3423
3424 length = ScsiClassModeSense(DeviceObject,
3425 modeData,
3426 MODE_DATA_SIZE,
3427 MODE_SENSE_RETURN_ALL);
3428
3429 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3430
3431
3432 DebugPrint((1,
3433 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3434
3435 ExFreePool(modeData);
3436 return;
3437
3438 }
3439 }
3440
3441 //
3442 // If the length is greater than length indicated by the mode data reset
3443 // the data to the mode data.
3444 //
3445
3446 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3447 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3448 }
3449
3450 //
3451 // Check to see if the write cache is enabled.
3452 //
3453
3454 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3455
3456 //
3457 // Assume that write cache is disabled or not supported.
3458 //
3459
3460 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3461
3462 //
3463 // Check if valid caching page exists.
3464 //
3465
3466 if (pageData != NULL) {
3467
3468 BOOLEAN savePage = FALSE;
3469
3470 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
3471
3472 //
3473 // Check if write cache is disabled.
3474 //
3475
3476 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3477
3478 PIO_ERROR_LOG_PACKET errorLogEntry;
3479 LONG errorCode;
3480
3481
3482 //
3483 // Disable write cache and ensure necessary fields are zeroed.
3484 //
3485
3486 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
3487 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
3488 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
3489 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
3490
3491 //
3492 // Extract length from caching page.
3493 //
3494
3495 length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
3496
3497 //
3498 // Compensate for page code and page length.
3499 //
3500
3501 length += 2;
3502
3503 //
3504 // Issue mode select to set the parameter.
3505 //
3506
3507 if (ScsiDiskModeSelect(DeviceObject,
3508 (PCHAR)pageData,
3509 length,
3510 savePage)) {
3511
3512 DebugPrint((1,
3513 "SCSIDISK: Disk write cache disabled\n"));
3514
3515 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3516 errorCode = IO_WRITE_CACHE_DISABLED;
3517
3518 } else {
3519 if (ScsiDiskModeSelect(DeviceObject,
3520 (PCHAR)pageData,
3521 length,
3522 savePage)) {
3523
3524 DebugPrint((1,
3525 "SCSIDISK: Disk write cache disabled\n"));
3526
3527
3528 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3529 errorCode = IO_WRITE_CACHE_DISABLED;
3530
3531 } else {
3532
3533 DebugPrint((1,
3534 "SCSIDISK: Mode select to disable write cache failed\n"));
3535
3536 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3537 errorCode = IO_WRITE_CACHE_ENABLED;
3538 }
3539 }
3540
3541 //
3542 // Log the appropriate informational or error entry.
3543 //
3544
3545 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3546 DeviceObject,
3547 sizeof(IO_ERROR_LOG_PACKET) + 3
3548 * sizeof(ULONG));
3549
3550 if (errorLogEntry != NULL) {
3551
3552 errorLogEntry->FinalStatus = STATUS_SUCCESS;
3553 errorLogEntry->ErrorCode = errorCode;
3554 errorLogEntry->SequenceNumber = 0;
3555 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
3556 errorLogEntry->IoControlCode = 0;
3557 errorLogEntry->RetryCount = 0;
3558 errorLogEntry->UniqueErrorValue = 0x1;
3559 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG);
3560 errorLogEntry->DumpData[0] = LunInfo->PathId;
3561 errorLogEntry->DumpData[1] = LunInfo->TargetId;
3562 errorLogEntry->DumpData[2] = LunInfo->Lun;
3563
3564 //
3565 // Write the error log packet.
3566 //
3567
3568 IoWriteErrorLogEntry(errorLogEntry);
3569 }
3570 }
3571 }
3572
3573 //
3574 // Found device so exit the loop and return.
3575 //
3576
3577 break;
3578 }
3579
3580 return;
3581 }
3582
3583 \f
3584 BOOLEAN
3585 NTAPI
3586 CalculateMbrCheckSum(
3587 IN PDEVICE_EXTENSION DeviceExtension,
3588 OUT PULONG Checksum
3589 )
3590
3591 /*++
3592
3593 Routine Description:
3594
3595 Read MBR and calculate checksum.
3596
3597 Arguments:
3598
3599 DeviceExtension - Supplies a pointer to the device information for disk.
3600 Checksum - Memory location to return MBR checksum.
3601
3602 Return Value:
3603
3604 Returns TRUE if checksum is valid.
3605
3606 --*/
3607 {
3608 LARGE_INTEGER sectorZero;
3609 PIRP irp;
3610 IO_STATUS_BLOCK ioStatus;
3611 KEVENT event;
3612 NTSTATUS status;
3613 ULONG sectorSize;
3614 PULONG mbr;
3615 ULONG i;
3616
3617 PAGED_CODE();
3618 sectorZero.QuadPart = (LONGLONG) 0;
3619
3620 //
3621 // Create notification event object to be used to signal the inquiry
3622 // request completion.
3623 //
3624
3625 KeInitializeEvent(&event, NotificationEvent, FALSE);
3626
3627 //
3628 // Get sector size.
3629 //
3630
3631 sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
3632
3633 //
3634 // Make sure sector size is at least 512 bytes.
3635 //
3636
3637 if (sectorSize < 512) {
3638 sectorSize = 512;
3639 }
3640
3641 //
3642 // Allocate buffer for sector read.
3643 //
3644
3645 mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize);
3646
3647 if (!mbr) {
3648 return FALSE;
3649 }
3650
3651 //
3652 // Build IRP to read MBR.
3653 //
3654
3655 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
3656 DeviceExtension->DeviceObject,
3657 mbr,
3658 sectorSize,
3659 &sectorZero,
3660 &event,
3661 &ioStatus );
3662
3663 if (!irp) {
3664 ExFreePool(mbr);
3665 return FALSE;
3666 }
3667
3668 //
3669 // Pass request to port driver and wait for request to complete.
3670 //
3671
3672 status = IoCallDriver(DeviceExtension->DeviceObject,
3673 irp);
3674
3675 if (status == STATUS_PENDING) {
3676 KeWaitForSingleObject(&event,
3677 Suspended,
3678 KernelMode,
3679 FALSE,
3680 NULL);
3681 status = ioStatus.Status;
3682 }
3683
3684 if (!NT_SUCCESS(status)) {
3685 ExFreePool(mbr);
3686 return FALSE;
3687 }
3688
3689 //
3690 // Calculate MBR checksum.
3691 //
3692
3693 *Checksum = 0;
3694
3695 for (i = 0; i < 128; i++) {
3696 *Checksum += mbr[i];
3697 }
3698
3699 *Checksum = ~*Checksum + 1;
3700
3701 ExFreePool(mbr);
3702 return TRUE;
3703 }
3704
3705 \f
3706 BOOLEAN
3707 NTAPI
3708 EnumerateBusKey(
3709 IN PDEVICE_EXTENSION DeviceExtension,
3710 HANDLE BusKey,
3711 PULONG DiskNumber
3712 )
3713
3714 /*++
3715
3716 Routine Description:
3717
3718 The routine queries the registry to determine if this disk is visible to
3719 the BIOS. If the disk is visable to the BIOS, then the geometry information
3720 is updated.
3721
3722 Arguments:
3723
3724 DeviceExtension - Supplies a pointer to the device information for disk.
3725 Signature - Unique identifier recorded in MBR.
3726 BusKey - Handle of bus key.
3727 DiskNumber - Returns ordinal of disk as BIOS sees it.
3728
3729 Return Value:
3730
3731 TRUE is disk signature matched.
3732
3733 --*/
3734 {
3735 PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1);
3736 BOOLEAN diskFound = FALSE;
3737 OBJECT_ATTRIBUTES objectAttributes;
3738 UNICODE_STRING unicodeString;
3739 UNICODE_STRING identifier;
3740 ULONG busNumber;
3741 ULONG adapterNumber;
3742 ULONG diskNumber;
3743 HANDLE adapterKey;
3744 HANDLE spareKey;
3745 HANDLE diskKey;
3746 HANDLE targetKey;
3747 NTSTATUS status;
3748 STRING string;
3749 STRING anotherString;
3750 ULONG length;
3751 UCHAR buffer[20];
3752 PKEY_VALUE_FULL_INFORMATION keyData;
3753
3754 PAGED_CODE();
3755
3756 for (busNumber = 0; ; busNumber++) {
3757
3758 //
3759 // Open controller name key.
3760 //
3761
3762 sprintf((PCHAR)buffer,
3763 "%lu",
3764 busNumber);
3765
3766 RtlInitString(&string,
3767 (PCSZ)buffer);
3768
3769 status = RtlAnsiStringToUnicodeString(&unicodeString,
3770 &string,
3771 TRUE);
3772
3773 if (!NT_SUCCESS(status)){
3774 break;
3775 }
3776
3777 InitializeObjectAttributes(&objectAttributes,
3778 &unicodeString,
3779 OBJ_CASE_INSENSITIVE,
3780 BusKey,
3781 (PSECURITY_DESCRIPTOR)NULL);
3782
3783 status = ZwOpenKey(&spareKey,
3784 KEY_READ,
3785 &objectAttributes);
3786
3787 RtlFreeUnicodeString(&unicodeString);
3788
3789 if (!NT_SUCCESS(status)) {
3790 break;
3791 }
3792
3793 //
3794 // Open up controller ordinal key.
3795 //
3796
3797 RtlInitUnicodeString(&unicodeString, L"DiskController");
3798 InitializeObjectAttributes(&objectAttributes,
3799 &unicodeString,
3800 OBJ_CASE_INSENSITIVE,
3801 spareKey,
3802 (PSECURITY_DESCRIPTOR)NULL);
3803
3804 status = ZwOpenKey(&adapterKey,
3805 KEY_READ,
3806 &objectAttributes);
3807
3808 //
3809 // This could fail even with additional adapters of this type
3810 // to search.
3811 //
3812
3813 if (!NT_SUCCESS(status)) {
3814 continue;
3815 }
3816
3817 for (adapterNumber = 0; ; adapterNumber++) {
3818
3819 //
3820 // Open disk key.
3821 //
3822
3823 sprintf((PCHAR)buffer,
3824 "%lu\\DiskPeripheral",
3825 adapterNumber);
3826
3827 RtlInitString(&string,
3828 (PCSZ)buffer);
3829
3830 status = RtlAnsiStringToUnicodeString(&unicodeString,
3831 &string,
3832 TRUE);
3833
3834 if (!NT_SUCCESS(status)){
3835 break;
3836 }
3837
3838 InitializeObjectAttributes(&objectAttributes,
3839 &unicodeString,
3840 OBJ_CASE_INSENSITIVE,
3841 adapterKey,
3842 (PSECURITY_DESCRIPTOR)NULL);
3843
3844 status = ZwOpenKey(&diskKey,
3845 KEY_READ,
3846 &objectAttributes);
3847
3848 RtlFreeUnicodeString(&unicodeString);
3849
3850 if (!NT_SUCCESS(status)) {
3851 break;
3852 }
3853
3854 for (diskNumber = 0; ; diskNumber++) {
3855
3856 sprintf((PCHAR)buffer,
3857 "%lu",
3858 diskNumber);
3859
3860 RtlInitString(&string,
3861 (PCSZ)buffer);
3862
3863 status = RtlAnsiStringToUnicodeString(&unicodeString,
3864 &string,
3865 TRUE);
3866
3867 if (!NT_SUCCESS(status)){
3868 break;
3869 }
3870
3871 InitializeObjectAttributes(&objectAttributes,
3872 &unicodeString,
3873 OBJ_CASE_INSENSITIVE,
3874 diskKey,
3875 (PSECURITY_DESCRIPTOR)NULL);
3876
3877 status = ZwOpenKey(&targetKey,
3878 KEY_READ,
3879 &objectAttributes);
3880
3881 RtlFreeUnicodeString(&unicodeString);
3882
3883 if (!NT_SUCCESS(status)) {
3884 break;
3885 }
3886
3887 //
3888 // Allocate buffer for registry query.
3889 //
3890
3891 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
3892
3893 if (keyData == NULL) {
3894 ZwClose(targetKey);
3895 continue;
3896 }
3897
3898 //
3899 // Get disk peripheral identifier.
3900 //
3901
3902 RtlInitUnicodeString(&unicodeString, L"Identifier");
3903 status = ZwQueryValueKey(targetKey,
3904 &unicodeString,
3905 KeyValueFullInformation,
3906 keyData,
3907 VALUE_BUFFER_SIZE,
3908 &length);
3909
3910 ZwClose(targetKey);
3911
3912 if (!NT_SUCCESS(status)) {
3913 continue;
3914 }
3915
3916 //
3917 // Complete unicode string.
3918 //
3919
3920 identifier.Buffer =
3921 (PWSTR)((PUCHAR)keyData + keyData->DataOffset);
3922 identifier.Length = (USHORT)keyData->DataLength;
3923 identifier.MaximumLength = (USHORT)keyData->DataLength;
3924
3925 //
3926 // Convert unicode identifier to ansi string.
3927 //
3928
3929 status =
3930 RtlUnicodeStringToAnsiString(&anotherString,
3931 &identifier,
3932 TRUE);
3933
3934 if (!NT_SUCCESS(status)) {
3935 continue;
3936 }
3937
3938 //
3939 // If checksum is zero, then the MBR is valid and
3940 // the signature is meaningful.
3941 //
3942
3943 if (diskData->MbrCheckSum) {
3944
3945 //
3946 // Convert checksum to ansi string.
3947 //
3948
3949 sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum);
3950
3951 } else {
3952
3953 //
3954 // Convert signature to ansi string.
3955 //
3956
3957 sprintf((PCHAR)buffer, "%08lx", diskData->Signature);
3958
3959 //
3960 // Make string point at signature. Can't use scan
3961 // functions because they are not exported for driver use.
3962 //
3963
3964 anotherString.Buffer+=9;
3965 }
3966
3967 //
3968 // Convert to ansi string.
3969 //
3970
3971 RtlInitString(&string,
3972 (PCSZ)buffer);
3973
3974
3975 //
3976 // Make string lengths equal.
3977 //
3978
3979 anotherString.Length = string.Length;
3980
3981 //
3982 // Check if strings match.
3983 //
3984
3985 if (RtlCompareString(&string,
3986 &anotherString,
3987 TRUE) == 0) {
3988
3989 diskFound = TRUE;
3990 *DiskNumber = diskNumber;
3991 }
3992
3993 ExFreePool(keyData);
3994
3995 //
3996 // Readjust indentifier string if necessary.
3997 //
3998
3999 if (!diskData->MbrCheckSum) {
4000 anotherString.Buffer-=9;
4001 }
4002
4003 RtlFreeAnsiString(&anotherString);
4004
4005 if (diskFound) {
4006 break;
4007 }
4008 }
4009
4010 ZwClose(diskKey);
4011 }
4012
4013 ZwClose(adapterKey);
4014 }
4015
4016 ZwClose(BusKey);
4017 return diskFound;
4018
4019 } // end EnumerateBusKey()
4020
4021 \f
4022 VOID
4023 NTAPI
4024 UpdateGeometry(
4025 IN PDEVICE_EXTENSION DeviceExtension
4026 )
4027 /*++
4028
4029 Routine Description:
4030
4031 The routine queries the registry to determine if this disk is visible to
4032 the BIOS. If the disk is visable to the BIOS, then the geometry information
4033 is updated.
4034
4035 Arguments:
4036
4037 DeviceExtension - Supplies a pointer to the device information for disk.
4038
4039 Return Value:
4040
4041 None.
4042
4043 --*/
4044
4045 {
4046 OBJECT_ATTRIBUTES objectAttributes;
4047 UNICODE_STRING unicodeString;
4048 NTSTATUS status;
4049 HANDLE hardwareKey;
4050 HANDLE busKey;
4051 PCM_INT13_DRIVE_PARAMETER driveParameters;
4052 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
4053 PKEY_VALUE_FULL_INFORMATION keyData;
4054 ULONG diskNumber;
4055 PUCHAR buffer;
4056 ULONG length;
4057 ULONG numberOfDrives;
4058 ULONG cylinders;
4059 ULONG sectors;
4060 ULONG sectorsPerTrack;
4061 ULONG tracksPerCylinder;
4062 BOOLEAN foundEZHooker;
4063 PVOID tmpPtr;
4064
4065 PAGED_CODE();
4066
4067 //
4068 // Initialize the object for the key.
4069 //
4070
4071 InitializeObjectAttributes(&objectAttributes,
4072 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
4073 OBJ_CASE_INSENSITIVE,
4074 NULL,
4075 (PSECURITY_DESCRIPTOR) NULL);
4076
4077 //
4078 // Create the hardware base key.