[CMAKE]
[reactos.git] / drivers / storage / class / disk / disk.c
1 /*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/disk/disk.c
5 * PURPOSE: Disk class driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9 #include <ntddk.h>
10 #include <ntdddisk.h>
11 #include <scsi.h>
12 #include <ntddscsi.h>
13 #include <mountdev.h>
14 #include <mountmgr.h>
15 #include <include/class2.h>
16 #include <stdio.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #define IO_WRITE_CACHE_ENABLED ((NTSTATUS)0x80040020L)
22 #define IO_WRITE_CACHE_DISABLED ((NTSTATUS)0x80040022L)
23
24 #ifdef POOL_TAGGING
25 #ifdef ExAllocatePool
26 #undef ExAllocatePool
27 #endif
28 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
29 #endif
30
31 typedef enum {
32 NotInitialized,
33 Initializing,
34 Initialized
35 } PARTITION_LIST_STATE;
36
37 //
38 // Disk device data
39 //
40
41 typedef struct _DISK_DATA {
42
43 //
44 // Partition chain
45 //
46
47 PDEVICE_EXTENSION NextPartition;
48
49 //
50 // Disk signature (from MBR)
51 //
52
53 ULONG Signature;
54
55 //
56 // MBR checksum
57 //
58
59 ULONG MbrCheckSum;
60
61 //
62 // Number of hidden sectors for BPB.
63 //
64
65 ULONG HiddenSectors;
66
67 //
68 // Partition number of this device object
69 //
70 // This field is set during driver initialization or when the partition
71 // is created to identify a parition to the system.
72 //
73
74 ULONG PartitionNumber;
75
76 //
77 // This field is the ordinal of a partition as it appears on a disk.
78 //
79
80 ULONG PartitionOrdinal;
81
82 //
83 // Partition type of this device object
84 //
85 // This field is set by:
86 //
87 // 1) Initially set according to the partition list entry partition
88 // type returned by IoReadPartitionTable.
89 //
90 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
91 // I/O control function when IoSetPartitionInformation function
92 // successfully updates the partition type on the disk.
93 //
94
95 UCHAR PartitionType;
96
97 //
98 // Boot indicator - indicates whether this partition is a bootable (active)
99 // partition for this device
100 //
101 // This field is set according to the partition list entry boot indicator
102 // returned by IoReadPartitionTable.
103 //
104
105 BOOLEAN BootIndicator;
106
107 //
108 // DriveNotReady - inidicates that the this device is currenly not ready
109 // because there is no media in the device.
110 //
111
112 BOOLEAN DriveNotReady;
113
114 //
115 // State of PartitionList initialization
116 //
117
118 PARTITION_LIST_STATE PartitionListState;
119
120 } DISK_DATA, *PDISK_DATA;
121
122 //
123 // Define a general structure of identfing disk controllers with bad
124 // hardware.
125 //
126
127 typedef struct _BAD_CONTROLLER_INFORMATION {
128 PCHAR InquiryString;
129 BOOLEAN DisableTaggedQueuing;
130 BOOLEAN DisableSynchronousTransfers;
131 BOOLEAN DisableDisconnects;
132 BOOLEAN DisableWriteCache;
133 }BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION;
134
135 BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = {
136 { "TOSHIBA MK538FB 60", TRUE, FALSE, FALSE, FALSE },
137 { "CONNER CP3500", FALSE, TRUE, FALSE, FALSE },
138 { "OLIVETTICP3500", FALSE, TRUE, FALSE, FALSE },
139 { "SyQuest SQ5110 CHC", TRUE, TRUE, FALSE, FALSE },
140 { "SEAGATE ST41601N 0102", FALSE, TRUE, FALSE, FALSE },
141 { "SEAGATE ST3655N", FALSE, FALSE, FALSE, TRUE },
142 { "SEAGATE ST3390N", FALSE, FALSE, FALSE, TRUE },
143 { "SEAGATE ST12550N", FALSE, FALSE, FALSE, TRUE },
144 { "SEAGATE ST32430N", FALSE, FALSE, FALSE, TRUE },
145 { "SEAGATE ST31230N", FALSE, FALSE, FALSE, TRUE },
146 { "SEAGATE ST15230N", FALSE, FALSE, FALSE, TRUE },
147 { "FUJITSU M2652S-512", TRUE, FALSE, FALSE, FALSE },
148 { "MAXTOR MXT-540SL I1.2", TRUE, FALSE, FALSE, FALSE },
149 { "COMPAQ PD-1", FALSE, TRUE, FALSE, FALSE }
150 };
151
152
153 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
154 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
155
156 #define MODE_DATA_SIZE 192
157 #define VALUE_BUFFER_SIZE 2048
158 #define SCSI_DISK_TIMEOUT 10
159 #define PARTITION0_LIST_SIZE 4
160
161 \f
162 NTSTATUS
163 NTAPI
164 DriverEntry(
165 IN PDRIVER_OBJECT DriverObject,
166 IN PUNICODE_STRING RegistryPath
167 );
168
169 BOOLEAN
170 NTAPI
171 ScsiDiskDeviceVerification(
172 IN PINQUIRYDATA InquiryData
173 );
174
175 BOOLEAN
176 NTAPI
177 FindScsiDisks(
178 IN PDRIVER_OBJECT DriveObject,
179 IN PUNICODE_STRING RegistryPath,
180 IN PCLASS_INIT_DATA InitializationData,
181 IN PDEVICE_OBJECT PortDeviceObject,
182 IN ULONG PortNumber
183 );
184
185 NTSTATUS
186 NTAPI
187 ScsiDiskCreateClose (
188 IN PDEVICE_OBJECT DeviceObject,
189 IN PIRP Irp
190 );
191
192 NTSTATUS
193 NTAPI
194 ScsiDiskReadWriteVerification(
195 IN PDEVICE_OBJECT DeviceObject,
196 IN PIRP Irp
197 );
198
199 NTSTATUS
200 NTAPI
201 ScsiDiskDeviceControl(
202 IN PDEVICE_OBJECT DeviceObject,
203 IN PIRP Irp
204 );
205
206 VOID
207 NTAPI
208 ScsiDiskProcessError(
209 PDEVICE_OBJECT DeviceObject,
210 PSCSI_REQUEST_BLOCK Srb,
211 NTSTATUS *Status,
212 BOOLEAN *Retry
213 );
214
215 NTSTATUS
216 NTAPI
217 ScsiDiskShutdownFlush(
218 IN PDEVICE_OBJECT DeviceObject,
219 IN PIRP Irp
220 );
221
222 VOID
223 NTAPI
224 DisableWriteCache(
225 IN PDEVICE_OBJECT DeviceObject,
226 IN PSCSI_INQUIRY_DATA LunInfo
227 );
228
229 BOOLEAN
230 NTAPI
231 ScsiDiskModeSelect(
232 IN PDEVICE_OBJECT DeviceObject,
233 IN PCHAR ModeSelectBuffer,
234 IN ULONG Length,
235 IN BOOLEAN SavePage
236 );
237
238 BOOLEAN
239 NTAPI
240 IsFloppyDevice(
241 IN PDEVICE_OBJECT DeviceObject
242 );
243
244 BOOLEAN
245 NTAPI
246 CalculateMbrCheckSum(
247 IN PDEVICE_EXTENSION DeviceExtension,
248 OUT PULONG Checksum
249 );
250
251 BOOLEAN
252 NTAPI
253 EnumerateBusKey(
254 IN PDEVICE_EXTENSION DeviceExtension,
255 HANDLE BusKey,
256 PULONG DiskNumber
257 );
258
259 VOID
260 NTAPI
261 UpdateGeometry(
262 IN PDEVICE_EXTENSION DeviceExtension
263 );
264
265 NTSTATUS
266 NTAPI
267 UpdateRemovableGeometry (
268 IN PDEVICE_OBJECT DeviceObject,
269 IN PIRP Irp
270 );
271
272 NTSTATUS
273 NTAPI
274 CreateDiskDeviceObject(
275 IN PDRIVER_OBJECT DriverObject,
276 IN PUNICODE_STRING RegistryPath,
277 IN PDEVICE_OBJECT PortDeviceObject,
278 IN ULONG PortNumber,
279 IN PULONG DeviceCount,
280 IN PIO_SCSI_CAPABILITIES PortCapabilities,
281 IN PSCSI_INQUIRY_DATA LunInfo,
282 IN PCLASS_INIT_DATA InitData
283 );
284
285 NTSTATUS
286 NTAPI
287 CreatePartitionDeviceObjects(
288 IN PDEVICE_OBJECT PhysicalDeviceObject,
289 IN PUNICODE_STRING RegistryPath
290 );
291
292 VOID
293 NTAPI
294 UpdateDeviceObjects(
295 IN PDEVICE_OBJECT DeviceObject,
296 IN PIRP Irp
297 );
298
299 VOID
300 NTAPI
301 ScanForSpecial(
302 PDEVICE_OBJECT DeviceObject,
303 PSCSI_INQUIRY_DATA LunInfo,
304 PIO_SCSI_CAPABILITIES PortCapabilities
305 );
306
307 VOID
308 NTAPI
309 ResetScsiBus(
310 IN PDEVICE_OBJECT DeviceObject
311 );
312
313 #ifdef ALLOC_PRAGMA
314 #pragma alloc_text(PAGE, DriverEntry)
315 #pragma alloc_text(PAGE, FindScsiDisks)
316 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
317 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
318 #pragma alloc_text(PAGE, EnumerateBusKey)
319 #pragma alloc_text(PAGE, UpdateGeometry)
320 #pragma alloc_text(PAGE, IsFloppyDevice)
321 #pragma alloc_text(PAGE, ScanForSpecial)
322 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
323 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
324 #endif
325
326 \f
327 NTSTATUS
328 NTAPI
329 DriverEntry(
330 IN PDRIVER_OBJECT DriverObject,
331 IN PUNICODE_STRING RegistryPath
332 )
333
334 /*++
335
336 Routine Description:
337
338 This routine initializes the SCSI hard disk class driver.
339
340 Arguments:
341
342 DriverObject - Pointer to driver object created by system.
343
344 RegistryPath - Pointer to the name of the services node for this driver.
345
346 Return Value:
347
348 The function value is the final status from the initialization operation.
349
350 --*/
351
352 {
353 CLASS_INIT_DATA InitializationData;
354
355 //
356 // Zero InitData
357 //
358
359 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
360
361 //
362 // Set sizes
363 //
364
365 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
366 InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
367
368 InitializationData.DeviceType = FILE_DEVICE_DISK;
369 InitializationData.DeviceCharacteristics = 0;
370
371 //
372 // Set entry points
373 //
374
375 InitializationData.ClassError = ScsiDiskProcessError;
376 InitializationData.ClassReadWriteVerification = ScsiDiskReadWriteVerification;
377 InitializationData.ClassFindDevices = FindScsiDisks;
378 InitializationData.ClassFindDeviceCallBack = ScsiDiskDeviceVerification;
379 InitializationData.ClassDeviceControl = ScsiDiskDeviceControl;
380 InitializationData.ClassShutdownFlush = ScsiDiskShutdownFlush;
381 InitializationData.ClassCreateClose = NULL;
382
383 //
384 // Call the class init routine
385 //
386
387 return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
388
389 } // end DriverEntry()
390
391
392 \f
393 BOOLEAN
394 NTAPI
395 ScsiDiskDeviceVerification(
396 IN PINQUIRYDATA InquiryData
397 )
398
399 /*++
400
401 Routine Description:
402
403 This routine checks InquiryData for the correct device type and qualifier.
404
405 Arguments:
406
407 InquiryData - Pointer to the inquiry data for the device in question.
408
409 Return Value:
410
411 True is returned if the correct device type is found.
412
413 --*/
414 {
415
416 if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
417 (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
418 InquiryData->DeviceTypeQualifier == 0) {
419
420 return TRUE;
421
422 } else {
423 return FALSE;
424 }
425 }
426
427 \f
428 BOOLEAN
429 NTAPI
430 FindScsiDisks(
431 IN PDRIVER_OBJECT DriverObject,
432 IN PUNICODE_STRING RegistryPath,
433 IN PCLASS_INIT_DATA InitializationData,
434 IN PDEVICE_OBJECT PortDeviceObject,
435 IN ULONG PortNumber
436 )
437
438 /*++
439
440 Routine Description:
441
442 This routine gets a port drivers capabilities, obtains the
443 inquiry data, searches the SCSI bus for the port driver and creates
444 the device objects for the disks found.
445
446 Arguments:
447
448 DriverObject - Pointer to driver object created by system.
449
450 PortDeviceObject - Device object use to send requests to port driver.
451
452 PortNumber - Number for port driver. Used to pass on to
453 CreateDiskDeviceObjects() and create device objects.
454
455 Return Value:
456
457 True is returned if one disk was found and successfully created.
458
459 --*/
460
461 {
462 PIO_SCSI_CAPABILITIES portCapabilities;
463 PULONG diskCount;
464 PCONFIGURATION_INFORMATION configurationInformation;
465 PCHAR buffer;
466 PSCSI_INQUIRY_DATA lunInfo;
467 PSCSI_ADAPTER_BUS_INFO adapterInfo;
468 PINQUIRYDATA inquiryData;
469 ULONG scsiBus;
470 ULONG adapterDisk;
471 NTSTATUS status;
472 BOOLEAN foundOne = FALSE;
473
474 PAGED_CODE();
475
476 //
477 // Call port driver to get adapter capabilities.
478 //
479
480 status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
481
482 if (!NT_SUCCESS(status)) {
483 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
484 return(FALSE);
485 }
486
487 //
488 // Call port driver to get inquiry information to find disks.
489 //
490
491 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
492
493 if (!NT_SUCCESS(status)) {
494 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
495 return(FALSE);
496 }
497
498 //
499 // Do a quick scan of the devices on this adapter to determine how many
500 // disks are on this adapter. This is used to determine the number of
501 // SRB zone elements to allocate.
502 //
503
504 adapterDisk = 0;
505 adapterInfo = (PVOID) buffer;
506
507 adapterDisk = ScsiClassFindUnclaimedDevices(InitializationData, adapterInfo);
508
509 //
510 // Allocate a zone of SRB for disks on this adapter.
511 //
512
513 if (adapterDisk == 0) {
514
515 //
516 // No free disks were found.
517 //
518
519 return(FALSE);
520 }
521
522 //
523 // Get the number of disks already initialized.
524 //
525
526 configurationInformation = IoGetConfigurationInformation();
527 diskCount = &configurationInformation->DiskCount;
528
529 //
530 // For each SCSI bus this adapter supports ...
531 //
532
533 for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
534
535 //
536 // Get the SCSI bus scan data for this bus.
537 //
538
539 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
540
541 //
542 // Search list for unclaimed disk devices.
543 //
544
545 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
546
547 inquiryData = (PVOID)lunInfo->InquiryData;
548
549 if (((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
550 (inquiryData->DeviceType == OPTICAL_DEVICE)) &&
551 inquiryData->DeviceTypeQualifier == 0 &&
552 (!lunInfo->DeviceClaimed)) {
553
554 DebugPrint((1,
555 "FindScsiDevices: Vendor string is %.24s\n",
556 inquiryData->VendorId));
557
558 //
559 // Create device objects for disk
560 //
561
562 status = CreateDiskDeviceObject(DriverObject,
563 RegistryPath,
564 PortDeviceObject,
565 PortNumber,
566 diskCount,
567 portCapabilities,
568 lunInfo,
569 InitializationData);
570
571 if (NT_SUCCESS(status)) {
572
573 //
574 // Increment system disk device count.
575 //
576
577 (*diskCount)++;
578 foundOne = TRUE;
579
580 }
581 }
582
583 //
584 // Get next LunInfo.
585 //
586
587 if (lunInfo->NextInquiryDataOffset == 0) {
588 break;
589 }
590
591 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
592
593 }
594 }
595
596 //
597 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
598 //
599
600 ExFreePool(buffer);
601
602 return(foundOne);
603
604 } // end FindScsiDisks()
605
606 \f
607 NTSTATUS
608 NTAPI
609 CreateDiskDeviceObject(
610 IN PDRIVER_OBJECT DriverObject,
611 IN PUNICODE_STRING RegistryPath,
612 IN PDEVICE_OBJECT PortDeviceObject,
613 IN ULONG PortNumber,
614 IN PULONG DeviceCount,
615 IN PIO_SCSI_CAPABILITIES PortCapabilities,
616 IN PSCSI_INQUIRY_DATA LunInfo,
617 IN PCLASS_INIT_DATA InitData
618 )
619
620 /*++
621
622 Routine Description:
623
624 This routine creates an object for the physical device and then searches
625 the device for partitions and creates an object for each partition.
626
627 Arguments:
628
629 DriverObject - Pointer to driver object created by system.
630
631 PortDeviceObject - Miniport device object.
632
633 PortNumber - port number. Used in creating disk objects.
634
635 DeviceCount - Number of previously installed devices.
636
637 PortCapabilities - Capabilities of this SCSI port.
638
639 LunInfo - LUN specific information.
640
641 Return Value:
642
643 NTSTATUS
644
645 --*/
646 {
647 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
648 STRING ntNameString;
649 UNICODE_STRING ntUnicodeString;
650 OBJECT_ATTRIBUTES objectAttributes;
651 HANDLE handle;
652 NTSTATUS status;
653 PDEVICE_OBJECT deviceObject = NULL;
654 PDEVICE_OBJECT physicalDevice;
655 PDISK_GEOMETRY_EX diskGeometry = NULL;
656 PDEVICE_EXTENSION deviceExtension = NULL;
657 PDEVICE_EXTENSION physicalDeviceExtension;
658 UCHAR pathId = LunInfo->PathId;
659 UCHAR targetId = LunInfo->TargetId;
660 UCHAR lun = LunInfo->Lun;
661 BOOLEAN writeCache;
662 PVOID senseData = NULL;
663 ULONG srbFlags;
664 ULONG timeOut = 0;
665 BOOLEAN srbListInitialized = FALSE;
666
667
668 PAGED_CODE();
669
670 //
671 // Set up an object directory to contain the objects for this
672 // device and all its partitions.
673 //
674
675 sprintf(ntNameBuffer,
676 "\\Device\\Harddisk%lu",
677 *DeviceCount);
678
679 RtlInitString(&ntNameString,
680 ntNameBuffer);
681
682 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
683 &ntNameString,
684 TRUE);
685
686 if (!NT_SUCCESS(status)) {
687 return(status);
688 }
689
690 InitializeObjectAttributes(&objectAttributes,
691 &ntUnicodeString,
692 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
693 NULL,
694 NULL);
695
696 status = ZwCreateDirectoryObject(&handle,
697 DIRECTORY_ALL_ACCESS,
698 &objectAttributes);
699
700 RtlFreeUnicodeString(&ntUnicodeString);
701
702 if (!NT_SUCCESS(status)) {
703
704 DebugPrint((1,
705 "CreateDiskDeviceObjects: Could not create directory %s\n",
706 ntNameBuffer));
707
708 return(status);
709 }
710
711 //
712 // Claim the device.
713 //
714
715 status = ScsiClassClaimDevice(PortDeviceObject,
716 LunInfo,
717 FALSE,
718 &PortDeviceObject);
719
720 if (!NT_SUCCESS(status)) {
721 ZwMakeTemporaryObject(handle);
722 ZwClose(handle);
723 return status;
724 }
725
726 //
727 // Create a device object for this device. Each physical disk will
728 // have at least one device object. The required device object
729 // describes the entire device. Its directory path is
730 // \Device\HarddiskN\Partition0, where N = device number.
731 //
732
733 sprintf(ntNameBuffer,
734 "\\Device\\Harddisk%lu\\Partition0",
735 *DeviceCount);
736
737
738 status = ScsiClassCreateDeviceObject(DriverObject,
739 ntNameBuffer,
740 NULL,
741 &deviceObject,
742 InitData);
743
744 if (!NT_SUCCESS(status)) {
745
746 DebugPrint((1,
747 "CreateDiskDeviceObjects: Can not create device object %s\n",
748 ntNameBuffer));
749
750 goto CreateDiskDeviceObjectsExit;
751 }
752
753 //
754 // Indicate that IRPs should include MDLs for data transfers.
755 //
756
757 deviceObject->Flags |= DO_DIRECT_IO;
758
759 //
760 // Check if this is during initialization. If not indicate that
761 // system initialization already took place and this disk is ready
762 // to be accessed.
763 //
764
765 if (!RegistryPath) {
766 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
767 }
768
769 //
770 // Check for removable media support.
771 //
772
773 if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) {
774 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
775 }
776
777 //
778 // Set up required stack size in device object.
779 //
780
781 deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
782
783 deviceExtension = deviceObject->DeviceExtension;
784
785 //
786 // Allocate spinlock for split request completion.
787 //
788
789 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
790
791 //
792 // Initialize lock count to zero. The lock count is used to
793 // disable the ejection mechanism on devices that support
794 // removable media. Only the lock count in the physical
795 // device extension is used.
796 //
797
798 deviceExtension->LockCount = 0;
799
800 //
801 // Save system disk number.
802 //
803
804 deviceExtension->DeviceNumber = *DeviceCount;
805
806 //
807 // Copy port device object pointer to the device extension.
808 //
809
810 deviceExtension->PortDeviceObject = PortDeviceObject;
811
812 //
813 // Set the alignment requirements for the device based on the
814 // host adapter requirements
815 //
816
817 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
818 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
819 }
820
821 //
822 // This is the physical device object.
823 //
824
825 physicalDevice = deviceObject;
826 physicalDeviceExtension = deviceExtension;
827
828 //
829 // Save address of port driver capabilities.
830 //
831
832 deviceExtension->PortCapabilities = PortCapabilities;
833
834 //
835 // Build the lookaside list for srb's for the physical disk. Should only
836 // need a couple.
837 //
838
839 ScsiClassInitializeSrbLookasideList(deviceExtension,
840 PARTITION0_LIST_SIZE);
841
842 srbListInitialized = TRUE;
843
844 //
845 // Initialize the srb flags.
846 //
847
848 if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue &&
849 PortCapabilities->TaggedQueuing) {
850
851 deviceExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE;
852
853 } else {
854
855 deviceExtension->SrbFlags = 0;
856
857 }
858
859 //
860 // Allow queued requests if this is not removable media.
861 //
862
863 if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
864
865 deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
866
867 }
868
869 //
870 // Look for controller that require special flags.
871 //
872
873 ScanForSpecial(deviceObject,
874 LunInfo,
875 PortCapabilities);
876
877 srbFlags = deviceExtension->SrbFlags;
878
879 //
880 // Allocate buffer for drive geometry.
881 //
882
883 diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX));
884
885 if (diskGeometry == NULL) {
886
887 DebugPrint((1,
888 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
889 status = STATUS_INSUFFICIENT_RESOURCES;
890 goto CreateDiskDeviceObjectsExit;
891 }
892
893 deviceExtension->DiskGeometry = diskGeometry;
894
895 //
896 // Allocate request sense buffer.
897 //
898
899 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
900
901 if (senseData == NULL) {
902
903 //
904 // The buffer can not be allocated.
905 //
906
907 DebugPrint((1,
908 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
909
910 status = STATUS_INSUFFICIENT_RESOURCES;
911 goto CreateDiskDeviceObjectsExit;
912 }
913
914 //
915 // Set the sense data pointer in the device extension.
916 //
917
918 deviceExtension->SenseData = senseData;
919
920 //
921 // Physical device object will describe the entire
922 // device, starting at byte offset 0.
923 //
924
925 deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0);
926
927 //
928 // TargetId/LUN describes a device location on the SCSI bus.
929 // This information comes from the inquiry buffer.
930 //
931
932 deviceExtension->PortNumber = (UCHAR)PortNumber;
933 deviceExtension->PathId = pathId;
934 deviceExtension->TargetId = targetId;
935 deviceExtension->Lun = lun;
936
937 //
938 // Set timeout value in seconds.
939 //
940
941 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
942 if (timeOut) {
943 deviceExtension->TimeOutValue = timeOut;
944 } else {
945 deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
946 }
947
948 //
949 // Back pointer to device object.
950 //
951
952 deviceExtension->DeviceObject = deviceObject;
953
954 //
955 // If this is a removable device, then make sure it is not a floppy.
956 // Perform a mode sense command to determine the media type. Note
957 // IsFloppyDevice also checks for write cache enabled.
958 //
959
960 if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
961 (((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) {
962
963 status = STATUS_NO_SUCH_DEVICE;
964 goto CreateDiskDeviceObjectsExit;
965 }
966
967 DisableWriteCache(deviceObject,LunInfo);
968
969 writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
970
971 //
972 // NOTE: At this point one device object has been successfully created.
973 // from here on out return success.
974 //
975
976 //
977 // Do READ CAPACITY. This SCSI command
978 // returns the number of bytes on a device.
979 // Device extension is updated with device size.
980 //
981
982 status = ScsiClassReadDriveCapacity(deviceObject);
983
984 //
985 // If the read capcity failed then just return, unless this is a
986 // removable disk where a device object partition needs to be created.
987 //
988
989 if (!NT_SUCCESS(status) &&
990 !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
991
992 DebugPrint((1,
993 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
994 ntNameBuffer));
995
996 return(STATUS_SUCCESS);
997
998 } else {
999
1000 //
1001 // Make sure the volume verification bit is off so that
1002 // IoReadPartitionTable will work.
1003 //
1004
1005 deviceObject->Flags &= ~DO_VERIFY_VOLUME;
1006 }
1007
1008 status = CreatePartitionDeviceObjects(deviceObject, RegistryPath);
1009
1010 if (NT_SUCCESS(status))
1011 return STATUS_SUCCESS;
1012
1013
1014 CreateDiskDeviceObjectsExit:
1015
1016 //
1017 // Release the device since an error occurred.
1018 //
1019
1020 ScsiClassClaimDevice(PortDeviceObject,
1021 LunInfo,
1022 TRUE,
1023 NULL);
1024
1025 if (diskGeometry != NULL) {
1026 ExFreePool(diskGeometry);
1027 }
1028
1029 if (senseData != NULL) {
1030 ExFreePool(senseData);
1031 }
1032
1033 if (deviceObject != NULL) {
1034
1035 if (srbListInitialized) {
1036 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
1037 }
1038
1039 IoDeleteDevice(deviceObject);
1040 }
1041
1042 //
1043 // Delete directory and return.
1044 //
1045
1046 if (!NT_SUCCESS(status)) {
1047 ZwMakeTemporaryObject(handle);
1048 }
1049
1050 ZwClose(handle);
1051
1052 return(status);
1053
1054 } // end CreateDiskDeviceObjects()
1055
1056 \f
1057 NTSTATUS
1058 NTAPI
1059 CreatePartitionDeviceObjects(
1060 IN PDEVICE_OBJECT PhysicalDeviceObject,
1061 IN PUNICODE_STRING RegistryPath
1062 )
1063 {
1064 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
1065 ULONG partitionNumber = 0;
1066 NTSTATUS status;
1067 PDEVICE_OBJECT deviceObject = NULL;
1068 PDISK_GEOMETRY_EX diskGeometry = NULL;
1069 PDRIVE_LAYOUT_INFORMATION partitionList = NULL;
1070 PDEVICE_EXTENSION deviceExtension;
1071 PDEVICE_EXTENSION physicalDeviceExtension;
1072 PCLASS_INIT_DATA initData = NULL;
1073 PDISK_DATA diskData;
1074 PDISK_DATA physicalDiskData;
1075 ULONG bytesPerSector;
1076 UCHAR sectorShift;
1077 ULONG srbFlags;
1078 ULONG dmByteSkew = 0;
1079 PULONG dmSkew;
1080 BOOLEAN dmActive = FALSE;
1081 ULONG numberListElements = 0;
1082
1083
1084 //
1085 // Get physical device geometry information for partition table reads.
1086 //
1087
1088 physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension;
1089 diskGeometry = physicalDeviceExtension->DiskGeometry;
1090 bytesPerSector = diskGeometry->Geometry.BytesPerSector;
1091
1092 //
1093 // Make sure sector size is not zero.
1094 //
1095
1096 if (bytesPerSector == 0) {
1097
1098 //
1099 // Default sector size for disk is 512.
1100 //
1101
1102 bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512;
1103 }
1104
1105 sectorShift = physicalDeviceExtension->SectorShift;
1106
1107 //
1108 // Set pointer to disk data area that follows device extension.
1109 //
1110
1111 diskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1112 diskData->PartitionListState = Initializing;
1113
1114 //
1115 // Determine is DM Driver is loaded on an IDE drive that is
1116 // under control of Atapi - this could be either a crashdump or
1117 // an Atapi device is sharing the controller with an IDE disk.
1118 //
1119
1120 HalExamineMBR(PhysicalDeviceObject,
1121 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1122 (ULONG)0x54,
1123 (PVOID)&dmSkew);
1124
1125 if (dmSkew) {
1126
1127 //
1128 // Update the device extension, so that the call to IoReadPartitionTable
1129 // will get the correct information. Any I/O to this disk will have
1130 // to be skewed by *dmSkew sectors aka DMByteSkew.
1131 //
1132
1133 physicalDeviceExtension->DMSkew = *dmSkew;
1134 physicalDeviceExtension->DMActive = TRUE;
1135 physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector;
1136
1137 //
1138 // Save away the infomation that we need, since this deviceExtension will soon be
1139 // blown away.
1140 //
1141
1142 dmActive = TRUE;
1143 dmByteSkew = physicalDeviceExtension->DMByteSkew;
1144
1145 }
1146
1147 //
1148 // Create objects for all the partitions on the device.
1149 //
1150
1151 status = IoReadPartitionTable(PhysicalDeviceObject,
1152 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1153 TRUE,
1154 (PVOID)&partitionList);
1155
1156 //
1157 // If the I/O read partition table failed and this is a removable device,
1158 // then fix up the partition list to make it look like there is one
1159 // zero length partition.
1160 //
1161 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status);
1162 if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
1163 PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1164
1165 if (!NT_SUCCESS(status)) {
1166
1167 //
1168 // Remember this disk is not ready.
1169 //
1170
1171 diskData->DriveNotReady = TRUE;
1172
1173 } else {
1174
1175 //
1176 // Free the partition list allocated by IoReadPartitionTable.
1177 //
1178
1179 ExFreePool(partitionList);
1180 }
1181
1182 //
1183 // Allocate and zero a partition list.
1184 //
1185
1186 partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList ));
1187
1188
1189 if (partitionList != NULL) {
1190
1191 RtlZeroMemory( partitionList, sizeof( *partitionList ));
1192
1193 //
1194 // Set the partition count to one and the status to success
1195 // so one device object will be created. Set the partition type
1196 // to a bogus value.
1197 //
1198
1199 partitionList->PartitionCount = 1;
1200
1201 status = STATUS_SUCCESS;
1202 }
1203 }
1204
1205 if (NT_SUCCESS(status)) {
1206
1207 //
1208 // Record disk signature.
1209 //
1210
1211 diskData->Signature = partitionList->Signature;
1212
1213 //
1214 // If disk signature is zero, then calculate the MBR checksum.
1215 //
1216
1217 if (!diskData->Signature) {
1218
1219 if (!CalculateMbrCheckSum(physicalDeviceExtension,
1220 &diskData->MbrCheckSum)) {
1221
1222 DebugPrint((1,
1223 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1224 physicalDeviceExtension->DeviceNumber));
1225 } else {
1226
1227 DebugPrint((2,
1228 "SCSIDISK: MBR checksum for disk %x is %x\n",
1229 physicalDeviceExtension->DeviceNumber,
1230 diskData->MbrCheckSum));
1231 }
1232 }
1233
1234 //
1235 // Check the registry and determine if the BIOS knew about this drive. If
1236 // it did then update the geometry with the BIOS information.
1237 //
1238
1239 UpdateGeometry(physicalDeviceExtension);
1240
1241 srbFlags = physicalDeviceExtension->SrbFlags;
1242
1243 initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA));
1244 if (!initData)
1245 {
1246 DebugPrint((1,
1247 "Disk.CreatePartionDeviceObjects - Allocation of initData failed\n"));
1248
1249 status = STATUS_INSUFFICIENT_RESOURCES;
1250 goto CreatePartitionDeviceObjectsExit;
1251 }
1252
1253 RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA));
1254
1255 initData->InitializationDataSize = sizeof(CLASS_INIT_DATA);
1256 initData->DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
1257 initData->DeviceType = FILE_DEVICE_DISK;
1258 initData->DeviceCharacteristics = PhysicalDeviceObject->Characteristics;
1259 initData->ClassError = physicalDeviceExtension->ClassError;
1260 initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification;
1261 initData->ClassFindDevices = physicalDeviceExtension->ClassFindDevices;
1262 initData->ClassDeviceControl = physicalDeviceExtension->ClassDeviceControl;
1263 initData->ClassShutdownFlush = physicalDeviceExtension->ClassShutdownFlush;
1264 initData->ClassCreateClose = physicalDeviceExtension->ClassCreateClose;
1265 initData->ClassStartIo = physicalDeviceExtension->ClassStartIo;
1266
1267 //
1268 // Create device objects for the device partitions (if any).
1269 // PartitionCount includes physical device partition 0,
1270 // so only one partition means no objects to create.
1271 //
1272
1273 DebugPrint((2,
1274 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1275 partitionList->PartitionCount));
1276
1277 for (partitionNumber = 0; partitionNumber <
1278 partitionList->PartitionCount; partitionNumber++) {
1279
1280 //
1281 // Create partition object and set up partition parameters.
1282 //
1283
1284 sprintf(ntNameBuffer,
1285 "\\Device\\Harddisk%lu\\Partition%lu",
1286 physicalDeviceExtension->DeviceNumber,
1287 partitionNumber + 1);
1288
1289 DebugPrint((2,
1290 "CreateDiskDeviceObjects: Create device object %s\n",
1291 ntNameBuffer));
1292
1293 status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject,
1294 ntNameBuffer,
1295 PhysicalDeviceObject,
1296 &deviceObject,
1297 initData);
1298
1299 if (!NT_SUCCESS(status)) {
1300
1301 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer));
1302
1303 break;
1304 }
1305
1306 //
1307 // Set up device object fields.
1308 //
1309
1310 deviceObject->Flags |= DO_DIRECT_IO;
1311
1312 //
1313 // Check if this is during initialization. If not indicate that
1314 // system initialization already took place and this disk is ready
1315 // to be accessed.
1316 //
1317
1318 if (!RegistryPath) {
1319 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1320 }
1321
1322 deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1;
1323
1324 //
1325 // Set up device extension fields.
1326 //
1327
1328 deviceExtension = deviceObject->DeviceExtension;
1329
1330 if (dmActive) {
1331
1332 //
1333 // Restore any saved DM values.
1334 //
1335
1336 deviceExtension->DMByteSkew = dmByteSkew;
1337 deviceExtension->DMSkew = *dmSkew;
1338 deviceExtension->DMActive = TRUE;
1339
1340 }
1341
1342 //
1343 // Link new device extension to previous disk data
1344 // to support dynamic partitioning.
1345 //
1346
1347 diskData->NextPartition = deviceExtension;
1348
1349 //
1350 // Get pointer to new disk data.
1351 //
1352
1353 diskData = (PDISK_DATA)(deviceExtension + 1);
1354
1355 //
1356 // Set next partition pointer to NULL in case this is the
1357 // last partition.
1358 //
1359
1360 diskData->NextPartition = NULL;
1361
1362 //
1363 // Allocate spinlock for zoning for split-request completion.
1364 //
1365
1366 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
1367
1368 //
1369 // Copy port device object pointer to device extension.
1370 //
1371
1372 deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject;
1373
1374 //
1375 // Set the alignment requirements for the device based on the
1376 // host adapter requirements
1377 //
1378
1379 if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
1380 deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement;
1381 }
1382
1383
1384 if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
1385 numberListElements = 30;
1386 } else {
1387 numberListElements = 8;
1388 }
1389
1390 //
1391 // Build the lookaside list for srb's for this partition based on
1392 // whether the adapter and disk can do tagged queueing.
1393 //
1394
1395 ScsiClassInitializeSrbLookasideList(deviceExtension,
1396 numberListElements);
1397
1398 deviceExtension->SrbFlags = srbFlags;
1399
1400 //
1401 // Set the sense-data pointer in the device extension.
1402 //
1403
1404 deviceExtension->SenseData = physicalDeviceExtension->SenseData;
1405 deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities;
1406 deviceExtension->DiskGeometry = diskGeometry;
1407 diskData->PartitionOrdinal = diskData->PartitionNumber = partitionNumber + 1;
1408 diskData->PartitionType = partitionList->PartitionEntry[partitionNumber].PartitionType;
1409 diskData->BootIndicator = partitionList->PartitionEntry[partitionNumber].BootIndicator;
1410
1411 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1412 diskData->PartitionType));
1413
1414 deviceExtension->StartingOffset = partitionList->PartitionEntry[partitionNumber].StartingOffset;
1415 deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength;
1416 diskData->HiddenSectors = partitionList->PartitionEntry[partitionNumber].HiddenSectors;
1417 deviceExtension->PortNumber = physicalDeviceExtension->PortNumber;
1418 deviceExtension->PathId = physicalDeviceExtension->PathId;
1419 deviceExtension->TargetId = physicalDeviceExtension->TargetId;
1420 deviceExtension->Lun = physicalDeviceExtension->Lun;
1421
1422 //
1423 // Check for removable media support.
1424 //
1425
1426 if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1427 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
1428 }
1429
1430 //
1431 // Set timeout value in seconds.
1432 //
1433
1434 deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue;
1435 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector;
1436 deviceExtension->SectorShift = sectorShift;
1437 deviceExtension->DeviceObject = deviceObject;
1438 deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags;
1439
1440 } // end for (partitionNumber) ...
1441
1442 //
1443 // Free the buffer allocated by reading the
1444 // partition table.
1445 //
1446
1447 ExFreePool(partitionList);
1448
1449 } else {
1450
1451 CreatePartitionDeviceObjectsExit:
1452
1453 if (partitionList) {
1454 ExFreePool(partitionList);
1455 }
1456 if (initData) {
1457 ExFreePool(initData);
1458 }
1459
1460 return status;
1461
1462 } // end if...else
1463
1464
1465 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1466 physicalDiskData->PartitionListState = Initialized;
1467
1468 return(STATUS_SUCCESS);
1469
1470
1471 } // end CreatePartitionDeviceObjects()
1472
1473 \f
1474 NTSTATUS
1475 NTAPI
1476 ScsiDiskReadWriteVerification(
1477 IN PDEVICE_OBJECT DeviceObject,
1478 IN PIRP Irp
1479 )
1480
1481 /*++
1482
1483 Routine Description:
1484
1485 I/O System entry for read and write requests to SCSI disks.
1486
1487 Arguments:
1488
1489 DeviceObject - Pointer to driver object created by system.
1490 Irp - IRP involved.
1491
1492 Return Value:
1493
1494 NT Status
1495
1496 --*/
1497
1498 {
1499 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1500 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1501 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1502 LARGE_INTEGER startingOffset;
1503
1504 //
1505 // Verify parameters of this request.
1506 // Check that ending sector is within partition and
1507 // that number of bytes to transfer is a multiple of
1508 // the sector size.
1509 //
1510
1511 startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
1512 transferByteCount);
1513
1514 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
1515 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
1516
1517 //
1518 // This error maybe caused by the fact that the drive is not ready.
1519 //
1520
1521 if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) {
1522
1523 //
1524 // Flag this as a user errror so that a popup is generated.
1525 //
1526
1527 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
1528 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1529
1530 } else {
1531
1532 //
1533 // Note fastfat depends on this parameter to determine when to
1534 // remount do to a sector size change.
1535 //
1536
1537 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1538 }
1539
1540 return STATUS_INVALID_PARAMETER;
1541 }
1542
1543 return STATUS_SUCCESS;
1544
1545 } // end ScsiDiskReadWrite()
1546
1547 \f
1548 NTSTATUS
1549 NTAPI
1550 ScsiDiskDeviceControl(
1551 PDEVICE_OBJECT DeviceObject,
1552 PIRP Irp
1553 )
1554
1555 /*++
1556
1557 Routine Description:
1558
1559 I/O system entry for device controls to SCSI disks.
1560
1561 Arguments:
1562
1563 DeviceObject - Pointer to driver object created by system.
1564 Irp - IRP involved.
1565
1566 Return Value:
1567
1568 Status is returned.
1569
1570 --*/
1571
1572 {
1573 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1574 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1575 PDISK_DATA diskData = (PDISK_DATA)(deviceExtension + 1);
1576 PSCSI_REQUEST_BLOCK srb;
1577 PCDB cdb;
1578 PMODE_PARAMETER_HEADER modeData;
1579 PIRP irp2;
1580 ULONG length;
1581 NTSTATUS status;
1582 KEVENT event;
1583 IO_STATUS_BLOCK ioStatus;
1584
1585 PAGED_CODE();
1586
1587 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
1588
1589 if (srb == NULL) {
1590
1591 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1592 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1593 return(STATUS_INSUFFICIENT_RESOURCES);
1594 }
1595
1596 //
1597 // Write zeros to Srb.
1598 //
1599
1600 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1601
1602 cdb = (PCDB)srb->Cdb;
1603
1604 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1605
1606 case SMART_GET_VERSION: {
1607
1608 ULONG_PTR buffer;
1609 PSRB_IO_CONTROL srbControl;
1610 PGETVERSIONINPARAMS versionParams;
1611
1612 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1613 sizeof(GETVERSIONINPARAMS)) {
1614 status = STATUS_INVALID_PARAMETER;
1615 break;
1616 }
1617
1618 //
1619 // Create notification event object to be used to signal the
1620 // request completion.
1621 //
1622
1623 KeInitializeEvent(&event, NotificationEvent, FALSE);
1624
1625 srbControl = ExAllocatePool(NonPagedPool,
1626 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
1627
1628 if (!srbControl) {
1629 status = STATUS_INSUFFICIENT_RESOURCES;
1630 break;
1631 }
1632
1633 //
1634 // fill in srbControl fields
1635 //
1636
1637 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1638 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1639 srbControl->Timeout = deviceExtension->TimeOutValue;
1640 srbControl->Length = sizeof(GETVERSIONINPARAMS);
1641 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
1642
1643 //
1644 // Point to the 'buffer' portion of the SRB_CONTROL
1645 //
1646
1647 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1648
1649 //
1650 // Ensure correct target is set in the cmd parameters.
1651 //
1652
1653 versionParams = (PGETVERSIONINPARAMS)buffer;
1654 versionParams->bIDEDeviceMap = deviceExtension->TargetId;
1655
1656 //
1657 // Copy the IOCTL parameters to the srb control buffer area.
1658 //
1659
1660 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS));
1661
1662
1663 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1664 deviceExtension->PortDeviceObject,
1665 srbControl,
1666 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1667 srbControl,
1668 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1669 FALSE,
1670 &event,
1671 &ioStatus);
1672
1673 if (irp2 == NULL) {
1674 status = STATUS_INSUFFICIENT_RESOURCES;
1675 break;
1676 }
1677
1678 //
1679 // Call the port driver with the request and wait for it to complete.
1680 //
1681
1682 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1683
1684 if (status == STATUS_PENDING) {
1685 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1686 status = ioStatus.Status;
1687 }
1688
1689 //
1690 // If successful, copy the data received into the output buffer.
1691 // This should only fail in the event that the IDE driver is older than this driver.
1692 //
1693
1694 if (NT_SUCCESS(status)) {
1695
1696 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1697
1698 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS));
1699 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1700 }
1701
1702 ExFreePool(srbControl);
1703 break;
1704 }
1705
1706 case SMART_RCV_DRIVE_DATA: {
1707
1708 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1709 ULONG controlCode = 0;
1710 PSRB_IO_CONTROL srbControl;
1711 ULONG_PTR buffer;
1712
1713 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1714 (sizeof(SENDCMDINPARAMS) - 1)) {
1715 status = STATUS_INVALID_PARAMETER;
1716 break;
1717
1718 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1719 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
1720 status = STATUS_INVALID_PARAMETER;
1721 break;
1722 }
1723
1724 //
1725 // Create notification event object to be used to signal the
1726 // request completion.
1727 //
1728
1729 KeInitializeEvent(&event, NotificationEvent, FALSE);
1730
1731 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
1732
1733 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1734 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
1735
1736 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1737 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1738 case READ_ATTRIBUTES:
1739 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
1740 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1741 break;
1742 case READ_THRESHOLDS:
1743 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
1744 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1745 break;
1746 default:
1747 status = STATUS_INVALID_PARAMETER;
1748 break;
1749 }
1750 } else {
1751
1752 status = STATUS_INVALID_PARAMETER;
1753 }
1754
1755 if (controlCode == 0) {
1756 status = STATUS_INVALID_PARAMETER;
1757 break;
1758 }
1759
1760 srbControl = ExAllocatePool(NonPagedPool,
1761 sizeof(SRB_IO_CONTROL) + length);
1762
1763 if (!srbControl) {
1764 status = STATUS_INSUFFICIENT_RESOURCES;
1765 break;
1766 }
1767
1768 //
1769 // fill in srbControl fields
1770 //
1771
1772 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1773 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1774 srbControl->Timeout = deviceExtension->TimeOutValue;
1775 srbControl->Length = length;
1776 srbControl->ControlCode = controlCode;
1777
1778 //
1779 // Point to the 'buffer' portion of the SRB_CONTROL
1780 //
1781
1782 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1783
1784 //
1785 // Ensure correct target is set in the cmd parameters.
1786 //
1787
1788 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1789
1790 //
1791 // Copy the IOCTL parameters to the srb control buffer area.
1792 //
1793
1794 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1795
1796 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1797 deviceExtension->PortDeviceObject,
1798 srbControl,
1799 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1800 srbControl,
1801 sizeof(SRB_IO_CONTROL) + length,
1802 FALSE,
1803 &event,
1804 &ioStatus);
1805
1806 if (irp2 == NULL) {
1807 status = STATUS_INSUFFICIENT_RESOURCES;
1808 break;
1809 }
1810
1811 //
1812 // Call the port driver with the request and wait for it to complete.
1813 //
1814
1815 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1816
1817 if (status == STATUS_PENDING) {
1818 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1819 status = ioStatus.Status;
1820 }
1821
1822 //
1823 // If successful, copy the data received into the output buffer
1824 //
1825
1826 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1827
1828 if (NT_SUCCESS(status)) {
1829
1830 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1);
1831 Irp->IoStatus.Information = length - 1;
1832
1833 } else {
1834
1835 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
1836 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
1837
1838 }
1839
1840 ExFreePool(srbControl);
1841 break;
1842
1843 }
1844
1845 case SMART_SEND_DRIVE_COMMAND: {
1846
1847 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1848 PSRB_IO_CONTROL srbControl;
1849 ULONG controlCode = 0;
1850 ULONG_PTR buffer;
1851
1852 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1853 (sizeof(SENDCMDINPARAMS) - 1)) {
1854 status = STATUS_INVALID_PARAMETER;
1855 break;
1856
1857 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1858 (sizeof(SENDCMDOUTPARAMS) - 1)) {
1859 status = STATUS_INVALID_PARAMETER;
1860 break;
1861 }
1862
1863 //
1864 // Create notification event object to be used to signal the
1865 // request completion.
1866 //
1867
1868 KeInitializeEvent(&event, NotificationEvent, FALSE);
1869
1870 length = 0;
1871
1872 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1873 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1874
1875 case ENABLE_SMART:
1876 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
1877 break;
1878
1879 case DISABLE_SMART:
1880 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
1881 break;
1882
1883 case RETURN_SMART_STATUS:
1884
1885 //
1886 // Ensure bBuffer is at least 2 bytes (to hold the values of
1887 // cylinderLow and cylinderHigh).
1888 //
1889
1890 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1891 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
1892
1893 status = STATUS_INVALID_PARAMETER;
1894 break;
1895 }
1896
1897 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
1898 length = sizeof(IDEREGS);
1899 break;
1900
1901 case ENABLE_DISABLE_AUTOSAVE:
1902 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
1903 break;
1904
1905 case SAVE_ATTRIBUTE_VALUES:
1906 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
1907 break;
1908
1909 case EXECUTE_OFFLINE_DIAGS:
1910 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
1911
1912 default:
1913 status = STATUS_INVALID_PARAMETER;
1914 break;
1915 }
1916 } else {
1917
1918 status = STATUS_INVALID_PARAMETER;
1919 }
1920
1921 if (controlCode == 0) {
1922 status = STATUS_INVALID_PARAMETER;
1923 break;
1924 }
1925
1926 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);
1927 srbControl = ExAllocatePool(NonPagedPool,
1928 sizeof(SRB_IO_CONTROL) + length);
1929
1930 if (!srbControl) {
1931 status = STATUS_INSUFFICIENT_RESOURCES;
1932 break;
1933 }
1934
1935 //
1936 // fill in srbControl fields
1937 //
1938
1939 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1940 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1941 srbControl->Timeout = deviceExtension->TimeOutValue;
1942 srbControl->Length = length;
1943
1944 //
1945 // Point to the 'buffer' portion of the SRB_CONTROL
1946 //
1947
1948 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1949
1950 //
1951 // Ensure correct target is set in the cmd parameters.
1952 //
1953
1954 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1955
1956 //
1957 // Copy the IOCTL parameters to the srb control buffer area.
1958 //
1959
1960 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1961
1962 srbControl->ControlCode = controlCode;
1963
1964 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1965 deviceExtension->PortDeviceObject,
1966 srbControl,
1967 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1968 srbControl,
1969 sizeof(SRB_IO_CONTROL) + length,
1970 FALSE,
1971 &event,
1972 &ioStatus);
1973
1974 if (irp2 == NULL) {
1975 status = STATUS_INSUFFICIENT_RESOURCES;
1976 break;
1977 }
1978
1979 //
1980 // Call the port driver with the request and wait for it to complete.
1981 //
1982
1983 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1984
1985 if (status == STATUS_PENDING) {
1986 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1987 status = ioStatus.Status;
1988 }
1989
1990 //
1991 // Copy the data received into the output buffer. Since the status buffer
1992 // contains error information also, always perform this copy. IO will will
1993 // either pass this back to the app, or zero it, in case of error.
1994 //
1995
1996 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1997
1998 //
1999 // Update the return buffer size based on the sub-command.
2000 //
2001
2002 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
2003 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
2004 } else {
2005 length = sizeof(SENDCMDOUTPARAMS) - 1;
2006 }
2007
2008 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length);
2009 Irp->IoStatus.Information = length;
2010
2011 ExFreePool(srbControl);
2012 break;
2013
2014 }
2015
2016 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
2017 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
2018 {
2019
2020 PDEVICE_EXTENSION physicalDeviceExtension;
2021 PDISK_DATA physicalDiskData;
2022 BOOLEAN removable = FALSE;
2023 BOOLEAN listInitialized = FALSE;
2024
2025 if ((irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY &&
2026 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2027 sizeof(DISK_GEOMETRY)) ||
2028 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX &&
2029 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2030 sizeof(DISK_GEOMETRY_EX))) {
2031
2032 status = STATUS_INFO_LENGTH_MISMATCH;
2033 break;
2034 }
2035
2036 status = STATUS_SUCCESS;
2037
2038 physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2039 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
2040
2041 removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA;
2042 listInitialized = (physicalDiskData->PartitionListState == Initialized);
2043
2044 if (removable || (!listInitialized))
2045 {
2046 //
2047 // Issue ReadCapacity to update device extension
2048 // with information for current media.
2049 //
2050
2051 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
2052
2053 }
2054
2055 if (removable) {
2056
2057 if (!NT_SUCCESS(status)) {
2058
2059 //
2060 // Note the drive is not ready.
2061 //
2062
2063 diskData->DriveNotReady = TRUE;
2064
2065 break;
2066 }
2067
2068 //
2069 // Note the drive is now ready.
2070 //
2071
2072 diskData->DriveNotReady = FALSE;
2073
2074 } else if (NT_SUCCESS(status)) {
2075
2076 // ReadDriveCapacity was allright, create Partition Objects
2077
2078 if (physicalDiskData->PartitionListState == NotInitialized) {
2079 status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL);
2080 }
2081 }
2082
2083 if (NT_SUCCESS(status)) {
2084
2085 //
2086 // Copy drive geometry information from device extension.
2087 //
2088
2089 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2090 deviceExtension->DiskGeometry,
2091 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2092 sizeof(DISK_GEOMETRY) :
2093 sizeof(DISK_GEOMETRY_EX));
2094
2095 status = STATUS_SUCCESS;
2096 Irp->IoStatus.Information =
2097 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2098 sizeof(DISK_GEOMETRY) :
2099 sizeof(DISK_GEOMETRY_EX);
2100 }
2101
2102 break;
2103
2104 }
2105
2106 case IOCTL_DISK_VERIFY:
2107
2108 {
2109
2110 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2111 LARGE_INTEGER byteOffset;
2112 ULONG sectorOffset;
2113 USHORT sectorCount;
2114
2115 //
2116 // Validate buffer length.
2117 //
2118
2119 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2120 sizeof(VERIFY_INFORMATION)) {
2121
2122 status = STATUS_INFO_LENGTH_MISMATCH;
2123 break;
2124 }
2125
2126 //
2127 // Verify sectors
2128 //
2129
2130 srb->CdbLength = 10;
2131
2132 cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2133
2134 //
2135 // Add disk offset to starting sector.
2136 //
2137
2138 byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart +
2139 verifyInfo->StartingOffset.QuadPart;
2140
2141 //
2142 // Convert byte offset to sector offset.
2143 //
2144
2145 sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift);
2146
2147 //
2148 // Convert ULONG byte count to USHORT sector count.
2149 //
2150
2151 sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift);
2152
2153 //
2154 // Move little endian values into CDB in big endian format.
2155 //
2156
2157 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2158 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2159 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2160 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2161
2162 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
2163 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
2164
2165 //
2166 // The verify command is used by the NT FORMAT utility and
2167 // requests are sent down for 5% of the volume size. The
2168 // request timeout value is calculated based on the number of
2169 // sectors verified.
2170 //
2171
2172 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
2173 deviceExtension->TimeOutValue;
2174
2175 status = ScsiClassSendSrbAsynchronous(DeviceObject,
2176 srb,
2177 Irp,
2178 NULL,
2179 0,
2180 FALSE);
2181
2182 return(status);
2183
2184 }
2185
2186 case IOCTL_DISK_GET_PARTITION_INFO:
2187
2188 //
2189 // Return the information about the partition specified by the device
2190 // object. Note that no information is ever returned about the size
2191 // or partition type of the physical disk, as this doesn't make any
2192 // sense.
2193 //
2194
2195 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2196 sizeof(PARTITION_INFORMATION)) {
2197
2198 status = STATUS_INFO_LENGTH_MISMATCH;
2199
2200 }
2201 #if 0 // HACK: ReactOS partition numbers must be wrong
2202 else if (diskData->PartitionNumber == 0) {
2203
2204 //
2205 // Paritition zero is not a partition so this is not a
2206 // reasonable request.
2207 //
2208
2209 status = STATUS_INVALID_DEVICE_REQUEST;
2210
2211 }
2212 #endif
2213 else {
2214
2215 PPARTITION_INFORMATION outputBuffer;
2216
2217 //
2218 // Update the geometry in case it has changed.
2219 //
2220
2221 status = UpdateRemovableGeometry (DeviceObject, Irp);
2222
2223 if (!NT_SUCCESS(status)) {
2224
2225 //
2226 // Note the drive is not ready.
2227 //
2228
2229 diskData->DriveNotReady = TRUE;
2230 break;
2231 }
2232
2233 //
2234 // Note the drive is now ready.
2235 //
2236
2237 diskData->DriveNotReady = FALSE;
2238 // HACK: ReactOS partition numbers must be wrong (>0 part)
2239 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2240
2241 status = STATUS_INVALID_DEVICE_REQUEST;
2242 break;
2243 }
2244
2245 outputBuffer =
2246 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2247
2248 outputBuffer->PartitionType = diskData->PartitionType;
2249 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2250 outputBuffer->PartitionLength.QuadPart = (diskData->PartitionNumber) ?
2251 deviceExtension->PartitionLength.QuadPart : 2305843009213693951LL; // HACK
2252 outputBuffer->HiddenSectors = diskData->HiddenSectors;
2253 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2254 outputBuffer->BootIndicator = diskData->BootIndicator;
2255 outputBuffer->RewritePartition = FALSE;
2256 outputBuffer->RecognizedPartition =
2257 IsRecognizedPartition(diskData->PartitionType);
2258
2259 status = STATUS_SUCCESS;
2260 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
2261 }
2262
2263 break;
2264
2265 case IOCTL_DISK_GET_PARTITION_INFO_EX:
2266
2267 //
2268 // Return the information about the partition specified by the device
2269 // object. Note that no information is ever returned about the size
2270 // or partition type of the physical disk, as this doesn't make any
2271 // sense.
2272 //
2273
2274 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2275 sizeof(PARTITION_INFORMATION_EX)) {
2276
2277 status = STATUS_INFO_LENGTH_MISMATCH;
2278
2279 }
2280 else if (diskData->PartitionNumber == 0) {
2281
2282 //
2283 // Paritition zero is not a partition so this is not a
2284 // reasonable request.
2285 //
2286
2287 status = STATUS_INVALID_DEVICE_REQUEST;
2288
2289 }
2290 else {
2291
2292 PPARTITION_INFORMATION_EX outputBuffer;
2293
2294 //
2295 // Update the geometry in case it has changed.
2296 //
2297
2298 status = UpdateRemovableGeometry (DeviceObject, Irp);
2299
2300 if (!NT_SUCCESS(status)) {
2301
2302 //
2303 // Note the drive is not ready.
2304 //
2305
2306 diskData->DriveNotReady = TRUE;
2307 break;
2308 }
2309
2310 //
2311 // Note the drive is now ready.
2312 //
2313
2314 diskData->DriveNotReady = FALSE;
2315
2316 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2317
2318 status = STATUS_INVALID_DEVICE_REQUEST;
2319 break;
2320 }
2321
2322 outputBuffer =
2323 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
2324
2325 //
2326 // FIXME: hack of the year, assume that partition is MBR
2327 // Thing that can obviously be wrong...
2328 //
2329
2330 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
2331 outputBuffer->Mbr.PartitionType = diskData->PartitionType;
2332 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2333 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2334 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors;
2335 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2336 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator;
2337 outputBuffer->RewritePartition = FALSE;
2338 outputBuffer->Mbr.RecognizedPartition =
2339 IsRecognizedPartition(diskData->PartitionType);
2340
2341 status = STATUS_SUCCESS;
2342 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
2343 }
2344
2345 break;
2346
2347 case IOCTL_DISK_SET_PARTITION_INFO:
2348
2349 if (diskData->PartitionNumber == 0) {
2350
2351 status = STATUS_UNSUCCESSFUL;
2352
2353 } else {
2354
2355 PSET_PARTITION_INFORMATION inputBuffer =
2356 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2357
2358 //
2359 // Validate buffer length.
2360 //
2361
2362 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2363 sizeof(SET_PARTITION_INFORMATION)) {
2364
2365 status = STATUS_INFO_LENGTH_MISMATCH;
2366 break;
2367 }
2368
2369 //
2370 // The HAL routines IoGet- and IoSetPartitionInformation were
2371 // developed before support of dynamic partitioning and therefore
2372 // don't distinguish between partition ordinal (that is the order
2373 // of a partition on a disk) and the partition number. (The
2374 // partition number is assigned to a partition to identify it to
2375 // the system.) Use partition ordinals for these legacy calls.
2376 //
2377
2378 status = IoSetPartitionInformation(
2379 deviceExtension->PhysicalDevice,
2380 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2381 diskData->PartitionOrdinal,
2382 inputBuffer->PartitionType);
2383
2384 if (NT_SUCCESS(status)) {
2385
2386 diskData->PartitionType = inputBuffer->PartitionType;
2387 }
2388 }
2389
2390 break;
2391
2392 case IOCTL_DISK_GET_DRIVE_LAYOUT:
2393
2394 //
2395 // Return the partition layout for the physical drive. Note that
2396 // the layout is returned for the actual physical drive, regardless
2397 // of which partition was specified for the request.
2398 //
2399
2400 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2401 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2402 status = STATUS_INFO_LENGTH_MISMATCH;
2403
2404 } else {
2405
2406 PDRIVE_LAYOUT_INFORMATION partitionList;
2407 PDEVICE_EXTENSION physicalExtension = deviceExtension;
2408 PPARTITION_INFORMATION partitionEntry;
2409 PDISK_DATA diskData;
2410 ULONG tempSize;
2411 ULONG i;
2412
2413 //
2414 // Read partition information.
2415 //
2416
2417 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
2418 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2419 FALSE,
2420 &partitionList);
2421
2422 if (!NT_SUCCESS(status)) {
2423 break;
2424 }
2425
2426 //
2427 // The disk layout has been returned in the partitionList
2428 // buffer. Determine its size and, if the data will fit
2429 // into the intermediatery buffer, return it.
2430 //
2431
2432 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
2433 tempSize += partitionList->PartitionCount *
2434 sizeof(PARTITION_INFORMATION);
2435
2436 if (tempSize >
2437 irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
2438
2439 status = STATUS_BUFFER_TOO_SMALL;
2440 ExFreePool(partitionList);
2441 break;
2442 }
2443
2444 //
2445 // Walk partition list to associate partition numbers with
2446 // partition entries.
2447 //
2448
2449 for (i = 0; i < partitionList->PartitionCount; i++) {
2450
2451 //
2452 // Walk partition chain anchored at physical disk extension.
2453 //
2454
2455 deviceExtension = physicalExtension;
2456 diskData = (PDISK_DATA)(deviceExtension + 1);
2457
2458 do {
2459
2460 deviceExtension = diskData->NextPartition;
2461
2462 //
2463 // Check if this is the last partition in the chain.
2464 //
2465
2466 if (!deviceExtension) {
2467 break;
2468 }
2469
2470 //
2471 // Get the partition device extension from disk data.
2472 //
2473
2474 diskData = (PDISK_DATA)(deviceExtension + 1);
2475
2476 //
2477 // Check if this partition is not currently being used.
2478 //
2479
2480 if (!deviceExtension->PartitionLength.QuadPart) {
2481 continue;
2482 }
2483
2484 partitionEntry = &partitionList->PartitionEntry[i];
2485
2486 //
2487 // Check if empty, or describes extended partiton or hasn't changed.
2488 //
2489
2490 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2491 IsContainerPartition(partitionEntry->PartitionType)) {
2492 continue;
2493 }
2494
2495 //
2496 // Check if new partition starts where this partition starts.
2497 //
2498
2499 if (partitionEntry->StartingOffset.QuadPart !=
2500 deviceExtension->StartingOffset.QuadPart) {
2501 continue;
2502 }
2503
2504 //
2505 // Check if partition length is the same.
2506 //
2507
2508 if (partitionEntry->PartitionLength.QuadPart ==
2509 deviceExtension->PartitionLength.QuadPart) {
2510
2511 //
2512 // Partitions match. Update partition number.
2513 //
2514
2515 partitionEntry->PartitionNumber =
2516 diskData->PartitionNumber;
2517 break;
2518 }
2519
2520 } while (TRUE);
2521 }
2522
2523 //
2524 // Copy partition information to system buffer.
2525 //
2526
2527 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2528 partitionList,
2529 tempSize);
2530 status = STATUS_SUCCESS;
2531 Irp->IoStatus.Information = tempSize;
2532
2533 //
2534 // Finally, free the buffer allocated by reading the
2535 // partition table.
2536 //
2537
2538 ExFreePool(partitionList);
2539 }
2540
2541 break;
2542
2543 case IOCTL_DISK_SET_DRIVE_LAYOUT:
2544
2545 {
2546
2547 //
2548 // Update the disk with new partition information.
2549 //
2550
2551 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
2552
2553 //
2554 // Validate buffer length.
2555 //
2556
2557 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2558 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2559
2560 status = STATUS_INFO_LENGTH_MISMATCH;
2561 break;
2562 }
2563
2564 length = sizeof(DRIVE_LAYOUT_INFORMATION) +
2565 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
2566
2567
2568 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2569 length) {
2570
2571 status = STATUS_BUFFER_TOO_SMALL;
2572 break;
2573 }
2574
2575 //
2576 // Verify that device object is for physical disk.
2577 //
2578
2579 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
2580 status = STATUS_INVALID_PARAMETER;
2581 break;
2582 }
2583
2584 //
2585 // Walk through partition table comparing partitions to
2586 // existing partitions to create, delete and change
2587 // device objects as necessary.
2588 //
2589
2590 UpdateDeviceObjects(DeviceObject,
2591 Irp);
2592
2593 //
2594 // Write changes to disk.
2595 //
2596
2597 status = IoWritePartitionTable(
2598 deviceExtension->DeviceObject,
2599 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2600 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
2601 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
2602 partitionList);
2603 }
2604
2605 //
2606 // Update IRP with bytes returned.
2607 //
2608
2609 if (NT_SUCCESS(status)) {
2610 Irp->IoStatus.Information = length;
2611 }
2612
2613 break;
2614
2615 case IOCTL_DISK_REASSIGN_BLOCKS:
2616
2617 //
2618 // Map defective blocks to new location on disk.
2619 //
2620
2621 {
2622
2623 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2624 ULONG bufferSize;
2625 ULONG blockNumber;
2626 ULONG blockCount;
2627
2628 //
2629 // Validate buffer length.
2630 //
2631
2632 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2633 sizeof(REASSIGN_BLOCKS)) {
2634
2635 status = STATUS_INFO_LENGTH_MISMATCH;
2636 break;
2637 }
2638
2639 bufferSize = sizeof(REASSIGN_BLOCKS) +
2640 (badBlocks->Count - 1) * sizeof(ULONG);
2641
2642 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2643 bufferSize) {
2644
2645 status = STATUS_INFO_LENGTH_MISMATCH;
2646 break;
2647 }
2648
2649 //
2650 // Build the data buffer to be transferred in the input buffer.
2651 // The format of the data to the device is:
2652 //
2653 // 2 bytes Reserved
2654 // 2 bytes Length
2655 // x * 4 btyes Block Address
2656 //
2657 // All values are big endian.
2658 //
2659
2660 badBlocks->Reserved = 0;
2661 blockCount = badBlocks->Count;
2662
2663 //
2664 // Convert # of entries to # of bytes.
2665 //
2666
2667 blockCount *= 4;
2668 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2669 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2670
2671 //
2672 // Convert back to number of entries.
2673 //
2674
2675 blockCount /= 4;
2676
2677 for (; blockCount > 0; blockCount--) {
2678
2679 blockNumber = badBlocks->BlockNumber[blockCount-1];
2680
2681 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2682 (PFOUR_BYTE) &blockNumber);
2683 }
2684
2685 srb->CdbLength = 6;
2686
2687 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2688
2689 //
2690 // Set timeout value.
2691 //
2692
2693 srb->TimeOutValue = deviceExtension->TimeOutValue;
2694
2695 status = ScsiClassSendSrbSynchronous(DeviceObject,
2696 srb,
2697 badBlocks,
2698 bufferSize,
2699 TRUE);
2700
2701 Irp->IoStatus.Status = status;
2702 Irp->IoStatus.Information = 0;
2703 ExFreePool(srb);
2704 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2705 }
2706
2707 return(status);
2708
2709 case IOCTL_DISK_IS_WRITABLE:
2710
2711 //
2712 // Determine if the device is writable.
2713 //
2714
2715 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
2716
2717 if (modeData == NULL) {
2718 status = STATUS_INSUFFICIENT_RESOURCES;
2719 break;
2720 }
2721
2722 RtlZeroMemory(modeData, MODE_DATA_SIZE);
2723
2724 length = ScsiClassModeSense(DeviceObject,
2725 (PCHAR) modeData,
2726 MODE_DATA_SIZE,
2727 MODE_SENSE_RETURN_ALL);
2728
2729 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2730
2731 //
2732 // Retry the request in case of a check condition.
2733 //
2734
2735 length = ScsiClassModeSense(DeviceObject,
2736 (PCHAR) modeData,
2737 MODE_DATA_SIZE,
2738 MODE_SENSE_RETURN_ALL);
2739
2740 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2741 status = STATUS_IO_DEVICE_ERROR;
2742 ExFreePool(modeData);
2743 break;
2744 }
2745 }
2746
2747 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
2748 status = STATUS_MEDIA_WRITE_PROTECTED;
2749 } else {
2750 status = STATUS_SUCCESS;
2751 }
2752
2753 ExFreePool(modeData);
2754 break;
2755
2756 case IOCTL_DISK_INTERNAL_SET_VERIFY:
2757
2758 //
2759 // If the caller is kernel mode, set the verify bit.
2760 //
2761
2762 if (Irp->RequestorMode == KernelMode) {
2763 DeviceObject->Flags |= DO_VERIFY_VOLUME;
2764 }
2765 status = STATUS_SUCCESS;
2766 break;
2767
2768 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
2769
2770 //
2771 // If the caller is kernel mode, clear the verify bit.
2772 //
2773
2774 if (Irp->RequestorMode == KernelMode) {
2775 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
2776 }
2777 status = STATUS_SUCCESS;
2778 break;
2779
2780 case IOCTL_DISK_FIND_NEW_DEVICES:
2781
2782 //
2783 // Search for devices that have been powered on since the last
2784 // device search or system initialization.
2785 //
2786
2787 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2788 status = DriverEntry(DeviceObject->DriverObject,
2789 NULL);
2790
2791 Irp->IoStatus.Status = status;
2792 ExFreePool(srb);
2793 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2794 return status;
2795
2796 case IOCTL_DISK_MEDIA_REMOVAL:
2797
2798 //
2799 // If the disk is not removable then don't allow this command.
2800 //
2801
2802 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
2803 status = STATUS_INVALID_DEVICE_REQUEST;
2804 break;
2805 }
2806
2807 //
2808 // Fall through and let the class driver process the request.
2809 //
2810
2811 case IOCTL_DISK_GET_LENGTH_INFO:
2812
2813 //
2814 // Validate buffer length.
2815 //
2816
2817 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2818 sizeof(GET_LENGTH_INFORMATION)) {
2819 status = STATUS_BUFFER_TOO_SMALL;
2820
2821 } else {
2822
2823 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer;
2824
2825 //
2826 // Update the geometry in case it has changed.
2827 //
2828
2829 status = UpdateRemovableGeometry (DeviceObject, Irp);
2830
2831 if (!NT_SUCCESS(status)) {
2832
2833 //
2834 // Note the drive is not ready.
2835 //
2836
2837 diskData->DriveNotReady = TRUE;
2838 break;
2839 }
2840
2841 //
2842 // Note the drive is now ready.
2843 //
2844
2845 diskData->DriveNotReady = FALSE;
2846
2847 //
2848 // Output data, and return
2849 //
2850
2851 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart;
2852 status = STATUS_SUCCESS;
2853 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
2854 }
2855
2856 break;
2857
2858 default:
2859
2860 //
2861 // Free the Srb, since it is not needed.
2862 //
2863
2864 ExFreePool(srb);
2865
2866 //
2867 // Pass the request to the common device control routine.
2868 //
2869
2870 return(ScsiClassDeviceControl(DeviceObject, Irp));
2871
2872 break;
2873
2874 } // end switch( ...
2875
2876 Irp->IoStatus.Status = status;
2877
2878 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
2879
2880 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
2881 }
2882
2883 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2884 ExFreePool(srb);
2885 return(status);
2886
2887 } // end ScsiDiskDeviceControl()
2888 \f
2889 NTSTATUS
2890 NTAPI
2891 ScsiDiskShutdownFlush (
2892 IN PDEVICE_OBJECT DeviceObject,
2893 IN PIRP Irp
2894 )
2895
2896 /*++
2897
2898 Routine Description:
2899
2900 This routine is called for a shutdown and flush IRPs. These are sent by the
2901 system before it actually shuts down or when the file system does a flush.
2902 A synchronize cache command is sent to the device if it is write caching.
2903 If the device is removable an unlock command will be sent. This routine
2904 will sent a shutdown or flush Srb to the port driver.
2905
2906 Arguments:
2907
2908 DriverObject - Pointer to device object to being shutdown by system.
2909
2910 Irp - IRP involved.
2911
2912 Return Value:
2913
2914 NT Status
2915
2916 --*/
2917
2918 {
2919 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2920 PIO_STACK_LOCATION irpStack;
2921 PSCSI_REQUEST_BLOCK srb;
2922 NTSTATUS status;
2923 PCDB cdb;
2924
2925 //
2926 // Allocate SCSI request block.
2927 //
2928
2929 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
2930
2931 if (srb == NULL) {
2932
2933 //
2934 // Set the status and complete the request.
2935 //
2936
2937 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2938 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2939 return(STATUS_INSUFFICIENT_RESOURCES);
2940 }
2941
2942 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2943
2944 //
2945 // Write length to SRB.
2946 //
2947
2948 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2949
2950 //
2951 // Set SCSI bus address.
2952 //
2953
2954 srb->PathId = deviceExtension->PathId;
2955 srb->TargetId = deviceExtension->TargetId;
2956 srb->Lun = deviceExtension->Lun;
2957
2958 //
2959 // Set timeout value and mark the request as not being a tagged request.
2960 //
2961
2962 srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
2963 srb->QueueTag = SP_UNTAGGED;
2964 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
2965 srb->SrbFlags = deviceExtension->SrbFlags;
2966
2967 //
2968 // If the write cache is enabled then send a synchronize cache request.
2969 //
2970
2971 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
2972
2973 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2974 srb->CdbLength = 10;
2975
2976 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
2977
2978 status = ScsiClassSendSrbSynchronous(DeviceObject,
2979 srb,
2980 NULL,
2981 0,
2982 TRUE);
2983
2984 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status ));
2985 }
2986
2987 //
2988 // Unlock the device if it is removable and this is a shutdown.
2989 //
2990
2991 irpStack = IoGetCurrentIrpStackLocation(Irp);
2992
2993 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
2994 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
2995
2996 srb->CdbLength = 6;
2997 cdb = (PVOID) srb->Cdb;
2998 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
2999 cdb->MEDIA_REMOVAL.Prevent = FALSE;
3000
3001 //
3002 // Set timeout value.
3003 //
3004
3005 srb->TimeOutValue = deviceExtension->TimeOutValue;
3006 status = ScsiClassSendSrbSynchronous(DeviceObject,
3007 srb,
3008 NULL,
3009 0,
3010 TRUE);
3011
3012 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
3013 }
3014
3015 srb->CdbLength = 0;
3016
3017 //
3018 // Save a few parameters in the current stack location.
3019 //
3020
3021 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
3022 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
3023
3024 //
3025 // Set the retry count to zero.
3026 //
3027
3028 irpStack->Parameters.Others.Argument4 = (PVOID) 0;
3029
3030 //
3031 // Set up IoCompletion routine address.
3032 //
3033
3034 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
3035
3036 //
3037 // Get next stack location and
3038 // set major function code.
3039 //
3040
3041 irpStack = IoGetNextIrpStackLocation(Irp);
3042
3043 irpStack->MajorFunction = IRP_MJ_SCSI;
3044
3045 //
3046 // Set up SRB for execute scsi request.
3047 // Save SRB address in next stack for port driver.
3048 //
3049
3050 irpStack->Parameters.Scsi.Srb = srb;
3051
3052 //
3053 // Set up Irp Address.
3054 //
3055
3056 srb->OriginalRequest = Irp;
3057
3058 //
3059 // Call the port driver to process the request.
3060 //
3061
3062 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3063
3064 } // end ScsiDiskShutdown()
3065
3066 \f
3067 BOOLEAN
3068 NTAPI
3069 IsFloppyDevice(
3070 PDEVICE_OBJECT DeviceObject
3071 )
3072 /*++
3073
3074 Routine Description:
3075
3076 The routine performs the necessary functions to determine if a device is
3077 really a floppy rather than a harddisk. This is done by a mode sense
3078 command. First, a check is made to see if the medimum type is set. Second
3079 a check is made for the flexible parameters mode page. Also a check is
3080 made to see if the write cache is enabled.
3081
3082 Arguments:
3083
3084 DeviceObject - Supplies the device object to be tested.
3085
3086 Return Value:
3087
3088 Return TRUE if the indicated device is a floppy.
3089
3090 --*/
3091 {
3092 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3093 PVOID modeData;
3094 PUCHAR pageData;
3095 ULONG length;
3096
3097 PAGED_CODE();
3098
3099 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3100
3101 if (modeData == NULL) {
3102 return(FALSE);
3103 }
3104
3105 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3106
3107 length = ScsiClassModeSense(DeviceObject,
3108 modeData,
3109 MODE_DATA_SIZE,
3110 MODE_SENSE_RETURN_ALL);
3111
3112 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3113
3114 //
3115 // Retry the request in case of a check condition.
3116 //
3117
3118 length = ScsiClassModeSense(DeviceObject,
3119 modeData,
3120 MODE_DATA_SIZE,
3121 MODE_SENSE_RETURN_ALL);
3122
3123 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3124
3125 ExFreePool(modeData);
3126 return(FALSE);
3127
3128 }
3129 }
3130
3131 //
3132 // If the length is greater than length indicated by the mode data reset
3133 // the data to the mode data.
3134 //
3135
3136 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3137 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3138 }
3139
3140 //
3141 // Look for the flexible disk mode page.
3142 //
3143
3144 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
3145
3146 if (pageData != NULL) {
3147
3148 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3149 ExFreePool(modeData);
3150 return(TRUE);
3151 }
3152
3153 //
3154 // Check to see if the write cache is enabled.
3155 //
3156
3157 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3158
3159 //
3160 // Assume that write cache is disabled or not supported.
3161 //
3162
3163 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3164
3165 //
3166 // Check if valid caching page exists.
3167 //
3168
3169 if (pageData != NULL) {
3170
3171 //
3172 // Check if write cache is disabled.
3173 //
3174
3175 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3176
3177 DebugPrint((1,
3178 "SCSIDISK: Disk write cache enabled\n"));
3179
3180 //
3181 // Check if forced unit access (FUA) is supported.
3182 //
3183
3184 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
3185
3186 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3187
3188 } else {
3189
3190 DebugPrint((1,
3191 "SCSIDISK: Disk does not support FUA or DPO\n"));
3192
3193 //
3194 // TODO: Log this.
3195 //
3196
3197 }
3198 }
3199 }
3200
3201 ExFreePool(modeData);
3202 return(FALSE);
3203
3204 } // end IsFloppyDevice()
3205
3206 \f
3207 BOOLEAN
3208 NTAPI
3209 ScsiDiskModeSelect(
3210 IN PDEVICE_OBJECT DeviceObject,
3211 IN PCHAR ModeSelectBuffer,
3212 IN ULONG Length,
3213 IN BOOLEAN SavePage
3214 )
3215
3216 /*++
3217
3218 Routine Description:
3219
3220 This routine sends a mode select command.
3221
3222 Arguments:
3223
3224 DeviceObject - Supplies the device object associated with this request.
3225
3226 ModeSelectBuffer - Supplies a buffer containing the page data.
3227
3228 Length - Supplies the length in bytes of the mode select buffer.
3229
3230 SavePage - Indicates that parameters should be written to disk.
3231
3232 Return Value:
3233
3234 Length of the transferred data is returned.
3235
3236 --*/
3237 {
3238 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3239 PCDB cdb;
3240 SCSI_REQUEST_BLOCK srb;
3241 ULONG retries = 1;
3242 ULONG length2;
3243 NTSTATUS status;
3244 ULONG_PTR buffer;
3245 PMODE_PARAMETER_BLOCK blockDescriptor;
3246
3247 PAGED_CODE();
3248
3249 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
3250
3251 //
3252 // Allocate buffer for mode select header, block descriptor, and mode page.
3253 //
3254
3255 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
3256
3257 RtlZeroMemory((PVOID)buffer, length2);
3258
3259 //
3260 // Set length in header to size of mode page.
3261 //
3262
3263 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
3264
3265 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
3266
3267 //
3268 // Set size
3269 //
3270
3271 blockDescriptor->BlockLength[1]=0x02;
3272
3273 //
3274 // Copy mode page to buffer.
3275 //
3276
3277 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
3278
3279 //
3280 // Zero SRB.
3281 //
3282
3283 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3284
3285 //
3286 // Build the MODE SELECT CDB.
3287 //
3288
3289 srb.CdbLength = 6;
3290 cdb = (PCDB)srb.Cdb;
3291
3292 //
3293 // Set timeout value from device extension.
3294 //
3295
3296 srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
3297
3298 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3299 cdb->MODE_SELECT.SPBit = SavePage;
3300 cdb->MODE_SELECT.PFBit = 1;
3301 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
3302
3303 Retry:
3304
3305 status = ScsiClassSendSrbSynchronous(DeviceObject,
3306 &srb,
3307 (PVOID)buffer,
3308 length2,
3309 TRUE);
3310
3311
3312 if (status == STATUS_VERIFY_REQUIRED) {
3313
3314 //
3315 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3316 // this status.
3317 //
3318
3319 if (retries--) {
3320
3321 //
3322 // Retry request.
3323 //
3324
3325 goto Retry;
3326 }
3327
3328 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3329 status = STATUS_SUCCESS;
3330 }
3331
3332 ExFreePool((PVOID)buffer);
3333
3334 if (NT_SUCCESS(status)) {
3335 return(TRUE);
3336 } else {
3337 return(FALSE);
3338 }
3339
3340 } // end SciDiskModeSelect()
3341
3342 \f
3343 VOID
3344 NTAPI
3345 DisableWriteCache(
3346 IN PDEVICE_OBJECT DeviceObject,
3347 IN PSCSI_INQUIRY_DATA LunInfo
3348 )
3349
3350 {
3351 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3352 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3353 BAD_CONTROLLER_INFORMATION const *controller;
3354 ULONG j,length;
3355 PVOID modeData;
3356 PUCHAR pageData;
3357
3358 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
3359
3360 controller = &ScsiDiskBadControllers[j];
3361
3362 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
3363 continue;
3364 }
3365
3366 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
3367
3368 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3369
3370 if (modeData == NULL) {
3371
3372 DebugPrint((1,
3373 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3374 return;
3375 }
3376
3377 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3378
3379 length = ScsiClassModeSense(DeviceObject,
3380 modeData,
3381 MODE_DATA_SIZE,
3382 MODE_SENSE_RETURN_ALL);
3383
3384 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3385
3386 //
3387 // Retry the request in case of a check condition.
3388 //
3389
3390 length = ScsiClassModeSense(DeviceObject,
3391 modeData,
3392 MODE_DATA_SIZE,
3393 MODE_SENSE_RETURN_ALL);
3394
3395 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3396
3397
3398 DebugPrint((1,
3399 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3400
3401 ExFreePool(modeData);
3402 return;
3403
3404 }
3405 }
3406
3407 //
3408 // If the length is greater than length indicated by the mode data reset
3409 // the data to the mode data.
3410 //
3411
3412 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3413 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3414 }
3415
3416 //
3417 // Check to see if the write cache is enabled.
3418 //
3419
3420 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3421
3422 //
3423 // Assume that write cache is disabled or not supported.
3424 //
3425
3426 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3427
3428 //
3429 // Check if valid caching page exists.
3430 //
3431
3432 if (pageData != NULL) {
3433
3434 BOOLEAN savePage = FALSE;
3435
3436 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
3437
3438 //
3439 // Check if write cache is disabled.
3440 //
3441
3442 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3443
3444 PIO_ERROR_LOG_PACKET errorLogEntry;
3445 LONG errorCode;
3446
3447
3448 //
3449 // Disable write cache and ensure necessary fields are zeroed.
3450 //
3451
3452 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
3453 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
3454 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
3455 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
3456
3457 //
3458 // Extract length from caching page.
3459 //
3460
3461 length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
3462
3463 //
3464 // Compensate for page code and page length.
3465 //
3466
3467 length += 2;
3468
3469 //
3470 // Issue mode select to set the parameter.
3471 //
3472
3473 if (ScsiDiskModeSelect(DeviceObject,
3474 (PCHAR)pageData,
3475 length,
3476 savePage)) {
3477
3478 DebugPrint((1,
3479 "SCSIDISK: Disk write cache disabled\n"));
3480
3481 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3482 errorCode = IO_WRITE_CACHE_DISABLED;
3483
3484 } else {
3485 if (ScsiDiskModeSelect(DeviceObject,
3486 (PCHAR)pageData,
3487 length,
3488 savePage)) {
3489
3490 DebugPrint((1,
3491 "SCSIDISK: Disk write cache disabled\n"));
3492
3493
3494 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3495 errorCode = IO_WRITE_CACHE_DISABLED;
3496
3497 } else {
3498
3499 DebugPrint((1,
3500 "SCSIDISK: Mode select to disable write cache failed\n"));
3501
3502 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3503 errorCode = IO_WRITE_CACHE_ENABLED;
3504 }
3505 }
3506
3507 //
3508 // Log the appropriate informational or error entry.
3509 //
3510
3511 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3512 DeviceObject,
3513 sizeof(IO_ERROR_LOG_PACKET) + 3
3514 * sizeof(ULONG));
3515
3516 if (errorLogEntry != NULL) {
3517
3518 errorLogEntry->FinalStatus = STATUS_SUCCESS;
3519 errorLogEntry->ErrorCode = errorCode;
3520 errorLogEntry->SequenceNumber = 0;
3521 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
3522 errorLogEntry->IoControlCode = 0;
3523 errorLogEntry->RetryCount = 0;
3524 errorLogEntry->UniqueErrorValue = 0x1;
3525 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG);
3526 errorLogEntry->DumpData[0] = LunInfo->PathId;
3527 errorLogEntry->DumpData[1] = LunInfo->TargetId;
3528 errorLogEntry->DumpData[2] = LunInfo->Lun;
3529
3530 //
3531 // Write the error log packet.
3532 //
3533
3534 IoWriteErrorLogEntry(errorLogEntry);
3535 }
3536 }
3537 }
3538
3539 //
3540 // Found device so exit the loop and return.
3541 //
3542
3543 break;
3544 }
3545
3546 return;
3547 }
3548
3549 \f
3550 BOOLEAN
3551 NTAPI
3552 CalculateMbrCheckSum(
3553 IN PDEVICE_EXTENSION DeviceExtension,
3554 OUT PULONG Checksum
3555 )
3556
3557 /*++
3558
3559 Routine Description:
3560
3561 Read MBR and calculate checksum.
3562
3563 Arguments:
3564
3565 DeviceExtension - Supplies a pointer to the device information for disk.
3566 Checksum - Memory location to return MBR checksum.
3567
3568 Return Value:
3569
3570 Returns TRUE if checksum is valid.