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