[DISK]
[reactos.git] / reactos / drivers / storage / class / disk / disk.c
1 /*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/disk/disk.c
5 * PURPOSE: Disk class driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9 #include <ntddk.h>
10 #include <ntdddisk.h>
11 #include <scsi.h>
12 #include <ntddscsi.h>
13 #include <mountdev.h>
14 #include <mountmgr.h>
15 #include <ntiologc.h>
16 #include <include/class2.h>
17 #include <stdio.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22
23 #ifdef POOL_TAGGING
24 #ifdef ExAllocatePool
25 #undef ExAllocatePool
26 #endif
27 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
28 #endif
29
30 typedef enum {
31 NotInitialized,
32 Initializing,
33 Initialized
34 } PARTITION_LIST_STATE;
35
36 //
37 // Disk device data
38 //
39
40 typedef struct _DISK_DATA {
41
42 //
43 // Partition chain
44 //
45
46 PDEVICE_EXTENSION NextPartition;
47
48 //
49 // Disk signature (from MBR)
50 //
51
52 ULONG Signature;
53
54 //
55 // MBR checksum
56 //
57
58 ULONG MbrCheckSum;
59
60 //
61 // Number of hidden sectors for BPB.
62 //
63
64 ULONG HiddenSectors;
65
66 //
67 // Partition number of this device object
68 //
69 // This field is set during driver initialization or when the partition
70 // is created to identify a parition to the system.
71 //
72
73 ULONG PartitionNumber;
74
75 //
76 // This field is the ordinal of a partition as it appears on a disk.
77 //
78
79 ULONG PartitionOrdinal;
80
81 //
82 // Partition type of this device object
83 //
84 // This field is set by:
85 //
86 // 1) Initially set according to the partition list entry partition
87 // type returned by IoReadPartitionTable.
88 //
89 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
90 // I/O control function when IoSetPartitionInformation function
91 // successfully updates the partition type on the disk.
92 //
93
94 UCHAR PartitionType;
95
96 //
97 // Boot indicator - indicates whether this partition is a bootable (active)
98 // partition for this device
99 //
100 // This field is set according to the partition list entry boot indicator
101 // returned by IoReadPartitionTable.
102 //
103
104 BOOLEAN BootIndicator;
105
106 //
107 // DriveNotReady - inidicates that the this device is currenly not ready
108 // because there is no media in the device.
109 //
110
111 BOOLEAN DriveNotReady;
112
113 //
114 // State of PartitionList initialization
115 //
116
117 PARTITION_LIST_STATE PartitionListState;
118
119 } DISK_DATA, *PDISK_DATA;
120
121 //
122 // Define a general structure of identfing disk controllers with bad
123 // hardware.
124 //
125
126 typedef struct _BAD_CONTROLLER_INFORMATION {
127 PCHAR InquiryString;
128 BOOLEAN DisableTaggedQueuing;
129 BOOLEAN DisableSynchronousTransfers;
130 BOOLEAN DisableDisconnects;
131 BOOLEAN DisableWriteCache;
132 }BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION;
133
134 BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = {
135 { "TOSHIBA MK538FB 60", TRUE, FALSE, FALSE, FALSE },
136 { "CONNER CP3500", FALSE, TRUE, FALSE, FALSE },
137 { "OLIVETTICP3500", FALSE, TRUE, FALSE, FALSE },
138 { "SyQuest SQ5110 CHC", TRUE, TRUE, FALSE, FALSE },
139 { "SEAGATE ST41601N 0102", FALSE, TRUE, FALSE, FALSE },
140 { "SEAGATE ST3655N", FALSE, FALSE, FALSE, TRUE },
141 { "SEAGATE ST3390N", FALSE, FALSE, FALSE, TRUE },
142 { "SEAGATE ST12550N", FALSE, FALSE, FALSE, TRUE },
143 { "SEAGATE ST32430N", FALSE, FALSE, FALSE, TRUE },
144 { "SEAGATE ST31230N", FALSE, FALSE, FALSE, TRUE },
145 { "SEAGATE ST15230N", FALSE, FALSE, FALSE, TRUE },
146 { "FUJITSU M2652S-512", TRUE, FALSE, FALSE, FALSE },
147 { "MAXTOR MXT-540SL I1.2", TRUE, FALSE, FALSE, FALSE },
148 { "COMPAQ PD-1", FALSE, TRUE, FALSE, FALSE }
149 };
150
151
152 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
153 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
154
155 #define MODE_DATA_SIZE 192
156 #define VALUE_BUFFER_SIZE 2048
157 #define SCSI_DISK_TIMEOUT 10
158 #define PARTITION0_LIST_SIZE 4
159
160 \f
161 NTSTATUS
162 NTAPI
163 DriverEntry(
164 IN PDRIVER_OBJECT DriverObject,
165 IN PUNICODE_STRING RegistryPath
166 );
167
168 BOOLEAN
169 NTAPI
170 ScsiDiskDeviceVerification(
171 IN PINQUIRYDATA InquiryData
172 );
173
174 BOOLEAN
175 NTAPI
176 FindScsiDisks(
177 IN PDRIVER_OBJECT DriveObject,
178 IN PUNICODE_STRING RegistryPath,
179 IN PCLASS_INIT_DATA InitializationData,
180 IN PDEVICE_OBJECT PortDeviceObject,
181 IN ULONG PortNumber
182 );
183
184 NTSTATUS
185 NTAPI
186 ScsiDiskCreateClose (
187 IN PDEVICE_OBJECT DeviceObject,
188 IN PIRP Irp
189 );
190
191 NTSTATUS
192 NTAPI
193 ScsiDiskReadWriteVerification(
194 IN PDEVICE_OBJECT DeviceObject,
195 IN PIRP Irp
196 );
197
198 NTSTATUS
199 NTAPI
200 ScsiDiskDeviceControl(
201 IN PDEVICE_OBJECT DeviceObject,
202 IN PIRP Irp
203 );
204
205 VOID
206 NTAPI
207 ScsiDiskProcessError(
208 PDEVICE_OBJECT DeviceObject,
209 PSCSI_REQUEST_BLOCK Srb,
210 NTSTATUS *Status,
211 BOOLEAN *Retry
212 );
213
214 NTSTATUS
215 NTAPI
216 ScsiDiskShutdownFlush(
217 IN PDEVICE_OBJECT DeviceObject,
218 IN PIRP Irp
219 );
220
221 VOID
222 NTAPI
223 DisableWriteCache(
224 IN PDEVICE_OBJECT DeviceObject,
225 IN PSCSI_INQUIRY_DATA LunInfo
226 );
227
228 BOOLEAN
229 NTAPI
230 ScsiDiskModeSelect(
231 IN PDEVICE_OBJECT DeviceObject,
232 IN PCHAR ModeSelectBuffer,
233 IN ULONG Length,
234 IN BOOLEAN SavePage
235 );
236
237 BOOLEAN
238 NTAPI
239 IsFloppyDevice(
240 IN PDEVICE_OBJECT DeviceObject
241 );
242
243 BOOLEAN
244 NTAPI
245 CalculateMbrCheckSum(
246 IN PDEVICE_EXTENSION DeviceExtension,
247 OUT PULONG Checksum
248 );
249
250 BOOLEAN
251 NTAPI
252 EnumerateBusKey(
253 IN PDEVICE_EXTENSION DeviceExtension,
254 HANDLE BusKey,
255 PULONG DiskNumber
256 );
257
258 VOID
259 NTAPI
260 UpdateGeometry(
261 IN PDEVICE_EXTENSION DeviceExtension
262 );
263
264 NTSTATUS
265 NTAPI
266 UpdateRemovableGeometry (
267 IN PDEVICE_OBJECT DeviceObject,
268 IN PIRP Irp
269 );
270
271 NTSTATUS
272 NTAPI
273 CreateDiskDeviceObject(
274 IN PDRIVER_OBJECT DriverObject,
275 IN PUNICODE_STRING RegistryPath,
276 IN PDEVICE_OBJECT PortDeviceObject,
277 IN ULONG PortNumber,
278 IN PULONG DeviceCount,
279 IN PIO_SCSI_CAPABILITIES PortCapabilities,
280 IN PSCSI_INQUIRY_DATA LunInfo,
281 IN PCLASS_INIT_DATA InitData
282 );
283
284 NTSTATUS
285 NTAPI
286 CreatePartitionDeviceObjects(
287 IN PDEVICE_OBJECT PhysicalDeviceObject,
288 IN PUNICODE_STRING RegistryPath
289 );
290
291 VOID
292 NTAPI
293 UpdateDeviceObjects(
294 IN PDEVICE_OBJECT DeviceObject,
295 IN PIRP Irp
296 );
297
298 VOID
299 NTAPI
300 ScanForSpecial(
301 PDEVICE_OBJECT DeviceObject,
302 PSCSI_INQUIRY_DATA LunInfo,
303 PIO_SCSI_CAPABILITIES PortCapabilities
304 );
305
306 VOID
307 NTAPI
308 ResetScsiBus(
309 IN PDEVICE_OBJECT DeviceObject
310 );
311
312 NTSTATUS
313 NTAPI
314 ScsiDiskFileSystemControl(PDEVICE_OBJECT DeviceObject,
315 PIRP Irp);
316
317 #ifdef ALLOC_PRAGMA
318 #pragma alloc_text(PAGE, DriverEntry)
319 #pragma alloc_text(PAGE, FindScsiDisks)
320 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
321 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
322 #pragma alloc_text(PAGE, EnumerateBusKey)
323 #pragma alloc_text(PAGE, UpdateGeometry)
324 #pragma alloc_text(PAGE, IsFloppyDevice)
325 #pragma alloc_text(PAGE, ScanForSpecial)
326 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
327 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
328 #endif
329
330 \f
331 NTSTATUS
332 NTAPI
333 DriverEntry(
334 IN PDRIVER_OBJECT DriverObject,
335 IN PUNICODE_STRING RegistryPath
336 )
337
338 /*++
339
340 Routine Description:
341
342 This routine initializes the SCSI hard disk class driver.
343
344 Arguments:
345
346 DriverObject - Pointer to driver object created by system.
347
348 RegistryPath - Pointer to the name of the services node for this driver.
349
350 Return Value:
351
352 The function value is the final status from the initialization operation.
353
354 --*/
355
356 {
357 CLASS_INIT_DATA InitializationData;
358
359 //
360 // Zero InitData
361 //
362
363 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
364
365 //
366 // Set sizes
367 //
368
369 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
370 InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
371
372 InitializationData.DeviceType = FILE_DEVICE_DISK;
373 InitializationData.DeviceCharacteristics = 0;
374
375 //
376 // Set entry points
377 //
378
379 InitializationData.ClassError = ScsiDiskProcessError;
380 InitializationData.ClassReadWriteVerification = ScsiDiskReadWriteVerification;
381 InitializationData.ClassFindDevices = FindScsiDisks;
382 InitializationData.ClassFindDeviceCallBack = ScsiDiskDeviceVerification;
383 InitializationData.ClassDeviceControl = ScsiDiskDeviceControl;
384 InitializationData.ClassShutdownFlush = ScsiDiskShutdownFlush;
385 InitializationData.ClassCreateClose = NULL;
386
387 //
388 // Call the class init routine
389 //
390
391 return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
392
393 } // end DriverEntry()
394
395
396 \f
397 BOOLEAN
398 NTAPI
399 ScsiDiskDeviceVerification(
400 IN PINQUIRYDATA InquiryData
401 )
402
403 /*++
404
405 Routine Description:
406
407 This routine checks InquiryData for the correct device type and qualifier.
408
409 Arguments:
410
411 InquiryData - Pointer to the inquiry data for the device in question.
412
413 Return Value:
414
415 True is returned if the correct device type is found.
416
417 --*/
418 {
419
420 if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
421 (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
422 InquiryData->DeviceTypeQualifier == 0) {
423
424 return TRUE;
425
426 } else {
427 return FALSE;
428 }
429 }
430
431 \f
432 BOOLEAN
433 NTAPI
434 FindScsiDisks(
435 IN PDRIVER_OBJECT DriverObject,
436 IN PUNICODE_STRING RegistryPath,
437 IN PCLASS_INIT_DATA InitializationData,
438 IN PDEVICE_OBJECT PortDeviceObject,
439 IN ULONG PortNumber
440 )
441
442 /*++
443
444 Routine Description:
445
446 This routine gets a port drivers capabilities, obtains the
447 inquiry data, searches the SCSI bus for the port driver and creates
448 the device objects for the disks found.
449
450 Arguments:
451
452 DriverObject - Pointer to driver object created by system.
453
454 PortDeviceObject - Device object use to send requests to port driver.
455
456 PortNumber - Number for port driver. Used to pass on to
457 CreateDiskDeviceObjects() and create device objects.
458
459 Return Value:
460
461 True is returned if one disk was found and successfully created.
462
463 --*/
464
465 {
466 PIO_SCSI_CAPABILITIES portCapabilities;
467 PULONG diskCount;
468 PCONFIGURATION_INFORMATION configurationInformation;
469 PCHAR buffer;
470 PSCSI_INQUIRY_DATA lunInfo;
471 PSCSI_ADAPTER_BUS_INFO adapterInfo;
472 PINQUIRYDATA inquiryData;
473 ULONG scsiBus;
474 ULONG adapterDisk;
475 NTSTATUS status;
476 BOOLEAN foundOne = FALSE;
477
478 PAGED_CODE();
479
480 //
481 // Call port driver to get adapter capabilities.
482 //
483
484 status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
485
486 if (!NT_SUCCESS(status)) {
487 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
488 return(FALSE);
489 }
490
491 //
492 // Call port driver to get inquiry information to find disks.
493 //
494
495 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
496
497 if (!NT_SUCCESS(status)) {
498 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
499 return(FALSE);
500 }
501
502 //
503 // Do a quick scan of the devices on this adapter to determine how many
504 // disks are on this adapter. This is used to determine the number of
505 // SRB zone elements to allocate.
506 //
507
508 adapterDisk = 0;
509 adapterInfo = (PVOID) buffer;
510
511 adapterDisk = ScsiClassFindUnclaimedDevices(InitializationData, adapterInfo);
512
513 //
514 // Allocate a zone of SRB for disks on this adapter.
515 //
516
517 if (adapterDisk == 0) {
518
519 //
520 // No free disks were found.
521 //
522
523 return(FALSE);
524 }
525
526 //
527 // Get the number of disks already initialized.
528 //
529
530 configurationInformation = IoGetConfigurationInformation();
531 diskCount = &configurationInformation->DiskCount;
532
533 //
534 // For each SCSI bus this adapter supports ...
535 //
536
537 for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
538
539 //
540 // Get the SCSI bus scan data for this bus.
541 //
542
543 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
544
545 //
546 // Search list for unclaimed disk devices.
547 //
548
549 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
550
551 inquiryData = (PVOID)lunInfo->InquiryData;
552
553 if (((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
554 (inquiryData->DeviceType == OPTICAL_DEVICE)) &&
555 inquiryData->DeviceTypeQualifier == 0 &&
556 (!lunInfo->DeviceClaimed)) {
557
558 DebugPrint((1,
559 "FindScsiDevices: Vendor string is %.24s\n",
560 inquiryData->VendorId));
561
562 //
563 // Create device objects for disk
564 //
565
566 status = CreateDiskDeviceObject(DriverObject,
567 RegistryPath,
568 PortDeviceObject,
569 PortNumber,
570 diskCount,
571 portCapabilities,
572 lunInfo,
573 InitializationData);
574
575 if (NT_SUCCESS(status)) {
576
577 //
578 // Increment system disk device count.
579 //
580
581 (*diskCount)++;
582 foundOne = TRUE;
583
584 }
585 }
586
587 //
588 // Get next LunInfo.
589 //
590
591 if (lunInfo->NextInquiryDataOffset == 0) {
592 break;
593 }
594
595 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
596
597 }
598 }
599
600 //
601 // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
602 //
603
604 ExFreePool(buffer);
605
606 return(foundOne);
607
608 } // end FindScsiDisks()
609
610 \f
611 NTSTATUS
612 NTAPI
613 CreateDiskDeviceObject(
614 IN PDRIVER_OBJECT DriverObject,
615 IN PUNICODE_STRING RegistryPath,
616 IN PDEVICE_OBJECT PortDeviceObject,
617 IN ULONG PortNumber,
618 IN PULONG DeviceCount,
619 IN PIO_SCSI_CAPABILITIES PortCapabilities,
620 IN PSCSI_INQUIRY_DATA LunInfo,
621 IN PCLASS_INIT_DATA InitData
622 )
623
624 /*++
625
626 Routine Description:
627
628 This routine creates an object for the physical device and then searches
629 the device for partitions and creates an object for each partition.
630
631 Arguments:
632
633 DriverObject - Pointer to driver object created by system.
634
635 PortDeviceObject - Miniport device object.
636
637 PortNumber - port number. Used in creating disk objects.
638
639 DeviceCount - Number of previously installed devices.
640
641 PortCapabilities - Capabilities of this SCSI port.
642
643 LunInfo - LUN specific information.
644
645 Return Value:
646
647 NTSTATUS
648
649 --*/
650 {
651 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
652 STRING ntNameString;
653 UNICODE_STRING ntUnicodeString;
654 OBJECT_ATTRIBUTES objectAttributes;
655 HANDLE handle;
656 NTSTATUS status;
657 PDEVICE_OBJECT deviceObject = NULL;
658 //PDEVICE_OBJECT physicalDevice;
659 PDISK_GEOMETRY_EX diskGeometry = NULL;
660 PDEVICE_EXTENSION deviceExtension = NULL;
661 //PDEVICE_EXTENSION physicalDeviceExtension;
662 UCHAR pathId = LunInfo->PathId;
663 UCHAR targetId = LunInfo->TargetId;
664 UCHAR lun = LunInfo->Lun;
665 //BOOLEAN writeCache;
666 PVOID senseData = NULL;
667 //ULONG srbFlags;
668 ULONG timeOut = 0;
669 BOOLEAN srbListInitialized = FALSE;
670
671
672 PAGED_CODE();
673
674 //
675 // Set up an object directory to contain the objects for this
676 // device and all its partitions.
677 //
678
679 sprintf(ntNameBuffer,
680 "\\Device\\Harddisk%lu",
681 *DeviceCount);
682
683 RtlInitString(&ntNameString,
684 ntNameBuffer);
685
686 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
687 &ntNameString,
688 TRUE);
689
690 if (!NT_SUCCESS(status)) {
691 return(status);
692 }
693
694 InitializeObjectAttributes(&objectAttributes,
695 &ntUnicodeString,
696 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
697 NULL,
698 NULL);
699
700 status = ZwCreateDirectoryObject(&handle,
701 DIRECTORY_ALL_ACCESS,
702 &objectAttributes);
703
704 RtlFreeUnicodeString(&ntUnicodeString);
705
706 if (!NT_SUCCESS(status)) {
707
708 DebugPrint((1,
709 "CreateDiskDeviceObjects: Could not create directory %s\n",
710 ntNameBuffer));
711
712 return(status);
713 }
714
715 //
716 // Claim the device.
717 //
718
719 status = ScsiClassClaimDevice(PortDeviceObject,
720 LunInfo,
721 FALSE,
722 &PortDeviceObject);
723
724 if (!NT_SUCCESS(status)) {
725 ZwMakeTemporaryObject(handle);
726 ZwClose(handle);
727 return status;
728 }
729
730 //
731 // Create a device object for this device. Each physical disk will
732 // have at least one device object. The required device object
733 // describes the entire device. Its directory path is
734 // \Device\HarddiskN\Partition0, where N = device number.
735 //
736
737 sprintf(ntNameBuffer,
738 "\\Device\\Harddisk%lu\\Partition0",
739 *DeviceCount);
740
741
742 status = ScsiClassCreateDeviceObject(DriverObject,
743 ntNameBuffer,
744 NULL,
745 &deviceObject,
746 InitData);
747
748 if (!NT_SUCCESS(status)) {
749
750 DebugPrint((1,
751 "CreateDiskDeviceObjects: Can not create device object %s\n",
752 ntNameBuffer));
753
754 goto CreateDiskDeviceObjectsExit;
755 }
756
757 //
758 // Indicate that IRPs should include MDLs for data transfers.
759 //
760
761 deviceObject->Flags |= DO_DIRECT_IO;
762
763 //
764 // Check if this is during initialization. If not indicate that
765 // system initialization already took place and this disk is ready
766 // to be accessed.
767 //
768
769 if (!RegistryPath) {
770 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
771 }
772
773 //
774 // Check for removable media support.
775 //
776
777 if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) {
778 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
779 }
780
781 //
782 // Set up required stack size in device object.
783 //
784
785 deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
786
787 deviceExtension = deviceObject->DeviceExtension;
788
789 //
790 // Allocate spinlock for split request completion.
791 //
792
793 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
794
795 //
796 // Initialize lock count to zero. The lock count is used to
797 // disable the ejection mechanism on devices that support
798 // removable media. Only the lock count in the physical
799 // device extension is used.
800 //
801
802 deviceExtension->LockCount = 0;
803
804 //
805 // Save system disk number.
806 //
807
808 deviceExtension->DeviceNumber = *DeviceCount;
809
810 //
811 // Copy port device object pointer to the device extension.
812 //
813
814 deviceExtension->PortDeviceObject = PortDeviceObject;
815
816 //
817 // Set the alignment requirements for the device based on the
818 // host adapter requirements
819 //
820
821 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
822 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
823 }
824
825 //
826 // This is the physical device object.
827 //
828
829 //physicalDevice = deviceObject;
830 //physicalDeviceExtension = deviceExtension;
831
832 //
833 // Save address of port driver capabilities.
834 //
835
836 deviceExtension->PortCapabilities = PortCapabilities;
837
838 //
839 // Build the lookaside list for srb's for the physical disk. Should only
840 // need a couple.
841 //
842
843 ScsiClassInitializeSrbLookasideList(deviceExtension,
844 PARTITION0_LIST_SIZE);
845
846 srbListInitialized = TRUE;
847
848 //
849 // Initialize the srb flags.
850 //
851
852 if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue &&
853 PortCapabilities->TaggedQueuing) {
854
855 deviceExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE;
856
857 } else {
858
859 deviceExtension->SrbFlags = 0;
860
861 }
862
863 //
864 // Allow queued requests if this is not removable media.
865 //
866
867 if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
868
869 deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
870
871 }
872
873 //
874 // Look for controller that require special flags.
875 //
876
877 ScanForSpecial(deviceObject,
878 LunInfo,
879 PortCapabilities);
880
881 //srbFlags = deviceExtension->SrbFlags;
882
883 //
884 // Allocate buffer for drive geometry.
885 //
886
887 diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX));
888
889 if (diskGeometry == NULL) {
890
891 DebugPrint((1,
892 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
893 status = STATUS_INSUFFICIENT_RESOURCES;
894 goto CreateDiskDeviceObjectsExit;
895 }
896
897 deviceExtension->DiskGeometry = diskGeometry;
898
899 //
900 // Allocate request sense buffer.
901 //
902
903 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
904
905 if (senseData == NULL) {
906
907 //
908 // The buffer can not be allocated.
909 //
910
911 DebugPrint((1,
912 "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
913
914 status = STATUS_INSUFFICIENT_RESOURCES;
915 goto CreateDiskDeviceObjectsExit;
916 }
917
918 //
919 // Set the sense data pointer in the device extension.
920 //
921
922 deviceExtension->SenseData = senseData;
923
924 //
925 // Physical device object will describe the entire
926 // device, starting at byte offset 0.
927 //
928
929 deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0);
930
931 //
932 // TargetId/LUN describes a device location on the SCSI bus.
933 // This information comes from the inquiry buffer.
934 //
935
936 deviceExtension->PortNumber = (UCHAR)PortNumber;
937 deviceExtension->PathId = pathId;
938 deviceExtension->TargetId = targetId;
939 deviceExtension->Lun = lun;
940
941 //
942 // Set timeout value in seconds.
943 //
944
945 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
946 if (timeOut) {
947 deviceExtension->TimeOutValue = timeOut;
948 } else {
949 deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
950 }
951
952 //
953 // Back pointer to device object.
954 //
955
956 deviceExtension->DeviceObject = deviceObject;
957
958 //
959 // If this is a removable device, then make sure it is not a floppy.
960 // Perform a mode sense command to determine the media type. Note
961 // IsFloppyDevice also checks for write cache enabled.
962 //
963
964 if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
965 (((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) {
966
967 status = STATUS_NO_SUCH_DEVICE;
968 goto CreateDiskDeviceObjectsExit;
969 }
970
971 DisableWriteCache(deviceObject,LunInfo);
972
973 //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
974
975 //
976 // NOTE: At this point one device object has been successfully created.
977 // from here on out return success.
978 //
979
980 //
981 // Do READ CAPACITY. This SCSI command
982 // returns the number of bytes on a device.
983 // Device extension is updated with device size.
984 //
985
986 status = ScsiClassReadDriveCapacity(deviceObject);
987
988 //
989 // If the read capcity failed then just return, unless this is a
990 // removable disk where a device object partition needs to be created.
991 //
992
993 if (!NT_SUCCESS(status) &&
994 !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
995
996 DebugPrint((1,
997 "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
998 ntNameBuffer));
999
1000 return(STATUS_SUCCESS);
1001
1002 } else {
1003
1004 //
1005 // Make sure the volume verification bit is off so that
1006 // IoReadPartitionTable will work.
1007 //
1008
1009 deviceObject->Flags &= ~DO_VERIFY_VOLUME;
1010 }
1011
1012 status = CreatePartitionDeviceObjects(deviceObject, RegistryPath);
1013
1014 if (NT_SUCCESS(status))
1015 return STATUS_SUCCESS;
1016
1017
1018 CreateDiskDeviceObjectsExit:
1019
1020 //
1021 // Release the device since an error occurred.
1022 //
1023
1024 ScsiClassClaimDevice(PortDeviceObject,
1025 LunInfo,
1026 TRUE,
1027 NULL);
1028
1029 if (diskGeometry != NULL) {
1030 ExFreePool(diskGeometry);
1031 }
1032
1033 if (senseData != NULL) {
1034 ExFreePool(senseData);
1035 }
1036
1037 if (deviceObject != NULL) {
1038
1039 if (srbListInitialized) {
1040 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
1041 }
1042
1043 IoDeleteDevice(deviceObject);
1044 }
1045
1046 //
1047 // Delete directory and return.
1048 //
1049
1050 if (!NT_SUCCESS(status)) {
1051 ZwMakeTemporaryObject(handle);
1052 }
1053
1054 ZwClose(handle);
1055
1056 return(status);
1057
1058 } // end CreateDiskDeviceObjects()
1059
1060 \f
1061 NTSTATUS
1062 NTAPI
1063 CreatePartitionDeviceObjects(
1064 IN PDEVICE_OBJECT PhysicalDeviceObject,
1065 IN PUNICODE_STRING RegistryPath
1066 )
1067 {
1068 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
1069 ULONG partitionNumber = 0;
1070 NTSTATUS status;
1071 PDEVICE_OBJECT deviceObject = NULL;
1072 PDISK_GEOMETRY_EX diskGeometry = NULL;
1073 PDRIVE_LAYOUT_INFORMATION partitionList = NULL;
1074 PDEVICE_EXTENSION deviceExtension;
1075 PDEVICE_EXTENSION physicalDeviceExtension;
1076 PCLASS_INIT_DATA initData = NULL;
1077 PDISK_DATA diskData;
1078 PDISK_DATA physicalDiskData;
1079 ULONG bytesPerSector;
1080 UCHAR sectorShift;
1081 ULONG srbFlags;
1082 ULONG dmByteSkew = 0;
1083 PULONG dmSkew;
1084 BOOLEAN dmActive = FALSE;
1085 ULONG numberListElements = 0;
1086
1087
1088 //
1089 // Get physical device geometry information for partition table reads.
1090 //
1091
1092 physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension;
1093 diskGeometry = physicalDeviceExtension->DiskGeometry;
1094 bytesPerSector = diskGeometry->Geometry.BytesPerSector;
1095
1096 //
1097 // Make sure sector size is not zero.
1098 //
1099
1100 if (bytesPerSector == 0) {
1101
1102 //
1103 // Default sector size for disk is 512.
1104 //
1105
1106 bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512;
1107 }
1108
1109 sectorShift = physicalDeviceExtension->SectorShift;
1110
1111 //
1112 // Set pointer to disk data area that follows device extension.
1113 //
1114
1115 diskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1116 diskData->PartitionListState = Initializing;
1117
1118 //
1119 // Determine is DM Driver is loaded on an IDE drive that is
1120 // under control of Atapi - this could be either a crashdump or
1121 // an Atapi device is sharing the controller with an IDE disk.
1122 //
1123
1124 HalExamineMBR(PhysicalDeviceObject,
1125 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1126 (ULONG)0x54,
1127 (PVOID)&dmSkew);
1128
1129 if (dmSkew) {
1130
1131 //
1132 // Update the device extension, so that the call to IoReadPartitionTable
1133 // will get the correct information. Any I/O to this disk will have
1134 // to be skewed by *dmSkew sectors aka DMByteSkew.
1135 //
1136
1137 physicalDeviceExtension->DMSkew = *dmSkew;
1138 physicalDeviceExtension->DMActive = TRUE;
1139 physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector;
1140
1141 //
1142 // Save away the infomation that we need, since this deviceExtension will soon be
1143 // blown away.
1144 //
1145
1146 dmActive = TRUE;
1147 dmByteSkew = physicalDeviceExtension->DMByteSkew;
1148
1149 }
1150
1151 //
1152 // Create objects for all the partitions on the device.
1153 //
1154
1155 status = IoReadPartitionTable(PhysicalDeviceObject,
1156 physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
1157 TRUE,
1158 (PVOID)&partitionList);
1159
1160 //
1161 // If the I/O read partition table failed and this is a removable device,
1162 // then fix up the partition list to make it look like there is one
1163 // zero length partition.
1164 //
1165 DPRINT("IoReadPartitionTable() status: 0x%08X\n", status);
1166 if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
1167 PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1168
1169 if (!NT_SUCCESS(status)) {
1170
1171 //
1172 // Remember this disk is not ready.
1173 //
1174
1175 diskData->DriveNotReady = TRUE;
1176
1177 } else {
1178
1179 //
1180 // Free the partition list allocated by IoReadPartitionTable.
1181 //
1182
1183 ExFreePool(partitionList);
1184 }
1185
1186 //
1187 // Allocate and zero a partition list.
1188 //
1189
1190 partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList));
1191
1192
1193 if (partitionList != NULL) {
1194
1195 RtlZeroMemory( partitionList, sizeof( *partitionList ));
1196
1197 //
1198 // Set the partition count to one and the status to success
1199 // so one device object will be created. Set the partition type
1200 // to a bogus value.
1201 //
1202
1203 partitionList->PartitionCount = 1;
1204
1205 status = STATUS_SUCCESS;
1206 }
1207 }
1208
1209 if (NT_SUCCESS(status)) {
1210
1211 //
1212 // Record disk signature.
1213 //
1214
1215 diskData->Signature = partitionList->Signature;
1216
1217 //
1218 // If disk signature is zero, then calculate the MBR checksum.
1219 //
1220
1221 if (!diskData->Signature) {
1222
1223 if (!CalculateMbrCheckSum(physicalDeviceExtension,
1224 &diskData->MbrCheckSum)) {
1225
1226 DebugPrint((1,
1227 "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
1228 physicalDeviceExtension->DeviceNumber));
1229 } else {
1230
1231 DebugPrint((2,
1232 "SCSIDISK: MBR checksum for disk %x is %x\n",
1233 physicalDeviceExtension->DeviceNumber,
1234 diskData->MbrCheckSum));
1235 }
1236 }
1237
1238 //
1239 // Check the registry and determine if the BIOS knew about this drive. If
1240 // it did then update the geometry with the BIOS information.
1241 //
1242
1243 UpdateGeometry(physicalDeviceExtension);
1244
1245 srbFlags = physicalDeviceExtension->SrbFlags;
1246
1247 initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA));
1248 if (!initData)
1249 {
1250 DebugPrint((1,
1251 "Disk.CreatePartionDeviceObjects - Allocation of initData failed\n"));
1252
1253 status = STATUS_INSUFFICIENT_RESOURCES;
1254 goto CreatePartitionDeviceObjectsExit;
1255 }
1256
1257 RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA));
1258
1259 initData->InitializationDataSize = sizeof(CLASS_INIT_DATA);
1260 initData->DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
1261 initData->DeviceType = FILE_DEVICE_DISK;
1262 initData->DeviceCharacteristics = PhysicalDeviceObject->Characteristics;
1263 initData->ClassError = physicalDeviceExtension->ClassError;
1264 initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification;
1265 initData->ClassFindDevices = physicalDeviceExtension->ClassFindDevices;
1266 initData->ClassDeviceControl = physicalDeviceExtension->ClassDeviceControl;
1267 initData->ClassShutdownFlush = physicalDeviceExtension->ClassShutdownFlush;
1268 initData->ClassCreateClose = physicalDeviceExtension->ClassCreateClose;
1269 initData->ClassStartIo = physicalDeviceExtension->ClassStartIo;
1270
1271 //
1272 // Create device objects for the device partitions (if any).
1273 // PartitionCount includes physical device partition 0,
1274 // so only one partition means no objects to create.
1275 //
1276
1277 DebugPrint((2,
1278 "CreateDiskDeviceObjects: Number of partitions is %d\n",
1279 partitionList->PartitionCount));
1280
1281 for (partitionNumber = 0; partitionNumber <
1282 partitionList->PartitionCount; partitionNumber++) {
1283
1284 //
1285 // Create partition object and set up partition parameters.
1286 //
1287
1288 sprintf(ntNameBuffer,
1289 "\\Device\\Harddisk%lu\\Partition%lu",
1290 physicalDeviceExtension->DeviceNumber,
1291 partitionNumber + 1);
1292
1293 DebugPrint((2,
1294 "CreateDiskDeviceObjects: Create device object %s\n",
1295 ntNameBuffer));
1296
1297 status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject,
1298 ntNameBuffer,
1299 PhysicalDeviceObject,
1300 &deviceObject,
1301 initData);
1302
1303 if (!NT_SUCCESS(status)) {
1304
1305 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer));
1306
1307 break;
1308 }
1309
1310 //
1311 // Set up device object fields.
1312 //
1313
1314 deviceObject->Flags |= DO_DIRECT_IO;
1315
1316 //
1317 // Check if this is during initialization. If not indicate that
1318 // system initialization already took place and this disk is ready
1319 // to be accessed.
1320 //
1321
1322 if (!RegistryPath) {
1323 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1324 }
1325
1326 deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1;
1327
1328 //
1329 // Set up device extension fields.
1330 //
1331
1332 deviceExtension = deviceObject->DeviceExtension;
1333
1334 if (dmActive) {
1335
1336 //
1337 // Restore any saved DM values.
1338 //
1339
1340 deviceExtension->DMByteSkew = dmByteSkew;
1341 deviceExtension->DMSkew = *dmSkew;
1342 deviceExtension->DMActive = TRUE;
1343
1344 }
1345
1346 //
1347 // Link new device extension to previous disk data
1348 // to support dynamic partitioning.
1349 //
1350
1351 diskData->NextPartition = deviceExtension;
1352
1353 //
1354 // Get pointer to new disk data.
1355 //
1356
1357 diskData = (PDISK_DATA)(deviceExtension + 1);
1358
1359 //
1360 // Set next partition pointer to NULL in case this is the
1361 // last partition.
1362 //
1363
1364 diskData->NextPartition = NULL;
1365
1366 //
1367 // Allocate spinlock for zoning for split-request completion.
1368 //
1369
1370 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
1371
1372 //
1373 // Copy port device object pointer to device extension.
1374 //
1375
1376 deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject;
1377
1378 //
1379 // Set the alignment requirements for the device based on the
1380 // host adapter requirements
1381 //
1382
1383 if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
1384 deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement;
1385 }
1386
1387
1388 if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
1389 numberListElements = 30;
1390 } else {
1391 numberListElements = 8;
1392 }
1393
1394 //
1395 // Build the lookaside list for srb's for this partition based on
1396 // whether the adapter and disk can do tagged queueing.
1397 //
1398
1399 ScsiClassInitializeSrbLookasideList(deviceExtension,
1400 numberListElements);
1401
1402 deviceExtension->SrbFlags = srbFlags;
1403
1404 //
1405 // Set the sense-data pointer in the device extension.
1406 //
1407
1408 deviceExtension->SenseData = physicalDeviceExtension->SenseData;
1409 deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities;
1410 deviceExtension->DiskGeometry = diskGeometry;
1411 diskData->PartitionOrdinal = diskData->PartitionNumber = partitionNumber + 1;
1412 diskData->PartitionType = partitionList->PartitionEntry[partitionNumber].PartitionType;
1413 diskData->BootIndicator = partitionList->PartitionEntry[partitionNumber].BootIndicator;
1414
1415 DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
1416 diskData->PartitionType));
1417
1418 deviceExtension->StartingOffset = partitionList->PartitionEntry[partitionNumber].StartingOffset;
1419 deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength;
1420 diskData->HiddenSectors = partitionList->PartitionEntry[partitionNumber].HiddenSectors;
1421 deviceExtension->PortNumber = physicalDeviceExtension->PortNumber;
1422 deviceExtension->PathId = physicalDeviceExtension->PathId;
1423 deviceExtension->TargetId = physicalDeviceExtension->TargetId;
1424 deviceExtension->Lun = physicalDeviceExtension->Lun;
1425
1426 //
1427 // Check for removable media support.
1428 //
1429
1430 if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1431 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
1432 }
1433
1434 //
1435 // Set timeout value in seconds.
1436 //
1437
1438 deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue;
1439 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector;
1440 deviceExtension->SectorShift = sectorShift;
1441 deviceExtension->DeviceObject = deviceObject;
1442 deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags;
1443
1444 } // end for (partitionNumber) ...
1445
1446 //
1447 // Free the buffer allocated by reading the
1448 // partition table.
1449 //
1450
1451 ExFreePool(partitionList);
1452
1453 if (dmSkew) {
1454 ExFreePool(dmSkew);
1455 }
1456
1457 } else {
1458
1459 CreatePartitionDeviceObjectsExit:
1460
1461 if (partitionList) {
1462 ExFreePool(partitionList);
1463 }
1464 if (initData) {
1465 ExFreePool(initData);
1466 }
1467
1468 if (dmSkew) {
1469 ExFreePool(dmSkew);
1470 }
1471
1472 return status;
1473
1474 } // end if...else
1475
1476
1477 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1478 physicalDiskData->PartitionListState = Initialized;
1479
1480 return(STATUS_SUCCESS);
1481
1482
1483 } // end CreatePartitionDeviceObjects()
1484
1485 \f
1486 NTSTATUS
1487 NTAPI
1488 ScsiDiskReadWriteVerification(
1489 IN PDEVICE_OBJECT DeviceObject,
1490 IN PIRP Irp
1491 )
1492
1493 /*++
1494
1495 Routine Description:
1496
1497 I/O System entry for read and write requests to SCSI disks.
1498
1499 Arguments:
1500
1501 DeviceObject - Pointer to driver object created by system.
1502 Irp - IRP involved.
1503
1504 Return Value:
1505
1506 NT Status
1507
1508 --*/
1509
1510 {
1511 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1512 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1513 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1514 LARGE_INTEGER startingOffset;
1515
1516 //
1517 // HACK: How can we end here with null sector size?!
1518 //
1519
1520 if (deviceExtension->DiskGeometry->Geometry.BytesPerSector == 0) {
1521 DPRINT1("Hack! Received invalid sector size\n");
1522 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512;
1523 }
1524
1525 //
1526 // Verify parameters of this request.
1527 // Check that ending sector is within partition and
1528 // that number of bytes to transfer is a multiple of
1529 // the sector size.
1530 //
1531
1532 startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
1533 transferByteCount);
1534
1535 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
1536 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
1537
1538 //
1539 // This error maybe caused by the fact that the drive is not ready.
1540 //
1541
1542 if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) {
1543
1544 //
1545 // Flag this as a user errror so that a popup is generated.
1546 //
1547
1548 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
1549 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1550
1551 } else {
1552
1553 //
1554 // Note fastfat depends on this parameter to determine when to
1555 // remount do to a sector size change.
1556 //
1557
1558 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1559 }
1560
1561 if (startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) {
1562 DPRINT1("Reading beyond partition end! startingOffset: %I64d, PartitionLength: %I64d\n", startingOffset.QuadPart, deviceExtension->PartitionLength.QuadPart);
1563 }
1564
1565 if (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1)) {
1566 DPRINT1("Not reading sectors! TransferByteCount: %lu, BytesPerSector: %lu\n", transferByteCount, deviceExtension->DiskGeometry->Geometry.BytesPerSector);
1567 }
1568
1569 if (Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) {
1570 DPRINT1("Failing due to device not ready!\n");
1571 }
1572
1573 return STATUS_INVALID_PARAMETER;
1574 }
1575
1576 return STATUS_SUCCESS;
1577
1578 } // end ScsiDiskReadWrite()
1579
1580 \f
1581 NTSTATUS
1582 NTAPI
1583 ScsiDiskDeviceControl(
1584 PDEVICE_OBJECT DeviceObject,
1585 PIRP Irp
1586 )
1587
1588 /*++
1589
1590 Routine Description:
1591
1592 I/O system entry for device controls to SCSI disks.
1593
1594 Arguments:
1595
1596 DeviceObject - Pointer to driver object created by system.
1597 Irp - IRP involved.
1598
1599 Return Value:
1600
1601 Status is returned.
1602
1603 --*/
1604
1605 {
1606 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1607 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1608 PDISK_DATA diskData = (PDISK_DATA)(deviceExtension + 1);
1609 PSCSI_REQUEST_BLOCK srb;
1610 PCDB cdb;
1611 PMODE_PARAMETER_HEADER modeData;
1612 PIRP irp2;
1613 ULONG length;
1614 NTSTATUS status;
1615 KEVENT event;
1616 IO_STATUS_BLOCK ioStatus;
1617
1618 PAGED_CODE();
1619
1620 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
1621
1622 if (srb == NULL) {
1623
1624 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1625 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1626 return(STATUS_INSUFFICIENT_RESOURCES);
1627 }
1628
1629 //
1630 // Write zeros to Srb.
1631 //
1632
1633 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1634
1635 cdb = (PCDB)srb->Cdb;
1636
1637 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1638
1639 case SMART_GET_VERSION: {
1640
1641 ULONG_PTR buffer;
1642 PSRB_IO_CONTROL srbControl;
1643 PGETVERSIONINPARAMS versionParams;
1644
1645 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1646 sizeof(GETVERSIONINPARAMS)) {
1647 status = STATUS_INVALID_PARAMETER;
1648 break;
1649 }
1650
1651 //
1652 // Create notification event object to be used to signal the
1653 // request completion.
1654 //
1655
1656 KeInitializeEvent(&event, NotificationEvent, FALSE);
1657
1658 srbControl = ExAllocatePool(NonPagedPool,
1659 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
1660
1661 if (!srbControl) {
1662 status = STATUS_INSUFFICIENT_RESOURCES;
1663 break;
1664 }
1665
1666 //
1667 // fill in srbControl fields
1668 //
1669
1670 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1671 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1672 srbControl->Timeout = deviceExtension->TimeOutValue;
1673 srbControl->Length = sizeof(GETVERSIONINPARAMS);
1674 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
1675
1676 //
1677 // Point to the 'buffer' portion of the SRB_CONTROL
1678 //
1679
1680 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1681
1682 //
1683 // Ensure correct target is set in the cmd parameters.
1684 //
1685
1686 versionParams = (PGETVERSIONINPARAMS)buffer;
1687 versionParams->bIDEDeviceMap = deviceExtension->TargetId;
1688
1689 //
1690 // Copy the IOCTL parameters to the srb control buffer area.
1691 //
1692
1693 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS));
1694
1695
1696 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1697 deviceExtension->PortDeviceObject,
1698 srbControl,
1699 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1700 srbControl,
1701 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1702 FALSE,
1703 &event,
1704 &ioStatus);
1705
1706 if (irp2 == NULL) {
1707 status = STATUS_INSUFFICIENT_RESOURCES;
1708 break;
1709 }
1710
1711 //
1712 // Call the port driver with the request and wait for it to complete.
1713 //
1714
1715 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1716
1717 if (status == STATUS_PENDING) {
1718 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1719 status = ioStatus.Status;
1720 }
1721
1722 //
1723 // If successful, copy the data received into the output buffer.
1724 // This should only fail in the event that the IDE driver is older than this driver.
1725 //
1726
1727 if (NT_SUCCESS(status)) {
1728
1729 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1730
1731 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS));
1732 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1733 }
1734
1735 ExFreePool(srbControl);
1736 break;
1737 }
1738
1739 case SMART_RCV_DRIVE_DATA: {
1740
1741 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1742 ULONG controlCode = 0;
1743 PSRB_IO_CONTROL srbControl;
1744 ULONG_PTR buffer;
1745
1746 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1747 (sizeof(SENDCMDINPARAMS) - 1)) {
1748 status = STATUS_INVALID_PARAMETER;
1749 break;
1750
1751 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1752 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
1753 status = STATUS_INVALID_PARAMETER;
1754 break;
1755 }
1756
1757 //
1758 // Create notification event object to be used to signal the
1759 // request completion.
1760 //
1761
1762 KeInitializeEvent(&event, NotificationEvent, FALSE);
1763
1764 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
1765
1766 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1767 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
1768
1769 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1770 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1771 case READ_ATTRIBUTES:
1772 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
1773 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1774 break;
1775 case READ_THRESHOLDS:
1776 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
1777 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1778 break;
1779 default:
1780 status = STATUS_INVALID_PARAMETER;
1781 break;
1782 }
1783 } else {
1784
1785 status = STATUS_INVALID_PARAMETER;
1786 }
1787
1788 if (controlCode == 0) {
1789 status = STATUS_INVALID_PARAMETER;
1790 break;
1791 }
1792
1793 srbControl = ExAllocatePool(NonPagedPool,
1794 sizeof(SRB_IO_CONTROL) + length);
1795
1796 if (!srbControl) {
1797 status = STATUS_INSUFFICIENT_RESOURCES;
1798 break;
1799 }
1800
1801 //
1802 // fill in srbControl fields
1803 //
1804
1805 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1806 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1807 srbControl->Timeout = deviceExtension->TimeOutValue;
1808 srbControl->Length = length;
1809 srbControl->ControlCode = controlCode;
1810
1811 //
1812 // Point to the 'buffer' portion of the SRB_CONTROL
1813 //
1814
1815 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1816
1817 //
1818 // Ensure correct target is set in the cmd parameters.
1819 //
1820
1821 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1822
1823 //
1824 // Copy the IOCTL parameters to the srb control buffer area.
1825 //
1826
1827 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1828
1829 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1830 deviceExtension->PortDeviceObject,
1831 srbControl,
1832 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1833 srbControl,
1834 sizeof(SRB_IO_CONTROL) + length,
1835 FALSE,
1836 &event,
1837 &ioStatus);
1838
1839 if (irp2 == NULL) {
1840 status = STATUS_INSUFFICIENT_RESOURCES;
1841 break;
1842 }
1843
1844 //
1845 // Call the port driver with the request and wait for it to complete.
1846 //
1847
1848 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1849
1850 if (status == STATUS_PENDING) {
1851 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1852 status = ioStatus.Status;
1853 }
1854
1855 //
1856 // If successful, copy the data received into the output buffer
1857 //
1858
1859 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1860
1861 if (NT_SUCCESS(status)) {
1862
1863 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1);
1864 Irp->IoStatus.Information = length - 1;
1865
1866 } else {
1867
1868 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
1869 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
1870
1871 }
1872
1873 ExFreePool(srbControl);
1874 break;
1875
1876 }
1877
1878 case SMART_SEND_DRIVE_COMMAND: {
1879
1880 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1881 PSRB_IO_CONTROL srbControl;
1882 ULONG controlCode = 0;
1883 ULONG_PTR buffer;
1884
1885 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1886 (sizeof(SENDCMDINPARAMS) - 1)) {
1887 status = STATUS_INVALID_PARAMETER;
1888 break;
1889
1890 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1891 (sizeof(SENDCMDOUTPARAMS) - 1)) {
1892 status = STATUS_INVALID_PARAMETER;
1893 break;
1894 }
1895
1896 //
1897 // Create notification event object to be used to signal the
1898 // request completion.
1899 //
1900
1901 KeInitializeEvent(&event, NotificationEvent, FALSE);
1902
1903 length = 0;
1904
1905 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1906 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1907
1908 case ENABLE_SMART:
1909 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
1910 break;
1911
1912 case DISABLE_SMART:
1913 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
1914 break;
1915
1916 case RETURN_SMART_STATUS:
1917
1918 //
1919 // Ensure bBuffer is at least 2 bytes (to hold the values of
1920 // cylinderLow and cylinderHigh).
1921 //
1922
1923 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1924 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
1925
1926 status = STATUS_INVALID_PARAMETER;
1927 break;
1928 }
1929
1930 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
1931 length = sizeof(IDEREGS);
1932 break;
1933
1934 case ENABLE_DISABLE_AUTOSAVE:
1935 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
1936 break;
1937
1938 case SAVE_ATTRIBUTE_VALUES:
1939 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
1940 break;
1941
1942 case EXECUTE_OFFLINE_DIAGS:
1943 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
1944 break;
1945
1946 default:
1947 status = STATUS_INVALID_PARAMETER;
1948 break;
1949 }
1950 } else {
1951
1952 status = STATUS_INVALID_PARAMETER;
1953 }
1954
1955 if (controlCode == 0) {
1956 status = STATUS_INVALID_PARAMETER;
1957 break;
1958 }
1959
1960 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);
1961 srbControl = ExAllocatePool(NonPagedPool,
1962 sizeof(SRB_IO_CONTROL) + length);
1963
1964 if (!srbControl) {
1965 status = STATUS_INSUFFICIENT_RESOURCES;
1966 break;
1967 }
1968
1969 //
1970 // fill in srbControl fields
1971 //
1972
1973 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1974 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1975 srbControl->Timeout = deviceExtension->TimeOutValue;
1976 srbControl->Length = length;
1977
1978 //
1979 // Point to the 'buffer' portion of the SRB_CONTROL
1980 //
1981
1982 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1983
1984 //
1985 // Ensure correct target is set in the cmd parameters.
1986 //
1987
1988 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1989
1990 //
1991 // Copy the IOCTL parameters to the srb control buffer area.
1992 //
1993
1994 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1995
1996 srbControl->ControlCode = controlCode;
1997
1998 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1999 deviceExtension->PortDeviceObject,
2000 srbControl,
2001 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
2002 srbControl,
2003 sizeof(SRB_IO_CONTROL) + length,
2004 FALSE,
2005 &event,
2006 &ioStatus);
2007
2008 if (irp2 == NULL) {
2009 status = STATUS_INSUFFICIENT_RESOURCES;
2010 break;
2011 }
2012
2013 //
2014 // Call the port driver with the request and wait for it to complete.
2015 //
2016
2017 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2018
2019 if (status == STATUS_PENDING) {
2020 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
2021 status = ioStatus.Status;
2022 }
2023
2024 //
2025 // Copy the data received into the output buffer. Since the status buffer
2026 // contains error information also, always perform this copy. IO will will
2027 // either pass this back to the app, or zero it, in case of error.
2028 //
2029
2030 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
2031
2032 //
2033 // Update the return buffer size based on the sub-command.
2034 //
2035
2036 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
2037 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
2038 } else {
2039 length = sizeof(SENDCMDOUTPARAMS) - 1;
2040 }
2041
2042 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length);
2043 Irp->IoStatus.Information = length;
2044
2045 ExFreePool(srbControl);
2046 break;
2047
2048 }
2049
2050 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
2051 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
2052 {
2053
2054 PDEVICE_EXTENSION physicalDeviceExtension;
2055 PDISK_DATA physicalDiskData;
2056 BOOLEAN removable = FALSE;
2057 BOOLEAN listInitialized = FALSE;
2058
2059 if ((irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY &&
2060 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2061 sizeof(DISK_GEOMETRY)) ||
2062 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX &&
2063 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2064 sizeof(DISK_GEOMETRY_EX))) {
2065
2066 status = STATUS_INFO_LENGTH_MISMATCH;
2067 break;
2068 }
2069
2070 status = STATUS_SUCCESS;
2071
2072 physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2073 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
2074
2075 removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA;
2076 listInitialized = (physicalDiskData->PartitionListState == Initialized);
2077
2078 if (removable || (!listInitialized))
2079 {
2080 //
2081 // Issue ReadCapacity to update device extension
2082 // with information for current media.
2083 //
2084
2085 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
2086
2087 }
2088
2089 if (removable) {
2090
2091 if (!NT_SUCCESS(status)) {
2092
2093 //
2094 // Note the drive is not ready.
2095 //
2096
2097 diskData->DriveNotReady = TRUE;
2098
2099 break;
2100 }
2101
2102 //
2103 // Note the drive is now ready.
2104 //
2105
2106 diskData->DriveNotReady = FALSE;
2107
2108 } else if (NT_SUCCESS(status)) {
2109
2110 // ReadDriveCapacity was allright, create Partition Objects
2111
2112 if (physicalDiskData->PartitionListState == NotInitialized) {
2113 status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL);
2114 }
2115 }
2116
2117 if (NT_SUCCESS(status)) {
2118
2119 //
2120 // Copy drive geometry information from device extension.
2121 //
2122
2123 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2124 deviceExtension->DiskGeometry,
2125 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2126 sizeof(DISK_GEOMETRY) :
2127 sizeof(DISK_GEOMETRY_EX));
2128
2129 status = STATUS_SUCCESS;
2130 Irp->IoStatus.Information =
2131 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2132 sizeof(DISK_GEOMETRY) :
2133 sizeof(DISK_GEOMETRY_EX);
2134 }
2135
2136 break;
2137
2138 }
2139
2140 case IOCTL_DISK_VERIFY:
2141
2142 {
2143
2144 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2145 LARGE_INTEGER byteOffset;
2146 ULONG sectorOffset;
2147 USHORT sectorCount;
2148
2149 //
2150 // Validate buffer length.
2151 //
2152
2153 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2154 sizeof(VERIFY_INFORMATION)) {
2155
2156 status = STATUS_INFO_LENGTH_MISMATCH;
2157 break;
2158 }
2159
2160 //
2161 // Verify sectors
2162 //
2163
2164 srb->CdbLength = 10;
2165
2166 cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2167
2168 //
2169 // Add disk offset to starting sector.
2170 //
2171
2172 byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart +
2173 verifyInfo->StartingOffset.QuadPart;
2174
2175 //
2176 // Convert byte offset to sector offset.
2177 //
2178
2179 sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift);
2180
2181 //
2182 // Convert ULONG byte count to USHORT sector count.
2183 //
2184
2185 sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift);
2186
2187 //
2188 // Move little endian values into CDB in big endian format.
2189 //
2190
2191 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2192 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2193 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2194 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2195
2196 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
2197 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
2198
2199 //
2200 // The verify command is used by the NT FORMAT utility and
2201 // requests are sent down for 5% of the volume size. The
2202 // request timeout value is calculated based on the number of
2203 // sectors verified.
2204 //
2205
2206 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
2207 deviceExtension->TimeOutValue;
2208
2209 status = ScsiClassSendSrbAsynchronous(DeviceObject,
2210 srb,
2211 Irp,
2212 NULL,
2213 0,
2214 FALSE);
2215
2216 return(status);
2217
2218 }
2219
2220 case IOCTL_DISK_GET_PARTITION_INFO:
2221
2222 //
2223 // Return the information about the partition specified by the device
2224 // object. Note that no information is ever returned about the size
2225 // or partition type of the physical disk, as this doesn't make any
2226 // sense.
2227 //
2228
2229 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2230 sizeof(PARTITION_INFORMATION)) {
2231
2232 status = STATUS_INFO_LENGTH_MISMATCH;
2233
2234 }
2235 #if 0 // HACK: ReactOS partition numbers must be wrong
2236 else if (diskData->PartitionNumber == 0) {
2237
2238 //
2239 // Paritition zero is not a partition so this is not a
2240 // reasonable request.
2241 //
2242
2243 status = STATUS_INVALID_DEVICE_REQUEST;
2244
2245 }
2246 #endif
2247 else {
2248
2249 PPARTITION_INFORMATION outputBuffer;
2250
2251 if (diskData->PartitionNumber == 0) {
2252 DPRINT1("HACK: Handling partition 0 request!\n");
2253 //ASSERT(FALSE);
2254 }
2255
2256 //
2257 // Update the geometry in case it has changed.
2258 //
2259
2260 status = UpdateRemovableGeometry (DeviceObject, Irp);
2261
2262 if (!NT_SUCCESS(status)) {
2263
2264 //
2265 // Note the drive is not ready.
2266 //
2267
2268 diskData->DriveNotReady = TRUE;
2269 break;
2270 }
2271
2272 //
2273 // Note the drive is now ready.
2274 //
2275
2276 diskData->DriveNotReady = FALSE;
2277
2278 outputBuffer =
2279 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2280
2281 outputBuffer->PartitionType = diskData->PartitionType;
2282 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2283 outputBuffer->PartitionLength.QuadPart = (diskData->PartitionNumber) ?
2284 deviceExtension->PartitionLength.QuadPart : 2305843009213693951LL; // HACK
2285 outputBuffer->HiddenSectors = diskData->HiddenSectors;
2286 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2287 outputBuffer->BootIndicator = diskData->BootIndicator;
2288 outputBuffer->RewritePartition = FALSE;
2289 outputBuffer->RecognizedPartition =
2290 IsRecognizedPartition(diskData->PartitionType);
2291
2292 status = STATUS_SUCCESS;
2293 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
2294 }
2295
2296 break;
2297
2298 case IOCTL_DISK_GET_PARTITION_INFO_EX:
2299
2300 //
2301 // Return the information about the partition specified by the device
2302 // object. Note that no information is ever returned about the size
2303 // or partition type of the physical disk, as this doesn't make any
2304 // sense.
2305 //
2306
2307 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2308 sizeof(PARTITION_INFORMATION_EX)) {
2309
2310 status = STATUS_INFO_LENGTH_MISMATCH;
2311
2312 }
2313 else if (diskData->PartitionNumber == 0) {
2314
2315 //
2316 // Paritition zero is not a partition so this is not a
2317 // reasonable request.
2318 //
2319
2320 status = STATUS_INVALID_DEVICE_REQUEST;
2321
2322 }
2323 else {
2324
2325 PPARTITION_INFORMATION_EX outputBuffer;
2326
2327 //
2328 // Update the geometry in case it has changed.
2329 //
2330
2331 status = UpdateRemovableGeometry (DeviceObject, Irp);
2332
2333 if (!NT_SUCCESS(status)) {
2334
2335 //
2336 // Note the drive is not ready.
2337 //
2338
2339 diskData->DriveNotReady = TRUE;
2340 break;
2341 }
2342
2343 //
2344 // Note the drive is now ready.
2345 //
2346
2347 diskData->DriveNotReady = FALSE;
2348
2349 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2350
2351 status = STATUS_INVALID_DEVICE_REQUEST;
2352 break;
2353 }
2354
2355 outputBuffer =
2356 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
2357
2358 //
2359 // FIXME: hack of the year, assume that partition is MBR
2360 // Thing that can obviously be wrong...
2361 //
2362
2363 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
2364 outputBuffer->Mbr.PartitionType = diskData->PartitionType;
2365 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2366 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2367 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors;
2368 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2369 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator;
2370 outputBuffer->RewritePartition = FALSE;
2371 outputBuffer->Mbr.RecognizedPartition =
2372 IsRecognizedPartition(diskData->PartitionType);
2373
2374 status = STATUS_SUCCESS;
2375 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
2376 }
2377
2378 break;
2379
2380 case IOCTL_DISK_SET_PARTITION_INFO:
2381
2382 if (diskData->PartitionNumber == 0) {
2383
2384 status = STATUS_UNSUCCESSFUL;
2385
2386 } else {
2387
2388 PSET_PARTITION_INFORMATION inputBuffer =
2389 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2390
2391 //
2392 // Validate buffer length.
2393 //
2394
2395 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2396 sizeof(SET_PARTITION_INFORMATION)) {
2397
2398 status = STATUS_INFO_LENGTH_MISMATCH;
2399 break;
2400 }
2401
2402 //
2403 // The HAL routines IoGet- and IoSetPartitionInformation were
2404 // developed before support of dynamic partitioning and therefore
2405 // don't distinguish between partition ordinal (that is the order
2406 // of a partition on a disk) and the partition number. (The
2407 // partition number is assigned to a partition to identify it to
2408 // the system.) Use partition ordinals for these legacy calls.
2409 //
2410
2411 status = IoSetPartitionInformation(
2412 deviceExtension->PhysicalDevice,
2413 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2414 diskData->PartitionOrdinal,
2415 inputBuffer->PartitionType);
2416
2417 if (NT_SUCCESS(status)) {
2418
2419 diskData->PartitionType = inputBuffer->PartitionType;
2420 }
2421 }
2422
2423 break;
2424
2425 case IOCTL_DISK_GET_DRIVE_LAYOUT:
2426
2427 //
2428 // Return the partition layout for the physical drive. Note that
2429 // the layout is returned for the actual physical drive, regardless
2430 // of which partition was specified for the request.
2431 //
2432
2433 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2434 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2435 status = STATUS_INFO_LENGTH_MISMATCH;
2436
2437 } else {
2438
2439 PDRIVE_LAYOUT_INFORMATION partitionList;
2440 PDEVICE_EXTENSION physicalExtension = deviceExtension;
2441 PPARTITION_INFORMATION partitionEntry;
2442 PDISK_DATA diskData;
2443 ULONG tempSize;
2444 ULONG i;
2445
2446 //
2447 // Read partition information.
2448 //
2449
2450 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
2451 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2452 FALSE,
2453 &partitionList);
2454
2455 if (!NT_SUCCESS(status)) {
2456 break;
2457 }
2458
2459 //
2460 // The disk layout has been returned in the partitionList
2461 // buffer. Determine its size and, if the data will fit
2462 // into the intermediatery buffer, return it.
2463 //
2464
2465 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
2466 tempSize += partitionList->PartitionCount *
2467 sizeof(PARTITION_INFORMATION);
2468
2469 if (tempSize >
2470 irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
2471
2472 status = STATUS_BUFFER_TOO_SMALL;
2473 ExFreePool(partitionList);
2474 break;
2475 }
2476
2477 //
2478 // Walk partition list to associate partition numbers with
2479 // partition entries.
2480 //
2481
2482 for (i = 0; i < partitionList->PartitionCount; i++) {
2483
2484 //
2485 // Walk partition chain anchored at physical disk extension.
2486 //
2487
2488 deviceExtension = physicalExtension;
2489 diskData = (PDISK_DATA)(deviceExtension + 1);
2490
2491 do {
2492
2493 deviceExtension = diskData->NextPartition;
2494
2495 //
2496 // Check if this is the last partition in the chain.
2497 //
2498
2499 if (!deviceExtension) {
2500 break;
2501 }
2502
2503 //
2504 // Get the partition device extension from disk data.
2505 //
2506
2507 diskData = (PDISK_DATA)(deviceExtension + 1);
2508
2509 //
2510 // Check if this partition is not currently being used.
2511 //
2512
2513 if (!deviceExtension->PartitionLength.QuadPart) {
2514 continue;
2515 }
2516
2517 partitionEntry = &partitionList->PartitionEntry[i];
2518
2519 //
2520 // Check if empty, or describes extended partiton or hasn't changed.
2521 //
2522
2523 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2524 IsContainerPartition(partitionEntry->PartitionType)) {
2525 continue;
2526 }
2527
2528 //
2529 // Check if new partition starts where this partition starts.
2530 //
2531
2532 if (partitionEntry->StartingOffset.QuadPart !=
2533 deviceExtension->StartingOffset.QuadPart) {
2534 continue;
2535 }
2536
2537 //
2538 // Check if partition length is the same.
2539 //
2540
2541 if (partitionEntry->PartitionLength.QuadPart ==
2542 deviceExtension->PartitionLength.QuadPart) {
2543
2544 //
2545 // Partitions match. Update partition number.
2546 //
2547
2548 partitionEntry->PartitionNumber =
2549 diskData->PartitionNumber;
2550 break;
2551 }
2552
2553 } while (TRUE);
2554 }
2555
2556 //
2557 // Copy partition information to system buffer.
2558 //
2559
2560 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2561 partitionList,
2562 tempSize);
2563 status = STATUS_SUCCESS;
2564 Irp->IoStatus.Information = tempSize;
2565
2566 //
2567 // Finally, free the buffer allocated by reading the
2568 // partition table.
2569 //
2570
2571 ExFreePool(partitionList);
2572 }
2573
2574 break;
2575
2576 case IOCTL_DISK_SET_DRIVE_LAYOUT:
2577
2578 {
2579
2580 //
2581 // Update the disk with new partition information.
2582 //
2583
2584 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
2585
2586 //
2587 // Validate buffer length.
2588 //
2589
2590 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2591 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2592
2593 status = STATUS_INFO_LENGTH_MISMATCH;
2594 break;
2595 }
2596
2597 length = sizeof(DRIVE_LAYOUT_INFORMATION) +
2598 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
2599
2600
2601 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2602 length) {
2603
2604 status = STATUS_BUFFER_TOO_SMALL;
2605 break;
2606 }
2607
2608 //
2609 // Verify that device object is for physical disk.
2610 //
2611
2612 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
2613 status = STATUS_INVALID_PARAMETER;
2614 break;
2615 }
2616
2617 //
2618 // Walk through partition table comparing partitions to
2619 // existing partitions to create, delete and change
2620 // device objects as necessary.
2621 //
2622
2623 UpdateDeviceObjects(DeviceObject,
2624 Irp);
2625
2626 //
2627 // Write changes to disk.
2628 //
2629
2630 status = IoWritePartitionTable(
2631 deviceExtension->DeviceObject,
2632 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2633 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
2634 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
2635 partitionList);
2636 }
2637
2638 //
2639 // Update IRP with bytes returned.
2640 //
2641
2642 if (NT_SUCCESS(status)) {
2643 Irp->IoStatus.Information = length;
2644 }
2645
2646 break;
2647
2648 case IOCTL_DISK_REASSIGN_BLOCKS:
2649
2650 //
2651 // Map defective blocks to new location on disk.
2652 //
2653
2654 {
2655
2656 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2657 ULONG bufferSize;
2658 ULONG blockNumber;
2659 ULONG blockCount;
2660
2661 //
2662 // Validate buffer length.
2663 //
2664
2665 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2666 sizeof(REASSIGN_BLOCKS)) {
2667
2668 status = STATUS_INFO_LENGTH_MISMATCH;
2669 break;
2670 }
2671
2672 bufferSize = sizeof(REASSIGN_BLOCKS) +
2673 (badBlocks->Count - 1) * sizeof(ULONG);
2674
2675 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2676 bufferSize) {
2677
2678 status = STATUS_INFO_LENGTH_MISMATCH;
2679 break;
2680 }
2681
2682 //
2683 // Build the data buffer to be transferred in the input buffer.
2684 // The format of the data to the device is:
2685 //
2686 // 2 bytes Reserved
2687 // 2 bytes Length
2688 // x * 4 btyes Block Address
2689 //
2690 // All values are big endian.
2691 //
2692
2693 badBlocks->Reserved = 0;
2694 blockCount = badBlocks->Count;
2695
2696 //
2697 // Convert # of entries to # of bytes.
2698 //
2699
2700 blockCount *= 4;
2701 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2702 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2703
2704 //
2705 // Convert back to number of entries.
2706 //
2707
2708 blockCount /= 4;
2709
2710 for (; blockCount > 0; blockCount--) {
2711
2712 blockNumber = badBlocks->BlockNumber[blockCount-1];
2713
2714 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2715 (PFOUR_BYTE) &blockNumber);
2716 }
2717
2718 srb->CdbLength = 6;
2719
2720 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2721
2722 //
2723 // Set timeout value.
2724 //
2725
2726 srb->TimeOutValue = deviceExtension->TimeOutValue;
2727
2728 status = ScsiClassSendSrbSynchronous(DeviceObject,
2729 srb,
2730 badBlocks,
2731 bufferSize,
2732 TRUE);
2733
2734 Irp->IoStatus.Status = status;
2735 Irp->IoStatus.Information = 0;
2736 ExFreePool(srb);
2737 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2738 }
2739
2740 return(status);
2741
2742 case IOCTL_DISK_IS_WRITABLE:
2743
2744 //
2745 // Determine if the device is writable.
2746 //
2747
2748 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
2749
2750 if (modeData == NULL) {
2751 status = STATUS_INSUFFICIENT_RESOURCES;
2752 break;
2753 }
2754
2755 RtlZeroMemory(modeData, MODE_DATA_SIZE);
2756
2757 length = ScsiClassModeSense(DeviceObject,
2758 (PCHAR) modeData,
2759 MODE_DATA_SIZE,
2760 MODE_SENSE_RETURN_ALL);
2761
2762 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2763
2764 //
2765 // Retry the request in case of a check condition.
2766 //
2767
2768 length = ScsiClassModeSense(DeviceObject,
2769 (PCHAR) modeData,
2770 MODE_DATA_SIZE,
2771 MODE_SENSE_RETURN_ALL);
2772
2773 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2774 status = STATUS_IO_DEVICE_ERROR;
2775 ExFreePool(modeData);
2776 break;
2777 }
2778 }
2779
2780 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
2781 status = STATUS_MEDIA_WRITE_PROTECTED;
2782 } else {
2783 status = STATUS_SUCCESS;
2784 }
2785
2786 ExFreePool(modeData);
2787 break;
2788
2789 case IOCTL_DISK_INTERNAL_SET_VERIFY:
2790
2791 //
2792 // If the caller is kernel mode, set the verify bit.
2793 //
2794
2795 if (Irp->RequestorMode == KernelMode) {
2796 DeviceObject->Flags |= DO_VERIFY_VOLUME;
2797 }
2798 status = STATUS_SUCCESS;
2799 break;
2800
2801 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
2802
2803 //
2804 // If the caller is kernel mode, clear the verify bit.
2805 //
2806
2807 if (Irp->RequestorMode == KernelMode) {
2808 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
2809 }
2810 status = STATUS_SUCCESS;
2811 break;
2812
2813 case IOCTL_DISK_FIND_NEW_DEVICES:
2814
2815 //
2816 // Search for devices that have been powered on since the last
2817 // device search or system initialization.
2818 //
2819
2820 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2821 status = DriverEntry(DeviceObject->DriverObject,
2822 NULL);
2823
2824 Irp->IoStatus.Status = status;
2825 ExFreePool(srb);
2826 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2827 return status;
2828
2829 case IOCTL_DISK_MEDIA_REMOVAL:
2830
2831 //
2832 // If the disk is not removable then don't allow this command.
2833 //
2834
2835 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
2836 status = STATUS_INVALID_DEVICE_REQUEST;
2837 break;
2838 }
2839
2840 //
2841 // Fall through and let the class driver process the request.
2842 //
2843
2844 case IOCTL_DISK_GET_LENGTH_INFO:
2845
2846 //
2847 // Validate buffer length.
2848 //
2849
2850 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2851 sizeof(GET_LENGTH_INFORMATION)) {
2852 status = STATUS_BUFFER_TOO_SMALL;
2853
2854 } else {
2855
2856 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer;
2857
2858 //
2859 // Update the geometry in case it has changed.
2860 //
2861
2862 status = UpdateRemovableGeometry (DeviceObject, Irp);
2863
2864 if (!NT_SUCCESS(status)) {
2865
2866 //
2867 // Note the drive is not ready.
2868 //
2869
2870 diskData->DriveNotReady = TRUE;
2871 break;
2872 }
2873
2874 //
2875 // Note the drive is now ready.
2876 //
2877
2878 diskData->DriveNotReady = FALSE;
2879
2880 //
2881 // Output data, and return
2882 //
2883
2884 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart;
2885 status = STATUS_SUCCESS;
2886 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
2887 }
2888
2889 break;
2890
2891 default:
2892
2893 //
2894 // Free the Srb, since it is not needed.
2895 //
2896
2897 ExFreePool(srb);
2898
2899 //
2900 // Pass the request to the common device control routine.
2901 //
2902
2903 return(ScsiClassDeviceControl(DeviceObject, Irp));
2904
2905 break;
2906
2907 } // end switch( ...
2908
2909 Irp->IoStatus.Status = status;
2910
2911 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
2912
2913 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
2914 }
2915
2916 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2917 ExFreePool(srb);
2918 return(status);
2919
2920 } // end ScsiDiskDeviceControl()
2921 \f
2922 NTSTATUS
2923 NTAPI
2924 ScsiDiskShutdownFlush (
2925 IN PDEVICE_OBJECT DeviceObject,
2926 IN PIRP Irp
2927 )
2928
2929 /*++
2930
2931 Routine Description:
2932
2933 This routine is called for a shutdown and flush IRPs. These are sent by the
2934 system before it actually shuts down or when the file system does a flush.
2935 A synchronize cache command is sent to the device if it is write caching.
2936 If the device is removable an unlock command will be sent. This routine
2937 will sent a shutdown or flush Srb to the port driver.
2938
2939 Arguments:
2940
2941 DriverObject - Pointer to device object to being shutdown by system.
2942
2943 Irp - IRP involved.
2944
2945 Return Value:
2946
2947 NT Status
2948
2949 --*/
2950
2951 {
2952 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2953 PIO_STACK_LOCATION irpStack;
2954 PSCSI_REQUEST_BLOCK srb;
2955 NTSTATUS status;
2956 PCDB cdb;
2957
2958 //
2959 // Allocate SCSI request block.
2960 //
2961
2962 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
2963
2964 if (srb == NULL) {
2965
2966 //
2967 // Set the status and complete the request.
2968 //
2969
2970 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2971 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2972 return(STATUS_INSUFFICIENT_RESOURCES);
2973 }
2974
2975 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2976
2977 //
2978 // Write length to SRB.
2979 //
2980
2981 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2982
2983 //
2984 // Set SCSI bus address.
2985 //
2986
2987 srb->PathId = deviceExtension->PathId;
2988 srb->TargetId = deviceExtension->TargetId;
2989 srb->Lun = deviceExtension->Lun;
2990
2991 //
2992 // Set timeout value and mark the request as not being a tagged request.
2993 //
2994
2995 srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
2996 srb->QueueTag = SP_UNTAGGED;
2997 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
2998 srb->SrbFlags = deviceExtension->SrbFlags;
2999
3000 //
3001 // If the write cache is enabled then send a synchronize cache request.
3002 //
3003
3004 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
3005
3006 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3007 srb->CdbLength = 10;
3008
3009 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
3010
3011 status = ScsiClassSendSrbSynchronous(DeviceObject,
3012 srb,
3013 NULL,
3014 0,
3015 TRUE);
3016
3017 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status ));
3018 }
3019
3020 //
3021 // Unlock the device if it is removable and this is a shutdown.
3022 //
3023
3024 irpStack = IoGetCurrentIrpStackLocation(Irp);
3025
3026 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
3027 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
3028
3029 srb->CdbLength = 6;
3030 cdb = (PVOID) srb->Cdb;
3031 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3032 cdb->MEDIA_REMOVAL.Prevent = FALSE;
3033
3034 //
3035 // Set timeout value.
3036 //
3037
3038 srb->TimeOutValue = deviceExtension->TimeOutValue;
3039 status = ScsiClassSendSrbSynchronous(DeviceObject,
3040 srb,
3041 NULL,
3042 0,
3043 TRUE);
3044
3045 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
3046 }
3047
3048 srb->CdbLength = 0;
3049
3050 //
3051 // Save a few parameters in the current stack location.
3052 //
3053
3054 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
3055 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
3056
3057 //
3058 // Set the retry count to zero.
3059 //
3060
3061 irpStack->Parameters.Others.Argument4 = (PVOID) 0;
3062
3063 //
3064 // Set up IoCompletion routine address.
3065 //
3066
3067 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
3068
3069 //
3070 // Get next stack location and
3071 // set major function code.
3072 //
3073
3074 irpStack = IoGetNextIrpStackLocation(Irp);
3075
3076 irpStack->MajorFunction = IRP_MJ_SCSI;
3077
3078 //
3079 // Set up SRB for execute scsi request.
3080 // Save SRB address in next stack for port driver.
3081 //
3082
3083 irpStack->Parameters.Scsi.Srb = srb;
3084
3085 //
3086 // Set up Irp Address.
3087 //
3088
3089 srb->OriginalRequest = Irp;
3090
3091 //
3092 // Call the port driver to process the request.
3093 //
3094
3095 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3096
3097 } // end ScsiDiskShutdown()
3098
3099 \f
3100 BOOLEAN
3101 NTAPI
3102 IsFloppyDevice(
3103 PDEVICE_OBJECT DeviceObject
3104 )
3105 /*++
3106
3107 Routine Description:
3108
3109 The routine performs the necessary functions to determine if a device is
3110 really a floppy rather than a harddisk. This is done by a mode sense
3111 command. First, a check is made to see if the medimum type is set. Second
3112 a check is made for the flexible parameters mode page. Also a check is
3113 made to see if the write cache is enabled.
3114
3115 Arguments:
3116
3117 DeviceObject - Supplies the device object to be tested.
3118
3119 Return Value:
3120
3121 Return TRUE if the indicated device is a floppy.
3122
3123 --*/
3124 {
3125 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3126 PVOID modeData;
3127 PUCHAR pageData;
3128 ULONG length;
3129
3130 PAGED_CODE();
3131
3132 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3133
3134 if (modeData == NULL) {
3135 return(FALSE);
3136 }
3137
3138 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3139
3140 length = ScsiClassModeSense(DeviceObject,
3141 modeData,
3142 MODE_DATA_SIZE,
3143 MODE_SENSE_RETURN_ALL);
3144
3145 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3146
3147 //
3148 // Retry the request in case of a check condition.
3149 //
3150
3151 length = ScsiClassModeSense(DeviceObject,
3152 modeData,
3153 MODE_DATA_SIZE,
3154 MODE_SENSE_RETURN_ALL);
3155
3156 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3157
3158 ExFreePool(modeData);
3159 return(FALSE);
3160
3161 }
3162 }
3163
3164 //
3165 // If the length is greater than length indicated by the mode data reset
3166 // the data to the mode data.
3167 //
3168
3169 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3170 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3171 }
3172
3173 //
3174 // Look for the flexible disk mode page.
3175 //
3176
3177 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
3178
3179 if (pageData != NULL) {
3180
3181 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3182 ExFreePool(modeData);
3183 return(TRUE);
3184 }
3185
3186 //
3187 // Check to see if the write cache is enabled.
3188 //
3189
3190 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3191
3192 //
3193 // Assume that write cache is disabled or not supported.
3194 //
3195
3196 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3197
3198 //
3199 // Check if valid caching page exists.
3200 //
3201
3202 if (pageData != NULL) {
3203
3204 //
3205 // Check if write cache is disabled.
3206 //
3207
3208 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3209
3210 DebugPrint((1,
3211 "SCSIDISK: Disk write cache enabled\n"));
3212
3213 //
3214 // Check if forced unit access (FUA) is supported.
3215 //
3216
3217 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
3218
3219 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3220
3221 } else {
3222
3223 DebugPrint((1,
3224 "SCSIDISK: Disk does not support FUA or DPO\n"));
3225
3226 //
3227 // TODO: Log this.
3228 //
3229
3230 }
3231 }
3232 }
3233
3234 ExFreePool(modeData);
3235 return(FALSE);
3236
3237 } // end IsFloppyDevice()
3238
3239 \f
3240 BOOLEAN
3241 NTAPI
3242 ScsiDiskModeSelect(
3243 IN PDEVICE_OBJECT DeviceObject,
3244 IN PCHAR ModeSelectBuffer,
3245 IN ULONG Length,
3246 IN BOOLEAN SavePage
3247 )
3248
3249 /*++
3250
3251 Routine Description:
3252
3253 This routine sends a mode select command.
3254
3255 Arguments:
3256
3257 DeviceObject - Supplies the device object associated with this request.
3258
3259 ModeSelectBuffer - Supplies a buffer containing the page data.
3260
3261 Length - Supplies the length in bytes of the mode select buffer.
3262
3263 SavePage - Indicates that parameters should be written to disk.
3264
3265 Return Value:
3266
3267 Length of the transferred data is returned.
3268
3269 --*/
3270 {
3271 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3272 PCDB cdb;
3273 SCSI_REQUEST_BLOCK srb;
3274 ULONG retries = 1;
3275 ULONG length2;
3276 NTSTATUS status;
3277 ULONG_PTR buffer;
3278 PMODE_PARAMETER_BLOCK blockDescriptor;
3279
3280 PAGED_CODE();
3281
3282 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
3283
3284 //
3285 // Allocate buffer for mode select header, block descriptor, and mode page.
3286 //
3287
3288 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
3289
3290 RtlZeroMemory((PVOID)buffer, length2);
3291
3292 //
3293 // Set length in header to size of mode page.
3294 //
3295
3296 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
3297
3298 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
3299
3300 //
3301 // Set size
3302 //
3303
3304 blockDescriptor->BlockLength[1]=0x02;
3305
3306 //
3307 // Copy mode page to buffer.
3308 //
3309
3310 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
3311
3312 //
3313 // Zero SRB.
3314 //
3315
3316 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3317
3318 //
3319 // Build the MODE SELECT CDB.
3320 //
3321
3322 srb.CdbLength = 6;
3323 cdb = (PCDB)srb.Cdb;
3324
3325 //
3326 // Set timeout value from device extension.
3327 //
3328
3329 srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
3330
3331 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3332 cdb->MODE_SELECT.SPBit = SavePage;
3333 cdb->MODE_SELECT.PFBit = 1;
3334 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
3335
3336 Retry:
3337
3338 status = ScsiClassSendSrbSynchronous(DeviceObject,
3339 &srb,
3340 (PVOID)buffer,
3341 length2,
3342 TRUE);
3343
3344
3345 if (status == STATUS_VERIFY_REQUIRED) {
3346
3347 //
3348 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3349 // this status.
3350 //
3351
3352 if (retries--) {
3353
3354 //
3355 // Retry request.
3356 //
3357
3358 goto Retry;
3359 }
3360
3361 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3362 status = STATUS_SUCCESS;
3363 }
3364
3365 ExFreePool((PVOID)buffer);
3366
3367 if (NT_SUCCESS(status)) {
3368 return(TRUE);
3369 } else {
3370 return(FALSE);
3371 }
3372
3373 } // end SciDiskModeSelect()
3374
3375 \f
3376 VOID
3377 NTAPI
3378 DisableWriteCache(
3379 IN PDEVICE_OBJECT DeviceObject,
3380 IN PSCSI_INQUIRY_DATA LunInfo
3381 )
3382
3383 {
3384 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3385 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3386 BAD_CONTROLLER_INFORMATION const *controller;
3387 ULONG j,length;
3388 PVOID modeData;
3389 PUCHAR pageData;
3390
3391 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
3392
3393 controller = &ScsiDiskBadControllers[j];
3394
3395 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
3396 continue;
3397 }
3398
3399 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
3400
3401 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3402
3403 if (modeData == NULL) {
3404
3405 DebugPrint((1,
3406 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3407 return;
3408 }
3409
3410 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3411
3412 length = ScsiClassModeSense(DeviceObject,
3413 modeData,
3414 MODE_DATA_SIZE,
3415 MODE_SENSE_RETURN_ALL);
3416
3417 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3418
3419 //
3420 // Retry the request in case of a check condition.
3421 //
3422
3423 length = ScsiClassModeSense(DeviceObject,
3424 modeData,
3425 MODE_DATA_SIZE,
3426 MODE_SENSE_RETURN_ALL);
3427
3428 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3429
3430
3431 DebugPrint((1,
3432 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3433
3434 ExFreePool(modeData);
3435 return;
3436
3437 }
3438 }
3439
3440 //
3441 // If the length is greater than length indicated by the mode data reset
3442 // the data to the mode data.
3443 //
3444
3445 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3446 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3447 }
3448
3449 //
3450 // Check to see if the write cache is enabled.
3451 //
3452
3453 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3454
3455 //
3456 // Assume that write cache is disabled or not supported.
3457 //
3458
3459 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3460
3461 //
3462 // Check if valid caching page exists.
3463 //
3464
3465 if (pageData != NULL) {
3466
3467 BOOLEAN savePage = FALSE;
3468
3469 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
3470
3471 //
3472 // Check if write cache is disabled.
3473 //
3474
3475 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3476
3477 PIO_ERROR_LOG_PACKET errorLogEntry;
3478 LONG errorCode;
3479
3480
3481 //
3482 // Disable write cache and ensure necessary fields are zeroed.
3483 //
3484
3485 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
3486 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
3487 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
3488 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
3489
3490 //
3491 // Extract length from caching page.
3492 //
3493
3494 length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
3495
3496 //
3497 // Compensate for page code and page length.
3498 //
3499
3500 length += 2;
3501
3502 //
3503 // Issue mode select to set the parameter.
3504 //
3505
3506 if (ScsiDiskModeSelect(DeviceObject,
3507 (PCHAR)pageData,
3508 length,
3509 savePage)) {
3510
3511 DebugPrint((1,
3512 "SCSIDISK: Disk write cache disabled\n"));
3513
3514 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3515 errorCode = IO_WRITE_CACHE_DISABLED;
3516
3517 } else {
3518 if (ScsiDiskModeSelect(DeviceObject,
3519 (PCHAR)pageData,
3520 length,
3521 savePage)) {
3522
3523 DebugPrint((1,
3524 "SCSIDISK: Disk write cache disabled\n"));
3525
3526
3527 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3528 errorCode = IO_WRITE_CACHE_DISABLED;
3529
3530 } else {
3531
3532 DebugPrint((1,
3533 "SCSIDISK: Mode select to disable write cache failed\n"));
3534
3535 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3536 errorCode = IO_WRITE_CACHE_ENABLED;
3537 }
3538 }
3539
3540 //
3541 // Log the appropriate informational or error entry.
3542 //
3543
3544 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3545 DeviceObject,
3546 sizeof(IO_ERROR_LOG_PACKET) + 3
3547 * sizeof(ULONG));
3548
3549 if (errorLogEntry != NULL) {
3550
3551 errorLogEntry->FinalStatus = STATUS_SUCCESS;
3552 errorLogEntry->ErrorCode = errorCode;
3553 errorLogEntry->SequenceNumber = 0;
3554 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
3555 errorLogEntry->IoControlCode = 0;
3556 errorLogEntry->RetryCount = 0;
3557 errorLogEntry->UniqueErrorValue = 0x1;
3558 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG);
3559 errorLogEntry->DumpData[0] = LunInfo->PathId;
3560 errorLogEntry->DumpData[1] = LunInfo->TargetId;
3561 errorLogEntry->DumpData[2] = LunInfo->Lun;
3562
3563 //
3564 // Write the error log packet.
3565 //
3566
3567 IoWriteErrorLogEntry(errorLogEntry);
3568 }
3569 }
3570 }
3571
3572 //
3573 // Found device so exit the loop and return.
3574 //
3575
3576 break;
3577 }
3578
3579 return;
3580 }
3581
3582 \f
3583 BOOLEAN
3584 NTAPI
3585 CalculateMbrCheckSum(
3586 IN PDEVICE_EXTENSION DeviceExtension,
3587 OUT PULONG Checksum
3588 )
3589
3590 /*++
3591
3592 Routine Description:
3593
3594 Read MBR and calculate checksum.
3595
3596 Arguments:
3597
3598 DeviceExtension - Supplies a pointer to the device information for disk.
3599 Checksum - Memory location to return MBR checksum.
3600
3601 Return Value:
3602
3603 Returns TRUE if checksum is valid.
3604
3605 --*/
3606 {
3607 LARGE_INTEGER sectorZero;
3608 PIRP irp;
3609 IO_STATUS_BLOCK ioStatus;
3610 KEVENT event;
3611 NTSTATUS status;
3612 ULONG sectorSize;
3613 PULONG mbr;
3614 ULONG i;
3615
3616 PAGED_CODE();
3617 sectorZero.QuadPart = (LONGLONG) 0;
3618
3619 //
3620 // Create notification event object to be used to signal the inquiry
3621 // request completion.
3622 //
3623
3624 KeInitializeEvent(&event, NotificationEvent, FALSE);
3625
3626 //
3627 // Get sector size.
3628 //
3629
3630 sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
3631
3632 //
3633 // Make sure sector size is at least 512 bytes.
3634 //
3635
3636 if (sectorSize < 512) {
3637 sectorSize = 512;
3638 }
3639
3640 //
3641 // Allocate buffer for sector read.
3642 //
3643
3644 mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize);
3645
3646 if (!mbr) {
3647 return FALSE;
3648 }
3649
3650 //
3651 // Build IRP to read MBR.
3652 //
3653
3654 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
3655 DeviceExtension->DeviceObject,
3656 mbr,
3657 sectorSize,
3658 &sectorZero,
3659 &event,
3660 &ioStatus );
3661
3662 if (!irp) {
3663 ExFreePool(mbr);
3664 return FALSE;
3665 }
3666
3667 //
3668 // Pass request to port driver and wait for request to complete.
3669 //
3670
3671 status = IoCallDriver(DeviceExtension->DeviceObject,
3672 irp);
3673
3674 if (status == STATUS_PENDING) {
3675 KeWaitForSingleObject(&event,
3676 Suspended,
3677 KernelMode,
3678 FALSE,
3679 NULL);
3680 status = ioStatus.Status;
3681 }
3682
3683 if (!NT_SUCCESS(status)) {
3684 ExFreePool(mbr);
3685 return FALSE;
3686 }
3687
3688 //
3689 // Calculate MBR checksum.
3690 //
3691
3692 *Checksum = 0;
3693
3694 for (i = 0; i < 128; i++) {
3695 *Checksum += mbr[i];
3696 }
3697
3698 *Checksum = ~*Checksum + 1;
3699
3700 ExFreePool(mbr);
3701 return TRUE;
3702 }
3703
3704 \f
3705 BOOLEAN
3706 NTAPI
3707 EnumerateBusKey(
3708 IN PDEVICE_EXTENSION DeviceExtension,
3709 HANDLE BusKey,
3710 PULONG DiskNumber
3711 )
3712
3713 /*++
3714
3715 Routine Description:
3716
3717 The routine queries the registry to determine if this disk is visible to
3718 the BIOS. If the disk is visable to the BIOS, then the geometry information
3719 is updated.
3720
3721 Arguments:
3722
3723 DeviceExtension - Supplies a pointer to the device information for disk.
3724 Signature - Unique identifier recorded in MBR.
3725 BusKey - Handle of bus key.
3726 DiskNumber - Returns ordinal of disk as BIOS sees it.
3727
3728 Return Value:
3729
3730 TRUE is disk signature matched.
3731
3732 --*/
3733 {
3734 PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1);
3735 BOOLEAN diskFound = FALSE;
3736 OBJECT_ATTRIBUTES objectAttributes;
3737 UNICODE_STRING unicodeString;
3738 UNICODE_STRING identifier;
3739 ULONG busNumber;
3740 ULONG adapterNumber;
3741 ULONG diskNumber;
3742 HANDLE adapterKey;
3743 HANDLE spareKey;
3744 HANDLE diskKey;
3745 HANDLE targetKey;
3746 NTSTATUS status;
3747 STRING string;
3748 STRING anotherString;
3749 ULONG length;
3750 UCHAR buffer[20];
3751 PKEY_VALUE_FULL_INFORMATION keyData;
3752
3753 PAGED_CODE();
3754
3755 for (busNumber = 0; ; busNumber++) {
3756
3757 //
3758 // Open controller name key.
3759 //
3760
3761 sprintf((PCHAR)buffer,
3762 "%lu",
3763 busNumber);
3764
3765 RtlInitString(&string,
3766 (PCSZ)buffer);
3767
3768 status = RtlAnsiStringToUnicodeString(&unicodeString,
3769 &string,
3770 TRUE);
3771
3772 if (!NT_SUCCESS(status)){
3773 break;
3774 }
3775
3776 InitializeObjectAttributes(&objectAttributes,
3777 &unicodeString,
3778 OBJ_CASE_INSENSITIVE,
3779 BusKey,
3780 (PSECURITY_DESCRIPTOR)NULL);
3781
3782 status = ZwOpenKey(&spareKey,
3783 KEY_READ,
3784 &objectAttributes);
3785
3786 RtlFreeUnicodeString(&unicodeString);
3787
3788 if (!NT_SUCCESS(status)) {
3789 break;
3790 }
3791
3792 //
3793 // Open up controller ordinal key.
3794 //
3795
3796 RtlInitUnicodeString(&unicodeString, L"DiskController");
3797 InitializeObjectAttributes(&objectAttributes,
3798 &unicodeString,
3799 OBJ_CASE_INSENSITIVE,
3800 spareKey,
3801 (PSECURITY_DESCRIPTOR)NULL);
3802
3803 status = ZwOpenKey(&adapterKey,
3804 KEY_READ,
3805 &objectAttributes);
3806
3807 //
3808 // This could fail even with additional adapters of this type
3809 // to search.
3810 //
3811
3812 if (!NT_SUCCESS(status)) {
3813 continue;
3814 }
3815
3816 for (adapterNumber = 0; ; adapterNumber++) {
3817
3818 //
3819 // Open disk key.
3820 //
3821
3822 sprintf((PCHAR)buffer,
3823 "%lu\\DiskPeripheral",
3824 adapterNumber);
3825
3826 RtlInitString(&string,
3827 (PCSZ)buffer);
3828
3829 status = RtlAnsiStringToUnicodeString(&unicodeString,
3830 &string,
3831 TRUE);
3832
3833 if (!NT_SUCCESS(status)){
3834 break;
3835 }
3836
3837 InitializeObjectAttributes(&objectAttributes,
3838 &unicodeString,
3839 OBJ_CASE_INSENSITIVE,
3840 adapterKey,
3841 (PSECURITY_DESCRIPTOR)NULL);
3842
3843 status = ZwOpenKey(&diskKey,
3844 KEY_READ,
3845 &objectAttributes);
3846
3847 RtlFreeUnicodeString(&unicodeString);
3848
3849 if (!NT_SUCCESS(status)) {
3850 break;
3851 }
3852
3853 for (diskNumber = 0; ; diskNumber++) {
3854
3855 sprintf((PCHAR)buffer,
3856 "%lu",
3857 diskNumber);
3858
3859 RtlInitString(&string,
3860 (PCSZ)buffer);
3861
3862 status = RtlAnsiStringToUnicodeString(&unicodeString,
3863 &string,
3864 TRUE);
3865
3866 if (!NT_SUCCESS(status)){
3867 break;
3868 }
3869
3870 InitializeObjectAttributes(&objectAttributes,
3871 &unicodeString,
3872 OBJ_CASE_INSENSITIVE,
3873 diskKey,
3874 (PSECURITY_DESCRIPTOR)NULL);
3875
3876 status = ZwOpenKey(&targetKey,
3877 KEY_READ,
3878 &objectAttributes);
3879
3880 RtlFreeUnicodeString(&unicodeString);
3881
3882 if (!NT_SUCCESS(status)) {
3883 break;
3884 }
3885
3886 //
3887 // Allocate buffer for registry query.
3888 //
3889
3890 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
3891
3892 if (keyData == NULL) {
3893 ZwClose(targetKey);
3894 continue;
3895 }
3896
3897 //
3898 // Get disk peripheral identifier.
3899 //
3900
3901 RtlInitUnicodeString(&unicodeString, L"Identifier");
3902 status = ZwQueryValueKey(targetKey,
3903 &unicodeString,
3904 KeyValueFullInformation,
3905 keyData,
3906 VALUE_BUFFER_SIZE,
3907 &length);
3908
3909 ZwClose(targetKey);
3910
3911 if (!NT_SUCCESS(status)) {
3912 continue;
3913 }
3914
3915 //
3916 // Complete unicode string.
3917 //
3918
3919 identifier.Buffer =
3920 (PWSTR)((PUCHAR)keyData + keyData->DataOffset);
3921 identifier.Length = (USHORT)keyData->DataLength;
3922 identifier.MaximumLength = (USHORT)keyData->DataLength;
3923
3924 //
3925 // Convert unicode identifier to ansi string.
3926 //
3927
3928 status =
3929 RtlUnicodeStringToAnsiString(&anotherString,
3930 &identifier,
3931 TRUE);
3932
3933 if (!NT_SUCCESS(status)) {
3934 continue;
3935 }
3936
3937 //
3938 // If checksum is zero, then the MBR is valid and
3939 // the signature is meaningful.
3940 //
3941
3942 if (diskData->MbrCheckSum) {
3943
3944 //
3945 // Convert checksum to ansi string.
3946 //
3947
3948 sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum);
3949
3950 } else {
3951
3952 //
3953 // Convert signature to ansi string.
3954 //
3955
3956 sprintf((PCHAR)buffer, "%08lx", diskData->Signature);
3957
3958 //
3959 // Make string point at signature. Can't use scan
3960 // functions because they are not exported for driver use.
3961 //
3962
3963 anotherString.Buffer+=9;
3964 }
3965
3966 //
3967 // Convert to ansi string.
3968 //
3969
3970 RtlInitString(&string,
3971 (PCSZ)buffer);
3972
3973
3974 //
3975 // Make string lengths equal.
3976 //
3977
3978 anotherString.Length = string.Length;
3979
3980 //
3981 // Check if strings match.
3982 //
3983
3984 if (RtlCompareString(&string,
3985 &anotherString,
3986 TRUE) == 0) {
3987
3988 diskFound = TRUE;
3989 *DiskNumber = diskNumber;
3990 }
3991
3992 ExFreePool(keyData);
3993
3994 //
3995 // Readjust indentifier string if necessary.
3996 //
3997
3998 if (!diskData->MbrCheckSum) {
3999 anotherString.Buffer-=9;
4000 }
4001
4002 RtlFreeAnsiString(&anotherString);
4003
4004 if (diskFound) {
4005 break;
4006 }
4007 }
4008
4009 ZwClose(diskKey);
4010 }
4011
4012 ZwClose(adapterKey);
4013 }
4014
4015 ZwClose(BusKey);
4016 return diskFound;
4017
4018 } // end EnumerateBusKey()
4019
4020 \f
4021 VOID
4022 NTAPI
4023 UpdateGeometry(
4024 IN PDEVICE_EXTENSION DeviceExtension
4025 )
4026 /*++
4027
4028 Routine Description:
4029
4030 The routine queries the registry to determine if this disk is visible to
4031 the BIOS. If the disk is visable to the BIOS, then the geometry information
4032 is updated.
4033
4034 Arguments:
4035
4036 DeviceExtension - Supplies a pointer to the device information for disk.
4037
4038 Return Value:
4039
4040 None.
4041
4042 --*/
4043
4044 {
4045 OBJECT_ATTRIBUTES objectAttributes;
4046 UNICODE_STRING unicodeString;
4047 NTSTATUS status;
4048 HANDLE hardwareKey;
4049 HANDLE busKey;
4050 PCM_INT13_DRIVE_PARAMETER driveParameters;
4051 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
4052 PKEY_VALUE_FULL_INFORMATION keyData;
4053 ULONG diskNumber;
4054 PUCHAR buffer;
4055 ULONG length;
4056 ULONG numberOfDrives;
4057 ULONG cylinders;
4058 ULONG sectors;
4059 ULONG sectorsPerTrack;
4060 ULONG tracksPerCylinder;
4061 BOOLEAN foundEZHooker;
4062 PVOID tmpPtr;
4063
4064 PAGED_CODE();
4065
4066 //
4067 // Initialize the object for the key.
4068 //
4069
4070 InitializeObjectAttributes(&objectAttributes,
4071 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
4072 OBJ_CASE_INSENSITIVE,
4073 NULL,
4074 (PSECURITY_DESCRIPTOR) NULL);
4075
4076 //
4077 // Create the hardware base key.
4078 //
4079
4080 status = ZwOpenKey(&hardwareKey,
4081 KEY_READ,
4082 &objectAttributes);
4083
4084
4085 if (!NT_SUCCESS(status)) {
4086 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase));
4087 return;
4088 }
4089
4090
4091 //
4092 // Get disk BIOS geometry information.
4093 //
4094
4095 RtlInitUnicodeString(&unicodeString, L"Configuration Data");
4096
4097 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
4098
4099 if (keyData == NULL) {
4100 ZwClose(hardwareKey);
4101 return;
4102 }
4103
4104 status = ZwQueryValueKey(hardwareKey,
4105 &unicodeString,
4106 KeyValueFullInformation,
4107 keyData,
4108 VALUE_BUFFER_SIZE,
4109 &length);
4110
4111 if (!NT_SUCCESS(status)) {
4112 DebugPrint((1,
4113 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4114 status));
4115 ExFreePool(keyData);
4116 return;
4117 }
4118
4119 //
4120 // Open EISA bus key.
4121 //
4122
4123 RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
4124
4125 InitializeObjectAttributes(&objectAttributes,
4126 &unicodeString,
4127 OBJ_CASE_INSENSITIVE,
4128 hardwareKey,
4129 (PSECURITY_DESCRIPTOR)NULL);
4130
4131 status = ZwOpenKey(&busKey,
4132 KEY_READ,
4133 &objectAttributes);
4134
4135 if (!NT_SUCCESS(status)) {
4136 goto openMultiKey;
4137 }
4138
4139 DebugPrint((3,
4140 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4141 if (EnumerateBusKey(DeviceExtension,
4142 busKey,
4143 &diskNumber)) {
4144
4145 ZwClose(hardwareKey);
4146 goto diskMatched;
4147 }
4148
4149 openMultiKey:
4150
4151 //
4152 // Open Multifunction bus key.
4153 //
4154
4155 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
4156
4157 InitializeObjectAttributes(&objectAttributes,
4158 &unicodeString,
4159 OBJ_CASE_INSENSITIVE,
4160 hardwareKey,
4161 (PSECURITY_DESCRIPTOR)NULL);
4162
4163 status = ZwOpenKey(&busKey,
4164 KEY_READ,
4165 &objectAttributes);
4166
4167 ZwClose(hardwareKey);
4168 if (NT_SUCCESS(status)) {
4169 DebugPrint((3,
4170 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4171 if (EnumerateBusKey(DeviceExtension,
4172 busKey,
4173 &diskNumber)) {
4174
4175 goto diskMatched;
4176 }
4177 }
4178
4179 ExFreePool(keyData);
4180 return;
4181
4182 diskMatched:
4183
4184 resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData +
4185 keyData->DataOffset);
4186
4187 //
4188 // Check that the data is long enough to hold a full resource descriptor,
4189 // and that the last resouce list is device-specific and long enough.
4190 //
4191
4192 if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) ||
4193 resourceDescriptor->PartialResourceList.Count == 0 ||
4194 resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type !=
4195 CmResourceTypeDeviceSpecific ||
4196 resourceDescriptor->PartialResourceList.PartialDescriptors[0]
4197 .u.DeviceSpecificData.DataSize < sizeof(ULONG)) {
4198
4199 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4200 ExFreePool(keyData);
4201 return;
4202 }
4203
4204 length =
4205 resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize;
4206
4207 //
4208 // Point to the BIOS data. The BIOS data is located after the first
4209 // partial Resource list which should be device specific data.
4210 //
4211
4212 buffer = (PUCHAR) keyData + keyData->DataOffset +
4213 sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
4214
4215
4216 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
4217
4218 //
4219 // Use the defaults if the drive number is greater than the
4220 // number of drives detected by the BIOS.
4221 //
4222
4223 if (numberOfDrives <= diskNumber) {
4224 ExFreePool(keyData);
4225 return;
4226 }
4227
4228 //
4229 // Point to the array of drive parameters.
4230 //
4231
4232 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber;
4233 cylinders = driveParameters->MaxCylinders + 1;
4234 sectorsPerTrack = driveParameters->SectorsPerTrack;
4235 tracksPerCylinder = driveParameters->MaxHeads +1;
4236
4237 //
4238 // Calculate the actual number of sectors.
4239 //
4240
4241 sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >>
4242 DeviceExtension->SectorShift);
4243
4244 #if DBG
4245 if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) {
4246 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4247 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4248 sectors, cylinders, tracksPerCylinder, sectorsPerTrack));
4249 }
4250 #endif
4251
4252 //
4253 // Since the BIOS may not report the full drive, recalculate the drive
4254 // size based on the volume size and the BIOS values for tracks per
4255 // cylinder and sectors per track..
4256 //
4257
4258 length = tracksPerCylinder * sectorsPerTrack;
4259
4260 if (length == 0) {
4261
4262 //
4263 // The BIOS information is bogus.
4264 //
4265
4266 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4267 ExFreePool(keyData);
4268 return;
4269 }
4270
4271 cylinders = sectors / length;
4272
4273 //
4274 // Update the actual geometry information.
4275 //
4276
4277 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack;
4278 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder;
4279 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders;
4280 DeviceExtension->DiskGeometry->DiskSize.QuadPart = cylinders * tracksPerCylinder * sectorsPerTrack *
4281 DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4282
4283 DebugPrint((3,
4284 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4285 sectorsPerTrack,
4286 tracksPerCylinder,
4287 cylinders));
4288
4289 ExFreePool(keyData);
4290
4291 foundEZHooker = FALSE;
4292
4293 if (!DeviceExtension->DMActive) {
4294
4295 HalExamineMBR(DeviceExtension->DeviceObject,
4296 DeviceExtension->DiskGeometry->Geometry.BytesPerSector,
4297 (ULONG)0x55,
4298 &tmpPtr
4299 );
4300
4301 if (tmpPtr) {
4302
4303 ExFreePool(tmpPtr);
4304 foundEZHooker = TRUE;
4305
4306 }
4307
4308 }
4309
4310 if (DeviceExtension->DMActive || foundEZHooker) {
4311
4312 while (cylinders > 1024) {
4313
4314 tracksPerCylinder = tracksPerCylinder*2;
4315 cylinders = cylinders/2;
4316
4317 }
4318
4319 //
4320 // int 13 values are always 1 less.
4321 //
4322
4323 tracksPerCylinder -= 1;
4324 cylinders -= 1;
4325
4326 //
4327 // DM reserves the CE cylinder
4328 //
4329
4330 cylinders -= 1;
4331
4332 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1;
4333 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1;
4334
4335 DeviceExtension->PartitionLength.QuadPart =
4336 DeviceExtension->DiskGeometry->DiskSize.QuadPart =
4337 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart *
4338 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack *
4339 DeviceExtension->DiskGeometry->Geometry.BytesPerSector *
4340 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder;
4341
4342 if (DeviceExtension->DMActive) {
4343
4344 DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4345
4346 }
4347
4348 } else {
4349
4350 DeviceExtension->DMByteSkew = 0;
4351
4352 }
4353
4354 return;
4355
4356 } // end UpdateGeometry()
4357
4358
4359 \f
4360 NTSTATUS
4361 NTAPI
4362 UpdateRemovableGeometry (
4363 IN PDEVICE_OBJECT DeviceObject,
4364 IN PIRP Irp
4365 )
4366
4367 /*++
4368
4369 Routine Description:
4370
4371 This routines updates the size and starting offset of the device. This is
4372 used when the media on the device may have changed thereby changing the
4373 size of the device. If this is the physical device then a
4374 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4375
4376 Arguments:
4377
4378 DeviceObject - Supplies the device object whos size needs to be updated.
4379
4380 Irp - Supplies a reference where the status can be updated.
4381
4382 Return Value:
4383
4384 Returns the status of the opertion.
4385
4386 --*/
4387 {
4388
4389 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4390 PDRIVE_LAYOUT_INFORMATION partitionList;
4391 NTSTATUS status;
4392 PDISK_DATA diskData;
4393 ULONG partitionNumber;
4394
4395 //
4396 // Determine if the size of the partition may have changed because
4397 // the media has changed.
4398 //
4399
4400 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
4401
4402 return(STATUS_SUCCESS);
4403
4404 }
4405
4406 //
4407 // If this request is for partition zero then do a read drive
4408 // capacity otherwise do a I/O read partition table.
4409 //
4410
4411 diskData = (PDISK_DATA) (deviceExtension + 1);
4412
4413 //
4414 // Read the drive capcity. If that fails, give up.
4415 //
4416
4417 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
4418
4419 if (!NT_SUCCESS(status)) {
4420 return(status);
4421 }
4422
4423 //
4424 // Read the partition table agian.
4425 //
4426
4427 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
4428 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
4429 TRUE,
4430 &partitionList);
4431
4432
4433 if (!NT_SUCCESS(status)) {
4434
4435 //
4436 // Fail the request.
4437 //
4438
4439 return(status);
4440 }
4441
4442 if (diskData->PartitionNumber != 0 &&
4443 diskData->PartitionNumber <= partitionList->PartitionCount ) {
4444
4445 partitionNumber = diskData->PartitionNumber - 1;
4446
4447 //
4448 // Update the partition information for this parition.
4449 //
4450
4451 diskData->PartitionType =
4452 partitionList->PartitionEntry[partitionNumber].PartitionType;
4453
4454 diskData->BootIndicator =
4455 partitionList->PartitionEntry[partitionNumber].BootIndicator;
4456
4457 deviceExtension->StartingOffset =
4458 partitionList->PartitionEntry[partitionNumber].StartingOffset;
4459
4460 deviceExtension->PartitionLength =
4461 partitionList->PartitionEntry[partitionNumber].PartitionLength;
4462
4463 diskData->HiddenSectors =
4464 partitionList->PartitionEntry[partitionNumber].HiddenSectors;
4465
4466 deviceExtension->SectorShift = ((PDEVICE_EXTENSION)
4467 deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift;
4468
4469 } else if (diskData->PartitionNumber != 0) {
4470
4471 //
4472 // The paritition does not exist. Zero all the data.
4473 //
4474
4475 diskData->PartitionType = 0;
4476 diskData->BootIndicator = 0;
4477 diskData->HiddenSectors = 0;
4478 deviceExtension->StartingOffset.QuadPart = (LONGLONG)0;
4479 deviceExtension->PartitionLength.QuadPart = (LONGLONG)0;
4480 }
4481
4482 //
4483 // Free the parition list allocate by I/O read partition table.
4484 //
4485
4486 ExFreePool(partitionList);
4487
4488
4489 return(STATUS_SUCCESS);
4490 }
4491
4492 \f
4493 VOID
4494 NTAPI
4495 ScsiDiskProcessError(
4496 PDEVICE_OBJECT DeviceObject,
4497 PSCSI_REQUEST_BLOCK Srb,
4498 NTSTATUS *Status,
4499 BOOLEAN *Retry
4500 )
4501 /*++
4502
4503 Routine Description:
4504
4505 This routine checks the type of error. If the error indicates an underrun
4506 then indicate the request should be retried.
4507
4508 Arguments:
4509
4510 DeviceObject - Supplies a pointer to the device object.
4511
4512 Srb - Supplies a pointer to the failing Srb.
4513
4514 Status - Status with which the IRP will be completed.
4515
4516 Retry - Indication of whether the request will be retried.
4517
4518 Return Value:
4519
4520 None.
4521
4522 --*/
4523
4524 {
4525 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4526
4527 if (*Status == STATUS_DATA_OVERRUN &&
4528 ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) {
4529
4530 *Retry = TRUE;
4531
4532 //
4533 // Update the error count for the device.
4534 //
4535
4536 deviceExtension->ErrorCount++;
4537 }
4538
4539 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
4540 Srb->ScsiStatus == SCSISTAT_BUSY) {
4541
4542 //
4543 // The disk drive should never be busy this long. Reset the scsi bus
4544 // maybe this will clear the condition.
4545 //
4546
4547 ResetScsiBus(DeviceObject);
4548
4549 //
4550 // Update the error count for the device.
4551 //
4552
4553 deviceExtension->ErrorCount++;
4554 }
4555 }
4556 \f
4557 VOID
4558 NTAPI
4559 ScanForSpecial(
4560 PDEVICE_OBJECT DeviceObject,
4561 PSCSI_INQUIRY_DATA LunInfo,
4562 PIO_SCSI_CAPABILITIES PortCapabilities
4563 )
4564
4565 /*++
4566
4567 Routine Description:
4568
4569 This function checks to see if an SCSI logical unit requires speical
4570 flags to be set.
4571
4572 Arguments:
4573
4574 DeviceObject - Supplies the device object to be tested.
4575
4576 InquiryData - Supplies the inquiry data returned by the device of interest.
4577
4578 PortCapabilities - Supplies the capabilities of the device object.
4579
4580 Return Value:
4581
4582 None.
4583
4584 --*/
4585
4586 {
4587 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4588 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
4589 BAD_CONTROLLER_INFORMATION const *controller;
4590 ULONG j;
4591
4592 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
4593
4594 controller = &ScsiDiskBadControllers[j];
4595
4596 if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
4597 continue;
4598 }
4599
4600 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString));
4601
4602 //
4603 // Found a listed controller. Determine what must be done.
4604 //
4605
4606 if (controller->DisableTaggedQueuing) {
4607
4608 //
4609 // Disable tagged queuing.
4610 //
4611
4612 deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
4613 }
4614
4615 if (controller->DisableSynchronousTransfers) {
4616
4617 //
4618 // Disable synchronous data transfers.
4619 //
4620
4621 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
4622
4623 }
4624
4625 if (controller->DisableDisconnects) {
4626
4627 //
4628 // Disable disconnects.
4629 //
4630
4631 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
4632
4633 }
4634
4635 //
4636 // Found device so exit the loop and return.
4637 //
4638
4639 break;
4640 }
4641
4642 //
4643 // Set the StartUnit flag appropriately.
4644 //
4645
4646 if (DeviceObject->DeviceType == FILE_DEVICE_DISK) {
4647 deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT;
4648
4649 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
4650 if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) {
4651 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT;
4652 }
4653 }
4654 }
4655
4656 return;
4657 }
4658 \f
4659 VOID
4660 NTAPI
4661 ResetScsiBus(
4662 IN PDEVICE_OBJECT DeviceObject
4663 )
4664
4665 /*++
4666
4667 Routine Description:
4668
4669 This command sends a reset bus command to the SCSI port driver.
4670
4671 Arguments:
4672
4673 DeviceObject - The device object for the logical unit with
4674 hardware problem.
4675
4676 Return Value:
4677
4678 None.
4679
4680 --*/
4681 {
4682 PIO_STACK_LOCATION irpStack;
4683 PIRP irp;
4684 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4685 PSCSI_REQUEST_BLOCK srb;
4686 PCOMPLETION_CONTEXT context;
4687
4688 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4689
4690 //
4691 // Allocate Srb from nonpaged pool.
4692 //
4693
4694 context = ExAllocatePool(NonPagedPoolMustSucceed,
4695 sizeof(COMPLETION_CONTEXT));
4696
4697 //
4698 // Save the device object in the context for use by the completion
4699 // routine.
4700 //
4701
4702 context->DeviceObject = DeviceObject;
4703 srb = &context->Srb;
4704
4705 //
4706 // Zero out srb.
4707 //
4708
4709 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
4710
4711 //
4712 // Write length to SRB.
4713 //
4714
4715 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4716
4717 //
4718 // Set up SCSI bus address.
4719 //
4720
4721 srb->PathId = deviceExtension->PathId;
4722 srb->TargetId = deviceExtension->TargetId;
4723 srb->Lun = deviceExtension->Lun;
4724
4725 srb->Function = SRB_FUNCTION_RESET_BUS;
4726
4727 //
4728 // Build the asynchronous request to be sent to the port driver.
4729 // Since this routine is called from a DPC the IRP should always be
4730 // available.
4731 //
4732
4733 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4734
4735 IoSetCompletionRoutine(irp,
4736 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
4737 context,
4738 TRUE,
4739 TRUE,
4740 TRUE);
4741
4742 irpStack = IoGetNextIrpStackLocation(irp);
4743
4744 irpStack->MajorFunction = IRP_MJ_SCSI;
4745
4746 srb->OriginalRequest = irp;
4747
4748 //
4749 // Store the SRB address in next stack for port driver.
4750 //
4751
4752 irpStack->Parameters.Scsi.Srb = srb;
4753
4754 //
4755 // Call the port driver with the IRP.
4756 //
4757
4758 IoCallDriver(deviceExtension->PortDeviceObject, irp);
4759
4760 return;
4761
4762 } // end ResetScsiBus()
4763
4764 \f
4765 VOID
4766 NTAPI
4767 UpdateDeviceObjects(
4768 IN PDEVICE_OBJECT PhysicalDisk,
4769 IN PIRP Irp
4770 )
4771
4772 /*++
4773
4774 Routine Description:
4775
4776 This routine creates, deletes and changes device objects when
4777 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4778 the drive layout information for the user. It is possible to
4779 call this routine even in the GET_LAYOUT case because RewritePartition
4780 will be false.
4781
4782 Arguments:
4783
4784 DeviceObject - Device object for physical disk.
4785 Irp - IO Request Packet (IRP).
4786
4787 Return Value:
4788
4789 None.
4790
4791 --*/
4792 {
4793 PDEVICE_EXTENSION physicalExtension = PhysicalDisk->DeviceExtension;
4794 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
4795 ULONG partition;
4796 ULONG partitionNumber;
4797 ULONG partitionCount;
4798 ULONG lastPartition;
4799 ULONG partitionOrdinal;
4800 PPARTITION_INFORMATION partitionEntry;
4801 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
4802 STRING ntNameString;
4803 UNICODE_STRING ntUnicodeString;
4804 PDEVICE_OBJECT deviceObject;
4805 PDEVICE_EXTENSION deviceExtension;
4806 PDISK_DATA diskData;
4807 NTSTATUS status;
4808 ULONG numberListElements;
4809 BOOLEAN found;
4810
4811 partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4;
4812
4813 //
4814 // Zero all of the partition numbers.
4815 //
4816
4817 for (partition = 0; partition < partitionCount; partition++) {
4818 partitionEntry = &partitionList->PartitionEntry[partition];
4819 partitionEntry->PartitionNumber = 0;
4820 }
4821
4822 //
4823 // Walk through chain of partitions for this disk to determine
4824 // which existing partitions have no match.
4825 //
4826
4827 deviceExtension = physicalExtension;
4828 diskData = (PDISK_DATA)(deviceExtension + 1);
4829 lastPartition = 0;
4830
4831 do {
4832
4833 deviceExtension = diskData->NextPartition;
4834
4835 //
4836 // Check if this is the last partition in the chain.
4837 //
4838
4839 if (!deviceExtension) {
4840 break;
4841 }
4842
4843 //
4844 // Get the partition device extension from disk data.
4845 //
4846
4847 diskData = (PDISK_DATA)(deviceExtension + 1);
4848
4849 //
4850 // Check for highest partition number this far.
4851 //
4852
4853 if (diskData->PartitionNumber > lastPartition) {
4854 lastPartition = diskData->PartitionNumber;
4855 }
4856
4857 //
4858 // Check if this partition is not currently being used.
4859 //
4860
4861 if (!deviceExtension->PartitionLength.QuadPart) {
4862 continue;
4863 }
4864
4865 //
4866 // Loop through partition information to look for match.
4867 //
4868
4869 found = FALSE;
4870 partitionOrdinal = 0;
4871
4872 for (partition = 0; partition < partitionCount; partition++) {
4873
4874 //
4875 // Get partition descriptor.
4876 //
4877
4878 partitionEntry = &partitionList->PartitionEntry[partition];
4879
4880 //
4881 // Check if empty, or describes extended partiton or hasn't changed.
4882 //
4883
4884 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
4885 IsContainerPartition(partitionEntry->PartitionType)) {
4886 continue;
4887 }
4888
4889 //
4890 // Advance partition ordinal.
4891 //
4892
4893 partitionOrdinal++;
4894
4895 //
4896 // Check if new partition starts where this partition starts.
4897 //
4898
4899 if (partitionEntry->StartingOffset.QuadPart !=
4900 deviceExtension->StartingOffset.QuadPart) {
4901 continue;
4902 }
4903
4904 //
4905 // Check if partition length is the same.
4906 //
4907
4908 if (partitionEntry->PartitionLength.QuadPart ==
4909 deviceExtension->PartitionLength.QuadPart) {
4910
4911 DebugPrint((3,
4912 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4913 physicalExtension->DeviceNumber,
4914 diskData->PartitionNumber));
4915
4916 //
4917 // Indicate match is found and set partition number
4918 // in user buffer.
4919 //
4920
4921 found = TRUE;
4922 partitionEntry->PartitionNumber = diskData->PartitionNumber;
4923 break;
4924 }
4925 }
4926
4927 if (found) {
4928
4929 //
4930 // A match is found.
4931 //
4932
4933 diskData = (PDISK_DATA)(deviceExtension + 1);
4934
4935 //
4936 // If this partition is marked for update then update partition type.
4937 //
4938
4939 if (partitionEntry->RewritePartition) {
4940 diskData->PartitionType = partitionEntry->PartitionType;
4941 }
4942
4943 //
4944 // Update partitional ordinal for calls to HAL routine
4945 // IoSetPartitionInformation.
4946 //
4947
4948 diskData->PartitionOrdinal = partitionOrdinal;
4949
4950 DebugPrint((1,
4951 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4952 physicalExtension->DeviceNumber,
4953 diskData->PartitionOrdinal,
4954 diskData->PartitionNumber));
4955
4956 } else {
4957
4958 //
4959 // no match was found, indicate this partition is gone.
4960 //
4961
4962 DebugPrint((1,
4963 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4964 physicalExtension->DeviceNumber,
4965 diskData->PartitionNumber));
4966
4967 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
4968 }
4969
4970 } while (TRUE);
4971
4972 //
4973 // Walk through partition loop to find new partitions and set up
4974 // device extensions to describe them. In some cases new device
4975 // objects will be created.
4976 //
4977
4978 partitionOrdinal = 0;
4979
4980 for (partition = 0;
4981 partition < partitionCount;
4982 partition++) {
4983
4984 //
4985 // Get partition descriptor.
4986 //
4987
4988 partitionEntry = &partitionList->PartitionEntry[partition];
4989
4990 //
4991 // Check if empty, or describes an extended partiton.
4992 //
4993
4994 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
4995 IsContainerPartition(partitionEntry->PartitionType)) {
4996 continue;
4997 }
4998
4999 //
5000 // Keep track of position on the disk for calls to IoSetPartitionInformation.
5001 //
5002
5003 partitionOrdinal++;
5004
5005 //
5006 // Check if this entry should be rewritten.
5007 //
5008
5009 if (!partitionEntry->RewritePartition) {
5010 continue;
5011 }
5012
5013 if (partitionEntry->PartitionNumber) {
5014
5015 //
5016 // Partition is an exact match with an existing partition, but is
5017 // being written anyway.
5018 //
5019
5020 continue;
5021 }
5022
5023 //
5024 // Check first if existing device object is available by
5025 // walking partition extension list.
5026 //
5027
5028 partitionNumber = 0;
5029 deviceExtension = physicalExtension;
5030 diskData = (PDISK_DATA)(deviceExtension + 1);
5031
5032 do {
5033
5034 //
5035 // Get next partition device extension from disk data.
5036 //
5037
5038 deviceExtension = diskData->NextPartition;
5039
5040 if (!deviceExtension) {
5041 break;
5042 }
5043
5044 diskData = (PDISK_DATA)(deviceExtension + 1);
5045
5046 //
5047 // A device object is free if the partition length is set to zero.
5048 //
5049
5050 if (!deviceExtension->PartitionLength.QuadPart) {
5051 partitionNumber = diskData->PartitionNumber;
5052 break;
5053 }
5054
5055 } while (TRUE);
5056
5057 //
5058 // If partition number is still zero then a new device object
5059 // must be created.
5060 //
5061
5062 if (partitionNumber == 0) {
5063
5064 lastPartition++;
5065 partitionNumber = lastPartition;
5066
5067 //
5068 // Get or create partition object and set up partition parameters.
5069 //
5070
5071 sprintf(ntNameBuffer,
5072 "\\Device\\Harddisk%lu\\Partition%lu",
5073 physicalExtension->DeviceNumber,
5074 partitionNumber);
5075
5076 RtlInitString(&ntNameString,
5077 ntNameBuffer);
5078
5079 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
5080 &ntNameString,
5081 TRUE);
5082
5083 if (!NT_SUCCESS(status)) {
5084 continue;
5085 }
5086
5087 DebugPrint((3,
5088 "UpdateDeviceObjects: Create device object %s\n",
5089 ntNameBuffer));
5090
5091 //
5092 // This is a new name. Create the device object to represent it.
5093 //
5094
5095 status = IoCreateDevice(PhysicalDisk->DriverObject,
5096 DEVICE_EXTENSION_SIZE,
5097 &ntUnicodeString,
5098 FILE_DEVICE_DISK,
5099 0,
5100 FALSE,
5101 &deviceObject);
5102
5103 if (!NT_SUCCESS(status)) {
5104 DebugPrint((1,
5105 "UpdateDeviceObjects: Can't create device %s\n",
5106 ntNameBuffer));
5107 RtlFreeUnicodeString(&ntUnicodeString);
5108 continue;
5109 }
5110
5111 //
5112 // Set up device object fields.
5113 //
5114
5115 deviceObject->Flags |= DO_DIRECT_IO;
5116 deviceObject->StackSize = PhysicalDisk->StackSize;
5117
5118 //
5119 // Set up device extension fields.
5120 //
5121
5122 deviceExtension = deviceObject->DeviceExtension;
5123
5124 //
5125 // Copy physical disk extension to partition extension.
5126 //
5127
5128 RtlMoveMemory(deviceExtension,
5129 physicalExtension,
5130 sizeof(DEVICE_EXTENSION));
5131
5132 //
5133 // Initialize the new S-List.
5134 //
5135
5136 if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
5137 numberListElements = 30;
5138 } else {
5139 numberListElements = 8;
5140 }
5141
5142 //
5143 // Build the lookaside list for srb's for this partition based on
5144 // whether the adapter and disk can do tagged queueing.
5145 //
5146
5147 ScsiClassInitializeSrbLookasideList(deviceExtension,
5148 numberListElements);
5149
5150 //
5151 // Allocate spinlock for zoning for split-request completion.
5152 //
5153
5154 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
5155
5156 //
5157 // Write back partition number used in creating object name.
5158 //
5159
5160 partitionEntry->PartitionNumber = partitionNumber;
5161
5162 //
5163 // Clear flags initializing bit.
5164 //
5165
5166 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
5167
5168 //
5169 // Point back at device object.
5170 //
5171
5172 deviceExtension->DeviceObject = deviceObject;
5173
5174 RtlFreeUnicodeString(&ntUnicodeString);
5175
5176 //
5177 // Link to end of partition chain using previous disk data.
5178 //
5179
5180 diskData->NextPartition = deviceExtension;
5181
5182 //
5183 // Get new disk data and zero next partition pointer.
5184 //
5185
5186 diskData = (PDISK_DATA)(deviceExtension + 1);
5187 diskData->NextPartition = NULL;
5188
5189 } else {
5190
5191 //
5192 // Set pointer to disk data area that follows device extension.
5193 //
5194
5195 diskData = (PDISK_DATA)(deviceExtension + 1);
5196
5197 DebugPrint((1,
5198 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5199 physicalExtension->DeviceNumber,
5200 partitionNumber));
5201 }
5202
5203 //
5204 // Update partition information in partition device extension.
5205 //
5206
5207 diskData->PartitionNumber = partitionNumber;
5208 diskData->PartitionType = partitionEntry->PartitionType;
5209 diskData->BootIndicator = partitionEntry->BootIndicator;
5210 deviceExtension->StartingOffset = partitionEntry->StartingOffset;
5211 deviceExtension->PartitionLength = partitionEntry->PartitionLength;
5212 diskData->HiddenSectors = partitionEntry->HiddenSectors;
5213 diskData->PartitionOrdinal = partitionOrdinal;
5214
5215 DebugPrint((1,
5216 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5217 diskData->PartitionOrdinal,
5218 diskData->PartitionNumber));
5219
5220 //
5221 // Update partition number passed in to indicate the
5222 // device name for this partition.
5223 //
5224
5225 partitionEntry->PartitionNumber = partitionNumber;
5226 }
5227
5228 } // end UpdateDeviceObjects()
5229