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