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