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