[NTOSKRNL]
[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 parition 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 - inidicates that the this device is currenly 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 identfing 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 capcity 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 infomation 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.CreatePartionDeviceObjects - 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 errror 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
2058 if ((irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY &&
2059 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2060 sizeof(DISK_GEOMETRY)) ||
2061 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX &&
2062 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2063 sizeof(DISK_GEOMETRY_EX))) {
2064
2065 status = STATUS_INFO_LENGTH_MISMATCH;
2066 break;
2067 }
2068
2069 status = STATUS_SUCCESS;
2070
2071 physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2072 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
2073
2074 removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA;
2075 listInitialized = (physicalDiskData->PartitionListState == Initialized);
2076
2077 if (removable || (!listInitialized))
2078 {
2079 //
2080 // Issue ReadCapacity to update device extension
2081 // with information for current media.
2082 //
2083
2084 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
2085
2086 }
2087
2088 if (removable) {
2089
2090 if (!NT_SUCCESS(status)) {
2091
2092 //
2093 // Note the drive is not ready.
2094 //
2095
2096 diskData->DriveNotReady = TRUE;
2097
2098 break;
2099 }
2100
2101 //
2102 // Note the drive is now ready.
2103 //
2104
2105 diskData->DriveNotReady = FALSE;
2106
2107 } else if (NT_SUCCESS(status)) {
2108
2109 // ReadDriveCapacity was allright, create Partition Objects
2110
2111 if (physicalDiskData->PartitionListState == NotInitialized) {
2112 status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL);
2113 }
2114 }
2115
2116 if (NT_SUCCESS(status)) {
2117
2118 //
2119 // Copy drive geometry information from device extension.
2120 //
2121
2122 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2123 deviceExtension->DiskGeometry,
2124 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2125 sizeof(DISK_GEOMETRY) :
2126 sizeof(DISK_GEOMETRY_EX));
2127
2128 status = STATUS_SUCCESS;
2129 Irp->IoStatus.Information =
2130 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2131 sizeof(DISK_GEOMETRY) :
2132 sizeof(DISK_GEOMETRY_EX);
2133 }
2134
2135 break;
2136
2137 }
2138
2139 case IOCTL_DISK_VERIFY:
2140
2141 {
2142
2143 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2144 LARGE_INTEGER byteOffset;
2145 ULONG sectorOffset;
2146 USHORT sectorCount;
2147
2148 //
2149 // Validate buffer length.
2150 //
2151
2152 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2153 sizeof(VERIFY_INFORMATION)) {
2154
2155 status = STATUS_INFO_LENGTH_MISMATCH;
2156 break;
2157 }
2158
2159 //
2160 // Verify sectors
2161 //
2162
2163 srb->CdbLength = 10;
2164
2165 cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2166
2167 //
2168 // Add disk offset to starting sector.
2169 //
2170
2171 byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart +
2172 verifyInfo->StartingOffset.QuadPart;
2173
2174 //
2175 // Convert byte offset to sector offset.
2176 //
2177
2178 sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift);
2179
2180 //
2181 // Convert ULONG byte count to USHORT sector count.
2182 //
2183
2184 sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift);
2185
2186 //
2187 // Move little endian values into CDB in big endian format.
2188 //
2189
2190 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2191 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2192 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2193 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2194
2195 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
2196 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
2197
2198 //
2199 // The verify command is used by the NT FORMAT utility and
2200 // requests are sent down for 5% of the volume size. The
2201 // request timeout value is calculated based on the number of
2202 // sectors verified.
2203 //
2204
2205 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
2206 deviceExtension->TimeOutValue;
2207
2208 status = ScsiClassSendSrbAsynchronous(DeviceObject,
2209 srb,
2210 Irp,
2211 NULL,
2212 0,
2213 FALSE);
2214
2215 return(status);
2216
2217 }
2218
2219 case IOCTL_DISK_GET_PARTITION_INFO:
2220
2221 //
2222 // Return the information about the partition specified by the device
2223 // object. Note that no information is ever returned about the size
2224 // or partition type of the physical disk, as this doesn't make any
2225 // sense.
2226 //
2227
2228 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2229 sizeof(PARTITION_INFORMATION)) {
2230
2231 status = STATUS_INFO_LENGTH_MISMATCH;
2232
2233 }
2234 #if 0 // HACK: ReactOS partition numbers must be wrong
2235 else if (diskData->PartitionNumber == 0) {
2236
2237 //
2238 // Paritition zero is not a partition so this is not a
2239 // reasonable request.
2240 //
2241
2242 status = STATUS_INVALID_DEVICE_REQUEST;
2243
2244 }
2245 #endif
2246 else {
2247
2248 PPARTITION_INFORMATION outputBuffer;
2249
2250 if (diskData->PartitionNumber == 0) {
2251 DPRINT1("HACK: Handling partition 0 request!\n");
2252 //ASSERT(FALSE);
2253 }
2254
2255 //
2256 // Update the geometry in case it has changed.
2257 //
2258
2259 status = UpdateRemovableGeometry (DeviceObject, Irp);
2260
2261 if (!NT_SUCCESS(status)) {
2262
2263 //
2264 // Note the drive is not ready.
2265 //
2266
2267 diskData->DriveNotReady = TRUE;
2268 break;
2269 }
2270
2271 //
2272 // Note the drive is now ready.
2273 //
2274
2275 diskData->DriveNotReady = FALSE;
2276
2277 outputBuffer =
2278 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2279
2280 outputBuffer->PartitionType = diskData->PartitionType;
2281 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2282 outputBuffer->PartitionLength.QuadPart = (diskData->PartitionNumber) ?
2283 deviceExtension->PartitionLength.QuadPart : 2305843009213693951LL; // HACK
2284 outputBuffer->HiddenSectors = diskData->HiddenSectors;
2285 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2286 outputBuffer->BootIndicator = diskData->BootIndicator;
2287 outputBuffer->RewritePartition = FALSE;
2288 outputBuffer->RecognizedPartition =
2289 IsRecognizedPartition(diskData->PartitionType);
2290
2291 status = STATUS_SUCCESS;
2292 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
2293 }
2294
2295 break;
2296
2297 case IOCTL_DISK_GET_PARTITION_INFO_EX:
2298
2299 //
2300 // Return the information about the partition specified by the device
2301 // object. Note that no information is ever returned about the size
2302 // or partition type of the physical disk, as this doesn't make any
2303 // sense.
2304 //
2305
2306 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2307 sizeof(PARTITION_INFORMATION_EX)) {
2308
2309 status = STATUS_INFO_LENGTH_MISMATCH;
2310
2311 }
2312 #if 0 // HACK: ReactOS partition numbers must be wrong
2313 else if (diskData->PartitionNumber == 0) {
2314
2315 //
2316 // Paritition zero is not a partition so this is not a
2317 // reasonable request.
2318 //
2319
2320 status = STATUS_INVALID_DEVICE_REQUEST;
2321
2322 }
2323 #endif
2324 else {
2325
2326 PPARTITION_INFORMATION_EX outputBuffer;
2327
2328 if (diskData->PartitionNumber == 0) {
2329 DPRINT1("HACK: Handling partition 0 request!\n");
2330 //ASSERT(FALSE);
2331 }
2332
2333 //
2334 // Update the geometry in case it has changed.
2335 //
2336
2337 status = UpdateRemovableGeometry (DeviceObject, Irp);
2338
2339 if (!NT_SUCCESS(status)) {
2340
2341 //
2342 // Note the drive is not ready.
2343 //
2344
2345 diskData->DriveNotReady = TRUE;
2346 break;
2347 }
2348
2349 //
2350 // Note the drive is now ready.
2351 //
2352
2353 diskData->DriveNotReady = FALSE;
2354
2355 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2356
2357 status = STATUS_INVALID_DEVICE_REQUEST;
2358 break;
2359 }
2360
2361 outputBuffer =
2362 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
2363
2364 //
2365 // FIXME: hack of the year, assume that partition is MBR
2366 // Thing that can obviously be wrong...
2367 //
2368
2369 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
2370 outputBuffer->Mbr.PartitionType = diskData->PartitionType;
2371 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2372 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2373 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors;
2374 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2375 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator;
2376 outputBuffer->RewritePartition = FALSE;
2377 outputBuffer->Mbr.RecognizedPartition =
2378 IsRecognizedPartition(diskData->PartitionType);
2379
2380 status = STATUS_SUCCESS;
2381 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
2382 }
2383
2384 break;
2385
2386 case IOCTL_DISK_SET_PARTITION_INFO:
2387
2388 if (diskData->PartitionNumber == 0) {
2389
2390 status = STATUS_UNSUCCESSFUL;
2391
2392 } else {
2393
2394 PSET_PARTITION_INFORMATION inputBuffer =
2395 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2396
2397 //
2398 // Validate buffer length.
2399 //
2400
2401 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2402 sizeof(SET_PARTITION_INFORMATION)) {
2403
2404 status = STATUS_INFO_LENGTH_MISMATCH;
2405 break;
2406 }
2407
2408 //
2409 // The HAL routines IoGet- and IoSetPartitionInformation were
2410 // developed before support of dynamic partitioning and therefore
2411 // don't distinguish between partition ordinal (that is the order
2412 // of a partition on a disk) and the partition number. (The
2413 // partition number is assigned to a partition to identify it to
2414 // the system.) Use partition ordinals for these legacy calls.
2415 //
2416
2417 status = IoSetPartitionInformation(
2418 deviceExtension->PhysicalDevice,
2419 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2420 diskData->PartitionOrdinal,
2421 inputBuffer->PartitionType);
2422
2423 if (NT_SUCCESS(status)) {
2424
2425 diskData->PartitionType = inputBuffer->PartitionType;
2426 }
2427 }
2428
2429 break;
2430
2431 case IOCTL_DISK_GET_DRIVE_LAYOUT:
2432
2433 //
2434 // Return the partition layout for the physical drive. Note that
2435 // the layout is returned for the actual physical drive, regardless
2436 // of which partition was specified for the request.
2437 //
2438
2439 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2440 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2441 status = STATUS_INFO_LENGTH_MISMATCH;
2442
2443 } else {
2444
2445 PDRIVE_LAYOUT_INFORMATION partitionList;
2446 PDEVICE_EXTENSION physicalExtension = deviceExtension;
2447 PPARTITION_INFORMATION partitionEntry;
2448 PDISK_DATA diskData;
2449 ULONG tempSize;
2450 ULONG i;
2451
2452 //
2453 // Read partition information.
2454 //
2455
2456 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
2457 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2458 FALSE,
2459 &partitionList);
2460
2461 if (!NT_SUCCESS(status)) {
2462 break;
2463 }
2464
2465 //
2466 // The disk layout has been returned in the partitionList
2467 // buffer. Determine its size and, if the data will fit
2468 // into the intermediatery buffer, return it.
2469 //
2470
2471 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
2472 tempSize += partitionList->PartitionCount *
2473 sizeof(PARTITION_INFORMATION);
2474
2475 if (tempSize >
2476 irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
2477
2478 status = STATUS_BUFFER_TOO_SMALL;
2479 ExFreePool(partitionList);
2480 break;
2481 }
2482
2483 //
2484 // Walk partition list to associate partition numbers with
2485 // partition entries.
2486 //
2487
2488 for (i = 0; i < partitionList->PartitionCount; i++) {
2489
2490 //
2491 // Walk partition chain anchored at physical disk extension.
2492 //
2493
2494 deviceExtension = physicalExtension;
2495 diskData = (PDISK_DATA)(deviceExtension + 1);
2496
2497 do {
2498
2499 deviceExtension = diskData->NextPartition;
2500
2501 //
2502 // Check if this is the last partition in the chain.
2503 //
2504
2505 if (!deviceExtension) {
2506 break;
2507 }
2508
2509 //
2510 // Get the partition device extension from disk data.
2511 //
2512
2513 diskData = (PDISK_DATA)(deviceExtension + 1);
2514
2515 //
2516 // Check if this partition is not currently being used.
2517 //
2518
2519 if (!deviceExtension->PartitionLength.QuadPart) {
2520 continue;
2521 }
2522
2523 partitionEntry = &partitionList->PartitionEntry[i];
2524
2525 //
2526 // Check if empty, or describes extended partition or hasn't changed.
2527 //
2528
2529 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2530 IsContainerPartition(partitionEntry->PartitionType)) {
2531 continue;
2532 }
2533
2534 //
2535 // Check if new partition starts where this partition starts.
2536 //
2537
2538 if (partitionEntry->StartingOffset.QuadPart !=
2539 deviceExtension->StartingOffset.QuadPart) {
2540 continue;
2541 }
2542
2543 //
2544 // Check if partition length is the same.
2545 //
2546
2547 if (partitionEntry->PartitionLength.QuadPart ==
2548 deviceExtension->PartitionLength.QuadPart) {
2549
2550 //
2551 // Partitions match. Update partition number.
2552 //
2553
2554 partitionEntry->PartitionNumber =
2555 diskData->PartitionNumber;
2556 break;
2557 }
2558
2559 } while (TRUE);
2560 }
2561
2562 //
2563 // Copy partition information to system buffer.
2564 //
2565
2566 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2567 partitionList,
2568 tempSize);
2569 status = STATUS_SUCCESS;
2570 Irp->IoStatus.Information = tempSize;
2571
2572 //
2573 // Finally, free the buffer allocated by reading the
2574 // partition table.
2575 //
2576
2577 ExFreePool(partitionList);
2578 }
2579
2580 break;
2581
2582 case IOCTL_DISK_SET_DRIVE_LAYOUT:
2583
2584 {
2585
2586 //
2587 // Update the disk with new partition information.
2588 //
2589
2590 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
2591
2592 //
2593 // Validate buffer length.
2594 //
2595
2596 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2597 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2598
2599 status = STATUS_INFO_LENGTH_MISMATCH;
2600 break;
2601 }
2602
2603 length = sizeof(DRIVE_LAYOUT_INFORMATION) +
2604 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
2605
2606
2607 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2608 length) {
2609
2610 status = STATUS_BUFFER_TOO_SMALL;
2611 break;
2612 }
2613
2614 //
2615 // Verify that device object is for physical disk.
2616 //
2617
2618 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
2619 status = STATUS_INVALID_PARAMETER;
2620 break;
2621 }
2622
2623 //
2624 // Walk through partition table comparing partitions to
2625 // existing partitions to create, delete and change
2626 // device objects as necessary.
2627 //
2628
2629 UpdateDeviceObjects(DeviceObject,
2630 Irp);
2631
2632 //
2633 // Write changes to disk.
2634 //
2635
2636 status = IoWritePartitionTable(
2637 deviceExtension->DeviceObject,
2638 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2639 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
2640 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
2641 partitionList);
2642 }
2643
2644 //
2645 // Update IRP with bytes returned.
2646 //
2647
2648 if (NT_SUCCESS(status)) {
2649 Irp->IoStatus.Information = length;
2650 }
2651
2652 break;
2653
2654 case IOCTL_DISK_REASSIGN_BLOCKS:
2655
2656 //
2657 // Map defective blocks to new location on disk.
2658 //
2659
2660 {
2661
2662 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2663 ULONG bufferSize;
2664 ULONG blockNumber;
2665 ULONG blockCount;
2666
2667 //
2668 // Validate buffer length.
2669 //
2670
2671 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2672 sizeof(REASSIGN_BLOCKS)) {
2673
2674 status = STATUS_INFO_LENGTH_MISMATCH;
2675 break;
2676 }
2677
2678 bufferSize = sizeof(REASSIGN_BLOCKS) +
2679 (badBlocks->Count - 1) * sizeof(ULONG);
2680
2681 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2682 bufferSize) {
2683
2684 status = STATUS_INFO_LENGTH_MISMATCH;
2685 break;
2686 }
2687
2688 //
2689 // Build the data buffer to be transferred in the input buffer.
2690 // The format of the data to the device is:
2691 //
2692 // 2 bytes Reserved
2693 // 2 bytes Length
2694 // x * 4 btyes Block Address
2695 //
2696 // All values are big endian.
2697 //
2698
2699 badBlocks->Reserved = 0;
2700 blockCount = badBlocks->Count;
2701
2702 //
2703 // Convert # of entries to # of bytes.
2704 //
2705
2706 blockCount *= 4;
2707 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2708 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2709
2710 //
2711 // Convert back to number of entries.
2712 //
2713
2714 blockCount /= 4;
2715
2716 for (; blockCount > 0; blockCount--) {
2717
2718 blockNumber = badBlocks->BlockNumber[blockCount-1];
2719
2720 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2721 (PFOUR_BYTE) &blockNumber);
2722 }
2723
2724 srb->CdbLength = 6;
2725
2726 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2727
2728 //
2729 // Set timeout value.
2730 //
2731
2732 srb->TimeOutValue = deviceExtension->TimeOutValue;
2733
2734 status = ScsiClassSendSrbSynchronous(DeviceObject,
2735 srb,
2736 badBlocks,
2737 bufferSize,
2738 TRUE);
2739
2740 Irp->IoStatus.Status = status;
2741 Irp->IoStatus.Information = 0;
2742 ExFreePool(srb);
2743 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2744 }
2745
2746 return(status);
2747
2748 case IOCTL_DISK_IS_WRITABLE:
2749
2750 //
2751 // Determine if the device is writable.
2752 //
2753
2754 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
2755
2756 if (modeData == NULL) {
2757 status = STATUS_INSUFFICIENT_RESOURCES;
2758 break;
2759 }
2760
2761 RtlZeroMemory(modeData, MODE_DATA_SIZE);
2762
2763 length = ScsiClassModeSense(DeviceObject,
2764 (PCHAR) modeData,
2765 MODE_DATA_SIZE,
2766 MODE_SENSE_RETURN_ALL);
2767
2768 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2769
2770 //
2771 // Retry the request in case of a check condition.
2772 //
2773
2774 length = ScsiClassModeSense(DeviceObject,
2775 (PCHAR) modeData,
2776 MODE_DATA_SIZE,
2777 MODE_SENSE_RETURN_ALL);
2778
2779 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2780 status = STATUS_IO_DEVICE_ERROR;
2781 ExFreePool(modeData);
2782 break;
2783 }
2784 }
2785
2786 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
2787 status = STATUS_MEDIA_WRITE_PROTECTED;
2788 } else {
2789 status = STATUS_SUCCESS;
2790 }
2791
2792 ExFreePool(modeData);
2793 break;
2794
2795 case IOCTL_DISK_INTERNAL_SET_VERIFY:
2796
2797 //
2798 // If the caller is kernel mode, set the verify bit.
2799 //
2800
2801 if (Irp->RequestorMode == KernelMode) {
2802 DeviceObject->Flags |= DO_VERIFY_VOLUME;
2803 }
2804 status = STATUS_SUCCESS;
2805 break;
2806
2807 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
2808
2809 //
2810 // If the caller is kernel mode, clear the verify bit.
2811 //
2812
2813 if (Irp->RequestorMode == KernelMode) {
2814 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
2815 }
2816 status = STATUS_SUCCESS;
2817 break;
2818
2819 case IOCTL_DISK_FIND_NEW_DEVICES:
2820
2821 //
2822 // Search for devices that have been powered on since the last
2823 // device search or system initialization.
2824 //
2825
2826 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2827 status = DriverEntry(DeviceObject->DriverObject,
2828 NULL);
2829
2830 Irp->IoStatus.Status = status;
2831 ExFreePool(srb);
2832 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2833 return status;
2834
2835 case IOCTL_DISK_MEDIA_REMOVAL:
2836
2837 //
2838 // If the disk is not removable then don't allow this command.
2839 //
2840
2841 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
2842 status = STATUS_INVALID_DEVICE_REQUEST;
2843 break;
2844 }
2845
2846 //
2847 // Fall through and let the class driver process the request.
2848 //
2849
2850 case IOCTL_DISK_GET_LENGTH_INFO:
2851
2852 //
2853 // Validate buffer length.
2854 //
2855
2856 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2857 sizeof(GET_LENGTH_INFORMATION)) {
2858 status = STATUS_BUFFER_TOO_SMALL;
2859
2860 } else {
2861
2862 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer;
2863
2864 //
2865 // Update the geometry in case it has changed.
2866 //
2867
2868 status = UpdateRemovableGeometry (DeviceObject, Irp);
2869
2870 if (!NT_SUCCESS(status)) {
2871
2872 //
2873 // Note the drive is not ready.
2874 //
2875
2876 diskData->DriveNotReady = TRUE;
2877 break;
2878 }
2879
2880 //
2881 // Note the drive is now ready.
2882 //
2883
2884 diskData->DriveNotReady = FALSE;
2885
2886 //
2887 // Output data, and return
2888 //
2889
2890 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart;
2891 status = STATUS_SUCCESS;
2892 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
2893 }
2894
2895 break;
2896
2897 default:
2898
2899 //
2900 // Free the Srb, since it is not needed.
2901 //
2902
2903 ExFreePool(srb);
2904
2905 //
2906 // Pass the request to the common device control routine.
2907 //
2908
2909 return(ScsiClassDeviceControl(DeviceObject, Irp));
2910
2911 break;
2912
2913 } // end switch( ...
2914
2915 Irp->IoStatus.Status = status;
2916
2917 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
2918
2919 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
2920 }
2921
2922 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2923 ExFreePool(srb);
2924 return(status);
2925
2926 } // end ScsiDiskDeviceControl()
2927 \f
2928 NTSTATUS
2929 NTAPI
2930 ScsiDiskShutdownFlush (
2931 IN PDEVICE_OBJECT DeviceObject,
2932 IN PIRP Irp
2933 )
2934
2935 /*++
2936
2937 Routine Description:
2938
2939 This routine is called for a shutdown and flush IRPs. These are sent by the
2940 system before it actually shuts down or when the file system does a flush.
2941 A synchronize cache command is sent to the device if it is write caching.
2942 If the device is removable an unlock command will be sent. This routine
2943 will sent a shutdown or flush Srb to the port driver.
2944
2945 Arguments:
2946
2947 DriverObject - Pointer to device object to being shutdown by system.
2948
2949 Irp - IRP involved.
2950
2951 Return Value:
2952
2953 NT Status
2954
2955 --*/
2956
2957 {
2958 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2959 PIO_STACK_LOCATION irpStack;
2960 PSCSI_REQUEST_BLOCK srb;
2961 NTSTATUS status;
2962 PCDB cdb;
2963
2964 //
2965 // Allocate SCSI request block.
2966 //
2967
2968 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
2969
2970 if (srb == NULL) {
2971
2972 //
2973 // Set the status and complete the request.
2974 //
2975
2976 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2977 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2978 return(STATUS_INSUFFICIENT_RESOURCES);
2979 }
2980
2981 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2982
2983 //
2984 // Write length to SRB.
2985 //
2986
2987 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2988
2989 //
2990 // Set SCSI bus address.
2991 //
2992
2993 srb->PathId = deviceExtension->PathId;
2994 srb->TargetId = deviceExtension->TargetId;
2995 srb->Lun = deviceExtension->Lun;
2996
2997 //
2998 // Set timeout value and mark the request as not being a tagged request.
2999 //
3000
3001 srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
3002 srb->QueueTag = SP_UNTAGGED;
3003 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
3004 srb->SrbFlags = deviceExtension->SrbFlags;
3005
3006 //
3007 // If the write cache is enabled then send a synchronize cache request.
3008 //
3009
3010 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
3011
3012 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3013 srb->CdbLength = 10;
3014
3015 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
3016
3017 status = ScsiClassSendSrbSynchronous(DeviceObject,
3018 srb,
3019 NULL,
3020 0,
3021 TRUE);
3022
3023 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status ));
3024 }
3025
3026 //
3027 // Unlock the device if it is removable and this is a shutdown.
3028 //
3029
3030 irpStack = IoGetCurrentIrpStackLocation(Irp);
3031
3032 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
3033 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
3034
3035 srb->CdbLength = 6;
3036 cdb = (PVOID) srb->Cdb;
3037 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3038 cdb->MEDIA_REMOVAL.Prevent = FALSE;
3039
3040 //
3041 // Set timeout value.
3042 //
3043
3044 srb->TimeOutValue = deviceExtension->TimeOutValue;
3045 status = ScsiClassSendSrbSynchronous(DeviceObject,
3046 srb,
3047 NULL,
3048 0,
3049 TRUE);
3050
3051 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
3052 }
3053
3054 srb->CdbLength = 0;
3055
3056 //
3057 // Save a few parameters in the current stack location.
3058 //
3059
3060 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
3061 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
3062
3063 //
3064 // Set the retry count to zero.
3065 //
3066
3067 irpStack->Parameters.Others.Argument4 = (PVOID) 0;
3068
3069 //
3070 // Set up IoCompletion routine address.
3071 //
3072
3073 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
3074
3075 //
3076 // Get next stack location and
3077 // set major function code.
3078 //
3079
3080 irpStack = IoGetNextIrpStackLocation(Irp);
3081
3082 irpStack->MajorFunction = IRP_MJ_SCSI;
3083
3084 //
3085 // Set up SRB for execute scsi request.
3086 // Save SRB address in next stack for port driver.
3087 //
3088
3089 irpStack->Parameters.Scsi.Srb = srb;
3090
3091 //
3092 // Set up Irp Address.
3093 //
3094
3095 srb->OriginalRequest = Irp;
3096
3097 //
3098 // Call the port driver to process the request.
3099 //
3100
3101 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3102
3103 } // end ScsiDiskShutdown()
3104
3105 \f
3106 BOOLEAN
3107 NTAPI
3108 IsFloppyDevice(
3109 PDEVICE_OBJECT DeviceObject
3110 )
3111 /*++
3112
3113 Routine Description:
3114
3115 The routine performs the necessary functions to determine if a device is
3116 really a floppy rather than a harddisk. This is done by a mode sense
3117 command. First, a check is made to see if the medimum type is set. Second
3118 a check is made for the flexible parameters mode page. Also a check is
3119 made to see if the write cache is enabled.
3120
3121 Arguments:
3122
3123 DeviceObject - Supplies the device object to be tested.
3124
3125 Return Value:
3126
3127 Return TRUE if the indicated device is a floppy.
3128
3129 --*/
3130 {
3131 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3132 PVOID modeData;
3133 PUCHAR pageData;
3134 ULONG length;
3135
3136 PAGED_CODE();
3137
3138 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3139
3140 if (modeData == NULL) {
3141 return(FALSE);
3142 }
3143
3144 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3145
3146 length = ScsiClassModeSense(DeviceObject,
3147 modeData,
3148 MODE_DATA_SIZE,
3149 MODE_SENSE_RETURN_ALL);
3150
3151 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3152
3153 //
3154 // Retry the request in case of a check condition.
3155 //
3156
3157 length = ScsiClassModeSense(DeviceObject,
3158 modeData,
3159 MODE_DATA_SIZE,
3160 MODE_SENSE_RETURN_ALL);
3161
3162 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3163
3164 ExFreePool(modeData);
3165 return(FALSE);
3166
3167 }
3168 }
3169
3170 //
3171 // If the length is greater than length indicated by the mode data reset
3172 // the data to the mode data.
3173 //
3174
3175 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3176 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3177 }
3178
3179 //
3180 // Look for the flexible disk mode page.
3181 //
3182
3183 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
3184
3185 if (pageData != NULL) {
3186
3187 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3188 ExFreePool(modeData);
3189 return(TRUE);
3190 }
3191
3192 //
3193 // Check to see if the write cache is enabled.
3194 //
3195
3196 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3197
3198 //
3199 // Assume that write cache is disabled or not supported.
3200 //
3201
3202 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3203
3204 //
3205 // Check if valid caching page exists.
3206 //
3207
3208 if (pageData != NULL) {
3209
3210 //
3211 // Check if write cache is disabled.
3212 //
3213
3214 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3215
3216 DebugPrint((1,
3217 "SCSIDISK: Disk write cache enabled\n"));
3218
3219 //
3220 // Check if forced unit access (FUA) is supported.
3221 //
3222
3223 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
3224
3225 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3226
3227 } else {
3228
3229 DebugPrint((1,
3230 "SCSIDISK: Disk does not support FUA or DPO\n"));
3231
3232 //
3233 // TODO: Log this.
3234 //
3235
3236 }
3237 }
3238 }
3239
3240 ExFreePool(modeData);
3241 return(FALSE);
3242
3243 } // end IsFloppyDevice()
3244
3245 \f
3246 BOOLEAN
3247 NTAPI
3248 ScsiDiskModeSelect(
3249 IN PDEVICE_OBJECT DeviceObject,
3250 IN PCHAR ModeSelectBuffer,
3251 IN ULONG Length,
3252 IN BOOLEAN SavePage
3253 )
3254
3255 /*++
3256
3257 Routine Description:
3258
3259 This routine sends a mode select command.
3260
3261 Arguments:
3262
3263 DeviceObject - Supplies the device object associated with this request.
3264
3265 ModeSelectBuffer - Supplies a buffer containing the page data.
3266
3267 Length - Supplies the length in bytes of the mode select buffer.
3268
3269 SavePage - Indicates that parameters should be written to disk.
3270
3271 Return Value:
3272
3273 Length of the transferred data is returned.
3274
3275 --*/
3276 {
3277 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3278 PCDB cdb;
3279 SCSI_REQUEST_BLOCK srb;
3280 ULONG retries = 1;
3281 ULONG length2;
3282 NTSTATUS status;
3283 ULONG_PTR buffer;
3284 PMODE_PARAMETER_BLOCK blockDescriptor;
3285
3286 PAGED_CODE();
3287
3288 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
3289
3290 //
3291 // Allocate buffer for mode select header, block descriptor, and mode page.
3292 //
3293
3294 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
3295
3296 RtlZeroMemory((PVOID)buffer, length2);
3297
3298 //
3299 // Set length in header to size of mode page.
3300 //
3301
3302 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
3303
3304 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
3305
3306 //
3307 // Set size
3308 //
3309
3310 blockDescriptor->BlockLength[1]=0x02;
3311
3312 //
3313 // Copy mode page to buffer.
3314 //
3315
3316 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
3317
3318 //
3319 // Zero SRB.
3320 //
3321
3322 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3323
3324 //
3325 // Build the MODE SELECT CDB.
3326 //
3327
3328 srb.CdbLength = 6;
3329 cdb = (PCDB)srb.Cdb;
3330
3331 //
3332 // Set timeout value from device extension.
3333 //
3334
3335 srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
3336
3337 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3338 cdb->MODE_SELECT.SPBit = SavePage;
3339 cdb->MODE_SELECT.PFBit = 1;
3340 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
3341
3342 Retry:
3343
3344 status = ScsiClassSendSrbSynchronous(DeviceObject,
3345 &srb,
3346 (PVOID)buffer,
3347 length2,
3348 TRUE);
3349
3350
3351 if (status == STATUS_VERIFY_REQUIRED) {
3352
3353 //
3354 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3355 // this status.
3356 //
3357
3358 if (retries--) {
3359
3360 //
3361 // Retry request.
3362 //
3363
3364 goto Retry;
3365 }
3366
3367 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3368 status = STATUS_SUCCESS;
3369 }
3370
3371 ExFreePool((PVOID)buffer);
3372
3373 if (NT_SUCCESS(status)) {
3374 return(TRUE);
3375 } else {
3376 return(FALSE);
3377 }
3378
3379 } // end SciDiskModeSelect()
3380
3381 \f
3382 VOID
3383 NTAPI
3384 DisableWriteCache(
3385 IN PDEVICE_OBJECT DeviceObject,
3386 IN PSCSI_INQUIRY_DATA LunInfo
3387 )
3388
3389 {
3390 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3391 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3392 BAD_CONTROLLER_INFORMATION const *controller;
3393 ULONG j,length;
3394 PVOID modeData;
3395 PUCHAR pageData;
3396
3397 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
3398
3399 controller = &ScsiDiskBadControllers[j];
3400
3401 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
3402 continue;
3403 }
3404
3405 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
3406
3407 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3408
3409 if (modeData == NULL) {
3410
3411 DebugPrint((1,
3412 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3413 return;
3414 }
3415
3416 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3417
3418 length = ScsiClassModeSense(DeviceObject,
3419 modeData,
3420 MODE_DATA_SIZE,
3421 MODE_SENSE_RETURN_ALL);
3422
3423 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3424
3425 //
3426 // Retry the request in case of a check condition.
3427 //
3428
3429 length = ScsiClassModeSense(DeviceObject,
3430 modeData,
3431 MODE_DATA_SIZE,
3432 MODE_SENSE_RETURN_ALL);
3433
3434 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3435
3436
3437 DebugPrint((1,
3438 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3439
3440 ExFreePool(modeData);
3441 return;
3442
3443 }
3444 }
3445
3446 //
3447 // If the length is greater than length indicated by the mode data reset
3448 // the data to the mode data.
3449 //
3450
3451 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3452 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3453 }
3454
3455 //
3456 // Check to see if the write cache is enabled.
3457 //
3458
3459 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3460
3461 //
3462 // Assume that write cache is disabled or not supported.
3463 //
3464
3465 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3466
3467 //
3468 // Check if valid caching page exists.
3469 //
3470
3471 if (pageData != NULL) {
3472
3473 BOOLEAN savePage = FALSE