[DRIVERS] Spelling fixes by Josh Soref. CORE-12286
[reactos.git] / reactos / drivers / storage / class / disk / disk.c
1 /*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/disk/disk.c
5 * PURPOSE: Disk class driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9 #include <ntddk.h>
10 #include <ntdddisk.h>
11 #include <scsi.h>
12 #include <ntddscsi.h>
13 #include <mountdev.h>
14 #include <mountmgr.h>
15 #include <ntiologc.h>
16 #include <include/class2.h>
17 #include <stdio.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22
23 #ifdef POOL_TAGGING
24 #ifdef ExAllocatePool
25 #undef ExAllocatePool
26 #endif
27 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
28 #endif
29
30 typedef enum {
31 NotInitialized,
32 Initializing,
33 Initialized
34 } PARTITION_LIST_STATE;
35
36 //
37 // Disk device data
38 //
39
40 typedef struct _DISK_DATA {
41
42 //
43 // Partition chain
44 //
45
46 PDEVICE_EXTENSION NextPartition;
47
48 //
49 // Disk signature (from MBR)
50 //
51
52 ULONG Signature;
53
54 //
55 // MBR checksum
56 //
57
58 ULONG MbrCheckSum;
59
60 //
61 // Number of hidden sectors for BPB.
62 //
63
64 ULONG HiddenSectors;
65
66 //
67 // Partition number of this device object
68 //
69 // This field is set during driver initialization or when the partition
70 // is created to identify a partition to the system.
71 //
72
73 ULONG PartitionNumber;
74
75 //
76 // This field is the ordinal of a partition as it appears on a disk.
77 //
78
79 ULONG PartitionOrdinal;
80
81 //
82 // Partition type of this device object
83 //
84 // This field is set by:
85 //
86 // 1) Initially set according to the partition list entry partition
87 // type returned by IoReadPartitionTable.
88 //
89 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
90 // I/O control function when IoSetPartitionInformation function
91 // successfully updates the partition type on the disk.
92 //
93
94 UCHAR PartitionType;
95
96 //
97 // Boot indicator - indicates whether this partition is a bootable (active)
98 // partition for this device
99 //
100 // This field is set according to the partition list entry boot indicator
101 // returned by IoReadPartitionTable.
102 //
103
104 BOOLEAN BootIndicator;
105
106 //
107 // DriveNotReady - indicates that the this device is currently not ready
108 // because there is no media in the device.
109 //
110
111 BOOLEAN DriveNotReady;
112
113 //
114 // State of PartitionList initialization
115 //
116
117 PARTITION_LIST_STATE PartitionListState;
118
119 } DISK_DATA, *PDISK_DATA;
120
121 //
122 // Define a general structure of identifying disk controllers with bad
123 // hardware.
124 //
125
126 typedef struct _BAD_CONTROLLER_INFORMATION {
127 PCHAR InquiryString;
128 BOOLEAN DisableTaggedQueuing;
129 BOOLEAN DisableSynchronousTransfers;
130 BOOLEAN DisableDisconnects;
131 BOOLEAN DisableWriteCache;
132 }BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION;
133
134 BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = {
135 { "TOSHIBA MK538FB 60", TRUE, FALSE, FALSE, FALSE },
136 { "CONNER CP3500", FALSE, TRUE, FALSE, FALSE },
137 { "OLIVETTICP3500", FALSE, TRUE, FALSE, FALSE },
138 { "SyQuest SQ5110 CHC", TRUE, TRUE, FALSE, FALSE },
139 { "SEAGATE ST41601N 0102", FALSE, TRUE, FALSE, FALSE },
140 { "SEAGATE ST3655N", FALSE, FALSE, FALSE, TRUE },
141 { "SEAGATE ST3390N", FALSE, FALSE, FALSE, TRUE },
142 { "SEAGATE ST12550N", FALSE, FALSE, FALSE, TRUE },
143 { "SEAGATE ST32430N", FALSE, FALSE, FALSE, TRUE },
144 { "SEAGATE ST31230N", FALSE, FALSE, FALSE, TRUE },
145 { "SEAGATE ST15230N", FALSE, FALSE, FALSE, TRUE },
146 { "FUJITSU M2652S-512", TRUE, FALSE, FALSE, FALSE },
147 { "MAXTOR MXT-540SL I1.2", TRUE, FALSE, FALSE, FALSE },
148 { "COMPAQ PD-1", FALSE, TRUE, FALSE, FALSE }
149 };
150
151
152 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
153 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
154
155 #define MODE_DATA_SIZE 192
156 #define VALUE_BUFFER_SIZE 2048
157 #define SCSI_DISK_TIMEOUT 10
158 #define PARTITION0_LIST_SIZE 4
159
160 \f
161 NTSTATUS
162 NTAPI
163 DriverEntry(
164 IN PDRIVER_OBJECT DriverObject,
165 IN PUNICODE_STRING RegistryPath
166 );
167
168 BOOLEAN
169 NTAPI
170 ScsiDiskDeviceVerification(
171 IN PINQUIRYDATA InquiryData
172 );
173
174 BOOLEAN
175 NTAPI
176 FindScsiDisks(
177 IN PDRIVER_OBJECT DriveObject,
178 IN PUNICODE_STRING RegistryPath,
179 IN PCLASS_INIT_DATA InitializationData,
180 IN PDEVICE_OBJECT PortDeviceObject,
181 IN ULONG PortNumber
182 );
183
184 NTSTATUS
185 NTAPI
186 ScsiDiskCreateClose (
187 IN PDEVICE_OBJECT DeviceObject,
188 IN PIRP Irp
189 );
190
191 NTSTATUS
192 NTAPI
193 ScsiDiskReadWriteVerification(
194 IN PDEVICE_OBJECT DeviceObject,
195 IN PIRP Irp
196 );
197
198 NTSTATUS
199 NTAPI
200 ScsiDiskDeviceControl(
201 IN PDEVICE_OBJECT DeviceObject,
202 IN PIRP Irp
203 );
204
205 VOID
206 NTAPI
207 ScsiDiskProcessError(
208 PDEVICE_OBJECT DeviceObject,
209 PSCSI_REQUEST_BLOCK Srb,
210 NTSTATUS *Status,
211 BOOLEAN *Retry
212 );
213
214 NTSTATUS
215 NTAPI
216 ScsiDiskShutdownFlush(
217 IN PDEVICE_OBJECT DeviceObject,
218 IN PIRP Irp
219 );
220
221 VOID
222 NTAPI
223 DisableWriteCache(
224 IN PDEVICE_OBJECT DeviceObject,
225 IN PSCSI_INQUIRY_DATA LunInfo
226 );
227
228 BOOLEAN
229 NTAPI
230 ScsiDiskModeSelect(
231 IN PDEVICE_OBJECT DeviceObject,
232 IN PCHAR ModeSelectBuffer,
233 IN ULONG Length,
234 IN BOOLEAN SavePage
235 );
236
237 BOOLEAN
238 NTAPI
239 IsFloppyDevice(
240 IN PDEVICE_OBJECT DeviceObject
241 );
242
243 BOOLEAN
244 NTAPI
245 CalculateMbrCheckSum(
246 IN PDEVICE_EXTENSION DeviceExtension,
247 OUT PULONG Checksum
248 );
249
250 BOOLEAN
251 NTAPI
252 EnumerateBusKey(
253 IN PDEVICE_EXTENSION DeviceExtension,
254 HANDLE BusKey,
255 PULONG DiskNumber
256 );
257
258 VOID
259 NTAPI
260 UpdateGeometry(
261 IN PDEVICE_EXTENSION DeviceExtension
262 );
263
264 NTSTATUS
265 NTAPI
266 UpdateRemovableGeometry (
267 IN PDEVICE_OBJECT DeviceObject,
268 IN PIRP Irp
269 );
270
271 NTSTATUS
272 NTAPI
273 CreateDiskDeviceObject(
274 IN PDRIVER_OBJECT DriverObject,
275 IN PUNICODE_STRING RegistryPath,
276 IN PDEVICE_OBJECT PortDeviceObject,
277 IN ULONG PortNumber,
278 IN PULONG DeviceCount,
279 IN PIO_SCSI_CAPABILITIES PortCapabilities,
280 IN PSCSI_INQUIRY_DATA LunInfo,
281 IN PCLASS_INIT_DATA InitData
282 );
283
284 NTSTATUS
285 NTAPI
286 CreatePartitionDeviceObjects(
287 IN PDEVICE_OBJECT PhysicalDeviceObject,
288 IN PUNICODE_STRING RegistryPath
289 );
290
291 VOID
292 NTAPI
293 UpdateDeviceObjects(
294 IN PDEVICE_OBJECT DeviceObject,
295 IN PIRP Irp
296 );
297
298 VOID
299 NTAPI
300 ScanForSpecial(
301 PDEVICE_OBJECT DeviceObject,
302 PSCSI_INQUIRY_DATA LunInfo,
303 PIO_SCSI_CAPABILITIES PortCapabilities
304 );
305
306 VOID
307 NTAPI
308 ResetScsiBus(
309 IN PDEVICE_OBJECT DeviceObject
310 );
311
312 NTSTATUS
313 NTAPI
314 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject,
315 PIRP Irp);
316
317 #ifdef ALLOC_PRAGMA
318 #pragma alloc_text(PAGE, DriverEntry)
319 #pragma alloc_text(PAGE, FindScsiDisks)
320 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
321 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
322 #pragma alloc_text(PAGE, EnumerateBusKey)
323 #pragma alloc_text(PAGE, UpdateGeometry)
324 #pragma alloc_text(PAGE, IsFloppyDevice)
325 #pragma alloc_text(PAGE, ScanForSpecial)
326 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
327 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
328 #endif
329
330 \f
331 NTSTATUS
332 NTAPI
333 DriverEntry(
334 IN PDRIVER_OBJECT DriverObject,
335 IN PUNICODE_STRING RegistryPath
336 )
337
338 /*++
339
340 Routine Description:
341
342 This routine initializes the SCSI hard disk class driver.
343
344 Arguments:
345
346 DriverObject - Pointer to driver object created by system.
347
348 RegistryPath - Pointer to the name of the services node for this driver.
349
350 Return Value:
351
352 The function value is the final status from the initialization operation.
353
354 --*/
355
356 {
357 CLASS_INIT_DATA InitializationData;
358
359 //
360 // Zero InitData
361 //
362
363 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
364
365 //
366 // Set sizes
367 //
368
369 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
370 InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
371
372 InitializationData.DeviceType = FILE_DEVICE_DISK;
373 InitializationData.DeviceCharacteristics = 0;
374
375 //
376 // Set entry points
377 //
378
379 InitializationData.ClassError = ScsiDiskProcessError;
380 InitializationData.ClassReadWriteVerification = ScsiDiskReadWriteVerification;
381 InitializationData.ClassFindDevices = FindScsiDisks;
382 InitializationData.ClassFindDeviceCallBack = ScsiDiskDeviceVerification;
383 InitializationData.ClassDeviceControl = ScsiDiskDeviceControl;
384 InitializationData.ClassShutdownFlush = ScsiDiskShutdownFlush;
385 InitializationData.ClassCreateClose = NULL;
386
387 //
388 // Call the class init routine
389 //
390
391 return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
392
393 } // end DriverEntry()
394
395
396 \f
397 BOOLEAN
398 NTAPI
399 ScsiDiskDeviceVerification(
400 IN PINQUIRYDATA InquiryData
401 )
402
403 /*++
404
405 Routine Description:
406
407 This routine checks InquiryData for the correct device type and qualifier.
408
409 Arguments:
410
411 InquiryData - Pointer to the inquiry data for the device in question.
412
413 Return Value:
414
415 True is returned if the correct device type is found.
416
417 --*/
418 {
419
420 if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
421 (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
422 InquiryData->DeviceTypeQualifier == 0) {
423
424 return TRUE;
425
426 } else {
427 return FALSE;
428 }
429 }
430
431 \f
432 BOOLEAN
433 NTAPI
434 FindScsiDisks(
435 IN PDRIVER_OBJECT DriverObject,
436 IN PUNICODE_STRING RegistryPath,
437 IN PCLASS_INIT_DATA InitializationData,
438 IN PDEVICE_OBJECT PortDeviceObject,
439 IN ULONG PortNumber
440 )
441
442 /*++
443
444 Routine Description:
445
446 This routine gets a port drivers capabilities, obtains the
447 inquiry data, searches the SCSI bus for the port driver and creates
448 the device objects for the disks found.
449
450 Arguments:
451
452 DriverObject - Pointer to driver object created by system.
453
454 PortDeviceObject - Device object use to send requests to port driver.
455
456 PortNumber - Number for port driver. Used to pass on to
457 CreateDiskDeviceObjects() and create device objects.
458
459 Return Value:
460
461 True is returned if one disk was found and successfully created.
462
463 --*/
464
465 {
466 PIO_SCSI_CAPABILITIES portCapabilities;
467 PULONG diskCount;
468 PCONFIGURATION_INFORMATION configurationInformation;
469 PCHAR buffer;
470 PSCSI_INQUIRY_DATA lunInfo;
471 PSCSI_ADAPTER_BUS_INFO adapterInfo;
472 PINQUIRYDATA inquiryData;
473 ULONG scsiBus;
474 ULONG adapterDisk;
475 NTSTATUS status;
476 BOOLEAN foundOne = FALSE;
477
478 PAGED_CODE();
479
480 //
481 // Call port driver to get adapter capabilities.
482 //
483
484 status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
485
486 if (!NT_SUCCESS(status)) {
487 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
488 return(FALSE);
489 }
490
491 //
492 // Call port driver to get inquiry information to find disks.
493 //
494
495 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
496
497 if (!NT_SUCCESS(status)) {
498 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
499 return(FALSE);
500 }
501
502 //
503 // Do a quick scan of the devices on this adapter to determine how many
504 // disks are on this adapter. This is used to determine the number of
505 // SRB zone elements to allocate.
506 //
507
508 adapterInfo = (PVOID) buffer;
509
510 adapterDisk = ScsiClassFindUnclaimedDevices(InitializationData, adapterInfo);
511
512 //
513 // Allocate a zone of SRB for disks on this adapter.
514 //
515
516 if (adapterDisk == 0) {
517
518 //
519 // No free disks were found.
520 //
521
522 return(FALSE);
523 }
524
525 //
526 // Get the number of disks already initialized.
527 //
528
529 configurationInformation = IoGetConfigurationInformation();
530 diskCount = &configurationInformation->DiskCount;
531
532 //
533 // For each SCSI bus this adapter supports ...
534 //
535
536 for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
537
538 //
539 // Get the SCSI bus scan data for this bus.
540 //
541
542 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
543
544 //
545 // Search list for unclaimed disk devices.
546 //
547
548 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
549
550 inquiryData = (PVOID)lunInfo->InquiryData;
551
552 if (((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
553 (inquiryData->DeviceType == OPTICAL_DEVICE)) &&
554 inquiryData->DeviceTypeQualifier == 0 &&
555 (!lunInfo->DeviceClaimed)) {
556
557 DebugPrint((1,
558 "FindScsiDevices: Vendor string is %.24s\n",
559 inquiryData->VendorId));
560
561 //
562 // Create device objects for disk
563 //
564
565 status = CreateDiskDeviceObject(DriverObject,
566 RegistryPath,
567 PortDeviceObject,
568 PortNumber,
569 diskCount,
570 portCapabilities,
571 lunInfo,
572 InitializationData);
573
574 if (NT_SUCCESS(status)) {
575
576 //
577 // Increment system disk device count.
578 //
579
580 (*diskCount)++;
581 foundOne = TRUE;
582
583 }
584 }
585
586 //
587 // Get next LunInfo.
588 //
589
590 if (lunInfo->NextInquiryDataOffset == 0) {
591 break;
592 }
593
594 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
595
596 }
597 }
598
599 //
600 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
601 //
602
603 ExFreePool(buffer);
604
605 return(foundOne);
606
607 } // end FindScsiDisks()
608
609 \f
610 NTSTATUS
611 NTAPI
612 CreateDiskDeviceObject(
613 IN PDRIVER_OBJECT DriverObject,
614 IN PUNICODE_STRING RegistryPath,
615 IN PDEVICE_OBJECT PortDeviceObject,
616 IN ULONG PortNumber,
617 IN PULONG DeviceCount,
618 IN PIO_SCSI_CAPABILITIES PortCapabilities,
619 IN PSCSI_INQUIRY_DATA LunInfo,
620 IN PCLASS_INIT_DATA InitData
621 )
622
623 /*++
624
625 Routine Description:
626
627 This routine creates an object for the physical device and then searches
628 the device for partitions and creates an object for each partition.
629
630 Arguments:
631
632 DriverObject - Pointer to driver object created by system.
633
634 PortDeviceObject - Miniport device object.
635
636 PortNumber - port number. Used in creating disk objects.
637
638 DeviceCount - Number of previously installed devices.
639
640 PortCapabilities - Capabilities of this SCSI port.
641
642 LunInfo - LUN specific information.
643
644 Return Value:
645
646 NTSTATUS
647
648 --*/
649 {
650 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
651 STRING ntNameString;
652 UNICODE_STRING ntUnicodeString;
653 OBJECT_ATTRIBUTES objectAttributes;
654 HANDLE handle;
655 NTSTATUS status;
656 PDEVICE_OBJECT deviceObject = NULL;
657 //PDEVICE_OBJECT physicalDevice;
658 PDISK_GEOMETRY_EX diskGeometry = NULL;
659 PDEVICE_EXTENSION deviceExtension = NULL;
660 //PDEVICE_EXTENSION physicalDeviceExtension;
661 UCHAR pathId = LunInfo->PathId;
662 UCHAR targetId = LunInfo->TargetId;
663 UCHAR lun = LunInfo->Lun;
664 //BOOLEAN writeCache;
665 PVOID senseData = NULL;
666 //ULONG srbFlags;
667 ULONG timeOut = 0;
668 BOOLEAN srbListInitialized = FALSE;
669
670
671 PAGED_CODE();
672
673 //
674 // Set up an object directory to contain the objects for this
675 // device and all its partitions.
676 //
677
678 sprintf(ntNameBuffer,
679 "\\Device\\Harddisk%lu",
680 *DeviceCount);
681
682 RtlInitString(&ntNameString,
683 ntNameBuffer);
684
685 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
686 &ntNameString,
687 TRUE);
688
689 if (!NT_SUCCESS(status)) {
690 return(status);
691 }
692
693 InitializeObjectAttributes(&objectAttributes,
694 &ntUnicodeString,
695 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
696 NULL,
697 NULL);
698
699 status = ZwCreateDirectoryObject(&handle,
700 DIRECTORY_ALL_ACCESS,
701 &objectAttributes);
702
703 RtlFreeUnicodeString(&ntUnicodeString);
704
705 if (!NT_SUCCESS(status)) {
706
707 DebugPrint((1,
708 "CreateDiskDeviceObjects: Could not create directory %s\n",
709 ntNameBuffer));
710
711 return(status);
712 }
713
714 //
715 // Claim the device.
716 //
717
718 status = ScsiClassClaimDevice(PortDeviceObject,
719 LunInfo,
720 FALSE,
721 &PortDeviceObject);
722
723 if (!NT_SUCCESS(status)) {
724 ZwMakeTemporaryObject(handle);
725 ZwClose(handle);
726 return status;
727 }
728
729 //
730 // Create a device object for this device. Each physical disk will
731 // have at least one device object. The required device object
732 // describes the entire device. Its directory path is
733 // \Device\HarddiskN\Partition0, where N = device number.
734 //
735
736 sprintf(ntNameBuffer,
737 "\\Device\\Harddisk%lu\\Partition0",
738 *DeviceCount);
739
740
741 status = ScsiClassCreateDeviceObject(DriverObject,
742 ntNameBuffer,
743 NULL,
744 &deviceObject,
745 InitData);
746
747 if (!NT_SUCCESS(status)) {
748
749 DebugPrint((1,
750 "CreateDiskDeviceObjects: Can not create device object %s\n",
751 ntNameBuffer));
752
753 goto CreateDiskDeviceObjectsExit;
754 }
755
756 //
757 // Indicate that IRPs should include MDLs for data transfers.
758 //
759
760 deviceObject->Flags |= DO_DIRECT_IO;
761
762 //
763 // Check if this is during initialization. If not indicate that
764 // system initialization already took place and this disk is ready
765 // to be accessed.
766 //
767
768 if (!RegistryPath) {
769 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
770 }
771
772 //
773 // Check for removable media support.
774 //
775
776 if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) {
777 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
778 }
779
780 //
781 // Set up required stack size in device object.
782 //
783
784 deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
785
786 deviceExtension = deviceObject->DeviceExtension;
787
788 //
789 // Allocate spinlock for split request completion.
790 //
791
792 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
793
794 //
795 // Initialize lock count to zero. The lock count is used to
796 // disable the ejection mechanism on devices that support
797 // removable media. Only the lock count in the physical
798 // device extension is used.
799 //
800
801 deviceExtension->LockCount = 0;
802
803 //
804 // Save system disk number.
805 //
806
807 deviceExtension->DeviceNumber = *DeviceCount;
808
809 //
810 // Copy port device object pointer to the device extension.
811 //
812
813 deviceExtension->PortDeviceObject = PortDeviceObject;
814
815 //
816 // Set the alignment requirements for the device based on the
817 // host adapter requirements
818 //
819
820 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
821 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
822 }
823
824 //
825 // This is the physical device object.
826 //
827
828 //physicalDevice = deviceObject;
829 //physicalDeviceExtension = deviceExtension;
830
831 //
832 // Save address of port driver capabilities.
833 //
834
835 deviceExtension->PortCapabilities = PortCapabilities;
836
837 //
838 // Build the lookaside list for srb's for the physical disk. Should only
839 // need a couple.
840 //
841
842 ScsiClassInitializeSrbLookasideList(deviceExtension,
843 PARTITION0_LIST_SIZE);
844
845 srbListInitialized = TRUE;
846
847 //
848 // Initialize the srb flags.
849 //
850
851 if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue &&
852 PortCapabilities->TaggedQueuing) {
853
854 deviceExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE;
855
856 } else {
857
858 deviceExtension->SrbFlags = 0;
859
860 }
861
862 //
863 // Allow queued requests if this is not removable media.
864 //
865
866 if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
867
868 deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
869
870 }
871
872 //
873 // Look for controller that require special flags.
874 //
875
876 ScanForSpecial(deviceObject,
877 LunInfo,
878 PortCapabilities);
879
880 //srbFlags = deviceExtension->SrbFlags;
881
882 //
883 // Allocate buffer for drive geometry.
884 //
885
886 diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX));
887
888 if (diskGeometry == NULL) {
889
890 DebugPrint((1,
891 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
892 status = STATUS_INSUFFICIENT_RESOURCES;
893 goto CreateDiskDeviceObjectsExit;
894 }
895
896 deviceExtension->DiskGeometry = diskGeometry;
897
898 //
899 // Allocate request sense buffer.
900 //
901
902 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
903
904 if (senseData == NULL) {
905
906 //
907 // The buffer can not be allocated.
908 //
909
910 DebugPrint((1,
911 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
912
913 status = STATUS_INSUFFICIENT_RESOURCES;
914 goto CreateDiskDeviceObjectsExit;
915 }
916
917 //
918 // Set the sense data pointer in the device extension.
919 //
920
921 deviceExtension->SenseData = senseData;
922
923 //
924 // Physical device object will describe the entire
925 // device, starting at byte offset 0.
926 //
927
928 deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0);
929
930 //
931 // TargetId/LUN describes a device location on the SCSI bus.
932 // This information comes from the inquiry buffer.
933 //
934
935 deviceExtension->PortNumber = (UCHAR)PortNumber;
936 deviceExtension->PathId = pathId;
937 deviceExtension->TargetId = targetId;
938 deviceExtension->Lun = lun;
939
940 //
941 // Set timeout value in seconds.
942 //
943
944 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
945 if (timeOut) {
946 deviceExtension->TimeOutValue = timeOut;
947 } else {
948 deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
949 }
950
951 //
952 // Back pointer to device object.
953 //
954
955 deviceExtension->DeviceObject = deviceObject;
956
957 //
958 // If this is a removable device, then make sure it is not a floppy.
959 // Perform a mode sense command to determine the media type. Note
960 // IsFloppyDevice also checks for write cache enabled.
961 //
962
963 if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
964 (((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) {
965
966 status = STATUS_NO_SUCH_DEVICE;
967 goto CreateDiskDeviceObjectsExit;
968 }
969
970 DisableWriteCache(deviceObject,LunInfo);
971
972 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
973
974 //
975 // NOTE: At this point one device object has been successfully created.
976 // from here on out return success.
977 //
978
979 //
980 // Do READ CAPACITY. This SCSI command
981 // returns the number of bytes on a device.
982 // Device extension is updated with device size.
983 //
984
985 status = ScsiClassReadDriveCapacity(deviceObject);
986
987 //
988 // If the read capacity failed then just return, unless this is a
989 // removable disk where a device object partition needs to be created.
990 //
991
992 if (!NT_SUCCESS(status) &&
993 !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
994
995 DebugPrint((1,
996 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
997 ntNameBuffer));
998
999 return(STATUS_SUCCESS);
1000
1001 } else {
1002
1003 //
1004 // Make sure the volume verification bit is off so that
1005 // IoReadPartitionTable will work.
1006 //
1007
1008 deviceObject->Flags &= ~DO_VERIFY_VOLUME;
1009 }
1010
1011 status = CreatePartitionDeviceObjects(deviceObject, RegistryPath);
1012
1013 if (NT_SUCCESS(status))
1014 return STATUS_SUCCESS;
1015
1016
1017 CreateDiskDeviceObjectsExit:
1018
1019 //
1020 // Release the device since an error occurred.
1021 //
1022
1023 ScsiClassClaimDevice(PortDeviceObject,
1024 LunInfo,
1025 TRUE,
1026 NULL);
1027
1028 if (diskGeometry != NULL) {
1029 ExFreePool(diskGeometry);
1030 }
1031
1032 if (senseData != NULL) {
1033 ExFreePool(senseData);
1034 }
1035
1036 if (deviceObject != NULL) {
1037
1038 if (srbListInitialized) {
1039 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
1040 }
1041
1042 IoDeleteDevice(deviceObject);
1043 }
1044
1045 //
1046 // Delete directory and return.
1047 //
1048
1049 if (!NT_SUCCESS(status)) {
1050 ZwMakeTemporaryObject(handle);
1051 }
1052
1053 ZwClose(handle);
1054
1055 return(status);
1056
1057 } // end CreateDiskDeviceObjects()
1058
1059 \f
1060 NTSTATUS
1061 NTAPI
1062 CreatePartitionDeviceObjects(
1063 IN PDEVICE_OBJECT PhysicalDeviceObject,
1064 IN PUNICODE_STRING RegistryPath
1065 )
1066 {
1067 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
1068 ULONG partitionNumber = 0;
1069 NTSTATUS status;
1070 PDEVICE_OBJECT deviceObject = NULL;
1071 PDISK_GEOMETRY_EX diskGeometry = NULL;
1072 PDRIVE_LAYOUT_INFORMATION partitionList = NULL;
1073 PDEVICE_EXTENSION deviceExtension;
1074 PDEVICE_EXTENSION physicalDeviceExtension;
1075 PCLASS_INIT_DATA initData = NULL;
1076 PDISK_DATA diskData;
1077 PDISK_DATA physicalDiskData;
1078 ULONG bytesPerSector;
1079 UCHAR sectorShift;
1080 ULONG srbFlags;
1081 ULONG dmByteSkew = 0;
1082 PULONG dmSkew;
1083 BOOLEAN dmActive = FALSE;
1084 ULONG numberListElements = 0;
1085
1086
1087 //
1088 // Get physical device geometry information for partition table reads.
1089 //
1090
1091 physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension;
1092 diskGeometry = physicalDeviceExtension->DiskGeometry;
1093 bytesPerSector = diskGeometry->Geometry.BytesPerSector;
1094
1095 //
1096 // Make sure sector size is not zero.
1097 //
1098
1099 if (bytesPerSector == 0) {
1100
1101 //
1102 // Default sector size for disk is 512.
1103 //
1104
1105 bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512;
1106 }
1107
1108 sectorShift = physicalDeviceExtension->SectorShift;
1109
1110 //
1111 // Set pointer to disk data area that follows device extension.
1112 //
1113
1114 diskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1115 diskData->PartitionListState = Initializing;
1116
1117 //
1118 // Determine is DM Driver is loaded on an IDE drive that is
1119 // under control of Atapi - this could be either a crashdump or
1120 // an Atapi device is sharing the controller with an IDE disk.
1121 //
1122
1123 HalExamineMBR(PhysicalDeviceObject,
1124 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1125 (ULONG)0x54,
1126 (PVOID)&dmSkew);
1127
1128 if (dmSkew) {
1129
1130 //
1131 // Update the device extension, so that the call to IoReadPartitionTable
1132 // will get the correct information. Any I/O to this disk will have
1133 // to be skewed by *dmSkew sectors aka DMByteSkew.
1134 //
1135
1136 physicalDeviceExtension->DMSkew = *dmSkew;
1137 physicalDeviceExtension->DMActive = TRUE;
1138 physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector;
1139
1140 //
1141 // Save away the information that we need, since this deviceExtension will soon be
1142 // blown away.
1143 //
1144
1145 dmActive = TRUE;
1146 dmByteSkew = physicalDeviceExtension->DMByteSkew;
1147
1148 }
1149
1150 //
1151 // Create objects for all the partitions on the device.
1152 //
1153
1154 status = IoReadPartitionTable(PhysicalDeviceObject,
1155 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1156 TRUE,
1157 (PVOID)&partitionList);
1158
1159 //
1160 // If the I/O read partition table failed and this is a removable device,
1161 // then fix up the partition list to make it look like there is one
1162 // zero length partition.
1163 //
1164 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status);
1165 if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
1166 PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1167
1168 if (!NT_SUCCESS(status)) {
1169
1170 //
1171 // Remember this disk is not ready.
1172 //
1173
1174 diskData->DriveNotReady = TRUE;
1175
1176 } else {
1177
1178 //
1179 // Free the partition list allocated by IoReadPartitionTable.
1180 //
1181
1182 ExFreePool(partitionList);
1183 }
1184
1185 //
1186 // Allocate and zero a partition list.
1187 //
1188
1189 partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList));
1190
1191
1192 if (partitionList != NULL) {
1193
1194 RtlZeroMemory( partitionList, sizeof( *partitionList ));
1195
1196 //
1197 // Set the partition count to one and the status to success
1198 // so one device object will be created. Set the partition type
1199 // to a bogus value.
1200 //
1201
1202 partitionList->PartitionCount = 1;
1203
1204 status = STATUS_SUCCESS;
1205 }
1206 }
1207
1208 if (NT_SUCCESS(status)) {
1209
1210 //
1211 // Record disk signature.
1212 //
1213
1214 diskData->Signature = partitionList->Signature;
1215
1216 //
1217 // If disk signature is zero, then calculate the MBR checksum.
1218 //
1219
1220 if (!diskData->Signature) {
1221
1222 if (!CalculateMbrCheckSum(physicalDeviceExtension,
1223 &diskData->MbrCheckSum)) {
1224
1225 DebugPrint((1,
1226 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1227 physicalDeviceExtension->DeviceNumber));
1228 } else {
1229
1230 DebugPrint((2,
1231 "SCSIDISK: MBR checksum for disk %x is %x\n",
1232 physicalDeviceExtension->DeviceNumber,
1233 diskData->MbrCheckSum));
1234 }
1235 }
1236
1237 //
1238 // Check the registry and determine if the BIOS knew about this drive. If
1239 // it did then update the geometry with the BIOS information.
1240 //
1241
1242 UpdateGeometry(physicalDeviceExtension);
1243
1244 srbFlags = physicalDeviceExtension->SrbFlags;
1245
1246 initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA));
1247 if (!initData)
1248 {
1249 DebugPrint((1,
1250 "Disk.CreatePartitionDeviceObjects - Allocation of initData failed\n"));
1251
1252 status = STATUS_INSUFFICIENT_RESOURCES;
1253 goto CreatePartitionDeviceObjectsExit;
1254 }
1255
1256 RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA));
1257
1258 initData->InitializationDataSize = sizeof(CLASS_INIT_DATA);
1259 initData->DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
1260 initData->DeviceType = FILE_DEVICE_DISK;
1261 initData->DeviceCharacteristics = PhysicalDeviceObject->Characteristics;
1262 initData->ClassError = physicalDeviceExtension->ClassError;
1263 initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification;
1264 initData->ClassFindDevices = physicalDeviceExtension->ClassFindDevices;
1265 initData->ClassDeviceControl = physicalDeviceExtension->ClassDeviceControl;
1266 initData->ClassShutdownFlush = physicalDeviceExtension->ClassShutdownFlush;
1267 initData->ClassCreateClose = physicalDeviceExtension->ClassCreateClose;
1268 initData->ClassStartIo = physicalDeviceExtension->ClassStartIo;
1269
1270 //
1271 // Create device objects for the device partitions (if any).
1272 // PartitionCount includes physical device partition 0,
1273 // so only one partition means no objects to create.
1274 //
1275
1276 DebugPrint((2,
1277 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1278 partitionList->PartitionCount));
1279
1280 for (partitionNumber = 0; partitionNumber <
1281 partitionList->PartitionCount; partitionNumber++) {
1282
1283 //
1284 // Create partition object and set up partition parameters.
1285 //
1286
1287 sprintf(ntNameBuffer,
1288 "\\Device\\Harddisk%lu\\Partition%lu",
1289 physicalDeviceExtension->DeviceNumber,
1290 partitionNumber + 1);
1291
1292 DebugPrint((2,
1293 "CreateDiskDeviceObjects: Create device object %s\n",
1294 ntNameBuffer));
1295
1296 status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject,
1297 ntNameBuffer,
1298 PhysicalDeviceObject,
1299 &deviceObject,
1300 initData);
1301
1302 if (!NT_SUCCESS(status)) {
1303
1304 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer));
1305
1306 break;
1307 }
1308
1309 //
1310 // Set up device object fields.
1311 //
1312
1313 deviceObject->Flags |= DO_DIRECT_IO;
1314
1315 //
1316 // Check if this is during initialization. If not indicate that
1317 // system initialization already took place and this disk is ready
1318 // to be accessed.
1319 //
1320
1321 if (!RegistryPath) {
1322 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1323 }
1324
1325 deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1;
1326
1327 //
1328 // Set up device extension fields.
1329 //
1330
1331 deviceExtension = deviceObject->DeviceExtension;
1332
1333 if (dmActive) {
1334
1335 //
1336 // Restore any saved DM values.
1337 //
1338
1339 deviceExtension->DMByteSkew = dmByteSkew;
1340 deviceExtension->DMSkew = *dmSkew;
1341 deviceExtension->DMActive = TRUE;
1342
1343 }
1344
1345 //
1346 // Link new device extension to previous disk data
1347 // to support dynamic partitioning.
1348 //
1349
1350 diskData->NextPartition = deviceExtension;
1351
1352 //
1353 // Get pointer to new disk data.
1354 //
1355
1356 diskData = (PDISK_DATA)(deviceExtension + 1);
1357
1358 //
1359 // Set next partition pointer to NULL in case this is the
1360 // last partition.
1361 //
1362
1363 diskData->NextPartition = NULL;
1364
1365 //
1366 // Allocate spinlock for zoning for split-request completion.
1367 //
1368
1369 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
1370
1371 //
1372 // Copy port device object pointer to device extension.
1373 //
1374
1375 deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject;
1376
1377 //
1378 // Set the alignment requirements for the device based on the
1379 // host adapter requirements
1380 //
1381
1382 if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
1383 deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement;
1384 }
1385
1386
1387 if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
1388 numberListElements = 30;
1389 } else {
1390 numberListElements = 8;
1391 }
1392
1393 //
1394 // Build the lookaside list for srb's for this partition based on
1395 // whether the adapter and disk can do tagged queueing.
1396 //
1397
1398 ScsiClassInitializeSrbLookasideList(deviceExtension,
1399 numberListElements);
1400
1401 deviceExtension->SrbFlags = srbFlags;
1402
1403 //
1404 // Set the sense-data pointer in the device extension.
1405 //
1406
1407 deviceExtension->SenseData = physicalDeviceExtension->SenseData;
1408 deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities;
1409 deviceExtension->DiskGeometry = diskGeometry;
1410 diskData->PartitionOrdinal = diskData->PartitionNumber = partitionNumber + 1;
1411 diskData->PartitionType = partitionList->PartitionEntry[partitionNumber].PartitionType;
1412 diskData->BootIndicator = partitionList->PartitionEntry[partitionNumber].BootIndicator;
1413
1414 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1415 diskData->PartitionType));
1416
1417 deviceExtension->StartingOffset = partitionList->PartitionEntry[partitionNumber].StartingOffset;
1418 deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength;
1419 diskData->HiddenSectors = partitionList->PartitionEntry[partitionNumber].HiddenSectors;
1420 deviceExtension->PortNumber = physicalDeviceExtension->PortNumber;
1421 deviceExtension->PathId = physicalDeviceExtension->PathId;
1422 deviceExtension->TargetId = physicalDeviceExtension->TargetId;
1423 deviceExtension->Lun = physicalDeviceExtension->Lun;
1424
1425 //
1426 // Check for removable media support.
1427 //
1428
1429 if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1430 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
1431 }
1432
1433 //
1434 // Set timeout value in seconds.
1435 //
1436
1437 deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue;
1438 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector;
1439 deviceExtension->SectorShift = sectorShift;
1440 deviceExtension->DeviceObject = deviceObject;
1441 deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags;
1442
1443 } // end for (partitionNumber) ...
1444
1445 //
1446 // Free the buffer allocated by reading the
1447 // partition table.
1448 //
1449
1450 ExFreePool(partitionList);
1451
1452 if (dmSkew) {
1453 ExFreePool(dmSkew);
1454 }
1455
1456 } else {
1457
1458 CreatePartitionDeviceObjectsExit:
1459
1460 if (partitionList) {
1461 ExFreePool(partitionList);
1462 }
1463 if (initData) {
1464 ExFreePool(initData);
1465 }
1466
1467 if (dmSkew) {
1468 ExFreePool(dmSkew);
1469 }
1470
1471 return status;
1472
1473 } // end if...else
1474
1475
1476 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1477 physicalDiskData->PartitionListState = Initialized;
1478
1479 return(STATUS_SUCCESS);
1480
1481
1482 } // end CreatePartitionDeviceObjects()
1483
1484 \f
1485 NTSTATUS
1486 NTAPI
1487 ScsiDiskReadWriteVerification(
1488 IN PDEVICE_OBJECT DeviceObject,
1489 IN PIRP Irp
1490 )
1491
1492 /*++
1493
1494 Routine Description:
1495
1496 I/O System entry for read and write requests to SCSI disks.
1497
1498 Arguments:
1499
1500 DeviceObject - Pointer to driver object created by system.
1501 Irp - IRP involved.
1502
1503 Return Value:
1504
1505 NT Status
1506
1507 --*/
1508
1509 {
1510 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1511 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1512 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1513 LARGE_INTEGER startingOffset;
1514
1515 //
1516 // HACK: How can we end here with null sector size?!
1517 //
1518
1519 if (deviceExtension->DiskGeometry->Geometry.BytesPerSector == 0) {
1520 DPRINT1("Hack! Received invalid sector size\n");
1521 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512;
1522 }
1523
1524 //
1525 // Verify parameters of this request.
1526 // Check that ending sector is within partition and
1527 // that number of bytes to transfer is a multiple of
1528 // the sector size.
1529 //
1530
1531 startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
1532 transferByteCount);
1533
1534 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
1535 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
1536
1537 //
1538 // This error maybe caused by the fact that the drive is not ready.
1539 //
1540
1541 if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) {
1542
1543 //
1544 // Flag this as a user error so that a popup is generated.
1545 //
1546
1547 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
1548 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1549
1550 } else {
1551
1552 //
1553 // Note fastfat depends on this parameter to determine when to
1554 // remount do to a sector size change.
1555 //
1556
1557 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1558 }
1559
1560 if (startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) {
1561 DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset.QuadPart, deviceExtension->PartitionLength.QuadPart);
1562 }
1563
1564 if (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1)) {
1565 DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount, deviceExtension->DiskGeometry->Geometry.BytesPerSector);
1566 }
1567
1568 if (Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) {
1569 DPRINT1("Failing due to device not ready!\n");
1570 }
1571
1572 return STATUS_INVALID_PARAMETER;
1573 }
1574
1575 return STATUS_SUCCESS;
1576
1577 } // end ScsiDiskReadWrite()
1578
1579 \f
1580 NTSTATUS
1581 NTAPI
1582 ScsiDiskDeviceControl(
1583 PDEVICE_OBJECT DeviceObject,
1584 PIRP Irp
1585 )
1586
1587 /*++
1588
1589 Routine Description:
1590
1591 I/O system entry for device controls to SCSI disks.
1592
1593 Arguments:
1594
1595 DeviceObject - Pointer to driver object created by system.
1596 Irp - IRP involved.
1597
1598 Return Value:
1599
1600 Status is returned.
1601
1602 --*/
1603
1604 {
1605 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1606 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1607 PDISK_DATA diskData = (PDISK_DATA)(deviceExtension + 1);
1608 PSCSI_REQUEST_BLOCK srb;
1609 PCDB cdb;
1610 PMODE_PARAMETER_HEADER modeData;
1611 PIRP irp2;
1612 ULONG length;
1613 NTSTATUS status;
1614 KEVENT event;
1615 IO_STATUS_BLOCK ioStatus;
1616
1617 PAGED_CODE();
1618
1619 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
1620
1621 if (srb == NULL) {
1622
1623 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1624 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1625 return(STATUS_INSUFFICIENT_RESOURCES);
1626 }
1627
1628 //
1629 // Write zeros to Srb.
1630 //
1631
1632 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1633
1634 cdb = (PCDB)srb->Cdb;
1635
1636 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1637
1638 case SMART_GET_VERSION: {
1639
1640 ULONG_PTR buffer;
1641 PSRB_IO_CONTROL srbControl;
1642 PGETVERSIONINPARAMS versionParams;
1643
1644 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1645 sizeof(GETVERSIONINPARAMS)) {
1646 status = STATUS_INVALID_PARAMETER;
1647 break;
1648 }
1649
1650 //
1651 // Create notification event object to be used to signal the
1652 // request completion.
1653 //
1654
1655 KeInitializeEvent(&event, NotificationEvent, FALSE);
1656
1657 srbControl = ExAllocatePool(NonPagedPool,
1658 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
1659
1660 if (!srbControl) {
1661 status = STATUS_INSUFFICIENT_RESOURCES;
1662 break;
1663 }
1664
1665 //
1666 // fill in srbControl fields
1667 //
1668
1669 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1670 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1671 srbControl->Timeout = deviceExtension->TimeOutValue;
1672 srbControl->Length = sizeof(GETVERSIONINPARAMS);
1673 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
1674
1675 //
1676 // Point to the 'buffer' portion of the SRB_CONTROL
1677 //
1678
1679 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1680
1681 //
1682 // Ensure correct target is set in the cmd parameters.
1683 //
1684
1685 versionParams = (PGETVERSIONINPARAMS)buffer;
1686 versionParams->bIDEDeviceMap = deviceExtension->TargetId;
1687
1688 //
1689 // Copy the IOCTL parameters to the srb control buffer area.
1690 //
1691
1692 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS));
1693
1694
1695 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1696 deviceExtension->PortDeviceObject,
1697 srbControl,
1698 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1699 srbControl,
1700 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1701 FALSE,
1702 &event,
1703 &ioStatus);
1704
1705 if (irp2 == NULL) {
1706 status = STATUS_INSUFFICIENT_RESOURCES;
1707 break;
1708 }
1709
1710 //
1711 // Call the port driver with the request and wait for it to complete.
1712 //
1713
1714 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1715
1716 if (status == STATUS_PENDING) {
1717 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1718 status = ioStatus.Status;
1719 }
1720
1721 //
1722 // If successful, copy the data received into the output buffer.
1723 // This should only fail in the event that the IDE driver is older than this driver.
1724 //
1725
1726 if (NT_SUCCESS(status)) {
1727
1728 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1729
1730 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS));
1731 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1732 }
1733
1734 ExFreePool(srbControl);
1735 break;
1736 }
1737
1738 case SMART_RCV_DRIVE_DATA: {
1739
1740 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1741 ULONG controlCode = 0;
1742 PSRB_IO_CONTROL srbControl;
1743 ULONG_PTR buffer;
1744
1745 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1746 (sizeof(SENDCMDINPARAMS) - 1)) {
1747 status = STATUS_INVALID_PARAMETER;
1748 break;
1749
1750 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1751 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
1752 status = STATUS_INVALID_PARAMETER;
1753 break;
1754 }
1755
1756 //
1757 // Create notification event object to be used to signal the
1758 // request completion.
1759 //
1760
1761 KeInitializeEvent(&event, NotificationEvent, FALSE);
1762
1763 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
1764
1765 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1766 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
1767
1768 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1769 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1770 case READ_ATTRIBUTES:
1771 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
1772 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1773 break;
1774 case READ_THRESHOLDS:
1775 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
1776 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1777 break;
1778 default:
1779 status = STATUS_INVALID_PARAMETER;
1780 break;
1781 }
1782 } else {
1783
1784 status = STATUS_INVALID_PARAMETER;
1785 }
1786
1787 if (controlCode == 0) {
1788 status = STATUS_INVALID_PARAMETER;
1789 break;
1790 }
1791
1792 srbControl = ExAllocatePool(NonPagedPool,
1793 sizeof(SRB_IO_CONTROL) + length);
1794
1795 if (!srbControl) {
1796 status = STATUS_INSUFFICIENT_RESOURCES;
1797 break;
1798 }
1799
1800 //
1801 // fill in srbControl fields
1802 //
1803
1804 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1805 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1806 srbControl->Timeout = deviceExtension->TimeOutValue;
1807 srbControl->Length = length;
1808 srbControl->ControlCode = controlCode;
1809
1810 //
1811 // Point to the 'buffer' portion of the SRB_CONTROL
1812 //
1813
1814 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1815
1816 //
1817 // Ensure correct target is set in the cmd parameters.
1818 //
1819
1820 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1821
1822 //
1823 // Copy the IOCTL parameters to the srb control buffer area.
1824 //
1825
1826 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1827
1828 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1829 deviceExtension->PortDeviceObject,
1830 srbControl,
1831 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1832 srbControl,
1833 sizeof(SRB_IO_CONTROL) + length,
1834 FALSE,
1835 &event,
1836 &ioStatus);
1837
1838 if (irp2 == NULL) {
1839 status = STATUS_INSUFFICIENT_RESOURCES;
1840 break;
1841 }
1842
1843 //
1844 // Call the port driver with the request and wait for it to complete.
1845 //
1846
1847 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1848
1849 if (status == STATUS_PENDING) {
1850 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1851 status = ioStatus.Status;
1852 }
1853
1854 //
1855 // If successful, copy the data received into the output buffer
1856 //
1857
1858 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1859
1860 if (NT_SUCCESS(status)) {
1861
1862 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1);
1863 Irp->IoStatus.Information = length - 1;
1864
1865 } else {
1866
1867 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
1868 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
1869
1870 }
1871
1872 ExFreePool(srbControl);
1873 break;
1874
1875 }
1876
1877 case SMART_SEND_DRIVE_COMMAND: {
1878
1879 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1880 PSRB_IO_CONTROL srbControl;
1881 ULONG controlCode = 0;
1882 ULONG_PTR buffer;
1883
1884 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1885 (sizeof(SENDCMDINPARAMS) - 1)) {
1886 status = STATUS_INVALID_PARAMETER;
1887 break;
1888
1889 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1890 (sizeof(SENDCMDOUTPARAMS) - 1)) {
1891 status = STATUS_INVALID_PARAMETER;
1892 break;
1893 }
1894
1895 //
1896 // Create notification event object to be used to signal the
1897 // request completion.
1898 //
1899
1900 KeInitializeEvent(&event, NotificationEvent, FALSE);
1901
1902 length = 0;
1903
1904 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1905 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1906
1907 case ENABLE_SMART:
1908 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
1909 break;
1910
1911 case DISABLE_SMART:
1912 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
1913 break;
1914
1915 case RETURN_SMART_STATUS:
1916
1917 //
1918 // Ensure bBuffer is at least 2 bytes (to hold the values of
1919 // cylinderLow and cylinderHigh).
1920 //
1921
1922 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1923 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
1924
1925 status = STATUS_INVALID_PARAMETER;
1926 break;
1927 }
1928
1929 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
1930 length = sizeof(IDEREGS);
1931 break;
1932
1933 case ENABLE_DISABLE_AUTOSAVE:
1934 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
1935 break;
1936
1937 case SAVE_ATTRIBUTE_VALUES:
1938 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
1939 break;
1940
1941 case EXECUTE_OFFLINE_DIAGS:
1942 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
1943 break;
1944
1945 default:
1946 status = STATUS_INVALID_PARAMETER;
1947 break;
1948 }
1949 } else {
1950
1951 status = STATUS_INVALID_PARAMETER;
1952 }
1953
1954 if (controlCode == 0) {
1955 status = STATUS_INVALID_PARAMETER;
1956 break;
1957 }
1958
1959 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);
1960 srbControl = ExAllocatePool(NonPagedPool,
1961 sizeof(SRB_IO_CONTROL) + length);
1962
1963 if (!srbControl) {
1964 status = STATUS_INSUFFICIENT_RESOURCES;
1965 break;
1966 }
1967
1968 //
1969 // fill in srbControl fields
1970 //
1971
1972 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1973 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1974 srbControl->Timeout = deviceExtension->TimeOutValue;
1975 srbControl->Length = length;
1976
1977 //
1978 // Point to the 'buffer' portion of the SRB_CONTROL
1979 //
1980
1981 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1982
1983 //
1984 // Ensure correct target is set in the cmd parameters.
1985 //
1986
1987 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1988
1989 //
1990 // Copy the IOCTL parameters to the srb control buffer area.
1991 //
1992
1993 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1994
1995 srbControl->ControlCode = controlCode;
1996
1997 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1998 deviceExtension->PortDeviceObject,
1999 srbControl,
2000 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
2001 srbControl,
2002 sizeof(SRB_IO_CONTROL) + length,
2003 FALSE,
2004 &event,
2005 &ioStatus);
2006
2007 if (irp2 == NULL) {
2008 status = STATUS_INSUFFICIENT_RESOURCES;
2009 break;
2010 }
2011
2012 //
2013 // Call the port driver with the request and wait for it to complete.
2014 //
2015
2016 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2017
2018 if (status == STATUS_PENDING) {
2019 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
2020 status = ioStatus.Status;
2021 }
2022
2023 //
2024 // Copy the data received into the output buffer. Since the status buffer
2025 // contains error information also, always perform this copy. IO will will
2026 // either pass this back to the app, or zero it, in case of error.
2027 //
2028
2029 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
2030
2031 //
2032 // Update the return buffer size based on the sub-command.
2033 //
2034
2035 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
2036 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
2037 } else {
2038 length = sizeof(SENDCMDOUTPARAMS) - 1;
2039 }
2040
2041 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length);
2042 Irp->IoStatus.Information = length;
2043
2044 ExFreePool(srbControl);
2045 break;
2046
2047 }
2048
2049 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
2050 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
2051 {
2052
2053 PDEVICE_EXTENSION physicalDeviceExtension;
2054 PDISK_DATA physicalDiskData;
2055 BOOLEAN removable = FALSE;
2056 BOOLEAN listInitialized = FALSE;
2057
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 alright, 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 // Partition 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 // Partition 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 intermediary 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: Synchronize 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 media 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;
3474
3475 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
3476
3477 //
3478 // Check if write cache is disabled.
3479 //
3480
3481 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3482
3483 PIO_ERROR_LOG_PACKET errorLogEntry;
3484 LONG errorCode;
3485
3486
3487 //
3488 // Disable write cache and ensure necessary fields are zeroed.
3489 //
3490
3491 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
3492 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
3493 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
3494 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
3495
3496 //
3497 // Extract length from caching page.
3498 //
3499
3500 length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
3501
3502 //
3503 // Compensate for page code and page length.
3504 //
3505
3506 length += 2;
3507
3508 //
3509 // Issue mode select to set the parameter.
3510 //
3511
3512 if (ScsiDiskModeSelect(DeviceObject,
3513 (PCHAR)pageData,
3514 length,
3515 savePage)) {
3516
3517 DebugPrint((1,
3518 "SCSIDISK: Disk write cache disabled\n"));
3519
3520 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3521 errorCode = IO_WRITE_CACHE_DISABLED;
3522
3523 } else {
3524 if (ScsiDiskModeSelect(DeviceObject,
3525 (PCHAR)pageData,
3526 length,
3527 savePage)) {
3528
3529 DebugPrint((1,
3530 "SCSIDISK: Disk write cache disabled\n"));
3531
3532
3533 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3534 errorCode = IO_WRITE_CACHE_DISABLED;
3535
3536 } else {
3537
3538 DebugPrint((1,
3539 "SCSIDISK: Mode select to disable write cache failed\n"));
3540
3541 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3542 errorCode = IO_WRITE_CACHE_ENABLED;
3543 }
3544 }
3545
3546 //
3547 // Log the appropriate informational or error entry.
3548 //
3549
3550 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3551 DeviceObject,
3552 sizeof(IO_ERROR_LOG_PACKET) + 3
3553 * sizeof(ULONG));
3554
3555 if (errorLogEntry != NULL) {
3556
3557 errorLogEntry->FinalStatus = STATUS_SUCCESS;
3558 errorLogEntry->ErrorCode = errorCode;
3559 errorLogEntry->SequenceNumber = 0;
3560 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
3561 errorLogEntry->IoControlCode = 0;
3562 errorLogEntry->RetryCount = 0;
3563 errorLogEntry->UniqueErrorValue = 0x1;
3564 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG);
3565 errorLogEntry->DumpData[0] = LunInfo->PathId;
3566 errorLogEntry->DumpData[1] = LunInfo->TargetId;
3567 errorLogEntry->DumpData[2] = LunInfo->Lun;
3568
3569 //
3570 // Write the error log packet.
3571 //
3572
3573 IoWriteErrorLogEntry(errorLogEntry);
3574 }
3575 }
3576 }
3577
3578 //
3579 // Found device so exit the loop and return.
3580 //
3581
3582 break;
3583 }
3584
3585 return;
3586 }
3587
3588 \f
3589 BOOLEAN
3590 NTAPI
3591 CalculateMbrCheckSum(
3592 IN PDEVICE_EXTENSION DeviceExtension,
3593 OUT PULONG Checksum
3594 )
3595
3596 /*++
3597
3598 Routine Description:
3599
3600 Read MBR and calculate checksum.
3601
3602 Arguments:
3603
3604 DeviceExtension - Supplies a pointer to the device information for disk.
3605 Checksum - Memory location to return MBR checksum.
3606
3607 Return Value:
3608
3609 Returns TRUE if checksum is valid.
3610
3611 --*/
3612 {
3613 LARGE_INTEGER sectorZero;
3614 PIRP irp;
3615 IO_STATUS_BLOCK ioStatus;
3616 KEVENT event;
3617 NTSTATUS status;
3618 ULONG sectorSize;
3619 PULONG mbr;
3620 ULONG i;
3621
3622 PAGED_CODE();
3623 sectorZero.QuadPart = (LONGLONG) 0;
3624
3625 //
3626 // Create notification event object to be used to signal the inquiry
3627 // request completion.
3628 //
3629
3630 KeInitializeEvent(&event, NotificationEvent, FALSE);
3631
3632 //
3633 // Get sector size.
3634 //
3635
3636 sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
3637
3638 //
3639 // Make sure sector size is at least 512 bytes.
3640 //
3641
3642 if (sectorSize < 512) {
3643 sectorSize = 512;
3644 }
3645
3646 //
3647 // Allocate buffer for sector read.
3648 //
3649
3650 mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize);
3651
3652 if (!mbr) {
3653 return FALSE;
3654 }
3655
3656 //
3657 // Build IRP to read MBR.
3658 //
3659
3660 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
3661 DeviceExtension->DeviceObject,
3662 mbr,
3663 sectorSize,
3664 &sectorZero,
3665 &event,
3666 &ioStatus );
3667
3668 if (!irp) {
3669 ExFreePool(mbr);
3670 return FALSE;
3671 }
3672
3673 //
3674 // Pass request to port driver and wait for request to complete.
3675 //
3676
3677 status = IoCallDriver(DeviceExtension->DeviceObject,
3678 irp);
3679
3680 if (status == STATUS_PENDING) {
3681 KeWaitForSingleObject(&event,
3682 Suspended,
3683 KernelMode,
3684 FALSE,
3685 NULL);
3686 status = ioStatus.Status;
3687 }
3688
3689 if (!NT_SUCCESS(status)) {
3690 ExFreePool(mbr);
3691 return FALSE;
3692 }
3693
3694 //
3695 // Calculate MBR checksum.
3696 //
3697
3698 *Checksum = 0;
3699
3700 for (i = 0; i < 128; i++) {
3701 *Checksum += mbr[i];
3702 }
3703
3704 *Checksum = ~*Checksum + 1;
3705
3706 ExFreePool(mbr);
3707 return TRUE;
3708 }
3709
3710 \f
3711 BOOLEAN
3712 NTAPI
3713 EnumerateBusKey(
3714 IN PDEVICE_EXTENSION DeviceExtension,
3715 HANDLE BusKey,
3716 PULONG DiskNumber
3717 )
3718
3719 /*++
3720
3721 Routine Description:
3722
3723 The routine queries the registry to determine if this disk is visible to
3724 the BIOS. If the disk is visible to the BIOS, then the geometry information
3725 is updated.
3726
3727 Arguments:
3728
3729 DeviceExtension - Supplies a pointer to the device information for disk.
3730 Signature - Unique identifier recorded in MBR.
3731 BusKey - Handle of bus key.
3732 DiskNumber - Returns ordinal of disk as BIOS sees it.
3733
3734 Return Value:
3735
3736 TRUE is disk signature matched.
3737
3738 --*/
3739 {
3740 PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1);
3741 BOOLEAN diskFound = FALSE;
3742 OBJECT_ATTRIBUTES objectAttributes;
3743 UNICODE_STRING unicodeString;
3744 UNICODE_STRING identifier;
3745 ULONG busNumber;
3746 ULONG adapterNumber;
3747 ULONG diskNumber;
3748 HANDLE adapterKey;
3749 HANDLE spareKey;
3750 HANDLE diskKey;
3751 HANDLE targetKey;
3752 NTSTATUS status;
3753 STRING string;
3754 STRING anotherString;
3755 ULONG length;
3756 UCHAR buffer[20];
3757 PKEY_VALUE_FULL_INFORMATION keyData;
3758
3759 PAGED_CODE();
3760
3761 for (busNumber = 0; ; busNumber++) {
3762
3763 //
3764 // Open controller name key.
3765 //
3766
3767 sprintf((PCHAR)buffer,
3768 "%lu",
3769 busNumber);
3770
3771 RtlInitString(&string,
3772 (PCSZ)buffer);
3773
3774 status = RtlAnsiStringToUnicodeString(&unicodeString,
3775 &string,
3776 TRUE);
3777
3778 if (!NT_SUCCESS(status)){
3779 break;
3780 }
3781
3782 InitializeObjectAttributes(&objectAttributes,
3783 &unicodeString,
3784 OBJ_CASE_INSENSITIVE,
3785 BusKey,
3786 (PSECURITY_DESCRIPTOR)NULL);
3787
3788 status = ZwOpenKey(&spareKey,
3789 KEY_READ,
3790 &objectAttributes);
3791
3792 RtlFreeUnicodeString(&unicodeString);
3793
3794 if (!NT_SUCCESS(status)) {
3795 break;
3796 }
3797
3798 //
3799 // Open up controller ordinal key.
3800 //
3801
3802 RtlInitUnicodeString(&unicodeString, L"DiskController");
3803 InitializeObjectAttributes(&objectAttributes,
3804 &unicodeString,
3805 OBJ_CASE_INSENSITIVE,
3806 spareKey,
3807 (PSECURITY_DESCRIPTOR)NULL);
3808
3809 status = ZwOpenKey(&adapterKey,
3810 KEY_READ,
3811 &objectAttributes);
3812
3813 //
3814 // This could fail even with additional adapters of this type
3815 // to search.
3816 //
3817
3818 if (!NT_SUCCESS(status)) {
3819 continue;
3820 }
3821
3822 for (adapterNumber = 0; ; adapterNumber++) {
3823
3824 //
3825 // Open disk key.
3826 //
3827
3828 sprintf((PCHAR)buffer,
3829 "%lu\\DiskPeripheral",
3830 adapterNumber);
3831
3832 RtlInitString(&string,
3833 (PCSZ)buffer);
3834
3835 status = RtlAnsiStringToUnicodeString(&unicodeString,
3836 &string,
3837 TRUE);
3838
3839 if (!NT_SUCCESS(status)){
3840 break;
3841 }
3842
3843 InitializeObjectAttributes(&objectAttributes,
3844 &unicodeString,
3845 OBJ_CASE_INSENSITIVE,
3846 adapterKey,
3847 (PSECURITY_DESCRIPTOR)NULL);
3848
3849 status = ZwOpenKey(&diskKey,
3850 KEY_READ,
3851 &objectAttributes);
3852
3853 RtlFreeUnicodeString(&unicodeString);
3854
3855 if (!NT_SUCCESS(status)) {
3856 break;
3857 }
3858
3859 for (diskNumber = 0; ; diskNumber++) {
3860
3861 sprintf((PCHAR)buffer,
3862 "%lu",
3863 diskNumber);
3864
3865 RtlInitString(&string,
3866 (PCSZ)buffer);
3867
3868 status = RtlAnsiStringToUnicodeString(&unicodeString,
3869 &string,
3870 TRUE);
3871
3872 if (!NT_SUCCESS(status)){
3873 break;
3874 }
3875
3876 InitializeObjectAttributes(&objectAttributes,
3877 &unicodeString,
3878 OBJ_CASE_INSENSITIVE,
3879 diskKey,
3880 (PSECURITY_DESCRIPTOR)NULL);
3881
3882 status = ZwOpenKey(&targetKey,
3883 KEY_READ,
3884 &objectAttributes);
3885
3886 RtlFreeUnicodeString(&unicodeString);
3887
3888 if (!NT_SUCCESS(status)) {
3889 break;
3890 }
3891
3892 //
3893 // Allocate buffer for registry query.
3894 //
3895
3896 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
3897
3898 if (keyData == NULL) {
3899 ZwClose(targetKey);
3900 continue;
3901 }
3902
3903 //
3904 // Get disk peripheral identifier.
3905 //
3906
3907 RtlInitUnicodeString(&unicodeString, L"Identifier");
3908 status = ZwQueryValueKey(targetKey,
3909 &unicodeString,
3910 KeyValueFullInformation,
3911 keyData,
3912 VALUE_BUFFER_SIZE,
3913 &length);
3914
3915 ZwClose(targetKey);
3916
3917 if (!NT_SUCCESS(status)) {
3918 continue;
3919 }
3920
3921 //
3922 // Complete unicode string.
3923 //
3924
3925 identifier.Buffer =
3926 (PWSTR)((PUCHAR)keyData + keyData->DataOffset);
3927 identifier.Length = (USHORT)keyData->DataLength;
3928 identifier.MaximumLength = (USHORT)keyData->DataLength;
3929
3930 //
3931 // Convert unicode identifier to ansi string.
3932 //
3933
3934 status =
3935 RtlUnicodeStringToAnsiString(&anotherString,
3936 &identifier,
3937 TRUE);
3938
3939 if (!NT_SUCCESS(status)) {
3940 continue;
3941 }
3942
3943 //
3944 // If checksum is zero, then the MBR is valid and
3945 // the signature is meaningful.
3946 //
3947
3948 if (diskData->MbrCheckSum) {
3949
3950 //
3951 // Convert checksum to ansi string.
3952 //
3953
3954 sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum);
3955
3956 } else {
3957
3958 //
3959 // Convert signature to ansi string.
3960 //
3961
3962 sprintf((PCHAR)buffer, "%08lx", diskData->Signature);
3963
3964 //
3965 // Make string point at signature. Can't use scan
3966 // functions because they are not exported for driver use.
3967 //
3968
3969 anotherString.Buffer+=9;
3970 }
3971
3972 //
3973 // Convert to ansi string.
3974 //
3975
3976 RtlInitString(&string,
3977 (PCSZ)buffer);
3978
3979
3980 //
3981 // Make string lengths equal.
3982 //
3983
3984 anotherString.Length = string.Length;
3985
3986 //
3987 // Check if strings match.
3988 //
3989
3990 if (RtlCompareString(&string,
3991 &anotherString,
3992 TRUE) == 0) {
3993
3994 diskFound = TRUE;
3995 *DiskNumber = diskNumber;
3996 }
3997
3998 ExFreePool(keyData);
3999
4000 //
4001 // Readjust identifier string if necessary.
4002 //
4003
4004 if (!diskData->MbrCheckSum) {
4005 anotherString.Buffer-=9;
4006 }
4007
4008 RtlFreeAnsiString(&anotherString);
4009
4010 if (diskFound) {
4011 break;
4012 }
4013 }
4014
4015 ZwClose(diskKey);
4016 }
4017
4018 ZwClose(adapterKey);
4019 }
4020
4021 ZwClose(BusKey);
4022 return diskFound;
4023
4024 } // end EnumerateBusKey()
4025
4026 \f
4027 VOID
4028 NTAPI
4029 UpdateGeometry(
4030 IN PDEVICE_EXTENSION DeviceExtension
4031 )
4032 /*++
4033
4034 Routine Description:
4035
4036 The routine queries the registry to determine if this disk is visible to
4037 the BIOS. If the disk is visible to the BIOS, then the geometry information
4038 is updated.
4039
4040 Arguments:
4041
4042 DeviceExtension - Supplies a pointer to the device information for disk.
4043
4044 Return Value:
4045
4046 None.
4047
4048 --*/
4049
4050 {
4051 OBJECT_ATTRIBUTES objectAttributes;
4052 UNICODE_STRING unicodeString;
4053 NTSTATUS status;
4054 HANDLE hardwareKey;
4055 HANDLE busKey;
4056 PCM_INT13_DRIVE_PARAMETER driveParameters;
4057 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
4058 PKEY_VALUE_FULL_INFORMATION keyData;
4059 ULONG diskNumber;
4060 PUCHAR buffer;
4061 ULONG length;
4062 ULONG numberOfDrives;
4063 ULONG cylinders;
4064 ULONG sectors;
4065 ULONG sectorsPerTrack;
4066 ULONG tracksPerCylinder;
4067 BOOLEAN foundEZHooker;
4068 PVOID tmpPtr;
4069
4070 PAGED_CODE();
4071
4072 //
4073 // Initialize the object for the key.
4074 //
4075
4076 InitializeObjectAttributes(&objectAttributes,
4077 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
4078 OBJ_CASE_INSENSITIVE,
4079 NULL,
4080 (PSECURITY_DESCRIPTOR) NULL);
4081
4082 //
4083 // Create the hardware base key.
4084 //
4085
4086 status = ZwOpenKey(&hardwareKey,
4087 KEY_READ,
4088 &objectAttributes);
4089
4090
4091 if (!NT_SUCCESS(status)) {
4092 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase));
4093 return;
4094 }
4095
4096
4097 //
4098 // Get disk BIOS geometry information.
4099 //
4100
4101 RtlInitUnicodeString(&unicodeString, L"Configuration Data");
4102
4103 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
4104
4105 if (keyData == NULL) {
4106 ZwClose(hardwareKey);
4107 return;
4108 }
4109
4110 status = ZwQueryValueKey(hardwareKey,
4111 &unicodeString,
4112 KeyValueFullInformation,
4113 keyData,
4114 VALUE_BUFFER_SIZE,
4115 &length);
4116
4117 if (!NT_SUCCESS(status)) {
4118 DebugPrint((1,
4119 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4120 status));
4121 ExFreePool(keyData);
4122 return;
4123 }
4124
4125 //
4126 // Open EISA bus key.
4127 //
4128
4129 RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
4130
4131 InitializeObjectAttributes(&objectAttributes,
4132 &unicodeString,
4133 OBJ_CASE_INSENSITIVE,
4134 hardwareKey,
4135 (PSECURITY_DESCRIPTOR)NULL);
4136
4137 status = ZwOpenKey(&busKey,
4138 KEY_READ,
4139 &objectAttributes);
4140
4141 if (!NT_SUCCESS(status)) {
4142 goto openMultiKey;
4143 }
4144
4145 DebugPrint((3,
4146 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4147 if (EnumerateBusKey(DeviceExtension,
4148 busKey,
4149 &diskNumber)) {
4150
4151 ZwClose(hardwareKey);
4152 goto diskMatched;
4153 }
4154
4155 openMultiKey:
4156
4157 //
4158 // Open Multifunction bus key.
4159 //
4160
4161 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
4162
4163 InitializeObjectAttributes(&objectAttributes,
4164 &unicodeString,
4165 OBJ_CASE_INSENSITIVE,
4166 hardwareKey,
4167 (PSECURITY_DESCRIPTOR)NULL);
4168
4169 status = ZwOpenKey(&busKey,
4170 KEY_READ,
4171 &objectAttributes);
4172
4173 ZwClose(hardwareKey);
4174 if (NT_SUCCESS(status)) {
4175 DebugPrint((3,
4176 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4177 if (EnumerateBusKey(DeviceExtension,
4178 busKey,
4179 &diskNumber)) {
4180
4181 goto diskMatched;
4182 }
4183 }
4184
4185 ExFreePool(keyData);
4186 return;
4187
4188 diskMatched:
4189
4190 resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData +
4191 keyData->DataOffset);
4192
4193 //
4194 // Check that the data is long enough to hold a full resource descriptor,
4195 // and that the last resource list is device-specific and long enough.
4196 //
4197
4198 if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) ||
4199 resourceDescriptor->PartialResourceList.Count == 0 ||
4200 resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type !=
4201 CmResourceTypeDeviceSpecific ||
4202 resourceDescriptor->PartialResourceList.PartialDescriptors[0]
4203 .u.DeviceSpecificData.DataSize < sizeof(ULONG)) {
4204
4205 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4206 ExFreePool(keyData);
4207 return;
4208 }
4209
4210 length =
4211 resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize;
4212
4213 //
4214 // Point to the BIOS data. The BIOS data is located after the first
4215 // partial Resource list which should be device specific data.
4216 //
4217
4218 buffer = (PUCHAR) keyData + keyData->DataOffset +
4219 sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
4220
4221
4222 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
4223
4224 //
4225 // Use the defaults if the drive number is greater than the
4226 // number of drives detected by the BIOS.
4227 //
4228
4229 if (numberOfDrives <= diskNumber) {
4230 ExFreePool(keyData);
4231 return;
4232 }
4233
4234 //
4235 // Point to the array of drive parameters.
4236 //
4237
4238 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber;
4239 cylinders = driveParameters->MaxCylinders + 1;
4240 sectorsPerTrack = driveParameters->SectorsPerTrack;
4241 tracksPerCylinder = driveParameters->MaxHeads +1;
4242
4243 //
4244 // Calculate the actual number of sectors.
4245 //
4246
4247 sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >>
4248 DeviceExtension->SectorShift);
4249
4250 #if DBG
4251 if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) {
4252 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4253 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4254 sectors, cylinders, tracksPerCylinder, sectorsPerTrack));
4255 }
4256 #endif
4257
4258 //
4259 // Since the BIOS may not report the full drive, recalculate the drive
4260 // size based on the volume size and the BIOS values for tracks per
4261 // cylinder and sectors per track..
4262 //
4263
4264 length = tracksPerCylinder * sectorsPerTrack;
4265
4266 if (length == 0) {
4267
4268 //
4269 // The BIOS information is bogus.
4270 //
4271
4272 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4273 ExFreePool(keyData);
4274 return;
4275 }
4276
4277 cylinders = sectors / length;
4278
4279 //
4280 // Update the actual geometry information.
4281 //
4282
4283 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack;
4284 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder;
4285 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders;
4286 DeviceExtension->DiskGeometry->DiskSize.QuadPart = (LONGLONG)cylinders * tracksPerCylinder * sectorsPerTrack *
4287 DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4288
4289 DebugPrint((3,
4290 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4291 sectorsPerTrack,
4292 tracksPerCylinder,
4293 cylinders));
4294
4295 ExFreePool(keyData);
4296
4297 foundEZHooker = FALSE;
4298
4299 if (!DeviceExtension->DMActive) {
4300
4301 HalExamineMBR(DeviceExtension->DeviceObject,
4302 DeviceExtension->DiskGeometry->Geometry.BytesPerSector,
4303 (ULONG)0x55,
4304 &tmpPtr
4305 );
4306
4307 if (tmpPtr) {
4308
4309 ExFreePool(tmpPtr);
4310 foundEZHooker = TRUE;
4311
4312 }
4313
4314 }
4315
4316 if (DeviceExtension->DMActive || foundEZHooker) {
4317
4318 while (cylinders > 1024) {
4319
4320 tracksPerCylinder = tracksPerCylinder*2;
4321 cylinders = cylinders/2;
4322
4323 }
4324
4325 //
4326 // int 13 values are always 1 less.
4327 //
4328
4329 tracksPerCylinder -= 1;
4330 cylinders -= 1;
4331
4332 //
4333 // DM reserves the CE cylinder
4334 //
4335
4336 cylinders -= 1;
4337
4338 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1;
4339 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1;
4340
4341 DeviceExtension->PartitionLength.QuadPart =
4342 DeviceExtension->DiskGeometry->DiskSize.QuadPart =
4343 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart *
4344 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack *
4345 DeviceExtension->DiskGeometry->Geometry.BytesPerSector *
4346 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder;
4347
4348 if (DeviceExtension->DMActive) {
4349
4350 DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4351
4352 }
4353
4354 } else {
4355
4356 DeviceExtension->DMByteSkew = 0;
4357
4358 }
4359
4360 return;
4361
4362 } // end UpdateGeometry()
4363
4364
4365 \f
4366 NTSTATUS
4367 NTAPI
4368 UpdateRemovableGeometry (
4369 IN PDEVICE_OBJECT DeviceObject,
4370 IN PIRP Irp
4371 )
4372
4373 /*++
4374
4375 Routine Description:
4376
4377 This routines updates the size and starting offset of the device. This is
4378 used when the media on the device may have changed thereby changing the
4379 size of the device. If this is the physical device then a
4380 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4381
4382 Arguments:
4383
4384 DeviceObject - Supplies the device object whos size needs to be updated.
4385
4386 Irp - Supplies a reference where the status can be updated.
4387
4388 Return Value:
4389
4390 Returns the status of the operation.
4391
4392 --*/
4393 {
4394
4395 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4396 PDRIVE_LAYOUT_INFORMATION partitionList;
4397 NTSTATUS status;
4398 PDISK_DATA diskData;
4399 ULONG partitionNumber;
4400
4401 //
4402 // Determine if the size of the partition may have changed because
4403 // the media has changed.
4404 //
4405
4406 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
4407
4408 return(STATUS_SUCCESS);
4409
4410 }
4411
4412 //
4413 // If this request is for partition zero then do a read drive
4414 // capacity otherwise do a I/O read partition table.
4415 //
4416
4417 diskData = (PDISK_DATA) (deviceExtension + 1);
4418
4419 //
4420 // Read the drive capacity. If that fails, give up.
4421 //
4422
4423 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
4424
4425 if (!NT_SUCCESS(status)) {
4426 return(status);
4427 }
4428
4429 //
4430 // Read the partition table again.
4431 //
4432
4433 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
4434 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
4435 TRUE,
4436 &partitionList);
4437
4438
4439 if (!NT_SUCCESS(status)) {
4440
4441 //
4442 // Fail the request.
4443 //
4444
4445 return(status);
4446 }
4447
4448 if (diskData->PartitionNumber != 0 &&
4449 diskData->PartitionNumber <= partitionList->PartitionCount ) {
4450
4451 partitionNumber = diskData->PartitionNumber - 1;
4452
4453 //
4454 // Update the partition information for this partition.
4455 //
4456
4457 diskData->PartitionType =
4458 partitionList->PartitionEntry[partitionNumber].PartitionType;
4459
4460 diskData->BootIndicator =
4461 partitionList->PartitionEntry[partitionNumber].BootIndicator;
4462
4463 deviceExtension->StartingOffset =
4464 partitionList->PartitionEntry[partitionNumber].StartingOffset;
4465
4466 deviceExtension->PartitionLength =
4467 partitionList->PartitionEntry[partitionNumber].PartitionLength;
4468
4469 diskData->HiddenSectors =
4470 partitionList->PartitionEntry[partitionNumber].HiddenSectors;
4471
4472 deviceExtension->SectorShift = ((PDEVICE_EXTENSION)
4473 deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift;
4474
4475 } else if (diskData->PartitionNumber != 0) {
4476
4477 //
4478 // The partition does not exist. Zero all the data.
4479 //
4480
4481 diskData->PartitionType = 0;
4482 diskData->BootIndicator = 0;
4483 diskData->HiddenSectors = 0;
4484 deviceExtension->StartingOffset.QuadPart = (LONGLONG)0;
4485 deviceExtension->PartitionLength.QuadPart = (LONGLONG)0;
4486 }
4487
4488 //
4489 // Free the partition list allocate by I/O read partition table.
4490 //
4491
4492 ExFreePool(partitionList);
4493
4494
4495 return(STATUS_SUCCESS);
4496 }
4497
4498 \f
4499 VOID
4500 NTAPI
4501 ScsiDiskProcessError(
4502 PDEVICE_OBJECT DeviceObject,
4503 PSCSI_REQUEST_BLOCK Srb,
4504 NTSTATUS *Status,
4505 BOOLEAN *Retry
4506 )
4507 /*++
4508
4509 Routine Description:
4510
4511 This routine checks the type of error. If the error indicates an underrun
4512 then indicate the request should be retried.
4513
4514 Arguments:
4515
4516 DeviceObject - Supplies a pointer to the device object.
4517
4518 Srb - Supplies a pointer to the failing Srb.
4519
4520 Status - Status with which the IRP will be completed.
4521
4522 Retry - Indication of whether the request will be retried.
4523
4524 Return Value:
4525
4526 None.
4527
4528 --*/
4529
4530 {
4531 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4532
4533 if (*Status == STATUS_DATA_OVERRUN &&
4534 ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) {
4535
4536 *Retry = TRUE;
4537
4538 //
4539 // Update the error count for the device.
4540 //
4541
4542 deviceExtension->ErrorCount++;
4543 }
4544
4545 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
4546 Srb->ScsiStatus == SCSISTAT_BUSY) {
4547
4548 //
4549 // The disk drive should never be busy this long. Reset the scsi bus
4550 // maybe this will clear the condition.
4551 //
4552
4553 ResetScsiBus(DeviceObject);
4554
4555 //
4556 // Update the error count for the device.
4557 //
4558
4559 deviceExtension->ErrorCount++;
4560 }
4561 }
4562 \f
4563 VOID
4564 NTAPI
4565 ScanForSpecial(
4566 PDEVICE_OBJECT DeviceObject,
4567 PSCSI_INQUIRY_DATA LunInfo,
4568 PIO_SCSI_CAPABILITIES PortCapabilities
4569 )
4570
4571 /*++
4572
4573 Routine Description:
4574
4575 This function checks to see if an SCSI logical unit requires special
4576 flags to be set.
4577
4578 Arguments:
4579
4580 DeviceObject - Supplies the device object to be tested.
4581
4582 InquiryData - Supplies the inquiry data returned by the device of interest.
4583
4584 PortCapabilities - Supplies the capabilities of the device object.
4585
4586 Return Value:
4587
4588 None.
4589
4590 --*/
4591
4592 {
4593 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4594 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
4595 BAD_CONTROLLER_INFORMATION const *controller;
4596 ULONG j;
4597
4598 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
4599
4600 controller = &ScsiDiskBadControllers[j];
4601
4602 if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
4603 continue;
4604 }
4605
4606 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString));
4607
4608 //
4609 // Found a listed controller. Determine what must be done.
4610 //
4611
4612 if (controller->DisableTaggedQueuing) {
4613
4614 //
4615 // Disable tagged queuing.
4616 //
4617
4618 deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
4619 }
4620
4621 if (controller->DisableSynchronousTransfers) {
4622
4623 //
4624 // Disable synchronous data transfers.
4625 //
4626
4627 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
4628
4629 }
4630
4631 if (controller->DisableDisconnects) {
4632
4633 //
4634 // Disable disconnects.
4635 //
4636
4637 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
4638
4639 }
4640
4641 //
4642 // Found device so exit the loop and return.
4643 //
4644
4645 break;
4646 }
4647
4648 //
4649 // Set the StartUnit flag appropriately.
4650 //
4651
4652 if (DeviceObject->DeviceType == FILE_DEVICE_DISK) {
4653 deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT;
4654
4655 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
4656 if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) {
4657 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT;
4658 }
4659 }
4660 }
4661
4662 return;
4663 }
4664 \f
4665 VOID
4666 NTAPI
4667 ResetScsiBus(
4668 IN PDEVICE_OBJECT DeviceObject
4669 )
4670
4671 /*++
4672
4673 Routine Description:
4674
4675 This command sends a reset bus command to the SCSI port driver.
4676
4677 Arguments:
4678
4679 DeviceObject - The device object for the logical unit with
4680 hardware problem.
4681
4682 Return Value:
4683
4684 None.
4685
4686 --*/
4687 {
4688 PIO_STACK_LOCATION irpStack;
4689 PIRP irp;
4690 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4691 PSCSI_REQUEST_BLOCK srb;
4692 PCOMPLETION_CONTEXT context;
4693
4694 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4695
4696 //
4697 // Allocate Srb from nonpaged pool.
4698 //
4699
4700 context = ExAllocatePool(NonPagedPoolMustSucceed,
4701 sizeof(COMPLETION_CONTEXT));
4702
4703 //
4704 // Save the device object in the context for use by the completion
4705 // routine.
4706 //
4707
4708 context->DeviceObject = DeviceObject;
4709 srb = &context->Srb;
4710
4711 //
4712 // Zero out srb.
4713 //
4714
4715 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
4716
4717 //
4718 // Write length to SRB.
4719 //
4720
4721 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4722
4723 //
4724 // Set up SCSI bus address.
4725 //
4726
4727 srb->PathId = deviceExtension->PathId;
4728 srb->TargetId = deviceExtension->TargetId;
4729 srb->Lun = deviceExtension->Lun;
4730
4731 srb->Function = SRB_FUNCTION_RESET_BUS;
4732
4733 //
4734 // Build the asynchronous request to be sent to the port driver.
4735 // Since this routine is called from a DPC the IRP should always be
4736 // available.
4737 //
4738
4739 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4740
4741 IoSetCompletionRoutine(irp,
4742 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
4743 context,
4744 TRUE,
4745 TRUE,
4746 TRUE);
4747
4748 irpStack = IoGetNextIrpStackLocation(irp);
4749
4750 irpStack->MajorFunction = IRP_MJ_SCSI;
4751
4752 srb->OriginalRequest = irp;
4753
4754 //
4755 // Store the SRB address in next stack for port driver.
4756 //
4757
4758 irpStack->Parameters.Scsi.Srb = srb;
4759
4760 //
4761 // Call the port driver with the IRP.
4762 //
4763
4764 IoCallDriver(deviceExtension->PortDeviceObject, irp);
4765
4766 return;
4767
4768 } // end ResetScsiBus()
4769
4770 \f
4771 VOID
4772 NTAPI
4773 UpdateDeviceObjects(
4774 IN PDEVICE_OBJECT PhysicalDisk,
4775 IN PIRP Irp
4776 )
4777
4778 /*++
4779
4780 Routine Description:
4781
4782 This routine creates, deletes and changes device objects when
4783 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4784 the drive layout information for the user. It is possible to
4785 call this routine even in the GET_LAYOUT case because RewritePartition
4786 will be false.
4787
4788 Arguments:
4789
4790 DeviceObject - Device object for physical disk.
4791 Irp - IO Request Packet (IRP).
4792
4793 Return Value:
4794
4795 None.
4796
4797 --*/
4798 {
4799 PDEVICE_EXTENSION physicalExtension = PhysicalDisk->DeviceExtension;
4800 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
4801 ULONG partition;
4802 ULONG partitionNumber;
4803 ULONG partitionCount;
4804 ULONG lastPartition;
4805 ULONG partitionOrdinal;
4806 PPARTITION_INFORMATION partitionEntry;
4807 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
4808 STRING ntNameString;
4809 UNICODE_STRING ntUnicodeString;
4810 PDEVICE_OBJECT deviceObject;
4811 PDEVICE_EXTENSION deviceExtension;
4812 PDISK_DATA diskData;
4813 NTSTATUS status;
4814 ULONG numberListElements;
4815 BOOLEAN found;
4816
4817 partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4;
4818
4819 //
4820 // Zero all of the partition numbers.
4821 //
4822
4823 for (partition = 0; partition < partitionCount; partition++) {
4824 partitionEntry = &partitionList->PartitionEntry[partition];
4825 partitionEntry->PartitionNumber = 0;
4826 }
4827
4828 //
4829 // Walk through chain of partitions for this disk to determine
4830 // which existing partitions have no match.
4831 //
4832
4833 deviceExtension = physicalExtension;
4834 diskData = (PDISK_DATA)(deviceExtension + 1);
4835 lastPartition = 0;
4836
4837 do {
4838
4839 deviceExtension = diskData->NextPartition;
4840
4841 //
4842 // Check if this is the last partition in the chain.
4843 //
4844
4845 if (!deviceExtension) {
4846 break;
4847 }
4848
4849 //
4850 // Get the partition device extension from disk data.
4851 //
4852
4853 diskData = (PDISK_DATA)(deviceExtension + 1);
4854
4855 //
4856 // Check for highest partition number this far.
4857 //
4858
4859 if (diskData->PartitionNumber > lastPartition) {
4860 lastPartition = diskData->PartitionNumber;
4861 }
4862
4863 //
4864 // Check if this partition is not currently being used.
4865 //
4866
4867 if (!deviceExtension->PartitionLength.QuadPart) {
4868 continue;
4869 }
4870
4871 //
4872 // Loop through partition information to look for match.
4873 //
4874
4875 found = FALSE;
4876 partitionOrdinal = 0;
4877
4878 for (partition = 0; partition < partitionCount; partition++) {
4879
4880 //
4881 // Get partition descriptor.
4882 //
4883
4884 partitionEntry = &partitionList->PartitionEntry[partition];
4885
4886 //
4887 // Check if empty, or describes extended partition or hasn't changed.
4888 //
4889
4890 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
4891 IsContainerPartition(partitionEntry->PartitionType)) {
4892 continue;
4893 }
4894
4895 //
4896 // Advance partition ordinal.
4897 //
4898
4899 partitionOrdinal++;
4900
4901 //
4902 // Check if new partition starts where this partition starts.
4903 //
4904
4905 if (partitionEntry->StartingOffset.QuadPart !=
4906 deviceExtension->StartingOffset.QuadPart) {
4907 continue;
4908 }
4909
4910 //
4911 // Check if partition length is the same.
4912 //
4913
4914 if (partitionEntry->PartitionLength.QuadPart ==
4915 deviceExtension->PartitionLength.QuadPart) {
4916
4917 DebugPrint((3,
4918 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4919 physicalExtension->DeviceNumber,
4920 diskData->PartitionNumber));
4921
4922 //
4923 // Indicate match is found and set partition number
4924 // in user buffer.
4925 //
4926
4927 found = TRUE;
4928 partitionEntry->PartitionNumber = diskData->PartitionNumber;
4929 break;
4930 }
4931 }
4932
4933 if (found) {
4934
4935 //
4936 // A match is found.
4937 //
4938
4939 diskData = (PDISK_DATA)(deviceExtension + 1);
4940
4941 //
4942 // If this partition is marked for update then update partition type.
4943 //
4944
4945 if (partitionEntry->RewritePartition) {
4946 diskData->PartitionType = partitionEntry->PartitionType;
4947 }
4948
4949 //
4950 // Update partitional ordinal for calls to HAL routine
4951 // IoSetPartitionInformation.
4952 //
4953
4954 diskData->PartitionOrdinal = partitionOrdinal;
4955
4956 DebugPrint((1,
4957 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4958 physicalExtension->DeviceNumber,
4959 diskData->PartitionOrdinal,
4960 diskData->PartitionNumber));
4961
4962 } else {
4963
4964 //
4965 // no match was found, indicate this partition is gone.
4966 //
4967
4968 DebugPrint((1,
4969 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4970 physicalExtension->DeviceNumber,
4971 diskData->PartitionNumber));
4972
4973 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
4974 }
4975
4976 } while (TRUE);
4977
4978 //
4979 // Walk through partition loop to find new partitions and set up
4980 // device extensions to describe them. In some cases new device
4981 // objects will be created.
4982 //
4983
4984 partitionOrdinal = 0;
4985
4986 for (partition = 0;
4987 partition < partitionCount;
4988 partition++) {
4989
4990 //
4991 // Get partition descriptor.
4992 //
4993
4994 partitionEntry = &partitionList->PartitionEntry[partition];
4995
4996 //
4997 // Check if empty, or describes an extended partition.
4998 //
4999
5000 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
5001 IsContainerPartition(partitionEntry->PartitionType)) {
5002 continue;
5003 }
5004
5005 //
5006 // Keep track of position on the disk for calls to IoSetPartitionInformation.
5007 //
5008
5009 partitionOrdinal++;
5010
5011 //
5012 // Check if this entry should be rewritten.
5013 //
5014
5015 if (!partitionEntry->RewritePartition) {
5016 continue;
5017 }
5018
5019 if (partitionEntry->PartitionNumber) {
5020
5021 //
5022 // Partition is an exact match with an existing partition, but is
5023 // being written anyway.
5024 //
5025
5026 continue;
5027 }
5028
5029 //
5030 // Check first if existing device object is available by
5031 // walking partition extension list.
5032 //
5033
5034 partitionNumber = 0;
5035 deviceExtension = physicalExtension;
5036 diskData = (PDISK_DATA)(deviceExtension + 1);
5037
5038 do {
5039
5040 //
5041 // Get next partition device extension from disk data.
5042 //
5043
5044 deviceExtension = diskData->NextPartition;
5045
5046 if (!deviceExtension) {
5047 break;
5048 }
5049
5050 diskData = (PDISK_DATA)(deviceExtension + 1);
5051
5052 //
5053 // A device object is free if the partition length is set to zero.
5054 //
5055
5056 if (!deviceExtension->PartitionLength.QuadPart) {
5057 partitionNumber = diskData->PartitionNumber;
5058 break;
5059 }
5060
5061 } while (TRUE);
5062
5063 //
5064 // If partition number is still zero then a new device object
5065 // must be created.
5066 //
5067
5068 if (partitionNumber == 0) {
5069
5070 lastPartition++;
5071 partitionNumber = lastPartition;
5072
5073 //
5074 // Get or create partition object and set up partition parameters.
5075 //
5076
5077 sprintf(ntNameBuffer,
5078 "\\Device\\Harddisk%lu\\Partition%lu",
5079 physicalExtension->DeviceNumber,
5080 partitionNumber);
5081
5082 RtlInitString(&ntNameString,
5083 ntNameBuffer);
5084
5085 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
5086 &ntNameString,
5087 TRUE);
5088
5089 if (!NT_SUCCESS(status)) {
5090 continue;
5091 }
5092
5093 DebugPrint((3,
5094 "UpdateDeviceObjects: Create device object %s\n",
5095 ntNameBuffer));
5096
5097 //
5098 // This is a new name. Create the device object to represent it.
5099 //
5100
5101 status = IoCreateDevice(PhysicalDisk->DriverObject,
5102 DEVICE_EXTENSION_SIZE,
5103 &ntUnicodeString,
5104 FILE_DEVICE_DISK,
5105 0,
5106 FALSE,
5107 &deviceObject);
5108
5109 if (!NT_SUCCESS(status)) {
5110 DebugPrint((1,
5111 "UpdateDeviceObjects: Can't create device %s\n",
5112 ntNameBuffer));
5113 RtlFreeUnicodeString(&ntUnicodeString);
5114 continue;
5115 }
5116
5117 //
5118 // Set up device object fields.
5119 //
5120
5121 deviceObject->Flags |= DO_DIRECT_IO;
5122 deviceObject->StackSize = PhysicalDisk->StackSize;
5123
5124 //
5125 // Set up device extension fields.
5126 //
5127
5128 deviceExtension = deviceObject->DeviceExtension;
5129
5130 //
5131 // Copy physical disk extension to partition extension.
5132 //
5133
5134 RtlMoveMemory(deviceExtension,
5135 physicalExtension,
5136 sizeof(DEVICE_EXTENSION));
5137
5138 //
5139 // Initialize the new S-List.
5140 //
5141
5142 if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
5143 numberListElements = 30;
5144 } else {
5145 numberListElements = 8;
5146 }
5147
5148 //
5149 // Build the lookaside list for srb's for this partition based on
5150 // whether the adapter and disk can do tagged queueing.
5151 //
5152
5153 ScsiClassInitializeSrbLookasideList(deviceExtension,
5154 numberListElements);
5155
5156 //
5157 // Allocate spinlock for zoning for split-request completion.
5158 //
5159
5160 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
5161
5162 //
5163 // Write back partition number used in creating object name.
5164 //
5165
5166 partitionEntry->PartitionNumber = partitionNumber;
5167
5168 //
5169 // Clear flags initializing bit.
5170 //
5171
5172 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
5173
5174 //
5175 // Point back at device object.
5176 //
5177
5178 deviceExtension->DeviceObject = deviceObject;
5179
5180 RtlFreeUnicodeString(&ntUnicodeString);
5181
5182 //
5183 // Link to end of partition chain using previous disk data.
5184 //
5185
5186 diskData->NextPartition = deviceExtension;
5187
5188 //
5189 // Get new disk data and zero next partition pointer.
5190 //
5191
5192 diskData = (PDISK_DATA)(deviceExtension + 1);
5193 diskData->NextPartition = NULL;
5194
5195 } else {
5196
5197 //
5198 // Set pointer to disk data area that follows device extension.
5199 //
5200
5201 diskData = (PDISK_DATA)(deviceExtension + 1);
5202
5203 DebugPrint((1,
5204 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5205 physicalExtension->DeviceNumber,
5206 partitionNumber));
5207 }
5208
5209 //
5210 // Update partition information in partition device extension.
5211 //
5212
5213 diskData->PartitionNumber = partitionNumber;
5214 diskData->PartitionType = partitionEntry->PartitionType;
5215 diskData->BootIndicator = partitionEntry->BootIndicator;
5216 deviceExtension->StartingOffset = partitionEntry->StartingOffset;
5217 deviceExtension->PartitionLength = partitionEntry->PartitionLength;
5218 diskData->HiddenSectors = partitionEntry->HiddenSectors;
5219 diskData->PartitionOrdinal = partitionOrdinal;
5220
5221 DebugPrint((1,
5222 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5223 diskData->PartitionOrdinal,
5224 diskData->PartitionNumber));
5225
5226 //
5227 // Update partition number passed in to indicate the
5228 // device name for this partition.
5229 //
5230
5231 partitionEntry->PartitionNumber = partitionNumber;
5232 }
5233
5234 } // end UpdateDeviceObjects()
5235