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