Sync with trunk head (r49139)
[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_SET_PARTITION_INFO:
2266
2267 if (diskData->PartitionNumber == 0) {
2268
2269 status = STATUS_UNSUCCESSFUL;
2270
2271 } else {
2272
2273 PSET_PARTITION_INFORMATION inputBuffer =
2274 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2275
2276 //
2277 // Validate buffer length.
2278 //
2279
2280 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2281 sizeof(SET_PARTITION_INFORMATION)) {
2282
2283 status = STATUS_INFO_LENGTH_MISMATCH;
2284 break;
2285 }
2286
2287 //
2288 // The HAL routines IoGet- and IoSetPartitionInformation were
2289 // developed before support of dynamic partitioning and therefore
2290 // don't distinguish between partition ordinal (that is the order
2291 // of a partition on a disk) and the partition number. (The
2292 // partition number is assigned to a partition to identify it to
2293 // the system.) Use partition ordinals for these legacy calls.
2294 //
2295
2296 status = IoSetPartitionInformation(
2297 deviceExtension->PhysicalDevice,
2298 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2299 diskData->PartitionOrdinal,
2300 inputBuffer->PartitionType);
2301
2302 if (NT_SUCCESS(status)) {
2303
2304 diskData->PartitionType = inputBuffer->PartitionType;
2305 }
2306 }
2307
2308 break;
2309
2310 case IOCTL_DISK_GET_DRIVE_LAYOUT:
2311
2312 //
2313 // Return the partition layout for the physical drive. Note that
2314 // the layout is returned for the actual physical drive, regardless
2315 // of which partition was specified for the request.
2316 //
2317
2318 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2319 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2320 status = STATUS_INFO_LENGTH_MISMATCH;
2321
2322 } else {
2323
2324 PDRIVE_LAYOUT_INFORMATION partitionList;
2325 PDEVICE_EXTENSION physicalExtension = deviceExtension;
2326 PPARTITION_INFORMATION partitionEntry;
2327 PDISK_DATA diskData;
2328 ULONG tempSize;
2329 ULONG i;
2330
2331 //
2332 // Read partition information.
2333 //
2334
2335 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
2336 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2337 FALSE,
2338 &partitionList);
2339
2340 if (!NT_SUCCESS(status)) {
2341 break;
2342 }
2343
2344 //
2345 // The disk layout has been returned in the partitionList
2346 // buffer. Determine its size and, if the data will fit
2347 // into the intermediatery buffer, return it.
2348 //
2349
2350 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
2351 tempSize += partitionList->PartitionCount *
2352 sizeof(PARTITION_INFORMATION);
2353
2354 if (tempSize >
2355 irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
2356
2357 status = STATUS_BUFFER_TOO_SMALL;
2358 ExFreePool(partitionList);
2359 break;
2360 }
2361
2362 //
2363 // Walk partition list to associate partition numbers with
2364 // partition entries.
2365 //
2366
2367 for (i = 0; i < partitionList->PartitionCount; i++) {
2368
2369 //
2370 // Walk partition chain anchored at physical disk extension.
2371 //
2372
2373 deviceExtension = physicalExtension;
2374 diskData = (PDISK_DATA)(deviceExtension + 1);
2375
2376 do {
2377
2378 deviceExtension = diskData->NextPartition;
2379
2380 //
2381 // Check if this is the last partition in the chain.
2382 //
2383
2384 if (!deviceExtension) {
2385 break;
2386 }
2387
2388 //
2389 // Get the partition device extension from disk data.
2390 //
2391
2392 diskData = (PDISK_DATA)(deviceExtension + 1);
2393
2394 //
2395 // Check if this partition is not currently being used.
2396 //
2397
2398 if (!deviceExtension->PartitionLength.QuadPart) {
2399 continue;
2400 }
2401
2402 partitionEntry = &partitionList->PartitionEntry[i];
2403
2404 //
2405 // Check if empty, or describes extended partiton or hasn't changed.
2406 //
2407
2408 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2409 IsContainerPartition(partitionEntry->PartitionType)) {
2410 continue;
2411 }
2412
2413 //
2414 // Check if new partition starts where this partition starts.
2415 //
2416
2417 if (partitionEntry->StartingOffset.QuadPart !=
2418 deviceExtension->StartingOffset.QuadPart) {
2419 continue;
2420 }
2421
2422 //
2423 // Check if partition length is the same.
2424 //
2425
2426 if (partitionEntry->PartitionLength.QuadPart ==
2427 deviceExtension->PartitionLength.QuadPart) {
2428
2429 //
2430 // Partitions match. Update partition number.
2431 //
2432
2433 partitionEntry->PartitionNumber =
2434 diskData->PartitionNumber;
2435 break;
2436 }
2437
2438 } while (TRUE);
2439 }
2440
2441 //
2442 // Copy partition information to system buffer.
2443 //
2444
2445 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2446 partitionList,
2447 tempSize);
2448 status = STATUS_SUCCESS;
2449 Irp->IoStatus.Information = tempSize;
2450
2451 //
2452 // Finally, free the buffer allocated by reading the
2453 // partition table.
2454 //
2455
2456 ExFreePool(partitionList);
2457 }
2458
2459 break;
2460
2461 case IOCTL_DISK_SET_DRIVE_LAYOUT:
2462
2463 {
2464
2465 //
2466 // Update the disk with new partition information.
2467 //
2468
2469 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
2470
2471 //
2472 // Validate buffer length.
2473 //
2474
2475 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2476 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2477
2478 status = STATUS_INFO_LENGTH_MISMATCH;
2479 break;
2480 }
2481
2482 length = sizeof(DRIVE_LAYOUT_INFORMATION) +
2483 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
2484
2485
2486 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2487 length) {
2488
2489 status = STATUS_BUFFER_TOO_SMALL;
2490 break;
2491 }
2492
2493 //
2494 // Verify that device object is for physical disk.
2495 //
2496
2497 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
2498 status = STATUS_INVALID_PARAMETER;
2499 break;
2500 }
2501
2502 //
2503 // Walk through partition table comparing partitions to
2504 // existing partitions to create, delete and change
2505 // device objects as necessary.
2506 //
2507
2508 UpdateDeviceObjects(DeviceObject,
2509 Irp);
2510
2511 //
2512 // Write changes to disk.
2513 //
2514
2515 status = IoWritePartitionTable(
2516 deviceExtension->DeviceObject,
2517 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2518 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
2519 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
2520 partitionList);
2521 }
2522
2523 //
2524 // Update IRP with bytes returned.
2525 //
2526
2527 if (NT_SUCCESS(status)) {
2528 Irp->IoStatus.Information = length;
2529 }
2530
2531 break;
2532
2533 case IOCTL_DISK_REASSIGN_BLOCKS:
2534
2535 //
2536 // Map defective blocks to new location on disk.
2537 //
2538
2539 {
2540
2541 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2542 ULONG bufferSize;
2543 ULONG blockNumber;
2544 ULONG blockCount;
2545
2546 //
2547 // Validate buffer length.
2548 //
2549
2550 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2551 sizeof(REASSIGN_BLOCKS)) {
2552
2553 status = STATUS_INFO_LENGTH_MISMATCH;
2554 break;
2555 }
2556
2557 bufferSize = sizeof(REASSIGN_BLOCKS) +
2558 (badBlocks->Count - 1) * sizeof(ULONG);
2559
2560 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2561 bufferSize) {
2562
2563 status = STATUS_INFO_LENGTH_MISMATCH;
2564 break;
2565 }
2566
2567 //
2568 // Build the data buffer to be transferred in the input buffer.
2569 // The format of the data to the device is:
2570 //
2571 // 2 bytes Reserved
2572 // 2 bytes Length
2573 // x * 4 btyes Block Address
2574 //
2575 // All values are big endian.
2576 //
2577
2578 badBlocks->Reserved = 0;
2579 blockCount = badBlocks->Count;
2580
2581 //
2582 // Convert # of entries to # of bytes.
2583 //
2584
2585 blockCount *= 4;
2586 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2587 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2588
2589 //
2590 // Convert back to number of entries.
2591 //
2592
2593 blockCount /= 4;
2594
2595 for (; blockCount > 0; blockCount--) {
2596
2597 blockNumber = badBlocks->BlockNumber[blockCount-1];
2598
2599 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2600 (PFOUR_BYTE) &blockNumber);
2601 }
2602
2603 srb->CdbLength = 6;
2604
2605 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2606
2607 //
2608 // Set timeout value.
2609 //
2610
2611 srb->TimeOutValue = deviceExtension->TimeOutValue;
2612
2613 status = ScsiClassSendSrbSynchronous(DeviceObject,
2614 srb,
2615 badBlocks,
2616 bufferSize,
2617 TRUE);
2618
2619 Irp->IoStatus.Status = status;
2620 Irp->IoStatus.Information = 0;
2621 ExFreePool(srb);
2622 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2623 }
2624
2625 return(status);
2626
2627 case IOCTL_DISK_IS_WRITABLE:
2628
2629 //
2630 // Determine if the device is writable.
2631 //
2632
2633 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
2634
2635 if (modeData == NULL) {
2636 status = STATUS_INSUFFICIENT_RESOURCES;
2637 break;
2638 }
2639
2640 RtlZeroMemory(modeData, MODE_DATA_SIZE);
2641
2642 length = ScsiClassModeSense(DeviceObject,
2643 (PCHAR) modeData,
2644 MODE_DATA_SIZE,
2645 MODE_SENSE_RETURN_ALL);
2646
2647 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2648
2649 //
2650 // Retry the request in case of a check condition.
2651 //
2652
2653 length = ScsiClassModeSense(DeviceObject,
2654 (PCHAR) modeData,
2655 MODE_DATA_SIZE,
2656 MODE_SENSE_RETURN_ALL);
2657
2658 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2659 status = STATUS_IO_DEVICE_ERROR;
2660 ExFreePool(modeData);
2661 break;
2662 }
2663 }
2664
2665 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
2666 status = STATUS_MEDIA_WRITE_PROTECTED;
2667 } else {
2668 status = STATUS_SUCCESS;
2669 }
2670
2671 ExFreePool(modeData);
2672 break;
2673
2674 case IOCTL_DISK_INTERNAL_SET_VERIFY:
2675
2676 //
2677 // If the caller is kernel mode, set the verify bit.
2678 //
2679
2680 if (Irp->RequestorMode == KernelMode) {
2681 DeviceObject->Flags |= DO_VERIFY_VOLUME;
2682 }
2683 status = STATUS_SUCCESS;
2684 break;
2685
2686 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
2687
2688 //
2689 // If the caller is kernel mode, clear the verify bit.
2690 //
2691
2692 if (Irp->RequestorMode == KernelMode) {
2693 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
2694 }
2695 status = STATUS_SUCCESS;
2696 break;
2697
2698 case IOCTL_DISK_FIND_NEW_DEVICES:
2699
2700 //
2701 // Search for devices that have been powered on since the last
2702 // device search or system initialization.
2703 //
2704
2705 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2706 status = DriverEntry(DeviceObject->DriverObject,
2707 NULL);
2708
2709 Irp->IoStatus.Status = status;
2710 ExFreePool(srb);
2711 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2712 return status;
2713
2714 case IOCTL_DISK_MEDIA_REMOVAL:
2715
2716 //
2717 // If the disk is not removable then don't allow this command.
2718 //
2719
2720 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
2721 status = STATUS_INVALID_DEVICE_REQUEST;
2722 break;
2723 }
2724
2725 //
2726 // Fall through and let the class driver process the request.
2727 //
2728
2729 default:
2730
2731 //
2732 // Free the Srb, since it is not needed.
2733 //
2734
2735 ExFreePool(srb);
2736
2737 //
2738 // Pass the request to the common device control routine.
2739 //
2740
2741 return(ScsiClassDeviceControl(DeviceObject, Irp));
2742
2743 break;
2744
2745 } // end switch( ...
2746
2747 Irp->IoStatus.Status = status;
2748
2749 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
2750
2751 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
2752 }
2753
2754 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2755 ExFreePool(srb);
2756 return(status);
2757
2758 } // end ScsiDiskDeviceControl()
2759 \f
2760 NTSTATUS
2761 NTAPI
2762 ScsiDiskShutdownFlush (
2763 IN PDEVICE_OBJECT DeviceObject,
2764 IN PIRP Irp
2765 )
2766
2767 /*++
2768
2769 Routine Description:
2770
2771 This routine is called for a shutdown and flush IRPs. These are sent by the
2772 system before it actually shuts down or when the file system does a flush.
2773 A synchronize cache command is sent to the device if it is write caching.
2774 If the device is removable an unlock command will be sent. This routine
2775 will sent a shutdown or flush Srb to the port driver.
2776
2777 Arguments:
2778
2779 DriverObject - Pointer to device object to being shutdown by system.
2780
2781 Irp - IRP involved.
2782
2783 Return Value:
2784
2785 NT Status
2786
2787 --*/
2788
2789 {
2790 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2791 PIO_STACK_LOCATION irpStack;
2792 PSCSI_REQUEST_BLOCK srb;
2793 NTSTATUS status;
2794 PCDB cdb;
2795
2796 //
2797 // Allocate SCSI request block.
2798 //
2799
2800 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
2801
2802 if (srb == NULL) {
2803
2804 //
2805 // Set the status and complete the request.
2806 //
2807
2808 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2809 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2810 return(STATUS_INSUFFICIENT_RESOURCES);
2811 }
2812
2813 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2814
2815 //
2816 // Write length to SRB.
2817 //
2818
2819 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2820
2821 //
2822 // Set SCSI bus address.
2823 //
2824
2825 srb->PathId = deviceExtension->PathId;
2826 srb->TargetId = deviceExtension->TargetId;
2827 srb->Lun = deviceExtension->Lun;
2828
2829 //
2830 // Set timeout value and mark the request as not being a tagged request.
2831 //
2832
2833 srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
2834 srb->QueueTag = SP_UNTAGGED;
2835 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
2836 srb->SrbFlags = deviceExtension->SrbFlags;
2837
2838 //
2839 // If the write cache is enabled then send a synchronize cache request.
2840 //
2841
2842 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
2843
2844 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2845 srb->CdbLength = 10;
2846
2847 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
2848
2849 status = ScsiClassSendSrbSynchronous(DeviceObject,
2850 srb,
2851 NULL,
2852 0,
2853 TRUE);
2854
2855 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status ));
2856 }
2857
2858 //
2859 // Unlock the device if it is removable and this is a shutdown.
2860 //
2861
2862 irpStack = IoGetCurrentIrpStackLocation(Irp);
2863
2864 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
2865 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
2866
2867 srb->CdbLength = 6;
2868 cdb = (PVOID) srb->Cdb;
2869 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
2870 cdb->MEDIA_REMOVAL.Prevent = FALSE;
2871
2872 //
2873 // Set timeout value.
2874 //
2875
2876 srb->TimeOutValue = deviceExtension->TimeOutValue;
2877 status = ScsiClassSendSrbSynchronous(DeviceObject,
2878 srb,
2879 NULL,
2880 0,
2881 TRUE);
2882
2883 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
2884 }
2885
2886 srb->CdbLength = 0;
2887
2888 //
2889 // Save a few parameters in the current stack location.
2890 //
2891
2892 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
2893 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
2894
2895 //
2896 // Set the retry count to zero.
2897 //
2898
2899 irpStack->Parameters.Others.Argument4 = (PVOID) 0;
2900
2901 //
2902 // Set up IoCompletion routine address.
2903 //
2904
2905 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
2906
2907 //
2908 // Get next stack location and
2909 // set major function code.
2910 //
2911
2912 irpStack = IoGetNextIrpStackLocation(Irp);
2913
2914 irpStack->MajorFunction = IRP_MJ_SCSI;
2915
2916 //
2917 // Set up SRB for execute scsi request.
2918 // Save SRB address in next stack for port driver.
2919 //
2920
2921 irpStack->Parameters.Scsi.Srb = srb;
2922
2923 //
2924 // Set up Irp Address.
2925 //
2926
2927 srb->OriginalRequest = Irp;
2928
2929 //
2930 // Call the port driver to process the request.
2931 //
2932
2933 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
2934
2935 } // end ScsiDiskShutdown()
2936
2937 \f
2938 BOOLEAN
2939 NTAPI
2940 IsFloppyDevice(
2941 PDEVICE_OBJECT DeviceObject
2942 )
2943 /*++
2944
2945 Routine Description:
2946
2947 The routine performs the necessary functions to determine if a device is
2948 really a floppy rather than a harddisk. This is done by a mode sense
2949 command. First, a check is made to see if the medimum type is set. Second
2950 a check is made for the flexible parameters mode page. Also a check is
2951 made to see if the write cache is enabled.
2952
2953 Arguments:
2954
2955 DeviceObject - Supplies the device object to be tested.
2956
2957 Return Value:
2958
2959 Return TRUE if the indicated device is a floppy.
2960
2961 --*/
2962 {
2963 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2964 PVOID modeData;
2965 PUCHAR pageData;
2966 ULONG length;
2967
2968 PAGED_CODE();
2969
2970 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
2971
2972 if (modeData == NULL) {
2973 return(FALSE);
2974 }
2975
2976 RtlZeroMemory(modeData, MODE_DATA_SIZE);
2977
2978 length = ScsiClassModeSense(DeviceObject,
2979 modeData,
2980 MODE_DATA_SIZE,
2981 MODE_SENSE_RETURN_ALL);
2982
2983 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2984
2985 //
2986 // Retry the request in case of a check condition.
2987 //
2988
2989 length = ScsiClassModeSense(DeviceObject,
2990 modeData,
2991 MODE_DATA_SIZE,
2992 MODE_SENSE_RETURN_ALL);
2993
2994 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2995
2996 ExFreePool(modeData);
2997 return(FALSE);
2998
2999 }
3000 }
3001
3002 //
3003 // If the length is greater than length indicated by the mode data reset
3004 // the data to the mode data.
3005 //
3006
3007 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3008 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3009 }
3010
3011 //
3012 // Look for the flexible disk mode page.
3013 //
3014
3015 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
3016
3017 if (pageData != NULL) {
3018
3019 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3020 ExFreePool(modeData);
3021 return(TRUE);
3022 }
3023
3024 //
3025 // Check to see if the write cache is enabled.
3026 //
3027
3028 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3029
3030 //
3031 // Assume that write cache is disabled or not supported.
3032 //
3033
3034 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3035
3036 //
3037 // Check if valid caching page exists.
3038 //
3039
3040 if (pageData != NULL) {
3041
3042 //
3043 // Check if write cache is disabled.
3044 //
3045
3046 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3047
3048 DebugPrint((1,
3049 "SCSIDISK: Disk write cache enabled\n"));
3050
3051 //
3052 // Check if forced unit access (FUA) is supported.
3053 //
3054
3055 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
3056
3057 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3058
3059 } else {
3060
3061 DebugPrint((1,
3062 "SCSIDISK: Disk does not support FUA or DPO\n"));
3063
3064 //
3065 // TODO: Log this.
3066 //
3067
3068 }
3069 }
3070 }
3071
3072 ExFreePool(modeData);
3073 return(FALSE);
3074
3075 } // end IsFloppyDevice()
3076
3077 \f
3078 BOOLEAN
3079 NTAPI
3080 ScsiDiskModeSelect(
3081 IN PDEVICE_OBJECT DeviceObject,
3082 IN PCHAR ModeSelectBuffer,
3083 IN ULONG Length,
3084 IN BOOLEAN SavePage
3085 )
3086
3087 /*++
3088
3089 Routine Description:
3090
3091 This routine sends a mode select command.
3092
3093 Arguments:
3094
3095 DeviceObject - Supplies the device object associated with this request.
3096
3097 ModeSelectBuffer - Supplies a buffer containing the page data.
3098
3099 Length - Supplies the length in bytes of the mode select buffer.
3100
3101 SavePage - Indicates that parameters should be written to disk.
3102
3103 Return Value:
3104
3105 Length of the transferred data is returned.
3106
3107 --*/
3108 {
3109 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3110 PCDB cdb;
3111 SCSI_REQUEST_BLOCK srb;
3112 ULONG retries = 1;
3113 ULONG length2;
3114 NTSTATUS status;
3115 ULONG_PTR buffer;
3116 PMODE_PARAMETER_BLOCK blockDescriptor;
3117
3118 PAGED_CODE();
3119
3120 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
3121
3122 //
3123 // Allocate buffer for mode select header, block descriptor, and mode page.
3124 //
3125
3126 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
3127
3128 RtlZeroMemory((PVOID)buffer, length2);
3129
3130 //
3131 // Set length in header to size of mode page.
3132 //
3133
3134 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
3135
3136 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
3137
3138 //
3139 // Set size
3140 //
3141
3142 blockDescriptor->BlockLength[1]=0x02;
3143
3144 //
3145 // Copy mode page to buffer.
3146 //
3147
3148 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
3149
3150 //
3151 // Zero SRB.
3152 //
3153
3154 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3155
3156 //
3157 // Build the MODE SELECT CDB.
3158 //
3159
3160 srb.CdbLength = 6;
3161 cdb = (PCDB)srb.Cdb;
3162
3163 //
3164 // Set timeout value from device extension.
3165 //
3166
3167 srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
3168
3169 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3170 cdb->MODE_SELECT.SPBit = SavePage;
3171 cdb->MODE_SELECT.PFBit = 1;
3172 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
3173
3174 Retry:
3175
3176 status = ScsiClassSendSrbSynchronous(DeviceObject,
3177 &srb,
3178 (PVOID)buffer,
3179 length2,
3180 TRUE);
3181
3182
3183 if (status == STATUS_VERIFY_REQUIRED) {
3184
3185 //
3186 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3187 // this status.
3188 //
3189
3190 if (retries--) {
3191
3192 //
3193 // Retry request.
3194 //
3195
3196 goto Retry;
3197 }
3198
3199 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3200 status = STATUS_SUCCESS;
3201 }
3202
3203 ExFreePool((PVOID)buffer);
3204
3205 if (NT_SUCCESS(status)) {
3206 return(TRUE);
3207 } else {
3208 return(FALSE);
3209 }
3210
3211 } // end SciDiskModeSelect()
3212
3213 \f
3214 VOID
3215 NTAPI
3216 DisableWriteCache(
3217 IN PDEVICE_OBJECT DeviceObject,
3218 IN PSCSI_INQUIRY_DATA LunInfo
3219 )
3220
3221 {
3222 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3223 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3224 BAD_CONTROLLER_INFORMATION const *controller;
3225 ULONG j,length;
3226 PVOID modeData;
3227 PUCHAR pageData;
3228
3229 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
3230
3231 controller = &ScsiDiskBadControllers[j];
3232
3233 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
3234 continue;
3235 }
3236
3237 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
3238
3239 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3240
3241 if (modeData == NULL) {
3242
3243 DebugPrint((1,
3244 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3245 return;
3246 }
3247
3248 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3249
3250 length = ScsiClassModeSense(DeviceObject,
3251 modeData,
3252 MODE_DATA_SIZE,
3253 MODE_SENSE_RETURN_ALL);
3254
3255 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3256
3257 //
3258 // Retry the request in case of a check condition.
3259 //
3260
3261 length = ScsiClassModeSense(DeviceObject,
3262 modeData,
3263 MODE_DATA_SIZE,
3264 MODE_SENSE_RETURN_ALL);
3265
3266 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3267
3268
3269 DebugPrint((1,
3270 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3271
3272 ExFreePool(modeData);
3273 return;
3274
3275 }
3276 }
3277
3278 //
3279 // If the length is greater than length indicated by the mode data reset
3280 // the data to the mode data.
3281 //
3282
3283 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3284 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3285 }
3286
3287 //
3288 // Check to see if the write cache is enabled.
3289 //
3290
3291 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3292
3293 //
3294 // Assume that write cache is disabled or not supported.
3295 //
3296
3297 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3298
3299 //
3300 // Check if valid caching page exists.
3301 //
3302
3303 if (pageData != NULL) {
3304
3305 BOOLEAN savePage = FALSE;
3306
3307 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
3308
3309 //
3310 // Check if write cache is disabled.
3311 //
3312
3313 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3314
3315 PIO_ERROR_LOG_PACKET errorLogEntry;
3316 LONG errorCode;
3317
3318
3319 //
3320 // Disable write cache and ensure necessary fields are zeroed.
3321 //
3322
3323 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
3324 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
3325 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
3326 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
3327
3328 //
3329 // Extract length from caching page.
3330 //
3331
3332 length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
3333
3334 //
3335 // Compensate for page code and page length.
3336 //
3337
3338 length += 2;
3339
3340 //
3341 // Issue mode select to set the parameter.
3342 //
3343
3344 if (ScsiDiskModeSelect(DeviceObject,
3345 (PCHAR)pageData,
3346 length,
3347 savePage)) {
3348
3349 DebugPrint((1,
3350 "SCSIDISK: Disk write cache disabled\n"));
3351
3352 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3353 errorCode = IO_WRITE_CACHE_DISABLED;
3354
3355 } else {
3356 if (ScsiDiskModeSelect(DeviceObject,
3357 (PCHAR)pageData,
3358 length,
3359 savePage)) {
3360
3361 DebugPrint((1,
3362 "SCSIDISK: Disk write cache disabled\n"));
3363
3364
3365 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3366 errorCode = IO_WRITE_CACHE_DISABLED;
3367
3368 } else {
3369
3370 DebugPrint((1,
3371 "SCSIDISK: Mode select to disable write cache failed\n"));
3372
3373 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3374 errorCode = IO_WRITE_CACHE_ENABLED;
3375 }
3376 }
3377
3378 //
3379 // Log the appropriate informational or error entry.
3380 //
3381
3382 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3383 DeviceObject,
3384 sizeof(IO_ERROR_LOG_PACKET) + 3
3385 * sizeof(ULONG));
3386
3387 if (errorLogEntry != NULL) {
3388
3389 errorLogEntry->FinalStatus = STATUS_SUCCESS;
3390 errorLogEntry->ErrorCode = errorCode;
3391 errorLogEntry->SequenceNumber = 0;
3392 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
3393 errorLogEntry->IoControlCode = 0;
3394 errorLogEntry->RetryCount = 0;
3395 errorLogEntry->UniqueErrorValue = 0x1;
3396 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG);
3397 errorLogEntry->DumpData[0] = LunInfo->PathId;
3398 errorLogEntry->DumpData[1] = LunInfo->TargetId;
3399 errorLogEntry->DumpData[2] = LunInfo->Lun;
3400
3401 //
3402 // Write the error log packet.
3403 //
3404
3405 IoWriteErrorLogEntry(errorLogEntry);
3406 }
3407 }
3408 }
3409
3410 //
3411 // Found device so exit the loop and return.
3412 //
3413
3414 break;
3415 }
3416
3417 return;
3418 }
3419
3420 \f
3421 BOOLEAN
3422 NTAPI
3423 CalculateMbrCheckSum(
3424 IN PDEVICE_EXTENSION DeviceExtension,
3425 OUT PULONG Checksum
3426 )
3427
3428 /*++
3429
3430 Routine Description:
3431
3432 Read MBR and calculate checksum.
3433
3434 Arguments:
3435
3436 DeviceExtension - Supplies a pointer to the device information for disk.
3437 Checksum - Memory location to return MBR checksum.
3438
3439 Return Value:
3440
3441 Returns TRUE if checksum is valid.
3442
3443 --*/
3444 {
3445 LARGE_INTEGER sectorZero;
3446 PIRP irp;
3447 IO_STATUS_BLOCK ioStatus;
3448 KEVENT event;
3449 NTSTATUS status;
3450 ULONG sectorSize;
3451 PULONG mbr;
3452 ULONG i;
3453
3454 PAGED_CODE();
3455 sectorZero.QuadPart = (LONGLONG) 0;
3456
3457 //
3458 // Create notification event object to be used to signal the inquiry
3459 // request completion.
3460 //
3461
3462 KeInitializeEvent(&event, NotificationEvent, FALSE);
3463
3464 //
3465 // Get sector size.
3466 //
3467
3468 sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
3469
3470 //
3471 // Make sure sector size is at least 512 bytes.
3472 //
3473
3474 if (sectorSize < 512) {
3475 sectorSize = 512;
3476 }
3477
3478 //
3479 // Allocate buffer for sector read.
3480 //
3481
3482 mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize);
3483
3484 if (!mbr) {
3485 return FALSE;
3486 }
3487
3488 //
3489 // Build IRP to read MBR.
3490 //
3491
3492 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
3493 DeviceExtension->DeviceObject,
3494 mbr,
3495 sectorSize,
3496 &sectorZero,
3497 &event,
3498 &ioStatus );
3499
3500 if (!irp) {
3501 ExFreePool(mbr);
3502 return FALSE;
3503 }
3504
3505 //
3506 // Pass request to port driver and wait for request to complete.
3507 //
3508
3509 status = IoCallDriver(DeviceExtension->DeviceObject,
3510 irp);
3511
3512 if (status == STATUS_PENDING) {
3513 KeWaitForSingleObject(&event,
3514 Suspended,
3515 KernelMode,
3516 FALSE,
3517 NULL);
3518 status = ioStatus.Status;
3519 }
3520
3521 if (!NT_SUCCESS(status)) {
3522 ExFreePool(mbr);
3523 return FALSE;
3524 }
3525
3526 //
3527 // Calculate MBR checksum.
3528 //
3529
3530 *Checksum = 0;
3531
3532 for (i = 0; i < 128; i++) {
3533 *Checksum += mbr[i];
3534 }
3535
3536 *Checksum = ~*Checksum + 1;
3537
3538 ExFreePool(mbr);
3539 return TRUE;
3540 }
3541
3542 \f
3543 BOOLEAN
3544 NTAPI
3545 EnumerateBusKey(
3546 IN PDEVICE_EXTENSION DeviceExtension,
3547 HANDLE BusKey,
3548 PULONG DiskNumber
3549 )
3550
3551 /*++
3552
3553 Routine Description:
3554
3555 The routine queries the registry to determine if this disk is visible to
3556 the BIOS. If the disk is visable to the BIOS, then the geometry information
3557 is updated.
3558
3559 Arguments:
3560
3561 DeviceExtension - Supplies a pointer to the device information for disk.
3562 Signature - Unique identifier recorded in MBR.
3563 BusKey - Handle of bus key.
3564 DiskNumber - Returns ordinal of disk as BIOS sees it.
3565
3566 Return Value:
3567
3568 TRUE is disk signature matched.
3569
3570 --*/
3571 {
3572 PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1);
3573 BOOLEAN diskFound = FALSE;
3574 OBJECT_ATTRIBUTES objectAttributes;
3575 UNICODE_STRING unicodeString;
3576 UNICODE_STRING identifier;
3577 ULONG busNumber;
3578 ULONG adapterNumber;
3579 ULONG diskNumber;
3580 HANDLE adapterKey;
3581 HANDLE spareKey;
3582 HANDLE diskKey;
3583 HANDLE targetKey;
3584 NTSTATUS status;
3585 STRING string;
3586 STRING anotherString;
3587 ULONG length;
3588 UCHAR buffer[20];
3589 PKEY_VALUE_FULL_INFORMATION keyData;
3590
3591 PAGED_CODE();
3592
3593 for (busNumber = 0; ; busNumber++) {
3594
3595 //
3596 // Open controller name key.
3597 //
3598
3599 sprintf((PCHAR)buffer,
3600 "%lu",
3601 busNumber);
3602
3603 RtlInitString(&string,
3604 (PCSZ)buffer);
3605
3606 status = RtlAnsiStringToUnicodeString(&unicodeString,
3607 &string,
3608 TRUE);
3609
3610 if (!NT_SUCCESS(status)){
3611 break;
3612 }
3613
3614 InitializeObjectAttributes(&objectAttributes,
3615 &unicodeString,
3616 OBJ_CASE_INSENSITIVE,
3617 BusKey,
3618 (PSECURITY_DESCRIPTOR)NULL);
3619
3620 status = ZwOpenKey(&spareKey,
3621 KEY_READ,
3622 &objectAttributes);
3623
3624 RtlFreeUnicodeString(&unicodeString);
3625
3626 if (!NT_SUCCESS(status)) {
3627 break;
3628 }
3629
3630 //
3631 // Open up controller ordinal key.
3632 //
3633
3634 RtlInitUnicodeString(&unicodeString, L"DiskController");
3635 InitializeObjectAttributes(&objectAttributes,
3636 &unicodeString,
3637 OBJ_CASE_INSENSITIVE,
3638 spareKey,
3639 (PSECURITY_DESCRIPTOR)NULL);
3640
3641 status = ZwOpenKey(&adapterKey,
3642 KEY_READ,
3643 &objectAttributes);
3644
3645 //
3646 // This could fail even with additional adapters of this type
3647 // to search.
3648 //
3649
3650 if (!NT_SUCCESS(status)) {
3651 continue;
3652 }
3653
3654 for (adapterNumber = 0; ; adapterNumber++) {
3655
3656 //
3657 // Open disk key.
3658 //
3659
3660 sprintf((PCHAR)buffer,
3661 "%lu\\DiskPeripheral",
3662 adapterNumber);
3663
3664 RtlInitString(&string,
3665 (PCSZ)buffer);
3666
3667 status = RtlAnsiStringToUnicodeString(&unicodeString,
3668 &string,
3669 TRUE);
3670
3671 if (!NT_SUCCESS(status)){
3672 break;
3673 }
3674
3675 InitializeObjectAttributes(&objectAttributes,
3676 &unicodeString,
3677 OBJ_CASE_INSENSITIVE,
3678 adapterKey,
3679 (PSECURITY_DESCRIPTOR)NULL);
3680
3681 status = ZwOpenKey(&diskKey,
3682 KEY_READ,
3683 &objectAttributes);
3684
3685 RtlFreeUnicodeString(&unicodeString);
3686
3687 if (!NT_SUCCESS(status)) {
3688 break;
3689 }
3690
3691 for (diskNumber = 0; ; diskNumber++) {
3692
3693 sprintf((PCHAR)buffer,
3694 "%lu",
3695 diskNumber);
3696
3697 RtlInitString(&string,
3698 (PCSZ)buffer);
3699
3700 status = RtlAnsiStringToUnicodeString(&unicodeString,
3701 &string,
3702 TRUE);
3703
3704 if (!NT_SUCCESS(status)){
3705 break;
3706 }
3707
3708 InitializeObjectAttributes(&objectAttributes,
3709 &unicodeString,
3710 OBJ_CASE_INSENSITIVE,
3711 diskKey,
3712 (PSECURITY_DESCRIPTOR)NULL);
3713
3714 status = ZwOpenKey(&targetKey,
3715 KEY_READ,
3716 &objectAttributes);
3717
3718 RtlFreeUnicodeString(&unicodeString);
3719
3720 if (!NT_SUCCESS(status)) {
3721 break;
3722 }
3723
3724 //
3725 // Allocate buffer for registry query.
3726 //
3727
3728 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
3729
3730 if (keyData == NULL) {
3731 ZwClose(targetKey);
3732 continue;
3733 }
3734
3735 //
3736 // Get disk peripheral identifier.
3737 //
3738
3739 RtlInitUnicodeString(&unicodeString, L"Identifier");
3740 status = ZwQueryValueKey(targetKey,
3741 &unicodeString,
3742 KeyValueFullInformation,
3743 keyData,
3744 VALUE_BUFFER_SIZE,
3745 &length);
3746
3747 ZwClose(targetKey);
3748
3749 if (!NT_SUCCESS(status)) {
3750 continue;
3751 }
3752
3753 //
3754 // Complete unicode string.
3755 //
3756
3757 identifier.Buffer =
3758 (PWSTR)((PUCHAR)keyData + keyData->DataOffset);
3759 identifier.Length = (USHORT)keyData->DataLength;
3760 identifier.MaximumLength = (USHORT)keyData->DataLength;
3761
3762 //
3763 // Convert unicode identifier to ansi string.
3764 //
3765
3766 status =
3767 RtlUnicodeStringToAnsiString(&anotherString,
3768 &identifier,
3769 TRUE);
3770
3771 if (!NT_SUCCESS(status)) {
3772 continue;
3773 }
3774
3775 //
3776 // If checksum is zero, then the MBR is valid and
3777 // the signature is meaningful.
3778 //
3779
3780 if (diskData->MbrCheckSum) {
3781
3782 //
3783 // Convert checksum to ansi string.
3784 //
3785
3786 sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum);
3787
3788 } else {
3789
3790 //
3791 // Convert signature to ansi string.
3792 //
3793
3794 sprintf((PCHAR)buffer, "%08lx", diskData->Signature);
3795
3796 //
3797 // Make string point at signature. Can't use scan
3798 // functions because they are not exported for driver use.
3799 //
3800
3801 anotherString.Buffer+=9;
3802 }
3803
3804 //
3805 // Convert to ansi string.
3806 //
3807
3808 RtlInitString(&string,
3809 (PCSZ)buffer);
3810
3811
3812 //
3813 // Make string lengths equal.
3814 //
3815
3816 anotherString.Length = string.Length;
3817
3818 //
3819 // Check if strings match.
3820 //
3821
3822 if (RtlCompareString(&string,
3823 &anotherString,
3824 TRUE) == 0) {
3825
3826 diskFound = TRUE;
3827 *DiskNumber = diskNumber;
3828 }
3829
3830 ExFreePool(keyData);
3831
3832 //
3833 // Readjust indentifier string if necessary.
3834 //
3835
3836 if (!diskData->MbrCheckSum) {
3837 anotherString.Buffer-=9;
3838 }
3839
3840 RtlFreeAnsiString(&anotherString);
3841
3842 if (diskFound) {
3843 break;
3844 }
3845 }
3846
3847 ZwClose(diskKey);
3848 }
3849
3850 ZwClose(adapterKey);
3851 }
3852
3853 ZwClose(BusKey);
3854 return diskFound;
3855
3856 } // end EnumerateBusKey()
3857
3858 \f
3859 VOID
3860 NTAPI
3861 UpdateGeometry(
3862 IN PDEVICE_EXTENSION DeviceExtension
3863 )
3864 /*++
3865
3866 Routine Description:
3867
3868 The routine queries the registry to determine if this disk is visible to
3869 the BIOS. If the disk is visable to the BIOS, then the geometry information
3870 is updated.
3871
3872 Arguments:
3873
3874 DeviceExtension - Supplies a pointer to the device information for disk.
3875
3876 Return Value:
3877
3878 None.
3879
3880 --*/
3881
3882 {
3883 OBJECT_ATTRIBUTES objectAttributes;
3884 UNICODE_STRING unicodeString;
3885 NTSTATUS status;
3886 HANDLE hardwareKey;
3887 HANDLE busKey;
3888 PCM_INT13_DRIVE_PARAMETER driveParameters;
3889 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
3890 PKEY_VALUE_FULL_INFORMATION keyData;
3891 ULONG diskNumber;
3892 PUCHAR buffer;
3893 ULONG length;
3894 ULONG numberOfDrives;
3895 ULONG cylinders;
3896 ULONG sectors;
3897 ULONG sectorsPerTrack;
3898 ULONG tracksPerCylinder;
3899 BOOLEAN foundEZHooker;
3900 PVOID tmpPtr;
3901
3902 PAGED_CODE();
3903
3904 //
3905 // Initialize the object for the key.
3906 //
3907
3908 InitializeObjectAttributes(&objectAttributes,
3909 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
3910 OBJ_CASE_INSENSITIVE,
3911 NULL,
3912 (PSECURITY_DESCRIPTOR) NULL);
3913
3914 //
3915 // Create the hardware base key.
3916 //
3917
3918 status = ZwOpenKey(&hardwareKey,
3919 KEY_READ,
3920 &objectAttributes);
3921
3922
3923 if (!NT_SUCCESS(status)) {
3924 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase));
3925 return;
3926 }
3927
3928
3929 //
3930 // Get disk BIOS geometry information.
3931 //
3932
3933 RtlInitUnicodeString(&unicodeString, L"Configuration Data");
3934
3935 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
3936
3937 if (keyData == NULL) {
3938 ZwClose(hardwareKey);
3939 return;
3940 }
3941
3942 status = ZwQueryValueKey(hardwareKey,
3943 &unicodeString,
3944 KeyValueFullInformation,
3945 keyData,
3946 VALUE_BUFFER_SIZE,
3947 &length);
3948
3949 if (!NT_SUCCESS(status)) {
3950 DebugPrint((1,
3951 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
3952 status));
3953 ExFreePool(keyData);
3954 return;
3955 }
3956
3957 //
3958 // Open EISA bus key.
3959 //
3960
3961 RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
3962
3963 InitializeObjectAttributes(&objectAttributes,
3964 &unicodeString,
3965 OBJ_CASE_INSENSITIVE,
3966 hardwareKey,
3967 (PSECURITY_DESCRIPTOR)NULL);
3968
3969 status = ZwOpenKey(&busKey,
3970 KEY_READ,
3971 &objectAttributes);
3972
3973 if (!NT_SUCCESS(status)) {
3974 goto openMultiKey;
3975 }
3976
3977 DebugPrint((3,
3978 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
3979 if (EnumerateBusKey(DeviceExtension,
3980 busKey,
3981 &diskNumber)) {
3982
3983 ZwClose(hardwareKey);
3984 goto diskMatched;
3985 }
3986
3987 openMultiKey:
3988
3989 //
3990 // Open Multifunction bus key.
3991 //
3992
3993 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
3994
3995 InitializeObjectAttributes(&objectAttributes,
3996 &unicodeString,
3997 OBJ_CASE_INSENSITIVE,
3998 hardwareKey,
3999 (PSECURITY_DESCRIPTOR)NULL);
4000
4001 status = ZwOpenKey(&busKey,
4002 KEY_READ,
4003 &objectAttributes);
4004
4005 ZwClose(hardwareKey);
4006 if (NT_SUCCESS(status)) {
4007 DebugPrint((3,
4008 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4009 if (EnumerateBusKey(DeviceExtension,
4010 busKey,
4011 &diskNumber)) {
4012
4013 goto diskMatched;
4014 }
4015 }
4016
4017 ExFreePool(keyData);
4018 return;
4019
4020 diskMatched:
4021
4022 resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData +
4023 keyData->DataOffset);
4024
4025 //
4026 // Check that the data is long enough to hold a full resource descriptor,
4027 // and that the last resouce list is device-specific and long enough.
4028 //
4029
4030 if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) ||
4031 resourceDescriptor->PartialResourceList.Count == 0 ||
4032 resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type !=
4033 CmResourceTypeDeviceSpecific ||
4034 resourceDescriptor->PartialResourceList.PartialDescriptors[0]
4035 .u.DeviceSpecificData.DataSize < sizeof(ULONG)) {
4036
4037 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4038 ExFreePool(keyData);
4039 return;
4040 }
4041
4042 length =
4043 resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize;
4044
4045 //
4046 // Point to the BIOS data. The BIOS data is located after the first
4047 // partial Resource list which should be device specific data.
4048 //
4049
4050 buffer = (PUCHAR) keyData + keyData->DataOffset +
4051 sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
4052
4053
4054 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
4055
4056 //
4057 // Use the defaults if the drive number is greater than the
4058 // number of drives detected by the BIOS.
4059 //
4060
4061 if (numberOfDrives <= diskNumber) {
4062 ExFreePool(keyData);
4063 return;
4064 }
4065
4066 //
4067 // Point to the array of drive parameters.
4068 //
4069
4070 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber;
4071 cylinders = driveParameters->MaxCylinders + 1;
4072 sectorsPerTrack = driveParameters->SectorsPerTrack;
4073 tracksPerCylinder = driveParameters->MaxHeads +1;
4074
4075 //
4076 // Calculate the actual number of sectors.
4077 //
4078
4079 sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >>
4080 DeviceExtension->SectorShift);
4081
4082 #if DBG
4083 if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) {
4084 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4085 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4086 sectors, cylinders, tracksPerCylinder, sectorsPerTrack));
4087 }
4088 #endif
4089
4090 //
4091 // Since the BIOS may not report the full drive, recalculate the drive
4092 // size based on the volume size and the BIOS values for tracks per
4093 // cylinder and sectors per track..
4094 //
4095
4096 length = tracksPerCylinder * sectorsPerTrack;
4097
4098 if (length == 0) {
4099
4100 //
4101 // The BIOS information is bogus.
4102 //
4103
4104 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4105 ExFreePool(keyData);
4106 return;
4107 }
4108
4109 cylinders = sectors / length;
4110
4111 //
4112 // Update the actual geometry information.
4113 //
4114
4115 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack;
4116 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder;
4117 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders;
4118 DeviceExtension->DiskGeometry->DiskSize.QuadPart = cylinders * tracksPerCylinder * sectorsPerTrack *
4119 DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4120
4121 DebugPrint((3,
4122 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4123 sectorsPerTrack,
4124 tracksPerCylinder,
4125 cylinders));
4126
4127 ExFreePool(keyData);
4128
4129 foundEZHooker = FALSE;
4130
4131 if (!DeviceExtension->DMActive) {
4132
4133 HalExamineMBR(DeviceExtension->DeviceObject,
4134 DeviceExtension->DiskGeometry->Geometry.BytesPerSector,
4135 (ULONG)0x55,
4136 &tmpPtr
4137 );
4138
4139 if (tmpPtr) {
4140
4141 ExFreePool(tmpPtr);
4142 foundEZHooker = TRUE;
4143
4144 }
4145
4146 }
4147
4148 if (DeviceExtension->DMActive || foundEZHooker) {
4149
4150 while (cylinders > 1024) {
4151
4152 tracksPerCylinder = tracksPerCylinder*2;
4153 cylinders = cylinders/2;
4154
4155 }
4156
4157 //
4158 // int 13 values are always 1 less.
4159 //
4160
4161 tracksPerCylinder -= 1;
4162 cylinders -= 1;
4163
4164 //
4165 // DM reserves the CE cylinder
4166 //
4167
4168 cylinders -= 1;
4169
4170 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1;
4171 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1;
4172
4173 DeviceExtension->PartitionLength.QuadPart =
4174 DeviceExtension->DiskGeometry->DiskSize.QuadPart =
4175 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart *
4176 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack *
4177 DeviceExtension->DiskGeometry->Geometry.BytesPerSector *
4178 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder;
4179
4180 if (DeviceExtension->DMActive) {
4181
4182 DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4183
4184 }
4185
4186 } else {
4187
4188 DeviceExtension->DMByteSkew = 0;
4189
4190 }
4191
4192 return;
4193
4194 } // end UpdateGeometry()
4195
4196
4197 \f
4198 NTSTATUS
4199 NTAPI
4200 UpdateRemovableGeometry (
4201 IN PDEVICE_OBJECT DeviceObject,
4202 IN PIRP Irp
4203 )
4204
4205 /*++
4206
4207 Routine Description:
4208
4209 This routines updates the size and starting offset of the device. This is
4210 used when the media on the device may have changed thereby changing the
4211 size of the device. If this is the physical device then a
4212 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4213
4214 Arguments:
4215
4216 DeviceObject - Supplies the device object whos size needs to be updated.
4217
4218 Irp - Supplies a reference where the status can be updated.
4219
4220 Return Value:
4221
4222 Returns the status of the opertion.
4223
4224 --*/
4225 {
4226
4227 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4228 PDRIVE_LAYOUT_INFORMATION partitionList;
4229 NTSTATUS status;
4230 PDISK_DATA diskData;
4231 ULONG partitionNumber;
4232
4233 //
4234 // Determine if the size of the partition may have changed because
4235 // the media has changed.
4236 //
4237
4238 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
4239
4240 return(STATUS_SUCCESS);
4241
4242 }
4243
4244 //
4245 // If this request is for partition zero then do a read drive
4246 // capacity otherwise do a I/O read partition table.
4247 //
4248
4249 diskData = (PDISK_DATA) (deviceExtension + 1);
4250
4251 //
4252 // Read the drive capcity. If that fails, give up.
4253 //
4254
4255 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
4256
4257 if (!NT_SUCCESS(status)) {
4258 return(status);
4259 }
4260
4261 //
4262 // Read the partition table agian.
4263 //
4264
4265 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
4266 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
4267 TRUE,
4268 &partitionList);
4269
4270
4271 if (!NT_SUCCESS(status)) {
4272
4273 //
4274 // Fail the request.
4275 //
4276
4277 return(status);
4278 }
4279
4280 if (diskData->PartitionNumber != 0 &&
4281 diskData->PartitionNumber <= partitionList->PartitionCount ) {
4282
4283 partitionNumber = diskData->PartitionNumber - 1;
4284
4285 //
4286 // Update the partition information for this parition.
4287 //
4288
4289 diskData->PartitionType =
4290 partitionList->PartitionEntry[partitionNumber].PartitionType;
4291
4292 diskData->BootIndicator =
4293 partitionList->PartitionEntry[partitionNumber].BootIndicator;
4294
4295 deviceExtension->StartingOffset =
4296 partitionList->PartitionEntry[partitionNumber].StartingOffset;
4297
4298 deviceExtension->PartitionLength =
4299 partitionList->PartitionEntry[partitionNumber].PartitionLength;
4300
4301 diskData->HiddenSectors =
4302 partitionList->PartitionEntry[partitionNumber].HiddenSectors;
4303
4304 deviceExtension->SectorShift = ((PDEVICE_EXTENSION)
4305 deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift;
4306
4307 } else if (diskData->PartitionNumber != 0) {
4308
4309 //
4310 // The paritition does not exist. Zero all the data.
4311 //
4312
4313 diskData->PartitionType = 0;
4314 diskData->BootIndicator = 0;
4315 diskData->HiddenSectors = 0;
4316 deviceExtension->StartingOffset.QuadPart = (LONGLONG)0;
4317 deviceExtension->PartitionLength.QuadPart = (LONGLONG)0;
4318 }
4319
4320 //
4321 // Free the parition list allocate by I/O read partition table.
4322 //
4323
4324 ExFreePool(partitionList);
4325
4326
4327 return(STATUS_SUCCESS);
4328 }
4329
4330 \f
4331 VOID
4332 NTAPI
4333 ScsiDiskProcessError(
4334 PDEVICE_OBJECT DeviceObject,
4335 PSCSI_REQUEST_BLOCK Srb,
4336 NTSTATUS *Status,
4337 BOOLEAN *Retry
4338 )
4339 /*++
4340
4341 Routine Description:
4342
4343 This routine checks the type of error. If the error indicates an underrun
4344 then indicate the request should be retried.
4345
4346 Arguments:
4347
4348 DeviceObject - Supplies a pointer to the device object.
4349
4350 Srb - Supplies a pointer to the failing Srb.
4351
4352 Status - Status with which the IRP will be completed.
4353
4354 Retry - Indication of whether the request will be retried.
4355
4356 Return Value:
4357
4358 None.
4359
4360 --*/
4361
4362 {
4363 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4364
4365 if (*Status == STATUS_DATA_OVERRUN &&
4366 ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) {
4367
4368 *Retry = TRUE;
4369
4370 //
4371 // Update the error count for the device.
4372 //
4373
4374 deviceExtension->ErrorCount++;
4375 }
4376
4377 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
4378 Srb->ScsiStatus == SCSISTAT_BUSY) {
4379
4380 //
4381 // The disk drive should never be busy this long. Reset the scsi bus
4382 // maybe this will clear the condition.
4383 //
4384
4385 ResetScsiBus(DeviceObject);
4386
4387 //
4388 // Update the error count for the device.
4389 //
4390
4391 deviceExtension->ErrorCount++;
4392 }
4393 }
4394 \f
4395 VOID
4396 NTAPI
4397 ScanForSpecial(
4398 PDEVICE_OBJECT DeviceObject,
4399 PSCSI_INQUIRY_DATA LunInfo,
4400 PIO_SCSI_CAPABILITIES PortCapabilities
4401 )
4402
4403 /*++
4404
4405 Routine Description:
4406
4407 This function checks to see if an SCSI logical unit requires speical
4408 flags to be set.
4409
4410 Arguments:
4411
4412 DeviceObject - Supplies the device object to be tested.
4413
4414 InquiryData - Supplies the inquiry data returned by the device of interest.
4415
4416 PortCapabilities - Supplies the capabilities of the device object.
4417
4418 Return Value:
4419
4420 None.
4421
4422 --*/
4423
4424 {
4425 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4426 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
4427 BAD_CONTROLLER_INFORMATION const *controller;
4428 ULONG j;
4429
4430 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
4431
4432 controller = &ScsiDiskBadControllers[j];
4433
4434 if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
4435 continue;
4436 }
4437
4438 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString));
4439
4440 //
4441 // Found a listed controller. Determine what must be done.
4442 //
4443
4444 if (controller->DisableTaggedQueuing) {
4445
4446 //
4447 // Disable tagged queuing.
4448 //
4449
4450 deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
4451 }
4452
4453 if (controller->DisableSynchronousTransfers) {
4454
4455 //
4456 // Disable synchronous data transfers.
4457 //
4458
4459 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
4460
4461 }
4462
4463 if (controller->DisableDisconnects) {
4464
4465 //
4466 // Disable disconnects.
4467 //
4468
4469 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
4470
4471 }
4472
4473 //
4474 // Found device so exit the loop and return.
4475 //
4476
4477 break;
4478 }
4479
4480 //
4481 // Set the StartUnit flag appropriately.
4482 //
4483
4484 if (DeviceObject->DeviceType == FILE_DEVICE_DISK) {
4485 deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT;
4486
4487 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
4488 if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) {
4489 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT;
4490 }
4491 }
4492 }
4493
4494 return;
4495 }
4496 \f
4497 VOID
4498 NTAPI
4499 ResetScsiBus(
4500 IN PDEVICE_OBJECT DeviceObject
4501 )
4502
4503 /*++
4504
4505 Routine Description:
4506
4507 This command sends a reset bus command to the SCSI port driver.
4508
4509 Arguments:
4510
4511 DeviceObject - The device object for the logical unit with
4512 hardware problem.
4513
4514 Return Value:
4515
4516 None.
4517
4518 --*/
4519 {
4520 PIO_STACK_LOCATION irpStack;
4521 PIRP irp;
4522 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4523 PSCSI_REQUEST_BLOCK srb;
4524 PCOMPLETION_CONTEXT context;
4525
4526 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4527
4528 //
4529 // Allocate Srb from nonpaged pool.
4530 //
4531
4532 context = ExAllocatePool(NonPagedPoolMustSucceed,
4533 sizeof(COMPLETION_CONTEXT));
4534
4535 //
4536 // Save the device object in the context for use by the completion
4537 // routine.
4538 //
4539
4540 context->DeviceObject = DeviceObject;
4541 srb = &context->Srb;
4542
4543 //
4544 // Zero out srb.
4545 //
4546
4547 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
4548
4549 //
4550 // Write length to SRB.
4551 //
4552
4553 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4554
4555 //
4556 // Set up SCSI bus address.
4557 //
4558
4559 srb->PathId = deviceExtension->PathId;
4560 srb->TargetId = deviceExtension->TargetId;
4561 srb->Lun = deviceExtension->Lun;
4562
4563 srb->Function = SRB_FUNCTION_RESET_BUS;
4564
4565 //
4566 // Build the asynchronous request to be sent to the port driver.
4567 // Since this routine is called from a DPC the IRP should always be
4568 // available.
4569 //
4570
4571 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4572
4573 IoSetCompletionRoutine(irp,
4574 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
4575 context,
4576 TRUE,
4577 TRUE,
4578 TRUE);
4579
4580 irpStack = IoGetNextIrpStackLocation(irp);
4581
4582 irpStack->MajorFunction = IRP_MJ_SCSI;
4583
4584 srb->OriginalRequest = irp;
4585
4586 //
4587 // Store the SRB address in next stack for port driver.
4588 //
4589
4590 irpStack->Parameters.Scsi.Srb = srb;
4591
4592 //
4593 // Call the port driver with the IRP.
4594 //
4595
4596 IoCallDriver(deviceExtension->PortDeviceObject, irp);
4597
4598 return;
4599
4600 } // end ResetScsiBus()
4601
4602 \f
4603 VOID
4604 NTAPI
4605 UpdateDeviceObjects(
4606 IN PDEVICE_OBJECT PhysicalDisk,
4607 IN PIRP Irp
4608 )
4609
4610 /*++
4611
4612 Routine Description:
4613
4614 This routine creates, deletes and changes device objects when
4615 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4616 the drive layout information for the user. It is possible to
4617 call this routine even in the GET_LAYOUT case because RewritePartition
4618 will be false.
4619
4620 Arguments:
4621
4622 DeviceObject - Device object for physical disk.
4623 Irp - IO Request Packet (IRP).
4624
4625 Return Value:
4626
4627 None.
4628
4629 --*/
4630 {
4631 PDEVICE_EXTENSION physicalExtension = PhysicalDisk->DeviceExtension;
4632 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
4633 ULONG partition;
4634 ULONG partitionNumber;
4635 ULONG partitionCount;
4636 ULONG lastPartition;
4637 ULONG partitionOrdinal;
4638 PPARTITION_INFORMATION partitionEntry;
4639 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
4640 STRING ntNameString;
4641 UNICODE_STRING ntUnicodeString;
4642 PDEVICE_OBJECT deviceObject;
4643 PDEVICE_EXTENSION deviceExtension;
4644 PDISK_DATA diskData;
4645 NTSTATUS status;
4646 ULONG numberListElements;
4647 BOOLEAN found;
4648
4649 partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4;
4650
4651 //
4652 // Zero all of the partition numbers.
4653 //
4654
4655 for (partition = 0; partition < partitionCount; partition++) {
4656 partitionEntry = &partitionList->PartitionEntry[partition];
4657 partitionEntry->PartitionNumber = 0;
4658 }
4659
4660 //
4661 // Walk through chain of partitions for this disk to determine
4662 // which existing partitions have no match.
4663 //
4664
4665 deviceExtension = physicalExtension;
4666 diskData = (PDISK_DATA)(deviceExtension + 1);
4667 lastPartition = 0;
4668
4669 do {
4670
4671 deviceExtension = diskData->NextPartition;
4672
4673 //
4674 // Check if this is the last partition in the chain.
4675 //
4676
4677 if (!deviceExtension) {
4678 break;
4679 }
4680
4681 //
4682 // Get the partition device extension from disk data.
4683 //
4684
4685 diskData = (PDISK_DATA)(deviceExtension + 1);
4686
4687 //
4688 // Check for highest partition number this far.
4689 //
4690
4691 if (diskData->PartitionNumber > lastPartition) {
4692 lastPartition = diskData->PartitionNumber;
4693 }
4694
4695 //
4696 // Check if this partition is not currently being used.
4697 //
4698
4699 if (!deviceExtension->PartitionLength.QuadPart) {
4700 continue;
4701 }
4702
4703 //
4704 // Loop through partition information to look for match.
4705 //
4706
4707 found = FALSE;
4708 partitionOrdinal = 0;
4709
4710 for (partition = 0; partition < partitionCount; partition++) {
4711
4712 //
4713 // Get partition descriptor.
4714 //
4715
4716 partitionEntry = &partitionList->PartitionEntry[partition];
4717
4718 //
4719 // Check if empty, or describes extended partiton or hasn't changed.
4720 //
4721
4722 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
4723 IsContainerPartition(partitionEntry->PartitionType)) {
4724 continue;
4725 }
4726
4727 //
4728 // Advance partition ordinal.
4729 //
4730
4731 partitionOrdinal++;
4732
4733 //
4734 // Check if new partition starts where this partition starts.
4735 //
4736
4737 if (partitionEntry->StartingOffset.QuadPart !=
4738 deviceExtension->StartingOffset.QuadPart) {
4739 continue;
4740 }
4741
4742 //
4743 // Check if partition length is the same.
4744 //
4745
4746 if (partitionEntry->PartitionLength.QuadPart ==
4747 deviceExtension->PartitionLength.QuadPart) {
4748
4749 DebugPrint((3,
4750 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4751 physicalExtension->DeviceNumber,
4752 diskData->PartitionNumber));
4753
4754 //
4755 // Indicate match is found and set partition number
4756 // in user buffer.
4757 //
4758
4759 found = TRUE;
4760 partitionEntry->PartitionNumber = diskData->PartitionNumber;
4761 break;
4762 }
4763 }
4764
4765 if (found) {
4766
4767 //
4768 // A match is found.
4769 //
4770
4771 diskData = (PDISK_DATA)(deviceExtension + 1);
4772
4773 //
4774 // If this partition is marked for update then update partition type.
4775 //
4776
4777 if (partitionEntry->RewritePartition) {
4778 diskData->PartitionType = partitionEntry->PartitionType;
4779 }
4780
4781 //
4782 // Update partitional ordinal for calls to HAL routine
4783 // IoSetPartitionInformation.
4784 //
4785
4786 diskData->PartitionOrdinal = partitionOrdinal;
4787
4788 DebugPrint((1,
4789 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4790 physicalExtension->DeviceNumber,
4791 diskData->PartitionOrdinal,
4792 diskData->PartitionNumber));
4793
4794 } else {
4795
4796 //
4797 // no match was found, indicate this partition is gone.
4798 //
4799
4800 DebugPrint((1,
4801 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4802 physicalExtension->DeviceNumber,
4803 diskData->PartitionNumber));
4804
4805 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
4806 }
4807
4808 } while (TRUE);
4809
4810 //
4811 // Walk through partition loop to find new partitions and set up
4812 // device extensions to describe them. In some cases new device
4813 // objects will be created.
4814 //
4815
4816 partitionOrdinal = 0;
4817
4818 for (partition = 0;
4819 partition < partitionCount;
4820 partition++) {
4821
4822 //
4823 // Get partition descriptor.
4824 //
4825
4826 partitionEntry = &partitionList->PartitionEntry[partition];
4827
4828 //
4829 // Check if empty, or describes an extended partiton.
4830 //
4831
4832 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
4833 IsContainerPartition(partitionEntry->PartitionType)) {
4834 continue;
4835 }
4836
4837 //
4838 // Keep track of position on the disk for calls to IoSetPartitionInformation.
4839 //
4840
4841 partitionOrdinal++;
4842
4843 //
4844 // Check if this entry should be rewritten.
4845 //
4846
4847 if (!partitionEntry->RewritePartition) {
4848 continue;
4849 }
4850
4851 if (partitionEntry->PartitionNumber) {
4852
4853 //
4854 // Partition is an exact match with an existing partition, but is
4855 // being written anyway.
4856 //
4857
4858 continue;
4859 }
4860
4861 //
4862 // Check first if existing device object is available by
4863 // walking partition extension list.
4864 //
4865
4866 partitionNumber = 0;
4867 deviceExtension = physicalExtension;
4868 diskData = (PDISK_DATA)(deviceExtension + 1);
4869
4870 do {
4871
4872 //
4873 // Get next partition device extension from disk data.
4874 //
4875
4876 deviceExtension = diskData->NextPartition;
4877
4878 if (!deviceExtension) {
4879 break;
4880 }
4881
4882 diskData = (PDISK_DATA)(deviceExtension + 1);
4883
4884 //
4885 // A device object is free if the partition length is set to zero.
4886 //
4887
4888 if (!deviceExtension->PartitionLength.QuadPart) {
4889 partitionNumber = diskData->PartitionNumber;
4890 break;
4891 }
4892
4893 } while (TRUE);
4894
4895 //
4896 // If partition number is still zero then a new device object
4897 // must be created.
4898 //
4899
4900 if (partitionNumber == 0) {
4901
4902 lastPartition++;
4903 partitionNumber = lastPartition;
4904
4905 //
4906 // Get or create partition object and set up partition parameters.
4907 //
4908
4909 sprintf(ntNameBuffer,
4910 "\\Device\\Harddisk%lu\\Partition%lu",
4911 physicalExtension->DeviceNumber,
4912 partitionNumber);
4913
4914 RtlInitString(&ntNameString,
4915 ntNameBuffer);
4916
4917 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
4918 &ntNameString,
4919 TRUE);
4920
4921 if (!NT_SUCCESS(status)) {
4922 continue;
4923 }
4924
4925 DebugPrint((3,
4926 "UpdateDeviceObjects: Create device object %s\n",
4927 ntNameBuffer));
4928
4929 //
4930 // This is a new name. Create the device object to represent it.
4931 //
4932
4933 status = IoCreateDevice(PhysicalDisk->DriverObject,
4934 DEVICE_EXTENSION_SIZE,
4935 &ntUnicodeString,
4936 FILE_DEVICE_DISK,
4937 0,
4938 FALSE,
4939 &deviceObject);
4940
4941 if (!NT_SUCCESS(status)) {
4942 DebugPrint((1,
4943 "UpdateDeviceObjects: Can't create device %s\n",
4944 ntNameBuffer));
4945 RtlFreeUnicodeString(&ntUnicodeString);
4946 continue;
4947 }
4948
4949 //
4950 // Set up device object fields.
4951 //
4952
4953 deviceObject->Flags |= DO_DIRECT_IO;
4954 deviceObject->StackSize = PhysicalDisk->StackSize;
4955
4956 //
4957 // Set up device extension fields.
4958 //
4959
4960 deviceExtension = deviceObject->DeviceExtension;
4961
4962 //
4963 // Copy physical disk extension to partition extension.
4964 //
4965
4966 RtlMoveMemory(deviceExtension,
4967 physicalExtension,
4968 sizeof(DEVICE_EXTENSION));
4969
4970 //
4971 // Initialize the new S-List.
4972 //
4973
4974 if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
4975 numberListElements = 30;
4976 } else {
4977 numberListElements = 8;
4978 }
4979
4980 //
4981 // Build the lookaside list for srb's for this partition based on
4982 // whether the adapter and disk can do tagged queueing.
4983 //
4984
4985 ScsiClassInitializeSrbLookasideList(deviceExtension,
4986 numberListElements);
4987
4988 //
4989 // Allocate spinlock for zoning for split-request completion.
4990 //
4991
4992 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
4993
4994 //
4995 // Write back partition number used in creating object name.
4996 //
4997
4998 partitionEntry->PartitionNumber = partitionNumber;
4999
5000 //
5001 // Clear flags initializing bit.
5002 //
5003
5004 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
5005
5006 //
5007 // Point back at device object.
5008 //
5009
5010 deviceExtension->DeviceObject = deviceObject;
5011
5012 RtlFreeUnicodeString(&ntUnicodeString);
5013
5014 //
5015 // Link to end of partition chain using previous disk data.
5016 //
5017
5018 diskData->NextPartition = deviceExtension;
5019
5020 //
5021 // Get new disk data and zero next partition pointer.
5022 //
5023
5024 diskData = (PDISK_DATA)(deviceExtension + 1);
5025 diskData->NextPartition = NULL;
5026
5027 } else {
5028
5029 //
5030 // Set pointer to disk data area that follows device extension.
5031 //
5032
5033 diskData = (PDISK_DATA)(deviceExtension + 1);
5034
5035 DebugPrint((1,
5036 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5037 physicalExtension->DeviceNumber,
5038 partitionNumber));
5039 }
5040
5041 //
5042 // Update partition information in partition device extension.
5043 //
5044
5045 diskData->PartitionNumber = partitionNumber;
5046 diskData->PartitionType = partitionEntry->PartitionType;
5047 diskData->BootIndicator = partitionEntry->BootIndicator;
5048 deviceExtension->StartingOffset = partitionEntry->StartingOffset;
5049 deviceExtension->PartitionLength = partitionEntry->PartitionLength;
5050 diskData->HiddenSectors = partitionEntry->HiddenSectors;
5051 diskData->PartitionOrdinal = partitionOrdinal;
5052
5053 DebugPrint((1,
5054 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5055 diskData->PartitionOrdinal,
5056 diskData->PartitionNumber));
5057
5058 //
5059 // Update partition number passed in to indicate the
5060 // device name for this partition.
5061 //
5062
5063 partitionEntry->PartitionNumber = partitionNumber;
5064 }
5065
5066 } // end UpdateDeviceObjects()