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