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