[DISK] Properly implement querying partition information for partition 0.
[reactos.git] / drivers / storage / class / disk / disk.c
1 /*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/disk/disk.c
5 * PURPOSE: Disk class driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9 #include <ntddk.h>
10 #include <ntdddisk.h>
11 #include <scsi.h>
12 #include <ntddscsi.h>
13 #include <mountdev.h>
14 #include <mountmgr.h>
15 #include <ntiologc.h>
16 #include <include/class2.h>
17 #include <stdio.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22
23 #ifdef POOL_TAGGING
24 #ifdef ExAllocatePool
25 #undef ExAllocatePool
26 #endif
27 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
28 #endif
29
30 typedef enum {
31 NotInitialized,
32 Initializing,
33 Initialized
34 } PARTITION_LIST_STATE;
35
36 //
37 // Disk device data
38 //
39
40 typedef struct _DISK_DATA {
41
42 //
43 // Partition chain
44 //
45
46 PDEVICE_EXTENSION NextPartition;
47
48 //
49 // Disk signature (from MBR)
50 //
51
52 ULONG Signature;
53
54 //
55 // MBR checksum
56 //
57
58 ULONG MbrCheckSum;
59
60 //
61 // Number of hidden sectors for BPB.
62 //
63
64 ULONG HiddenSectors;
65
66 //
67 // Partition number of this device object
68 //
69 // This field is set during driver initialization or when the partition
70 // is created to identify a partition to the system.
71 //
72
73 ULONG PartitionNumber;
74
75 //
76 // This field is the ordinal of a partition as it appears on a disk.
77 //
78
79 ULONG PartitionOrdinal;
80
81 //
82 // Partition type of this device object
83 //
84 // This field is set by:
85 //
86 // 1) Initially set according to the partition list entry partition
87 // type returned by IoReadPartitionTable.
88 //
89 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
90 // I/O control function when IoSetPartitionInformation function
91 // successfully updates the partition type on the disk.
92 //
93
94 UCHAR PartitionType;
95
96 //
97 // Boot indicator - indicates whether this partition is a bootable (active)
98 // partition for this device
99 //
100 // This field is set according to the partition list entry boot indicator
101 // returned by IoReadPartitionTable.
102 //
103
104 BOOLEAN BootIndicator;
105
106 //
107 // DriveNotReady - indicates that the this device is currently not ready
108 // because there is no media in the device.
109 //
110
111 BOOLEAN DriveNotReady;
112
113 //
114 // State of PartitionList initialization
115 //
116
117 PARTITION_LIST_STATE PartitionListState;
118
119 } 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 break;
2239 }
2240
2241 //
2242 // Update the geometry in case it has changed.
2243 //
2244
2245 status = UpdateRemovableGeometry (DeviceObject, Irp);
2246
2247 if (!NT_SUCCESS(status)) {
2248
2249 //
2250 // Note the drive is not ready.
2251 //
2252
2253 diskData->DriveNotReady = TRUE;
2254 break;
2255 }
2256
2257 //
2258 // Note the drive is now ready.
2259 //
2260
2261 diskData->DriveNotReady = FALSE;
2262
2263 //
2264 // Handle the case were we query the whole disk
2265 //
2266
2267 if (diskData->PartitionNumber == 0) {
2268
2269 PPARTITION_INFORMATION outputBuffer;
2270
2271 outputBuffer =
2272 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2273
2274 outputBuffer->PartitionType = PARTITION_ENTRY_UNUSED;
2275 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2276 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2277 outputBuffer->HiddenSectors = 0;
2278 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2279 outputBuffer->BootIndicator = FALSE;
2280 outputBuffer->RewritePartition = FALSE;
2281 outputBuffer->RecognizedPartition = FALSE;
2282
2283 status = STATUS_SUCCESS;
2284 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
2285
2286 } else {
2287
2288 PPARTITION_INFORMATION outputBuffer;
2289
2290 //
2291 // We query a single partition here
2292 // FIXME: this can only work for MBR-based disks, check for this!
2293 //
2294
2295 outputBuffer =
2296 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2297
2298 outputBuffer->PartitionType = diskData->PartitionType;
2299 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2300 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2301 outputBuffer->HiddenSectors = diskData->HiddenSectors;
2302 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2303 outputBuffer->BootIndicator = diskData->BootIndicator;
2304 outputBuffer->RewritePartition = FALSE;
2305 outputBuffer->RecognizedPartition =
2306 IsRecognizedPartition(diskData->PartitionType);
2307
2308 status = STATUS_SUCCESS;
2309 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
2310 }
2311
2312 break;
2313
2314 case IOCTL_DISK_GET_PARTITION_INFO_EX:
2315
2316 //
2317 // Return the information about the partition specified by the device
2318 // object. Note that no information is ever returned about the size
2319 // or partition type of the physical disk, as this doesn't make any
2320 // sense.
2321 //
2322
2323 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2324 sizeof(PARTITION_INFORMATION_EX)) {
2325
2326 status = STATUS_INFO_LENGTH_MISMATCH;
2327
2328 }
2329 #if 0 // HACK: ReactOS partition numbers must be wrong
2330 else if (diskData->PartitionNumber == 0) {
2331
2332 //
2333 // Partition zero is not a partition so this is not a
2334 // reasonable request.
2335 //
2336
2337 status = STATUS_INVALID_DEVICE_REQUEST;
2338
2339 }
2340 #endif
2341 else {
2342
2343 PPARTITION_INFORMATION_EX outputBuffer;
2344
2345 if (diskData->PartitionNumber == 0) {
2346 DPRINT1("HACK: Handling partition 0 request!\n");
2347 //ASSERT(FALSE);
2348 }
2349
2350 //
2351 // Update the geometry in case it has changed.
2352 //
2353
2354 status = UpdateRemovableGeometry (DeviceObject, Irp);
2355
2356 if (!NT_SUCCESS(status)) {
2357
2358 //
2359 // Note the drive is not ready.
2360 //
2361
2362 diskData->DriveNotReady = TRUE;
2363 break;
2364 }
2365
2366 //
2367 // Note the drive is now ready.
2368 //
2369
2370 diskData->DriveNotReady = FALSE;
2371
2372 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2373
2374 status = STATUS_INVALID_DEVICE_REQUEST;
2375 break;
2376 }
2377
2378 outputBuffer =
2379 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
2380
2381 //
2382 // FIXME: hack of the year, assume that partition is MBR
2383 // Thing that can obviously be wrong...
2384 //
2385
2386 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
2387 outputBuffer->Mbr.PartitionType = diskData->PartitionType;
2388 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2389 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2390 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors;
2391 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2392 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator;
2393 outputBuffer->RewritePartition = FALSE;
2394 outputBuffer->Mbr.RecognizedPartition =
2395 IsRecognizedPartition(diskData->PartitionType);
2396
2397 status = STATUS_SUCCESS;
2398 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
2399 }
2400
2401 break;
2402
2403 case IOCTL_DISK_SET_PARTITION_INFO:
2404
2405 if (diskData->PartitionNumber == 0) {
2406
2407 status = STATUS_UNSUCCESSFUL;
2408
2409 } else {
2410
2411 PSET_PARTITION_INFORMATION inputBuffer =
2412 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2413
2414 //
2415 // Validate buffer length.
2416 //
2417
2418 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2419 sizeof(SET_PARTITION_INFORMATION)) {
2420
2421 status = STATUS_INFO_LENGTH_MISMATCH;
2422 break;
2423 }
2424
2425 //
2426 // The HAL routines IoGet- and IoSetPartitionInformation were
2427 // developed before support of dynamic partitioning and therefore
2428 // don't distinguish between partition ordinal (that is the order
2429 // of a partition on a disk) and the partition number. (The
2430 // partition number is assigned to a partition to identify it to
2431 // the system.) Use partition ordinals for these legacy calls.
2432 //
2433
2434 status = IoSetPartitionInformation(
2435 deviceExtension->PhysicalDevice,
2436 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2437 diskData->PartitionOrdinal,
2438 inputBuffer->PartitionType);
2439
2440 if (NT_SUCCESS(status)) {
2441
2442 diskData->PartitionType = inputBuffer->PartitionType;
2443 }
2444 }
2445
2446 break;
2447
2448 case IOCTL_DISK_GET_DRIVE_LAYOUT:
2449
2450 //
2451 // Return the partition layout for the physical drive. Note that
2452 // the layout is returned for the actual physical drive, regardless
2453 // of which partition was specified for the request.
2454 //
2455
2456 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2457 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2458 status = STATUS_INFO_LENGTH_MISMATCH;
2459
2460 } else {
2461
2462 PDRIVE_LAYOUT_INFORMATION partitionList;
2463 PDEVICE_EXTENSION physicalExtension = deviceExtension;
2464 PPARTITION_INFORMATION partitionEntry;
2465 PDISK_DATA diskData;
2466 ULONG tempSize;
2467 ULONG i;
2468
2469 //
2470 // Read partition information.
2471 //
2472
2473 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
2474 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2475 FALSE,
2476 &partitionList);
2477
2478 if (!NT_SUCCESS(status)) {
2479 break;
2480 }
2481
2482 //
2483 // The disk layout has been returned in the partitionList
2484 // buffer. Determine its size and, if the data will fit
2485 // into the intermediary buffer, return it.
2486 //
2487
2488 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
2489 tempSize += partitionList->PartitionCount *
2490 sizeof(PARTITION_INFORMATION);
2491
2492 if (tempSize >
2493 irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
2494
2495 status = STATUS_BUFFER_TOO_SMALL;
2496 ExFreePool(partitionList);
2497 break;
2498 }
2499
2500 //
2501 // Walk partition list to associate partition numbers with
2502 // partition entries.
2503 //
2504
2505 for (i = 0; i < partitionList->PartitionCount; i++) {
2506
2507 //
2508 // Walk partition chain anchored at physical disk extension.
2509 //
2510
2511 deviceExtension = physicalExtension;
2512 diskData = (PDISK_DATA)(deviceExtension + 1);
2513
2514 do {
2515
2516 deviceExtension = diskData->NextPartition;
2517
2518 //
2519 // Check if this is the last partition in the chain.
2520 //
2521
2522 if (!deviceExtension) {
2523 break;
2524 }
2525
2526 //
2527 // Get the partition device extension from disk data.
2528 //
2529
2530 diskData = (PDISK_DATA)(deviceExtension + 1);
2531
2532 //
2533 // Check if this partition is not currently being used.
2534 //
2535
2536 if (!deviceExtension->PartitionLength.QuadPart) {
2537 continue;
2538 }
2539
2540 partitionEntry = &partitionList->PartitionEntry[i];
2541
2542 //
2543 // Check if empty, or describes extended partition or hasn't changed.
2544 //
2545
2546 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2547 IsContainerPartition(partitionEntry->PartitionType)) {
2548 continue;
2549 }
2550
2551 //
2552 // Check if new partition starts where this partition starts.
2553 //
2554
2555 if (partitionEntry->StartingOffset.QuadPart !=
2556 deviceExtension->StartingOffset.QuadPart) {
2557 continue;
2558 }
2559
2560 //
2561 // Check if partition length is the same.
2562 //
2563
2564 if (partitionEntry->PartitionLength.QuadPart ==
2565 deviceExtension->PartitionLength.QuadPart) {
2566
2567 //
2568 // Partitions match. Update partition number.
2569 //
2570
2571 partitionEntry->PartitionNumber =
2572 diskData->PartitionNumber;
2573 break;
2574 }
2575
2576 } while (TRUE);
2577 }
2578
2579 //
2580 // Copy partition information to system buffer.
2581 //
2582
2583 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2584 partitionList,
2585 tempSize);
2586 status = STATUS_SUCCESS;
2587 Irp->IoStatus.Information = tempSize;
2588
2589 //
2590 // Finally, free the buffer allocated by reading the
2591 // partition table.
2592 //
2593
2594 ExFreePool(partitionList);
2595 }
2596
2597 break;
2598
2599 case IOCTL_DISK_SET_DRIVE_LAYOUT:
2600
2601 {
2602
2603 //
2604 // Update the disk with new partition information.
2605 //
2606
2607 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
2608
2609 //
2610 // Validate buffer length.
2611 //
2612
2613 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2614 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2615
2616 status = STATUS_INFO_LENGTH_MISMATCH;
2617 break;
2618 }
2619
2620 length = sizeof(DRIVE_LAYOUT_INFORMATION) +
2621 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
2622
2623
2624 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2625 length) {
2626
2627 status = STATUS_BUFFER_TOO_SMALL;
2628 break;
2629 }
2630
2631 //
2632 // Verify that device object is for physical disk.
2633 //
2634
2635 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
2636 status = STATUS_INVALID_PARAMETER;
2637 break;
2638 }
2639
2640 //
2641 // Walk through partition table comparing partitions to
2642 // existing partitions to create, delete and change
2643 // device objects as necessary.
2644 //
2645
2646 UpdateDeviceObjects(DeviceObject,
2647 Irp);
2648
2649 //
2650 // Write changes to disk.
2651 //
2652
2653 status = IoWritePartitionTable(
2654 deviceExtension->DeviceObject,
2655 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2656 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
2657 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
2658 partitionList);
2659 }
2660
2661 //
2662 // Update IRP with bytes returned.
2663 //
2664
2665 if (NT_SUCCESS(status)) {
2666 Irp->IoStatus.Information = length;
2667 }
2668
2669 break;
2670
2671 case IOCTL_DISK_REASSIGN_BLOCKS:
2672
2673 //
2674 // Map defective blocks to new location on disk.
2675 //
2676
2677 {
2678
2679 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2680 ULONG bufferSize;
2681 ULONG blockNumber;
2682 ULONG blockCount;
2683
2684 //
2685 // Validate buffer length.
2686 //
2687
2688 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2689 sizeof(REASSIGN_BLOCKS)) {
2690
2691 status = STATUS_INFO_LENGTH_MISMATCH;
2692 break;
2693 }
2694
2695 bufferSize = sizeof(REASSIGN_BLOCKS) +
2696 (badBlocks->Count - 1) * sizeof(ULONG);
2697
2698 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2699 bufferSize) {
2700
2701 status = STATUS_INFO_LENGTH_MISMATCH;
2702 break;
2703 }
2704
2705 //
2706 // Build the data buffer to be transferred in the input buffer.
2707 // The format of the data to the device is:
2708 //
2709 // 2 bytes Reserved
2710 // 2 bytes Length
2711 // x * 4 btyes Block Address
2712 //
2713 // All values are big endian.
2714 //
2715
2716 badBlocks->Reserved = 0;
2717 blockCount = badBlocks->Count;
2718
2719 //
2720 // Convert # of entries to # of bytes.
2721 //
2722
2723 blockCount *= 4;
2724 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2725 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2726
2727 //
2728 // Convert back to number of entries.
2729 //
2730
2731 blockCount /= 4;
2732
2733 for (; blockCount > 0; blockCount--) {
2734
2735 blockNumber = badBlocks->BlockNumber[blockCount-1];
2736
2737 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2738 (PFOUR_BYTE) &blockNumber);
2739 }
2740
2741 srb->CdbLength = 6;
2742
2743 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2744
2745 //
2746 // Set timeout value.
2747 //
2748
2749 srb->TimeOutValue = deviceExtension->TimeOutValue;
2750
2751 status = ScsiClassSendSrbSynchronous(DeviceObject,
2752 srb,
2753 badBlocks,
2754 bufferSize,
2755 TRUE);
2756
2757 Irp->IoStatus.Status = status;
2758 Irp->IoStatus.Information = 0;
2759 ExFreePool(srb);
2760 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2761 }
2762
2763 return(status);
2764
2765 case IOCTL_DISK_IS_WRITABLE:
2766
2767 //
2768 // Determine if the device is writable.
2769 //
2770
2771 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
2772
2773 if (modeData == NULL) {
2774 status = STATUS_INSUFFICIENT_RESOURCES;
2775 break;
2776 }
2777
2778 RtlZeroMemory(modeData, MODE_DATA_SIZE);
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
2787 //
2788 // Retry the request in case of a check condition.
2789 //
2790
2791 length = ScsiClassModeSense(DeviceObject,
2792 (PCHAR) modeData,
2793 MODE_DATA_SIZE,
2794 MODE_SENSE_RETURN_ALL);
2795
2796 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2797 status = STATUS_IO_DEVICE_ERROR;
2798 ExFreePool(modeData);
2799 break;
2800 }
2801 }
2802
2803 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
2804 status = STATUS_MEDIA_WRITE_PROTECTED;
2805 } else {
2806 status = STATUS_SUCCESS;
2807 }
2808
2809 ExFreePool(modeData);
2810 break;
2811
2812 case IOCTL_DISK_INTERNAL_SET_VERIFY:
2813
2814 //
2815 // If the caller is kernel mode, set the verify bit.
2816 //
2817
2818 if (Irp->RequestorMode == KernelMode) {
2819 DeviceObject->Flags |= DO_VERIFY_VOLUME;
2820 }
2821 status = STATUS_SUCCESS;
2822 break;
2823
2824 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
2825
2826 //
2827 // If the caller is kernel mode, clear the verify bit.
2828 //
2829
2830 if (Irp->RequestorMode == KernelMode) {
2831 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
2832 }
2833 status = STATUS_SUCCESS;
2834 break;
2835
2836 case IOCTL_DISK_FIND_NEW_DEVICES:
2837
2838 //
2839 // Search for devices that have been powered on since the last
2840 // device search or system initialization.
2841 //
2842
2843 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2844 status = DriverEntry(DeviceObject->DriverObject,
2845 NULL);
2846
2847 Irp->IoStatus.Status = status;
2848 ExFreePool(srb);
2849 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2850 return status;
2851
2852 case IOCTL_DISK_MEDIA_REMOVAL:
2853
2854 //
2855 // If the disk is not removable then don't allow this command.
2856 //
2857
2858 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
2859 status = STATUS_INVALID_DEVICE_REQUEST;
2860 break;
2861 }
2862
2863 //
2864 // Fall through and let the class driver process the request.
2865 //
2866
2867 case IOCTL_DISK_GET_LENGTH_INFO:
2868
2869 //
2870 // Validate buffer length.
2871 //
2872
2873 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2874 sizeof(GET_LENGTH_INFORMATION)) {
2875 status = STATUS_BUFFER_TOO_SMALL;
2876
2877 } else {
2878
2879 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer;
2880
2881 //
2882 // Update the geometry in case it has changed.
2883 //
2884
2885 status = UpdateRemovableGeometry (DeviceObject, Irp);
2886
2887 if (!NT_SUCCESS(status)) {
2888
2889 //
2890 // Note the drive is not ready.
2891 //
2892
2893 diskData->DriveNotReady = TRUE;
2894 break;
2895 }
2896
2897 //
2898 // Note the drive is now ready.
2899 //
2900
2901 diskData->DriveNotReady = FALSE;
2902
2903 //
2904 // Output data, and return
2905 //
2906
2907 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart;
2908 status = STATUS_SUCCESS;
2909 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
2910 }
2911
2912 break;
2913
2914 default:
2915
2916 //
2917 // Free the Srb, since it is not needed.
2918 //
2919
2920 ExFreePool(srb);
2921
2922 //
2923 // Pass the request to the common device control routine.
2924 //
2925
2926 return(ScsiClassDeviceControl(DeviceObject, Irp));
2927
2928 break;
2929
2930 } // end switch( ...
2931
2932 Irp->IoStatus.Status = status;
2933
2934 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
2935
2936 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
2937 }
2938
2939 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2940 ExFreePool(srb);
2941 return(status);
2942
2943 } // end ScsiDiskDeviceControl()
2944 \f
2945 NTSTATUS
2946 NTAPI
2947 ScsiDiskShutdownFlush (
2948 IN PDEVICE_OBJECT DeviceObject,
2949 IN PIRP Irp
2950 )
2951
2952 /*++
2953
2954 Routine Description:
2955
2956 This routine is called for a shutdown and flush IRPs. These are sent by the
2957 system before it actually shuts down or when the file system does a flush.
2958 A synchronize cache command is sent to the device if it is write caching.
2959 If the device is removable an unlock command will be sent. This routine
2960 will sent a shutdown or flush Srb to the port driver.
2961
2962 Arguments:
2963
2964 DriverObject - Pointer to device object to being shutdown by system.
2965
2966 Irp - IRP involved.
2967
2968 Return Value:
2969
2970 NT Status
2971
2972 --*/
2973
2974 {
2975 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2976 PIO_STACK_LOCATION irpStack;
2977 PSCSI_REQUEST_BLOCK srb;
2978 NTSTATUS status;
2979 PCDB cdb;
2980
2981 //
2982 // Allocate SCSI request block.
2983 //
2984
2985 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
2986
2987 if (srb == NULL) {
2988
2989 //
2990 // Set the status and complete the request.
2991 //
2992
2993 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2994 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2995 return(STATUS_INSUFFICIENT_RESOURCES);
2996 }
2997
2998 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2999
3000 //
3001 // Write length to SRB.
3002 //
3003
3004 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
3005
3006 //
3007 // Set SCSI bus address.
3008 //
3009
3010 srb->PathId = deviceExtension->PathId;
3011 srb->TargetId = deviceExtension->TargetId;
3012 srb->Lun = deviceExtension->Lun;
3013
3014 //
3015 // Set timeout value and mark the request as not being a tagged request.
3016 //
3017
3018 srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
3019 srb->QueueTag = SP_UNTAGGED;
3020 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
3021 srb->SrbFlags = deviceExtension->SrbFlags;
3022
3023 //
3024 // If the write cache is enabled then send a synchronize cache request.
3025 //
3026
3027 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
3028
3029 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3030 srb->CdbLength = 10;
3031
3032 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
3033
3034 status = ScsiClassSendSrbSynchronous(DeviceObject,
3035 srb,
3036 NULL,
3037 0,
3038 TRUE);
3039
3040 DebugPrint((1, "ScsiDiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status ));
3041 }
3042
3043 //
3044 // Unlock the device if it is removable and this is a shutdown.
3045 //
3046
3047 irpStack = IoGetCurrentIrpStackLocation(Irp);
3048
3049 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
3050 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
3051
3052 srb->CdbLength = 6;
3053 cdb = (PVOID) srb->Cdb;
3054 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3055 cdb->MEDIA_REMOVAL.Prevent = FALSE;
3056
3057 //
3058 // Set timeout value.
3059 //
3060
3061 srb->TimeOutValue = deviceExtension->TimeOutValue;
3062 status = ScsiClassSendSrbSynchronous(DeviceObject,
3063 srb,
3064 NULL,
3065 0,
3066 TRUE);
3067
3068 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
3069 }
3070
3071 srb->CdbLength = 0;
3072
3073 //
3074 // Save a few parameters in the current stack location.
3075 //
3076
3077 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
3078 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
3079
3080 //
3081 // Set the retry count to zero.
3082 //
3083
3084 irpStack->Parameters.Others.Argument4 = (PVOID) 0;
3085
3086 //
3087 // Set up IoCompletion routine address.
3088 //
3089
3090 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
3091
3092 //
3093 // Get next stack location and
3094 // set major function code.
3095 //
3096
3097 irpStack = IoGetNextIrpStackLocation(Irp);
3098
3099 irpStack->MajorFunction = IRP_MJ_SCSI;
3100
3101 //
3102 // Set up SRB for execute scsi request.
3103 // Save SRB address in next stack for port driver.
3104 //
3105
3106 irpStack->Parameters.Scsi.Srb = srb;
3107
3108 //
3109 // Set up Irp Address.
3110 //
3111
3112 srb->OriginalRequest = Irp;
3113
3114 //
3115 // Call the port driver to process the request.
3116 //
3117
3118 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3119
3120 } // end ScsiDiskShutdown()
3121
3122 \f
3123 BOOLEAN
3124 NTAPI
3125 IsFloppyDevice(
3126 PDEVICE_OBJECT DeviceObject
3127 )
3128 /*++
3129
3130 Routine Description:
3131
3132 The routine performs the necessary functions to determine if a device is
3133 really a floppy rather than a harddisk. This is done by a mode sense
3134 command. First, a check is made to see if the media type is set. Second
3135 a check is made for the flexible parameters mode page. Also a check is
3136 made to see if the write cache is enabled.
3137
3138 Arguments:
3139
3140 DeviceObject - Supplies the device object to be tested.
3141
3142 Return Value:
3143
3144 Return TRUE if the indicated device is a floppy.
3145
3146 --*/
3147 {
3148 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3149 PVOID modeData;
3150 PUCHAR pageData;
3151 ULONG length;
3152
3153 PAGED_CODE();
3154
3155 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3156
3157 if (modeData == NULL) {
3158 return(FALSE);
3159 }
3160
3161 RtlZeroMemory(modeData, MODE_DATA_SIZE);
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 //
3171 // Retry the request in case of a check condition.
3172 //
3173
3174 length = ScsiClassModeSense(DeviceObject,
3175 modeData,
3176 MODE_DATA_SIZE,
3177 MODE_SENSE_RETURN_ALL);
3178
3179 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3180
3181 ExFreePool(modeData);
3182 return(FALSE);
3183
3184 }
3185 }
3186
3187 //
3188 // If the length is greater than length indicated by the mode data reset
3189 // the data to the mode data.
3190 //
3191
3192 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3193 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3194 }
3195
3196 //
3197 // Look for the flexible disk mode page.
3198 //
3199
3200 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
3201
3202 if (pageData != NULL) {
3203
3204 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3205 ExFreePool(modeData);
3206 return(TRUE);
3207 }
3208
3209 //
3210 // Check to see if the write cache is enabled.
3211 //
3212
3213 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3214
3215 //
3216 // Assume that write cache is disabled or not supported.
3217 //
3218
3219 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3220
3221 //
3222 // Check if valid caching page exists.
3223 //
3224
3225 if (pageData != NULL) {
3226
3227 //
3228 // Check if write cache is disabled.
3229 //
3230
3231 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3232
3233 DebugPrint((1,
3234 "SCSIDISK: Disk write cache enabled\n"));
3235
3236 //
3237 // Check if forced unit access (FUA) is supported.
3238 //
3239
3240 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
3241
3242 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3243
3244 } else {
3245
3246 DebugPrint((1,
3247 "SCSIDISK: Disk does not support FUA or DPO\n"));
3248
3249 //
3250 // TODO: Log this.
3251 //
3252
3253 }
3254 }
3255 }
3256
3257 ExFreePool(modeData);
3258 return(FALSE);
3259
3260 } // end IsFloppyDevice()
3261
3262 \f
3263 BOOLEAN
3264 NTAPI
3265 ScsiDiskModeSelect(
3266 IN PDEVICE_OBJECT DeviceObject,
3267 IN PCHAR ModeSelectBuffer,
3268 IN ULONG Length,
3269 IN BOOLEAN SavePage
3270 )
3271
3272 /*++
3273
3274 Routine Description:
3275
3276 This routine sends a mode select command.
3277
3278 Arguments:
3279
3280 DeviceObject - Supplies the device object associated with this request.
3281
3282 ModeSelectBuffer - Supplies a buffer containing the page data.
3283
3284 Length - Supplies the length in bytes of the mode select buffer.
3285
3286 SavePage - Indicates that parameters should be written to disk.
3287
3288 Return Value:
3289
3290 Length of the transferred data is returned.
3291
3292 --*/
3293 {
3294 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3295 PCDB cdb;
3296 SCSI_REQUEST_BLOCK srb;
3297 ULONG retries = 1;
3298 ULONG length2;
3299 NTSTATUS status;
3300 ULONG_PTR buffer;
3301 PMODE_PARAMETER_BLOCK blockDescriptor;
3302
3303 PAGED_CODE();
3304
3305 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
3306
3307 //
3308 // Allocate buffer for mode select header, block descriptor, and mode page.
3309 //
3310
3311 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
3312
3313 RtlZeroMemory((PVOID)buffer, length2);
3314
3315 //
3316 // Set length in header to size of mode page.
3317 //
3318
3319 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
3320
3321 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
3322
3323 //
3324 // Set size
3325 //
3326
3327 blockDescriptor->BlockLength[1]=0x02;
3328
3329 //
3330 // Copy mode page to buffer.
3331 //
3332
3333 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
3334
3335 //
3336 // Zero SRB.
3337 //
3338
3339 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3340
3341 //
3342 // Build the MODE SELECT CDB.
3343 //
3344
3345 srb.CdbLength = 6;
3346 cdb = (PCDB)srb.Cdb;
3347
3348 //
3349 // Set timeout value from device extension.
3350 //
3351
3352 srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
3353
3354 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3355 cdb->MODE_SELECT.SPBit = SavePage;
3356 cdb->MODE_SELECT.PFBit = 1;
3357 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
3358
3359 Retry:
3360
3361 status = ScsiClassSendSrbSynchronous(DeviceObject,
3362 &srb,
3363 (PVOID)buffer,
3364 length2,
3365 TRUE);
3366
3367
3368 if (status == STATUS_VERIFY_REQUIRED) {
3369
3370 //
3371 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3372 // this status.
3373 //
3374
3375 if (retries--) {
3376
3377 //
3378 // Retry request.
3379 //
3380
3381 goto Retry;
3382 }
3383
3384 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3385 status = STATUS_SUCCESS;
3386 }
3387
3388 ExFreePool((PVOID)buffer);
3389
3390 if (NT_SUCCESS(status)) {
3391 return(TRUE);
3392 } else {
3393 return(FALSE);
3394 }
3395
3396 } // end SciDiskModeSelect()
3397
3398 \f
3399 VOID
3400 NTAPI
3401 DisableWriteCache(
3402 IN PDEVICE_OBJECT DeviceObject,
3403 IN PSCSI_INQUIRY_DATA LunInfo
3404 )
3405
3406 {
3407 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3408 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3409 BAD_CONTROLLER_INFORMATION const *controller;
3410 ULONG j,length;
3411 PVOID modeData;
3412 PUCHAR pageData;
3413
3414 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
3415
3416 controller = &ScsiDiskBadControllers[j];
3417
3418 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
3419 continue;
3420 }
3421
3422 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
3423
3424 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3425
3426 if (modeData == NULL) {
3427
3428 DebugPrint((1,
3429 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3430 return;
3431 }
3432
3433 RtlZeroMemory(modeData, MODE_DATA_SIZE);
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 // Retry the request in case of a check condition.
3444 //
3445
3446 length = ScsiClassModeSense(DeviceObject,
3447 modeData,
3448 MODE_DATA_SIZE,
3449 MODE_SENSE_RETURN_ALL);
3450
3451 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3452
3453
3454 DebugPrint((1,
3455 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3456
3457 ExFreePool(modeData);
3458 return;
3459
3460 }
3461 }
3462
3463 //
3464 // If the length is greater than length indicated by the mode data reset
3465 // the data to the mode data.
3466 //
3467
3468 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3469 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3470 }
3471
3472 //
3473 // Check to see if the write cache is enabled.
3474 //
3475
3476 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3477
3478 //
3479 // Assume that write cache is disabled or not supported.
3480 //
3481
3482 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3483
3484 //
3485 // Check if valid caching page exists.
3486 //
3487
3488 if (pageData != NULL) {
3489
3490 BOOLEAN savePage = FALSE;
3491
3492 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
3493
3494 //
3495 // Check if write cache is disabled.
3496 //
3497
3498 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3499
3500 PIO_ERROR_LOG_PACKET errorLogEntry;
3501 LONG errorCode;
3502
3503
3504 //
3505 // Disable write cache and ensure necessary fields are zeroed.
3506 //
3507
3508 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
3509 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
3510 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
3511 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
3512
3513 //
3514 // Extract length from caching page.
3515 //
3516
3517 length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
3518
3519 //
3520 // Compensate for page code and page length.
3521 //
3522
3523 length += 2;
3524
3525 //
3526 // Issue mode select to set the parameter.
3527 //
3528
3529 if (ScsiDiskModeSelect(DeviceObject,
3530 (PCHAR)pageData,
3531 length,
3532 savePage)) {
3533
3534 DebugPrint((1,
3535 "SCSIDISK: Disk write cache disabled\n"));
3536
3537 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3538 errorCode = IO_WRITE_CACHE_DISABLED;
3539
3540 } else {
3541 if (ScsiDiskModeSelect(DeviceObject,
3542 (PCHAR)pageData,
3543 length,
3544 savePage)) {
3545
3546 DebugPrint((1,
3547 "SCSIDISK: Disk write cache disabled\n"));
3548
3549
3550 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3551 errorCode = IO_WRITE_CACHE_DISABLED;
3552
3553 } else {
3554
3555 DebugPrint((1,
3556 "SCSIDISK: Mode select to disable write cache failed\n"));
3557
3558 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3559 errorCode = IO_WRITE_CACHE_ENABLED;
3560 }
3561 }
3562
3563 //
3564 // Log the appropriate informational or error entry.