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