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