Partial merge of the condrv_restructure branch, including:
[reactos.git] / reactos / drivers / storage / class / disk / disk.c
1 /*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/disk/disk.c
5 * PURPOSE: Disk class driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9 #include <ntddk.h>
10 #include <ntdddisk.h>
11 #include <scsi.h>
12 #include <ntddscsi.h>
13 #include <mountdev.h>
14 #include <mountmgr.h>
15 #include <include/class2.h>
16 #include <stdio.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #define IO_WRITE_CACHE_ENABLED ((NTSTATUS)0x80040020L)
22 #define IO_WRITE_CACHE_DISABLED ((NTSTATUS)0x80040022L)
23
24 #ifdef POOL_TAGGING
25 #ifdef ExAllocatePool
26 #undef ExAllocatePool
27 #endif
28 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
29 #endif
30
31 typedef enum {
32 NotInitialized,
33 Initializing,
34 Initialized
35 } PARTITION_LIST_STATE;
36
37 //
38 // Disk device data
39 //
40
41 typedef struct _DISK_DATA {
42
43 //
44 // Partition chain
45 //
46
47 PDEVICE_EXTENSION NextPartition;
48
49 //
50 // Disk signature (from MBR)
51 //
52
53 ULONG Signature;
54
55 //
56 // MBR checksum
57 //
58
59 ULONG MbrCheckSum;
60
61 //
62 // Number of hidden sectors for BPB.
63 //
64
65 ULONG HiddenSectors;
66
67 //
68 // Partition number of this device object
69 //
70 // This field is set during driver initialization or when the partition
71 // is created to identify a parition to the system.
72 //
73
74 ULONG PartitionNumber;
75
76 //
77 // This field is the ordinal of a partition as it appears on a disk.
78 //
79
80 ULONG PartitionOrdinal;
81
82 //
83 // Partition type of this device object
84 //
85 // This field is set by:
86 //
87 // 1) Initially set according to the partition list entry partition
88 // type returned by IoReadPartitionTable.
89 //
90 // 2) Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
91 // I/O control function when IoSetPartitionInformation function
92 // successfully updates the partition type on the disk.
93 //
94
95 UCHAR PartitionType;
96
97 //
98 // Boot indicator - indicates whether this partition is a bootable (active)
99 // partition for this device
100 //
101 // This field is set according to the partition list entry boot indicator
102 // returned by IoReadPartitionTable.
103 //
104
105 BOOLEAN BootIndicator;
106
107 //
108 // DriveNotReady - inidicates that the this device is currenly not ready
109 // because there is no media in the device.
110 //
111
112 BOOLEAN DriveNotReady;
113
114 //
115 // State of PartitionList initialization
116 //
117
118 PARTITION_LIST_STATE PartitionListState;
119
120 } DISK_DATA, *PDISK_DATA;
121
122 //
123 // Define a general structure of identfing disk controllers with bad
124 // hardware.
125 //
126
127 typedef struct _BAD_CONTROLLER_INFORMATION {
128 PCHAR InquiryString;
129 BOOLEAN DisableTaggedQueuing;
130 BOOLEAN DisableSynchronousTransfers;
131 BOOLEAN DisableDisconnects;
132 BOOLEAN DisableWriteCache;
133 }BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION;
134
135 BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = {
136 { "TOSHIBA MK538FB 60", TRUE, FALSE, FALSE, FALSE },
137 { "CONNER CP3500", FALSE, TRUE, FALSE, FALSE },
138 { "OLIVETTICP3500", FALSE, TRUE, FALSE, FALSE },
139 { "SyQuest SQ5110 CHC", TRUE, TRUE, FALSE, FALSE },
140 { "SEAGATE ST41601N 0102", FALSE, TRUE, FALSE, FALSE },
141 { "SEAGATE ST3655N", FALSE, FALSE, FALSE, TRUE },
142 { "SEAGATE ST3390N", FALSE, FALSE, FALSE, TRUE },
143 { "SEAGATE ST12550N", FALSE, FALSE, FALSE, TRUE },
144 { "SEAGATE ST32430N", FALSE, FALSE, FALSE, TRUE },
145 { "SEAGATE ST31230N", FALSE, FALSE, FALSE, TRUE },
146 { "SEAGATE ST15230N", FALSE, FALSE, FALSE, TRUE },
147 { "FUJITSU M2652S-512", TRUE, FALSE, FALSE, FALSE },
148 { "MAXTOR MXT-540SL I1.2", TRUE, FALSE, FALSE, FALSE },
149 { "COMPAQ PD-1", FALSE, TRUE, FALSE, FALSE }
150 };
151
152
153 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
154 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
155
156 #define MODE_DATA_SIZE 192
157 #define VALUE_BUFFER_SIZE 2048
158 #define SCSI_DISK_TIMEOUT 10
159 #define PARTITION0_LIST_SIZE 4
160
161 \f
162 NTSTATUS
163 NTAPI
164 DriverEntry(
165 IN PDRIVER_OBJECT DriverObject,
166 IN PUNICODE_STRING RegistryPath
167 );
168
169 BOOLEAN
170 NTAPI
171 ScsiDiskDeviceVerification(
172 IN PINQUIRYDATA InquiryData
173 );
174
175 BOOLEAN
176 NTAPI
177 FindScsiDisks(
178 IN PDRIVER_OBJECT DriveObject,
179 IN PUNICODE_STRING RegistryPath,
180 IN PCLASS_INIT_DATA InitializationData,
181 IN PDEVICE_OBJECT PortDeviceObject,
182 IN ULONG PortNumber
183 );
184
185 NTSTATUS
186 NTAPI
187 ScsiDiskCreateClose (
188 IN PDEVICE_OBJECT DeviceObject,
189 IN PIRP Irp
190 );
191
192 NTSTATUS
193 NTAPI
194 ScsiDiskReadWriteVerification(
195 IN PDEVICE_OBJECT DeviceObject,
196 IN PIRP Irp
197 );
198
199 NTSTATUS
200 NTAPI
201 ScsiDiskDeviceControl(
202 IN PDEVICE_OBJECT DeviceObject,
203 IN PIRP Irp
204 );
205
206 VOID
207 NTAPI
208 ScsiDiskProcessError(
209 PDEVICE_OBJECT DeviceObject,
210 PSCSI_REQUEST_BLOCK Srb,
211 NTSTATUS *Status,
212 BOOLEAN *Retry
213 );
214
215 NTSTATUS
216 NTAPI
217 ScsiDiskShutdownFlush(
218 IN PDEVICE_OBJECT DeviceObject,
219 IN PIRP Irp
220 );
221
222 VOID
223 NTAPI
224 DisableWriteCache(
225 IN PDEVICE_OBJECT DeviceObject,
226 IN PSCSI_INQUIRY_DATA LunInfo
227 );
228
229 BOOLEAN
230 NTAPI
231 ScsiDiskModeSelect(
232 IN PDEVICE_OBJECT DeviceObject,
233 IN PCHAR ModeSelectBuffer,
234 IN ULONG Length,
235 IN BOOLEAN SavePage
236 );
237
238 BOOLEAN
239 NTAPI
240 IsFloppyDevice(
241 IN PDEVICE_OBJECT DeviceObject
242 );
243
244 BOOLEAN
245 NTAPI
246 CalculateMbrCheckSum(
247 IN PDEVICE_EXTENSION DeviceExtension,
248 OUT PULONG Checksum
249 );
250
251 BOOLEAN
252 NTAPI
253 EnumerateBusKey(
254 IN PDEVICE_EXTENSION DeviceExtension,
255 HANDLE BusKey,
256 PULONG DiskNumber
257 );
258
259 VOID
260 NTAPI
261 UpdateGeometry(
262 IN PDEVICE_EXTENSION DeviceExtension
263 );
264
265 NTSTATUS
266 NTAPI
267 UpdateRemovableGeometry (
268 IN PDEVICE_OBJECT DeviceObject,
269 IN PIRP Irp
270 );
271
272 NTSTATUS
273 NTAPI
274 CreateDiskDeviceObject(
275 IN PDRIVER_OBJECT DriverObject,
276 IN PUNICODE_STRING RegistryPath,
277 IN PDEVICE_OBJECT PortDeviceObject,
278 IN ULONG PortNumber,
279 IN PULONG DeviceCount,
280 IN PIO_SCSI_CAPABILITIES PortCapabilities,
281 IN PSCSI_INQUIRY_DATA LunInfo,
282 IN PCLASS_INIT_DATA InitData
283 );
284
285 NTSTATUS
286 NTAPI
287 CreatePartitionDeviceObjects(
288 IN PDEVICE_OBJECT PhysicalDeviceObject,
289 IN PUNICODE_STRING RegistryPath
290 );
291
292 VOID
293 NTAPI
294 UpdateDeviceObjects(
295 IN PDEVICE_OBJECT DeviceObject,
296 IN PIRP Irp
297 );
298
299 VOID
300 NTAPI
301 ScanForSpecial(
302 PDEVICE_OBJECT DeviceObject,
303 PSCSI_INQUIRY_DATA LunInfo,
304 PIO_SCSI_CAPABILITIES PortCapabilities
305 );
306
307 VOID
308 NTAPI
309 ResetScsiBus(
310 IN PDEVICE_OBJECT DeviceObject
311 );
312
313 #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 if (dmSkew) {
1450 ExFreePool(dmSkew);
1451 }
1452
1453 } else {
1454
1455 CreatePartitionDeviceObjectsExit:
1456
1457 if (partitionList) {
1458 ExFreePool(partitionList);
1459 }
1460 if (initData) {
1461 ExFreePool(initData);
1462 }
1463
1464 if (dmSkew) {
1465 ExFreePool(dmSkew);
1466 }
1467
1468 return status;
1469
1470 } // end if...else
1471
1472
1473 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
1474 physicalDiskData->PartitionListState = Initialized;
1475
1476 return(STATUS_SUCCESS);
1477
1478
1479 } // end CreatePartitionDeviceObjects()
1480
1481 \f
1482 NTSTATUS
1483 NTAPI
1484 ScsiDiskReadWriteVerification(
1485 IN PDEVICE_OBJECT DeviceObject,
1486 IN PIRP Irp
1487 )
1488
1489 /*++
1490
1491 Routine Description:
1492
1493 I/O System entry for read and write requests to SCSI disks.
1494
1495 Arguments:
1496
1497 DeviceObject - Pointer to driver object created by system.
1498 Irp - IRP involved.
1499
1500 Return Value:
1501
1502 NT Status
1503
1504 --*/
1505
1506 {
1507 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1508 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1509 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1510 LARGE_INTEGER startingOffset;
1511
1512 //
1513 // Verify parameters of this request.
1514 // Check that ending sector is within partition and
1515 // that number of bytes to transfer is a multiple of
1516 // the sector size.
1517 //
1518
1519 startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
1520 transferByteCount);
1521
1522 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
1523 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
1524
1525 //
1526 // This error maybe caused by the fact that the drive is not ready.
1527 //
1528
1529 if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) {
1530
1531 //
1532 // Flag this as a user errror so that a popup is generated.
1533 //
1534
1535 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
1536 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1537
1538 } else {
1539
1540 //
1541 // Note fastfat depends on this parameter to determine when to
1542 // remount do to a sector size change.
1543 //
1544
1545 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1546 }
1547
1548 return STATUS_INVALID_PARAMETER;
1549 }
1550
1551 return STATUS_SUCCESS;
1552
1553 } // end ScsiDiskReadWrite()
1554
1555 \f
1556 NTSTATUS
1557 NTAPI
1558 ScsiDiskDeviceControl(
1559 PDEVICE_OBJECT DeviceObject,
1560 PIRP Irp
1561 )
1562
1563 /*++
1564
1565 Routine Description:
1566
1567 I/O system entry for device controls to SCSI disks.
1568
1569 Arguments:
1570
1571 DeviceObject - Pointer to driver object created by system.
1572 Irp - IRP involved.
1573
1574 Return Value:
1575
1576 Status is returned.
1577
1578 --*/
1579
1580 {
1581 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1582 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1583 PDISK_DATA diskData = (PDISK_DATA)(deviceExtension + 1);
1584 PSCSI_REQUEST_BLOCK srb;
1585 PCDB cdb;
1586 PMODE_PARAMETER_HEADER modeData;
1587 PIRP irp2;
1588 ULONG length;
1589 NTSTATUS status;
1590 KEVENT event;
1591 IO_STATUS_BLOCK ioStatus;
1592
1593 PAGED_CODE();
1594
1595 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
1596
1597 if (srb == NULL) {
1598
1599 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1600 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1601 return(STATUS_INSUFFICIENT_RESOURCES);
1602 }
1603
1604 //
1605 // Write zeros to Srb.
1606 //
1607
1608 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1609
1610 cdb = (PCDB)srb->Cdb;
1611
1612 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1613
1614 case SMART_GET_VERSION: {
1615
1616 ULONG_PTR buffer;
1617 PSRB_IO_CONTROL srbControl;
1618 PGETVERSIONINPARAMS versionParams;
1619
1620 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1621 sizeof(GETVERSIONINPARAMS)) {
1622 status = STATUS_INVALID_PARAMETER;
1623 break;
1624 }
1625
1626 //
1627 // Create notification event object to be used to signal the
1628 // request completion.
1629 //
1630
1631 KeInitializeEvent(&event, NotificationEvent, FALSE);
1632
1633 srbControl = ExAllocatePool(NonPagedPool,
1634 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
1635
1636 if (!srbControl) {
1637 status = STATUS_INSUFFICIENT_RESOURCES;
1638 break;
1639 }
1640
1641 //
1642 // fill in srbControl fields
1643 //
1644
1645 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1646 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1647 srbControl->Timeout = deviceExtension->TimeOutValue;
1648 srbControl->Length = sizeof(GETVERSIONINPARAMS);
1649 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
1650
1651 //
1652 // Point to the 'buffer' portion of the SRB_CONTROL
1653 //
1654
1655 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1656
1657 //
1658 // Ensure correct target is set in the cmd parameters.
1659 //
1660
1661 versionParams = (PGETVERSIONINPARAMS)buffer;
1662 versionParams->bIDEDeviceMap = deviceExtension->TargetId;
1663
1664 //
1665 // Copy the IOCTL parameters to the srb control buffer area.
1666 //
1667
1668 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS));
1669
1670
1671 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1672 deviceExtension->PortDeviceObject,
1673 srbControl,
1674 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1675 srbControl,
1676 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1677 FALSE,
1678 &event,
1679 &ioStatus);
1680
1681 if (irp2 == NULL) {
1682 status = STATUS_INSUFFICIENT_RESOURCES;
1683 break;
1684 }
1685
1686 //
1687 // Call the port driver with the request and wait for it to complete.
1688 //
1689
1690 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1691
1692 if (status == STATUS_PENDING) {
1693 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1694 status = ioStatus.Status;
1695 }
1696
1697 //
1698 // If successful, copy the data received into the output buffer.
1699 // This should only fail in the event that the IDE driver is older than this driver.
1700 //
1701
1702 if (NT_SUCCESS(status)) {
1703
1704 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1705
1706 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS));
1707 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1708 }
1709
1710 ExFreePool(srbControl);
1711 break;
1712 }
1713
1714 case SMART_RCV_DRIVE_DATA: {
1715
1716 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1717 ULONG controlCode = 0;
1718 PSRB_IO_CONTROL srbControl;
1719 ULONG_PTR buffer;
1720
1721 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1722 (sizeof(SENDCMDINPARAMS) - 1)) {
1723 status = STATUS_INVALID_PARAMETER;
1724 break;
1725
1726 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1727 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
1728 status = STATUS_INVALID_PARAMETER;
1729 break;
1730 }
1731
1732 //
1733 // Create notification event object to be used to signal the
1734 // request completion.
1735 //
1736
1737 KeInitializeEvent(&event, NotificationEvent, FALSE);
1738
1739 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
1740
1741 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1742 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
1743
1744 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1745 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1746 case READ_ATTRIBUTES:
1747 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
1748 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1749 break;
1750 case READ_THRESHOLDS:
1751 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
1752 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1753 break;
1754 default:
1755 status = STATUS_INVALID_PARAMETER;
1756 break;
1757 }
1758 } else {
1759
1760 status = STATUS_INVALID_PARAMETER;
1761 }
1762
1763 if (controlCode == 0) {
1764 status = STATUS_INVALID_PARAMETER;
1765 break;
1766 }
1767
1768 srbControl = ExAllocatePool(NonPagedPool,
1769 sizeof(SRB_IO_CONTROL) + length);
1770
1771 if (!srbControl) {
1772 status = STATUS_INSUFFICIENT_RESOURCES;
1773 break;
1774 }
1775
1776 //
1777 // fill in srbControl fields
1778 //
1779
1780 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1781 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1782 srbControl->Timeout = deviceExtension->TimeOutValue;
1783 srbControl->Length = length;
1784 srbControl->ControlCode = controlCode;
1785
1786 //
1787 // Point to the 'buffer' portion of the SRB_CONTROL
1788 //
1789
1790 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1791
1792 //
1793 // Ensure correct target is set in the cmd parameters.
1794 //
1795
1796 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1797
1798 //
1799 // Copy the IOCTL parameters to the srb control buffer area.
1800 //
1801
1802 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1803
1804 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1805 deviceExtension->PortDeviceObject,
1806 srbControl,
1807 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1808 srbControl,
1809 sizeof(SRB_IO_CONTROL) + length,
1810 FALSE,
1811 &event,
1812 &ioStatus);
1813
1814 if (irp2 == NULL) {
1815 status = STATUS_INSUFFICIENT_RESOURCES;
1816 break;
1817 }
1818
1819 //
1820 // Call the port driver with the request and wait for it to complete.
1821 //
1822
1823 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1824
1825 if (status == STATUS_PENDING) {
1826 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1827 status = ioStatus.Status;
1828 }
1829
1830 //
1831 // If successful, copy the data received into the output buffer
1832 //
1833
1834 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1835
1836 if (NT_SUCCESS(status)) {
1837
1838 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1);
1839 Irp->IoStatus.Information = length - 1;
1840
1841 } else {
1842
1843 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
1844 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
1845
1846 }
1847
1848 ExFreePool(srbControl);
1849 break;
1850
1851 }
1852
1853 case SMART_SEND_DRIVE_COMMAND: {
1854
1855 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1856 PSRB_IO_CONTROL srbControl;
1857 ULONG controlCode = 0;
1858 ULONG_PTR buffer;
1859
1860 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1861 (sizeof(SENDCMDINPARAMS) - 1)) {
1862 status = STATUS_INVALID_PARAMETER;
1863 break;
1864
1865 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1866 (sizeof(SENDCMDOUTPARAMS) - 1)) {
1867 status = STATUS_INVALID_PARAMETER;
1868 break;
1869 }
1870
1871 //
1872 // Create notification event object to be used to signal the
1873 // request completion.
1874 //
1875
1876 KeInitializeEvent(&event, NotificationEvent, FALSE);
1877
1878 length = 0;
1879
1880 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1881 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1882
1883 case ENABLE_SMART:
1884 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
1885 break;
1886
1887 case DISABLE_SMART:
1888 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
1889 break;
1890
1891 case RETURN_SMART_STATUS:
1892
1893 //
1894 // Ensure bBuffer is at least 2 bytes (to hold the values of
1895 // cylinderLow and cylinderHigh).
1896 //
1897
1898 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1899 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
1900
1901 status = STATUS_INVALID_PARAMETER;
1902 break;
1903 }
1904
1905 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
1906 length = sizeof(IDEREGS);
1907 break;
1908
1909 case ENABLE_DISABLE_AUTOSAVE:
1910 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
1911 break;
1912
1913 case SAVE_ATTRIBUTE_VALUES:
1914 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
1915 break;
1916
1917 case EXECUTE_OFFLINE_DIAGS:
1918 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
1919 break;
1920
1921 default:
1922 status = STATUS_INVALID_PARAMETER;
1923 break;
1924 }
1925 } else {
1926
1927 status = STATUS_INVALID_PARAMETER;
1928 }
1929
1930 if (controlCode == 0) {
1931 status = STATUS_INVALID_PARAMETER;
1932 break;
1933 }
1934
1935 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);
1936 srbControl = ExAllocatePool(NonPagedPool,
1937 sizeof(SRB_IO_CONTROL) + length);
1938
1939 if (!srbControl) {
1940 status = STATUS_INSUFFICIENT_RESOURCES;
1941 break;
1942 }
1943
1944 //
1945 // fill in srbControl fields
1946 //
1947
1948 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1949 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1950 srbControl->Timeout = deviceExtension->TimeOutValue;
1951 srbControl->Length = length;
1952
1953 //
1954 // Point to the 'buffer' portion of the SRB_CONTROL
1955 //
1956
1957 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
1958
1959 //
1960 // Ensure correct target is set in the cmd parameters.
1961 //
1962
1963 cmdInParameters->bDriveNumber = deviceExtension->TargetId;
1964
1965 //
1966 // Copy the IOCTL parameters to the srb control buffer area.
1967 //
1968
1969 RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1970
1971 srbControl->ControlCode = controlCode;
1972
1973 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1974 deviceExtension->PortDeviceObject,
1975 srbControl,
1976 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1977 srbControl,
1978 sizeof(SRB_IO_CONTROL) + length,
1979 FALSE,
1980 &event,
1981 &ioStatus);
1982
1983 if (irp2 == NULL) {
1984 status = STATUS_INSUFFICIENT_RESOURCES;
1985 break;
1986 }
1987
1988 //
1989 // Call the port driver with the request and wait for it to complete.
1990 //
1991
1992 status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1993
1994 if (status == STATUS_PENDING) {
1995 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1996 status = ioStatus.Status;
1997 }
1998
1999 //
2000 // Copy the data received into the output buffer. Since the status buffer
2001 // contains error information also, always perform this copy. IO will will
2002 // either pass this back to the app, or zero it, in case of error.
2003 //
2004
2005 buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
2006
2007 //
2008 // Update the return buffer size based on the sub-command.
2009 //
2010
2011 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
2012 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
2013 } else {
2014 length = sizeof(SENDCMDOUTPARAMS) - 1;
2015 }
2016
2017 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length);
2018 Irp->IoStatus.Information = length;
2019
2020 ExFreePool(srbControl);
2021 break;
2022
2023 }
2024
2025 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
2026 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
2027 {
2028
2029 PDEVICE_EXTENSION physicalDeviceExtension;
2030 PDISK_DATA physicalDiskData;
2031 BOOLEAN removable = FALSE;
2032 BOOLEAN listInitialized = FALSE;
2033
2034 if ((irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY &&
2035 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2036 sizeof(DISK_GEOMETRY)) ||
2037 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX &&
2038 irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2039 sizeof(DISK_GEOMETRY_EX))) {
2040
2041 status = STATUS_INFO_LENGTH_MISMATCH;
2042 break;
2043 }
2044
2045 status = STATUS_SUCCESS;
2046
2047 physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2048 physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
2049
2050 removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA;
2051 listInitialized = (physicalDiskData->PartitionListState == Initialized);
2052
2053 if (removable || (!listInitialized))
2054 {
2055 //
2056 // Issue ReadCapacity to update device extension
2057 // with information for current media.
2058 //
2059
2060 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
2061
2062 }
2063
2064 if (removable) {
2065
2066 if (!NT_SUCCESS(status)) {
2067
2068 //
2069 // Note the drive is not ready.
2070 //
2071
2072 diskData->DriveNotReady = TRUE;
2073
2074 break;
2075 }
2076
2077 //
2078 // Note the drive is now ready.
2079 //
2080
2081 diskData->DriveNotReady = FALSE;
2082
2083 } else if (NT_SUCCESS(status)) {
2084
2085 // ReadDriveCapacity was allright, create Partition Objects
2086
2087 if (physicalDiskData->PartitionListState == NotInitialized) {
2088 status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL);
2089 }
2090 }
2091
2092 if (NT_SUCCESS(status)) {
2093
2094 //
2095 // Copy drive geometry information from device extension.
2096 //
2097
2098 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2099 deviceExtension->DiskGeometry,
2100 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2101 sizeof(DISK_GEOMETRY) :
2102 sizeof(DISK_GEOMETRY_EX));
2103
2104 status = STATUS_SUCCESS;
2105 Irp->IoStatus.Information =
2106 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
2107 sizeof(DISK_GEOMETRY) :
2108 sizeof(DISK_GEOMETRY_EX);
2109 }
2110
2111 break;
2112
2113 }
2114
2115 case IOCTL_DISK_VERIFY:
2116
2117 {
2118
2119 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2120 LARGE_INTEGER byteOffset;
2121 ULONG sectorOffset;
2122 USHORT sectorCount;
2123
2124 //
2125 // Validate buffer length.
2126 //
2127
2128 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2129 sizeof(VERIFY_INFORMATION)) {
2130
2131 status = STATUS_INFO_LENGTH_MISMATCH;
2132 break;
2133 }
2134
2135 //
2136 // Verify sectors
2137 //
2138
2139 srb->CdbLength = 10;
2140
2141 cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2142
2143 //
2144 // Add disk offset to starting sector.
2145 //
2146
2147 byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart +
2148 verifyInfo->StartingOffset.QuadPart;
2149
2150 //
2151 // Convert byte offset to sector offset.
2152 //
2153
2154 sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift);
2155
2156 //
2157 // Convert ULONG byte count to USHORT sector count.
2158 //
2159
2160 sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift);
2161
2162 //
2163 // Move little endian values into CDB in big endian format.
2164 //
2165
2166 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2167 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2168 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2169 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2170
2171 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
2172 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
2173
2174 //
2175 // The verify command is used by the NT FORMAT utility and
2176 // requests are sent down for 5% of the volume size. The
2177 // request timeout value is calculated based on the number of
2178 // sectors verified.
2179 //
2180
2181 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
2182 deviceExtension->TimeOutValue;
2183
2184 status = ScsiClassSendSrbAsynchronous(DeviceObject,
2185 srb,
2186 Irp,
2187 NULL,
2188 0,
2189 FALSE);
2190
2191 return(status);
2192
2193 }
2194
2195 case IOCTL_DISK_GET_PARTITION_INFO:
2196
2197 //
2198 // Return the information about the partition specified by the device
2199 // object. Note that no information is ever returned about the size
2200 // or partition type of the physical disk, as this doesn't make any
2201 // sense.
2202 //
2203
2204 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2205 sizeof(PARTITION_INFORMATION)) {
2206
2207 status = STATUS_INFO_LENGTH_MISMATCH;
2208
2209 }
2210 #if 0 // HACK: ReactOS partition numbers must be wrong
2211 else if (diskData->PartitionNumber == 0) {
2212
2213 //
2214 // Paritition zero is not a partition so this is not a
2215 // reasonable request.
2216 //
2217
2218 status = STATUS_INVALID_DEVICE_REQUEST;
2219
2220 }
2221 #endif
2222 else {
2223
2224 PPARTITION_INFORMATION outputBuffer;
2225
2226 //
2227 // Update the geometry in case it has changed.
2228 //
2229
2230 status = UpdateRemovableGeometry (DeviceObject, Irp);
2231
2232 if (!NT_SUCCESS(status)) {
2233
2234 //
2235 // Note the drive is not ready.
2236 //
2237
2238 diskData->DriveNotReady = TRUE;
2239 break;
2240 }
2241
2242 //
2243 // Note the drive is now ready.
2244 //
2245
2246 diskData->DriveNotReady = FALSE;
2247 // HACK: ReactOS partition numbers must be wrong (>0 part)
2248 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2249
2250 status = STATUS_INVALID_DEVICE_REQUEST;
2251 break;
2252 }
2253
2254 outputBuffer =
2255 (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2256
2257 outputBuffer->PartitionType = diskData->PartitionType;
2258 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2259 outputBuffer->PartitionLength.QuadPart = (diskData->PartitionNumber) ?
2260 deviceExtension->PartitionLength.QuadPart : 2305843009213693951LL; // HACK
2261 outputBuffer->HiddenSectors = diskData->HiddenSectors;
2262 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2263 outputBuffer->BootIndicator = diskData->BootIndicator;
2264 outputBuffer->RewritePartition = FALSE;
2265 outputBuffer->RecognizedPartition =
2266 IsRecognizedPartition(diskData->PartitionType);
2267
2268 status = STATUS_SUCCESS;
2269 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
2270 }
2271
2272 break;
2273
2274 case IOCTL_DISK_GET_PARTITION_INFO_EX:
2275
2276 //
2277 // Return the information about the partition specified by the device
2278 // object. Note that no information is ever returned about the size
2279 // or partition type of the physical disk, as this doesn't make any
2280 // sense.
2281 //
2282
2283 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2284 sizeof(PARTITION_INFORMATION_EX)) {
2285
2286 status = STATUS_INFO_LENGTH_MISMATCH;
2287
2288 }
2289 else if (diskData->PartitionNumber == 0) {
2290
2291 //
2292 // Paritition zero is not a partition so this is not a
2293 // reasonable request.
2294 //
2295
2296 status = STATUS_INVALID_DEVICE_REQUEST;
2297
2298 }
2299 else {
2300
2301 PPARTITION_INFORMATION_EX outputBuffer;
2302
2303 //
2304 // Update the geometry in case it has changed.
2305 //
2306
2307 status = UpdateRemovableGeometry (DeviceObject, Irp);
2308
2309 if (!NT_SUCCESS(status)) {
2310
2311 //
2312 // Note the drive is not ready.
2313 //
2314
2315 diskData->DriveNotReady = TRUE;
2316 break;
2317 }
2318
2319 //
2320 // Note the drive is now ready.
2321 //
2322
2323 diskData->DriveNotReady = FALSE;
2324
2325 if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
2326
2327 status = STATUS_INVALID_DEVICE_REQUEST;
2328 break;
2329 }
2330
2331 outputBuffer =
2332 (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
2333
2334 //
2335 // FIXME: hack of the year, assume that partition is MBR
2336 // Thing that can obviously be wrong...
2337 //
2338
2339 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
2340 outputBuffer->Mbr.PartitionType = diskData->PartitionType;
2341 outputBuffer->StartingOffset = deviceExtension->StartingOffset;
2342 outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
2343 outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors;
2344 outputBuffer->PartitionNumber = diskData->PartitionNumber;
2345 outputBuffer->Mbr.BootIndicator = diskData->BootIndicator;
2346 outputBuffer->RewritePartition = FALSE;
2347 outputBuffer->Mbr.RecognizedPartition =
2348 IsRecognizedPartition(diskData->PartitionType);
2349
2350 status = STATUS_SUCCESS;
2351 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
2352 }
2353
2354 break;
2355
2356 case IOCTL_DISK_SET_PARTITION_INFO:
2357
2358 if (diskData->PartitionNumber == 0) {
2359
2360 status = STATUS_UNSUCCESSFUL;
2361
2362 } else {
2363
2364 PSET_PARTITION_INFORMATION inputBuffer =
2365 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2366
2367 //
2368 // Validate buffer length.
2369 //
2370
2371 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2372 sizeof(SET_PARTITION_INFORMATION)) {
2373
2374 status = STATUS_INFO_LENGTH_MISMATCH;
2375 break;
2376 }
2377
2378 //
2379 // The HAL routines IoGet- and IoSetPartitionInformation were
2380 // developed before support of dynamic partitioning and therefore
2381 // don't distinguish between partition ordinal (that is the order
2382 // of a partition on a disk) and the partition number. (The
2383 // partition number is assigned to a partition to identify it to
2384 // the system.) Use partition ordinals for these legacy calls.
2385 //
2386
2387 status = IoSetPartitionInformation(
2388 deviceExtension->PhysicalDevice,
2389 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2390 diskData->PartitionOrdinal,
2391 inputBuffer->PartitionType);
2392
2393 if (NT_SUCCESS(status)) {
2394
2395 diskData->PartitionType = inputBuffer->PartitionType;
2396 }
2397 }
2398
2399 break;
2400
2401 case IOCTL_DISK_GET_DRIVE_LAYOUT:
2402
2403 //
2404 // Return the partition layout for the physical drive. Note that
2405 // the layout is returned for the actual physical drive, regardless
2406 // of which partition was specified for the request.
2407 //
2408
2409 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2410 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2411 status = STATUS_INFO_LENGTH_MISMATCH;
2412
2413 } else {
2414
2415 PDRIVE_LAYOUT_INFORMATION partitionList;
2416 PDEVICE_EXTENSION physicalExtension = deviceExtension;
2417 PPARTITION_INFORMATION partitionEntry;
2418 PDISK_DATA diskData;
2419 ULONG tempSize;
2420 ULONG i;
2421
2422 //
2423 // Read partition information.
2424 //
2425
2426 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
2427 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2428 FALSE,
2429 &partitionList);
2430
2431 if (!NT_SUCCESS(status)) {
2432 break;
2433 }
2434
2435 //
2436 // The disk layout has been returned in the partitionList
2437 // buffer. Determine its size and, if the data will fit
2438 // into the intermediatery buffer, return it.
2439 //
2440
2441 tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
2442 tempSize += partitionList->PartitionCount *
2443 sizeof(PARTITION_INFORMATION);
2444
2445 if (tempSize >
2446 irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
2447
2448 status = STATUS_BUFFER_TOO_SMALL;
2449 ExFreePool(partitionList);
2450 break;
2451 }
2452
2453 //
2454 // Walk partition list to associate partition numbers with
2455 // partition entries.
2456 //
2457
2458 for (i = 0; i < partitionList->PartitionCount; i++) {
2459
2460 //
2461 // Walk partition chain anchored at physical disk extension.
2462 //
2463
2464 deviceExtension = physicalExtension;
2465 diskData = (PDISK_DATA)(deviceExtension + 1);
2466
2467 do {
2468
2469 deviceExtension = diskData->NextPartition;
2470
2471 //
2472 // Check if this is the last partition in the chain.
2473 //
2474
2475 if (!deviceExtension) {
2476 break;
2477 }
2478
2479 //
2480 // Get the partition device extension from disk data.
2481 //
2482
2483 diskData = (PDISK_DATA)(deviceExtension + 1);
2484
2485 //
2486 // Check if this partition is not currently being used.
2487 //
2488
2489 if (!deviceExtension->PartitionLength.QuadPart) {
2490 continue;
2491 }
2492
2493 partitionEntry = &partitionList->PartitionEntry[i];
2494
2495 //
2496 // Check if empty, or describes extended partiton or hasn't changed.
2497 //
2498
2499 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2500 IsContainerPartition(partitionEntry->PartitionType)) {
2501 continue;
2502 }
2503
2504 //
2505 // Check if new partition starts where this partition starts.
2506 //
2507
2508 if (partitionEntry->StartingOffset.QuadPart !=
2509 deviceExtension->StartingOffset.QuadPart) {
2510 continue;
2511 }
2512
2513 //
2514 // Check if partition length is the same.
2515 //
2516
2517 if (partitionEntry->PartitionLength.QuadPart ==
2518 deviceExtension->PartitionLength.QuadPart) {
2519
2520 //
2521 // Partitions match. Update partition number.
2522 //
2523
2524 partitionEntry->PartitionNumber =
2525 diskData->PartitionNumber;
2526 break;
2527 }
2528
2529 } while (TRUE);
2530 }
2531
2532 //
2533 // Copy partition information to system buffer.
2534 //
2535
2536 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2537 partitionList,
2538 tempSize);
2539 status = STATUS_SUCCESS;
2540 Irp->IoStatus.Information = tempSize;
2541
2542 //
2543 // Finally, free the buffer allocated by reading the
2544 // partition table.
2545 //
2546
2547 ExFreePool(partitionList);
2548 }
2549
2550 break;
2551
2552 case IOCTL_DISK_SET_DRIVE_LAYOUT:
2553
2554 {
2555
2556 //
2557 // Update the disk with new partition information.
2558 //
2559
2560 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
2561
2562 //
2563 // Validate buffer length.
2564 //
2565
2566 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2567 sizeof(DRIVE_LAYOUT_INFORMATION)) {
2568
2569 status = STATUS_INFO_LENGTH_MISMATCH;
2570 break;
2571 }
2572
2573 length = sizeof(DRIVE_LAYOUT_INFORMATION) +
2574 (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
2575
2576
2577 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2578 length) {
2579
2580 status = STATUS_BUFFER_TOO_SMALL;
2581 break;
2582 }
2583
2584 //
2585 // Verify that device object is for physical disk.
2586 //
2587
2588 if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
2589 status = STATUS_INVALID_PARAMETER;
2590 break;
2591 }
2592
2593 //
2594 // Walk through partition table comparing partitions to
2595 // existing partitions to create, delete and change
2596 // device objects as necessary.
2597 //
2598
2599 UpdateDeviceObjects(DeviceObject,
2600 Irp);
2601
2602 //
2603 // Write changes to disk.
2604 //
2605
2606 status = IoWritePartitionTable(
2607 deviceExtension->DeviceObject,
2608 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
2609 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
2610 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
2611 partitionList);
2612 }
2613
2614 //
2615 // Update IRP with bytes returned.
2616 //
2617
2618 if (NT_SUCCESS(status)) {
2619 Irp->IoStatus.Information = length;
2620 }
2621
2622 break;
2623
2624 case IOCTL_DISK_REASSIGN_BLOCKS:
2625
2626 //
2627 // Map defective blocks to new location on disk.
2628 //
2629
2630 {
2631
2632 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2633 ULONG bufferSize;
2634 ULONG blockNumber;
2635 ULONG blockCount;
2636
2637 //
2638 // Validate buffer length.
2639 //
2640
2641 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2642 sizeof(REASSIGN_BLOCKS)) {
2643
2644 status = STATUS_INFO_LENGTH_MISMATCH;
2645 break;
2646 }
2647
2648 bufferSize = sizeof(REASSIGN_BLOCKS) +
2649 (badBlocks->Count - 1) * sizeof(ULONG);
2650
2651 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2652 bufferSize) {
2653
2654 status = STATUS_INFO_LENGTH_MISMATCH;
2655 break;
2656 }
2657
2658 //
2659 // Build the data buffer to be transferred in the input buffer.
2660 // The format of the data to the device is:
2661 //
2662 // 2 bytes Reserved
2663 // 2 bytes Length
2664 // x * 4 btyes Block Address
2665 //
2666 // All values are big endian.
2667 //
2668
2669 badBlocks->Reserved = 0;
2670 blockCount = badBlocks->Count;
2671
2672 //
2673 // Convert # of entries to # of bytes.
2674 //
2675
2676 blockCount *= 4;
2677 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2678 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2679
2680 //
2681 // Convert back to number of entries.
2682 //
2683
2684 blockCount /= 4;
2685
2686 for (; blockCount > 0; blockCount--) {
2687
2688 blockNumber = badBlocks->BlockNumber[blockCount-1];
2689
2690 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2691 (PFOUR_BYTE) &blockNumber);
2692 }
2693
2694 srb->CdbLength = 6;
2695
2696 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2697
2698 //
2699 // Set timeout value.
2700 //
2701
2702 srb->TimeOutValue = deviceExtension->TimeOutValue;
2703
2704 status = ScsiClassSendSrbSynchronous(DeviceObject,
2705 srb,
2706 badBlocks,
2707 bufferSize,
2708 TRUE);
2709
2710 Irp->IoStatus.Status = status;
2711 Irp->IoStatus.Information = 0;
2712 ExFreePool(srb);
2713 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2714 }
2715
2716 return(status);
2717
2718 case IOCTL_DISK_IS_WRITABLE:
2719
2720 //
2721 // Determine if the device is writable.
2722 //
2723
2724 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
2725
2726 if (modeData == NULL) {
2727 status = STATUS_INSUFFICIENT_RESOURCES;
2728 break;
2729 }
2730
2731 RtlZeroMemory(modeData, MODE_DATA_SIZE);
2732
2733 length = ScsiClassModeSense(DeviceObject,
2734 (PCHAR) modeData,
2735 MODE_DATA_SIZE,
2736 MODE_SENSE_RETURN_ALL);
2737
2738 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2739
2740 //
2741 // Retry the request in case of a check condition.
2742 //
2743
2744 length = ScsiClassModeSense(DeviceObject,
2745 (PCHAR) modeData,
2746 MODE_DATA_SIZE,
2747 MODE_SENSE_RETURN_ALL);
2748
2749 if (length < sizeof(MODE_PARAMETER_HEADER)) {
2750 status = STATUS_IO_DEVICE_ERROR;
2751 ExFreePool(modeData);
2752 break;
2753 }
2754 }
2755
2756 if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
2757 status = STATUS_MEDIA_WRITE_PROTECTED;
2758 } else {
2759 status = STATUS_SUCCESS;
2760 }
2761
2762 ExFreePool(modeData);
2763 break;
2764
2765 case IOCTL_DISK_INTERNAL_SET_VERIFY:
2766
2767 //
2768 // If the caller is kernel mode, set the verify bit.
2769 //
2770
2771 if (Irp->RequestorMode == KernelMode) {
2772 DeviceObject->Flags |= DO_VERIFY_VOLUME;
2773 }
2774 status = STATUS_SUCCESS;
2775 break;
2776
2777 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
2778
2779 //
2780 // If the caller is kernel mode, clear the verify bit.
2781 //
2782
2783 if (Irp->RequestorMode == KernelMode) {
2784 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
2785 }
2786 status = STATUS_SUCCESS;
2787 break;
2788
2789 case IOCTL_DISK_FIND_NEW_DEVICES:
2790
2791 //
2792 // Search for devices that have been powered on since the last
2793 // device search or system initialization.
2794 //
2795
2796 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
2797 status = DriverEntry(DeviceObject->DriverObject,
2798 NULL);
2799
2800 Irp->IoStatus.Status = status;
2801 ExFreePool(srb);
2802 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2803 return status;
2804
2805 case IOCTL_DISK_MEDIA_REMOVAL:
2806
2807 //
2808 // If the disk is not removable then don't allow this command.
2809 //
2810
2811 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
2812 status = STATUS_INVALID_DEVICE_REQUEST;
2813 break;
2814 }
2815
2816 //
2817 // Fall through and let the class driver process the request.
2818 //
2819
2820 case IOCTL_DISK_GET_LENGTH_INFO:
2821
2822 //
2823 // Validate buffer length.
2824 //
2825
2826 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2827 sizeof(GET_LENGTH_INFORMATION)) {
2828 status = STATUS_BUFFER_TOO_SMALL;
2829
2830 } else {
2831
2832 PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer;
2833
2834 //
2835 // Update the geometry in case it has changed.
2836 //
2837
2838 status = UpdateRemovableGeometry (DeviceObject, Irp);
2839
2840 if (!NT_SUCCESS(status)) {
2841
2842 //
2843 // Note the drive is not ready.
2844 //
2845
2846 diskData->DriveNotReady = TRUE;
2847 break;
2848 }
2849
2850 //
2851 // Note the drive is now ready.
2852 //
2853
2854 diskData->DriveNotReady = FALSE;
2855
2856 //
2857 // Output data, and return
2858 //
2859
2860 lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart;
2861 status = STATUS_SUCCESS;
2862 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
2863 }
2864
2865 break;
2866
2867 default:
2868
2869 //
2870 // Free the Srb, since it is not needed.
2871 //
2872
2873 ExFreePool(srb);
2874
2875 //
2876 // Pass the request to the common device control routine.
2877 //
2878
2879 return(ScsiClassDeviceControl(DeviceObject, Irp));
2880
2881 break;
2882
2883 } // end switch( ...
2884
2885 Irp->IoStatus.Status = status;
2886
2887 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
2888
2889 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
2890 }
2891
2892 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2893 ExFreePool(srb);
2894 return(status);
2895
2896 } // end ScsiDiskDeviceControl()
2897 \f
2898 NTSTATUS
2899 NTAPI
2900 ScsiDiskShutdownFlush (
2901 IN PDEVICE_OBJECT DeviceObject,
2902 IN PIRP Irp
2903 )
2904
2905 /*++
2906
2907 Routine Description:
2908
2909 This routine is called for a shutdown and flush IRPs. These are sent by the
2910 system before it actually shuts down or when the file system does a flush.
2911 A synchronize cache command is sent to the device if it is write caching.
2912 If the device is removable an unlock command will be sent. This routine
2913 will sent a shutdown or flush Srb to the port driver.
2914
2915 Arguments:
2916
2917 DriverObject - Pointer to device object to being shutdown by system.
2918
2919 Irp - IRP involved.
2920
2921 Return Value:
2922
2923 NT Status
2924
2925 --*/
2926
2927 {
2928 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2929 PIO_STACK_LOCATION irpStack;
2930 PSCSI_REQUEST_BLOCK srb;
2931 NTSTATUS status;
2932 PCDB cdb;
2933
2934 //
2935 // Allocate SCSI request block.
2936 //
2937
2938 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
2939
2940 if (srb == NULL) {
2941
2942 //
2943 // Set the status and complete the request.
2944 //
2945
2946 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2947 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2948 return(STATUS_INSUFFICIENT_RESOURCES);
2949 }
2950
2951 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2952
2953 //
2954 // Write length to SRB.
2955 //
2956
2957 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2958
2959 //
2960 // Set SCSI bus address.
2961 //
2962
2963 srb->PathId = deviceExtension->PathId;
2964 srb->TargetId = deviceExtension->TargetId;
2965 srb->Lun = deviceExtension->Lun;
2966
2967 //
2968 // Set timeout value and mark the request as not being a tagged request.
2969 //
2970
2971 srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
2972 srb->QueueTag = SP_UNTAGGED;
2973 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
2974 srb->SrbFlags = deviceExtension->SrbFlags;
2975
2976 //
2977 // If the write cache is enabled then send a synchronize cache request.
2978 //
2979
2980 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
2981
2982 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2983 srb->CdbLength = 10;
2984
2985 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
2986
2987 status = ScsiClassSendSrbSynchronous(DeviceObject,
2988 srb,
2989 NULL,
2990 0,
2991 TRUE);
2992
2993 DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status ));
2994 }
2995
2996 //
2997 // Unlock the device if it is removable and this is a shutdown.
2998 //
2999
3000 irpStack = IoGetCurrentIrpStackLocation(Irp);
3001
3002 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
3003 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
3004
3005 srb->CdbLength = 6;
3006 cdb = (PVOID) srb->Cdb;
3007 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3008 cdb->MEDIA_REMOVAL.Prevent = FALSE;
3009
3010 //
3011 // Set timeout value.
3012 //
3013
3014 srb->TimeOutValue = deviceExtension->TimeOutValue;
3015 status = ScsiClassSendSrbSynchronous(DeviceObject,
3016 srb,
3017 NULL,
3018 0,
3019 TRUE);
3020
3021 DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
3022 }
3023
3024 srb->CdbLength = 0;
3025
3026 //
3027 // Save a few parameters in the current stack location.
3028 //
3029
3030 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
3031 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
3032
3033 //
3034 // Set the retry count to zero.
3035 //
3036
3037 irpStack->Parameters.Others.Argument4 = (PVOID) 0;
3038
3039 //
3040 // Set up IoCompletion routine address.
3041 //
3042
3043 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
3044
3045 //
3046 // Get next stack location and
3047 // set major function code.
3048 //
3049
3050 irpStack = IoGetNextIrpStackLocation(Irp);
3051
3052 irpStack->MajorFunction = IRP_MJ_SCSI;
3053
3054 //
3055 // Set up SRB for execute scsi request.
3056 // Save SRB address in next stack for port driver.
3057 //
3058
3059 irpStack->Parameters.Scsi.Srb = srb;
3060
3061 //
3062 // Set up Irp Address.
3063 //
3064
3065 srb->OriginalRequest = Irp;
3066
3067 //
3068 // Call the port driver to process the request.
3069 //
3070
3071 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3072
3073 } // end ScsiDiskShutdown()
3074
3075 \f
3076 BOOLEAN
3077 NTAPI
3078 IsFloppyDevice(
3079 PDEVICE_OBJECT DeviceObject
3080 )
3081 /*++
3082
3083 Routine Description:
3084
3085 The routine performs the necessary functions to determine if a device is
3086 really a floppy rather than a harddisk. This is done by a mode sense
3087 command. First, a check is made to see if the medimum type is set. Second
3088 a check is made for the flexible parameters mode page. Also a check is
3089 made to see if the write cache is enabled.
3090
3091 Arguments:
3092
3093 DeviceObject - Supplies the device object to be tested.
3094
3095 Return Value:
3096
3097 Return TRUE if the indicated device is a floppy.
3098
3099 --*/
3100 {
3101 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3102 PVOID modeData;
3103 PUCHAR pageData;
3104 ULONG length;
3105
3106 PAGED_CODE();
3107
3108 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3109
3110 if (modeData == NULL) {
3111 return(FALSE);
3112 }
3113
3114 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3115
3116 length = ScsiClassModeSense(DeviceObject,
3117 modeData,
3118 MODE_DATA_SIZE,
3119 MODE_SENSE_RETURN_ALL);
3120
3121 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3122
3123 //
3124 // Retry the request in case of a check condition.
3125 //
3126
3127 length = ScsiClassModeSense(DeviceObject,
3128 modeData,
3129 MODE_DATA_SIZE,
3130 MODE_SENSE_RETURN_ALL);
3131
3132 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3133
3134 ExFreePool(modeData);
3135 return(FALSE);
3136
3137 }
3138 }
3139
3140 //
3141 // If the length is greater than length indicated by the mode data reset
3142 // the data to the mode data.
3143 //
3144
3145 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3146 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3147 }
3148
3149 //
3150 // Look for the flexible disk mode page.
3151 //
3152
3153 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
3154
3155 if (pageData != NULL) {
3156
3157 DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
3158 ExFreePool(modeData);
3159 return(TRUE);
3160 }
3161
3162 //
3163 // Check to see if the write cache is enabled.
3164 //
3165
3166 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3167
3168 //
3169 // Assume that write cache is disabled or not supported.
3170 //
3171
3172 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3173
3174 //
3175 // Check if valid caching page exists.
3176 //
3177
3178 if (pageData != NULL) {
3179
3180 //
3181 // Check if write cache is disabled.
3182 //
3183
3184 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3185
3186 DebugPrint((1,
3187 "SCSIDISK: Disk write cache enabled\n"));
3188
3189 //
3190 // Check if forced unit access (FUA) is supported.
3191 //
3192
3193 if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
3194
3195 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3196
3197 } else {
3198
3199 DebugPrint((1,
3200 "SCSIDISK: Disk does not support FUA or DPO\n"));
3201
3202 //
3203 // TODO: Log this.
3204 //
3205
3206 }
3207 }
3208 }
3209
3210 ExFreePool(modeData);
3211 return(FALSE);
3212
3213 } // end IsFloppyDevice()
3214
3215 \f
3216 BOOLEAN
3217 NTAPI
3218 ScsiDiskModeSelect(
3219 IN PDEVICE_OBJECT DeviceObject,
3220 IN PCHAR ModeSelectBuffer,
3221 IN ULONG Length,
3222 IN BOOLEAN SavePage
3223 )
3224
3225 /*++
3226
3227 Routine Description:
3228
3229 This routine sends a mode select command.
3230
3231 Arguments:
3232
3233 DeviceObject - Supplies the device object associated with this request.
3234
3235 ModeSelectBuffer - Supplies a buffer containing the page data.
3236
3237 Length - Supplies the length in bytes of the mode select buffer.
3238
3239 SavePage - Indicates that parameters should be written to disk.
3240
3241 Return Value:
3242
3243 Length of the transferred data is returned.
3244
3245 --*/
3246 {
3247 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3248 PCDB cdb;
3249 SCSI_REQUEST_BLOCK srb;
3250 ULONG retries = 1;
3251 ULONG length2;
3252 NTSTATUS status;
3253 ULONG_PTR buffer;
3254 PMODE_PARAMETER_BLOCK blockDescriptor;
3255
3256 PAGED_CODE();
3257
3258 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
3259
3260 //
3261 // Allocate buffer for mode select header, block descriptor, and mode page.
3262 //
3263
3264 buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
3265
3266 RtlZeroMemory((PVOID)buffer, length2);
3267
3268 //
3269 // Set length in header to size of mode page.
3270 //
3271
3272 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
3273
3274 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
3275
3276 //
3277 // Set size
3278 //
3279
3280 blockDescriptor->BlockLength[1]=0x02;
3281
3282 //
3283 // Copy mode page to buffer.
3284 //
3285
3286 RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
3287
3288 //
3289 // Zero SRB.
3290 //
3291
3292 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3293
3294 //
3295 // Build the MODE SELECT CDB.
3296 //
3297
3298 srb.CdbLength = 6;
3299 cdb = (PCDB)srb.Cdb;
3300
3301 //
3302 // Set timeout value from device extension.
3303 //
3304
3305 srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
3306
3307 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3308 cdb->MODE_SELECT.SPBit = SavePage;
3309 cdb->MODE_SELECT.PFBit = 1;
3310 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
3311
3312 Retry:
3313
3314 status = ScsiClassSendSrbSynchronous(DeviceObject,
3315 &srb,
3316 (PVOID)buffer,
3317 length2,
3318 TRUE);
3319
3320
3321 if (status == STATUS_VERIFY_REQUIRED) {
3322
3323 //
3324 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3325 // this status.
3326 //
3327
3328 if (retries--) {
3329
3330 //
3331 // Retry request.
3332 //
3333
3334 goto Retry;
3335 }
3336
3337 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3338 status = STATUS_SUCCESS;
3339 }
3340
3341 ExFreePool((PVOID)buffer);
3342
3343 if (NT_SUCCESS(status)) {
3344 return(TRUE);
3345 } else {
3346 return(FALSE);
3347 }
3348
3349 } // end SciDiskModeSelect()
3350
3351 \f
3352 VOID
3353 NTAPI
3354 DisableWriteCache(
3355 IN PDEVICE_OBJECT DeviceObject,
3356 IN PSCSI_INQUIRY_DATA LunInfo
3357 )
3358
3359 {
3360 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3361 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3362 BAD_CONTROLLER_INFORMATION const *controller;
3363 ULONG j,length;
3364 PVOID modeData;
3365 PUCHAR pageData;
3366
3367 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
3368
3369 controller = &ScsiDiskBadControllers[j];
3370
3371 if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
3372 continue;
3373 }
3374
3375 DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
3376
3377 modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
3378
3379 if (modeData == NULL) {
3380
3381 DebugPrint((1,
3382 "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
3383 return;
3384 }
3385
3386 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3387
3388 length = ScsiClassModeSense(DeviceObject,
3389 modeData,
3390 MODE_DATA_SIZE,
3391 MODE_SENSE_RETURN_ALL);
3392
3393 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3394
3395 //
3396 // Retry the request in case of a check condition.
3397 //
3398
3399 length = ScsiClassModeSense(DeviceObject,
3400 modeData,
3401 MODE_DATA_SIZE,
3402 MODE_SENSE_RETURN_ALL);
3403
3404 if (length < sizeof(MODE_PARAMETER_HEADER)) {
3405
3406
3407 DebugPrint((1,
3408 "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
3409
3410 ExFreePool(modeData);
3411 return;
3412
3413 }
3414 }
3415
3416 //
3417 // If the length is greater than length indicated by the mode data reset
3418 // the data to the mode data.
3419 //
3420
3421 if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
3422 length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
3423 }
3424
3425 //
3426 // Check to see if the write cache is enabled.
3427 //
3428
3429 pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
3430
3431 //
3432 // Assume that write cache is disabled or not supported.
3433 //
3434
3435 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3436
3437 //
3438 // Check if valid caching page exists.
3439 //
3440
3441 if (pageData != NULL) {
3442
3443 BOOLEAN savePage = FALSE;
3444
3445 savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
3446
3447 //
3448 // Check if write cache is disabled.
3449 //
3450
3451 if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
3452
3453 PIO_ERROR_LOG_PACKET errorLogEntry;
3454 LONG errorCode;
3455
3456
3457 //
3458 // Disable write cache and ensure necessary fields are zeroed.
3459 //
3460
3461 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
3462 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
3463 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
3464 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
3465
3466 //
3467 // Extract length from caching page.
3468 //
3469
3470 length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
3471
3472 //
3473 // Compensate for page code and page length.
3474 //
3475
3476 length += 2;
3477
3478 //
3479 // Issue mode select to set the parameter.
3480 //
3481
3482 if (ScsiDiskModeSelect(DeviceObject,
3483 (PCHAR)pageData,
3484 length,
3485 savePage)) {
3486
3487 DebugPrint((1,
3488 "SCSIDISK: Disk write cache disabled\n"));
3489
3490 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3491 errorCode = IO_WRITE_CACHE_DISABLED;
3492
3493 } else {
3494 if (ScsiDiskModeSelect(DeviceObject,
3495 (PCHAR)pageData,
3496 length,
3497 savePage)) {
3498
3499 DebugPrint((1,
3500 "SCSIDISK: Disk write cache disabled\n"));
3501
3502
3503 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
3504 errorCode = IO_WRITE_CACHE_DISABLED;
3505
3506 } else {
3507
3508 DebugPrint((1,
3509 "SCSIDISK: Mode select to disable write cache failed\n"));
3510
3511 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
3512 errorCode = IO_WRITE_CACHE_ENABLED;
3513 }
3514 }
3515
3516 //
3517 // Log the appropriate informational or error entry.
3518 //
3519
3520 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3521 DeviceObject,
3522 sizeof(IO_ERROR_LOG_PACKET) + 3
3523 * sizeof(ULONG));
3524
3525 if (errorLogEntry != NULL) {
3526
3527 errorLogEntry->FinalStatus = STATUS_SUCCESS;
3528 errorLogEntry->ErrorCode = errorCode;
3529 errorLogEntry->SequenceNumber = 0;
3530 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
3531 errorLogEntry->IoControlCode = 0;
3532 errorLogEntry->RetryCount = 0;
3533 errorLogEntry->UniqueErrorValue = 0x1;
3534 errorLogEntry->DumpDataSize = 3 * sizeof(ULONG);
3535 errorLogEntry->DumpData[0] = LunInfo->PathId;
3536 errorLogEntry->DumpData[1] = LunInfo->TargetId;
3537 errorLogEntry->DumpData[2] = LunInfo->Lun;
3538
3539 //
3540 // Write the error log packet.
3541 //
3542
3543 IoWriteErrorLogEntry(errorLogEntry);
3544 }
3545 }
3546 }
3547
3548 //
3549 // Found device so exit the loop and return.
3550 //
3551
3552 break;
3553 }
3554
3555 return;
3556 }
3557
3558 \f
3559 BOOLEAN
3560 NTAPI
3561 CalculateMbrCheckSum(
3562 IN PDEVICE_EXTENSION DeviceExtension,
3563 OUT PULONG Checksum
3564 )
3565
3566 /*++
3567
3568 Routine Description:
3569
3570 Read MBR and calculate checksum.
3571
3572 Arguments:
3573
3574 DeviceExtension - Supplies a pointer to the device information for disk.
3575 Checksum - Memory location to return MBR checksum.
3576
3577 Return Value:
3578
3579 Returns TRUE if checksum is valid.
3580
3581 --*/
3582 {
3583 LARGE_INTEGER sectorZero;
3584 PIRP irp;
3585 IO_STATUS_BLOCK ioStatus;
3586 KEVENT event;
3587 NTSTATUS status;
3588 ULONG sectorSize;
3589 PULONG mbr;
3590 ULONG i;
3591
3592 PAGED_CODE();
3593 sectorZero.QuadPart = (LONGLONG) 0;
3594
3595 //
3596 // Create notification event object to be used to signal the inquiry
3597 // request completion.
3598 //
3599
3600 KeInitializeEvent(&event, NotificationEvent, FALSE);
3601
3602 //
3603 // Get sector size.
3604 //
3605
3606 sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
3607
3608 //
3609 // Make sure sector size is at least 512 bytes.
3610 //
3611
3612 if (sectorSize < 512) {
3613 sectorSize = 512;
3614 }
3615
3616 //
3617 // Allocate buffer for sector read.
3618 //
3619
3620 mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize);
3621
3622 if (!mbr) {
3623 return FALSE;
3624 }
3625
3626 //
3627 // Build IRP to read MBR.
3628 //
3629
3630 irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
3631 DeviceExtension->DeviceObject,
3632 mbr,
3633 sectorSize,
3634 &sectorZero,
3635 &event,
3636 &ioStatus );
3637
3638 if (!irp) {
3639 ExFreePool(mbr);
3640 return FALSE;
3641 }
3642
3643 //
3644 // Pass request to port driver and wait for request to complete.
3645 //
3646
3647 status = IoCallDriver(DeviceExtension->DeviceObject,
3648 irp);
3649
3650 if (status == STATUS_PENDING) {
3651 KeWaitForSingleObject(&event,
3652 Suspended,
3653 KernelMode,
3654 FALSE,
3655 NULL);
3656 status = ioStatus.Status;
3657 }
3658
3659 if (!NT_SUCCESS(status)) {
3660 ExFreePool(mbr);
3661 return FALSE;
3662 }
3663
3664 //
3665 // Calculate MBR checksum.
3666 //
3667
3668 *Checksum = 0;
3669
3670 for (i = 0; i < 128; i++) {
3671 *Checksum += mbr[i];
3672 }
3673
3674 *Checksum = ~*Checksum + 1;
3675
3676 ExFreePool(mbr);
3677 return TRUE;
3678 }
3679
3680 \f
3681 BOOLEAN
3682 NTAPI
3683 EnumerateBusKey(
3684 IN PDEVICE_EXTENSION DeviceExtension,
3685 HANDLE BusKey,
3686 PULONG DiskNumber
3687 )
3688
3689 /*++
3690
3691 Routine Description:
3692
3693 The routine queries the registry to determine if this disk is visible to
3694 the BIOS. If the disk is visable to the BIOS, then the geometry information
3695 is updated.
3696
3697 Arguments:
3698
3699 DeviceExtension - Supplies a pointer to the device information for disk.
3700 Signature - Unique identifier recorded in MBR.
3701 BusKey - Handle of bus key.
3702 DiskNumber - Returns ordinal of disk as BIOS sees it.
3703
3704 Return Value:
3705
3706 TRUE is disk signature matched.
3707
3708 --*/
3709 {
3710 PDISK_DATA diskData = (PDISK_DATA)(DeviceExtension + 1);
3711 BOOLEAN diskFound = FALSE;
3712 OBJECT_ATTRIBUTES objectAttributes;
3713 UNICODE_STRING unicodeString;
3714 UNICODE_STRING identifier;
3715 ULONG busNumber;
3716 ULONG adapterNumber;
3717 ULONG diskNumber;
3718 HANDLE adapterKey;
3719 HANDLE spareKey;
3720 HANDLE diskKey;
3721 HANDLE targetKey;
3722 NTSTATUS status;
3723 STRING string;
3724 STRING anotherString;
3725 ULONG length;
3726 UCHAR buffer[20];
3727 PKEY_VALUE_FULL_INFORMATION keyData;
3728
3729 PAGED_CODE();
3730
3731 for (busNumber = 0; ; busNumber++) {
3732
3733 //
3734 // Open controller name key.
3735 //
3736
3737 sprintf((PCHAR)buffer,
3738 "%lu",
3739 busNumber);
3740
3741 RtlInitString(&string,
3742 (PCSZ)buffer);
3743
3744 status = RtlAnsiStringToUnicodeString(&unicodeString,
3745 &string,
3746 TRUE);
3747
3748 if (!NT_SUCCESS(status)){
3749 break;
3750 }
3751
3752 InitializeObjectAttributes(&objectAttributes,
3753 &unicodeString,
3754 OBJ_CASE_INSENSITIVE,
3755 BusKey,
3756 (PSECURITY_DESCRIPTOR)NULL);
3757
3758 status = ZwOpenKey(&spareKey,
3759 KEY_READ,
3760 &objectAttributes);
3761
3762 RtlFreeUnicodeString(&unicodeString);
3763
3764 if (!NT_SUCCESS(status)) {
3765 break;
3766 }
3767
3768 //
3769 // Open up controller ordinal key.
3770 //
3771
3772 RtlInitUnicodeString(&unicodeString, L"DiskController");
3773 InitializeObjectAttributes(&objectAttributes,
3774 &unicodeString,
3775 OBJ_CASE_INSENSITIVE,
3776 spareKey,
3777 (PSECURITY_DESCRIPTOR)NULL);
3778
3779 status = ZwOpenKey(&adapterKey,
3780 KEY_READ,
3781 &objectAttributes);
3782
3783 //
3784 // This could fail even with additional adapters of this type
3785 // to search.
3786 //
3787
3788 if (!NT_SUCCESS(status)) {
3789 continue;
3790 }
3791
3792 for (adapterNumber = 0; ; adapterNumber++) {
3793
3794 //
3795 // Open disk key.
3796 //
3797
3798 sprintf((PCHAR)buffer,
3799 "%lu\\DiskPeripheral",
3800 adapterNumber);
3801
3802 RtlInitString(&string,
3803 (PCSZ)buffer);
3804
3805 status = RtlAnsiStringToUnicodeString(&unicodeString,
3806 &string,
3807 TRUE);
3808
3809 if (!NT_SUCCESS(status)){
3810 break;
3811 }
3812
3813 InitializeObjectAttributes(&objectAttributes,
3814 &unicodeString,
3815 OBJ_CASE_INSENSITIVE,
3816 adapterKey,
3817 (PSECURITY_DESCRIPTOR)NULL);
3818
3819 status = ZwOpenKey(&diskKey,
3820 KEY_READ,
3821 &objectAttributes);
3822
3823 RtlFreeUnicodeString(&unicodeString);
3824
3825 if (!NT_SUCCESS(status)) {
3826 break;
3827 }
3828
3829 for (diskNumber = 0; ; diskNumber++) {
3830
3831 sprintf((PCHAR)buffer,
3832 "%lu",
3833 diskNumber);
3834
3835 RtlInitString(&string,
3836 (PCSZ)buffer);
3837
3838 status = RtlAnsiStringToUnicodeString(&unicodeString,
3839 &string,
3840 TRUE);
3841
3842 if (!NT_SUCCESS(status)){
3843 break;
3844 }
3845
3846 InitializeObjectAttributes(&objectAttributes,
3847 &unicodeString,
3848 OBJ_CASE_INSENSITIVE,
3849 diskKey,
3850 (PSECURITY_DESCRIPTOR)NULL);
3851
3852 status = ZwOpenKey(&targetKey,
3853 KEY_READ,
3854 &objectAttributes);
3855
3856 RtlFreeUnicodeString(&unicodeString);
3857
3858 if (!NT_SUCCESS(status)) {
3859 break;
3860 }
3861
3862 //
3863 // Allocate buffer for registry query.
3864 //
3865
3866 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
3867
3868 if (keyData == NULL) {
3869 ZwClose(targetKey);
3870 continue;
3871 }
3872
3873 //
3874 // Get disk peripheral identifier.
3875 //
3876
3877 RtlInitUnicodeString(&unicodeString, L"Identifier");
3878 status = ZwQueryValueKey(targetKey,
3879 &unicodeString,
3880 KeyValueFullInformation,
3881 keyData,
3882 VALUE_BUFFER_SIZE,
3883 &length);
3884
3885 ZwClose(targetKey);
3886
3887 if (!NT_SUCCESS(status)) {
3888 continue;
3889 }
3890
3891 //
3892 // Complete unicode string.
3893 //
3894
3895 identifier.Buffer =
3896 (PWSTR)((PUCHAR)keyData + keyData->DataOffset);
3897 identifier.Length = (USHORT)keyData->DataLength;
3898 identifier.MaximumLength = (USHORT)keyData->DataLength;
3899
3900 //
3901 // Convert unicode identifier to ansi string.
3902 //
3903
3904 status =
3905 RtlUnicodeStringToAnsiString(&anotherString,
3906 &identifier,
3907 TRUE);
3908
3909 if (!NT_SUCCESS(status)) {
3910 continue;
3911 }
3912
3913 //
3914 // If checksum is zero, then the MBR is valid and
3915 // the signature is meaningful.
3916 //
3917
3918 if (diskData->MbrCheckSum) {
3919
3920 //
3921 // Convert checksum to ansi string.
3922 //
3923
3924 sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum);
3925
3926 } else {
3927
3928 //
3929 // Convert signature to ansi string.
3930 //
3931
3932 sprintf((PCHAR)buffer, "%08lx", diskData->Signature);
3933
3934 //
3935 // Make string point at signature. Can't use scan
3936 // functions because they are not exported for driver use.
3937 //
3938
3939 anotherString.Buffer+=9;
3940 }
3941
3942 //
3943 // Convert to ansi string.
3944 //
3945
3946 RtlInitString(&string,
3947 (PCSZ)buffer);
3948
3949
3950 //
3951 // Make string lengths equal.
3952 //
3953
3954 anotherString.Length = string.Length;
3955
3956 //
3957 // Check if strings match.
3958 //
3959
3960 if (RtlCompareString(&string,
3961 &anotherString,
3962 TRUE) == 0) {
3963
3964 diskFound = TRUE;
3965 *DiskNumber = diskNumber;
3966 }
3967
3968 ExFreePool(keyData);
3969
3970 //
3971 // Readjust indentifier string if necessary.
3972 //
3973
3974 if (!diskData->MbrCheckSum) {
3975 anotherString.Buffer-=9;
3976 }
3977
3978 RtlFreeAnsiString(&anotherString);
3979
3980 if (diskFound) {
3981 break;
3982 }
3983 }
3984
3985 ZwClose(diskKey);
3986 }
3987
3988 ZwClose(adapterKey);
3989 }
3990
3991 ZwClose(BusKey);
3992 return diskFound;
3993
3994 } // end EnumerateBusKey()
3995
3996 \f
3997 VOID
3998 NTAPI
3999 UpdateGeometry(
4000 IN PDEVICE_EXTENSION DeviceExtension
4001 )
4002 /*++
4003
4004 Routine Description:
4005
4006 The routine queries the registry to determine if this disk is visible to
4007 the BIOS. If the disk is visable to the BIOS, then the geometry information
4008 is updated.
4009
4010 Arguments:
4011
4012 DeviceExtension - Supplies a pointer to the device information for disk.
4013
4014 Return Value:
4015
4016 None.
4017
4018 --*/
4019
4020 {
4021 OBJECT_ATTRIBUTES objectAttributes;
4022 UNICODE_STRING unicodeString;
4023 NTSTATUS status;
4024 HANDLE hardwareKey;
4025 HANDLE busKey;
4026 PCM_INT13_DRIVE_PARAMETER driveParameters;
4027 PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
4028 PKEY_VALUE_FULL_INFORMATION keyData;
4029 ULONG diskNumber;
4030 PUCHAR buffer;
4031 ULONG length;
4032 ULONG numberOfDrives;
4033 ULONG cylinders;
4034 ULONG sectors;
4035 ULONG sectorsPerTrack;
4036 ULONG tracksPerCylinder;
4037 BOOLEAN foundEZHooker;
4038 PVOID tmpPtr;
4039
4040 PAGED_CODE();
4041
4042 //
4043 // Initialize the object for the key.
4044 //
4045
4046 InitializeObjectAttributes(&objectAttributes,
4047 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
4048 OBJ_CASE_INSENSITIVE,
4049 NULL,
4050 (PSECURITY_DESCRIPTOR) NULL);
4051
4052 //
4053 // Create the hardware base key.
4054 //
4055
4056 status = ZwOpenKey(&hardwareKey,
4057 KEY_READ,
4058 &objectAttributes);
4059
4060
4061 if (!NT_SUCCESS(status)) {
4062 DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase));
4063 return;
4064 }
4065
4066
4067 //
4068 // Get disk BIOS geometry information.
4069 //
4070
4071 RtlInitUnicodeString(&unicodeString, L"Configuration Data");
4072
4073 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
4074
4075 if (keyData == NULL) {
4076 ZwClose(hardwareKey);
4077 return;
4078 }
4079
4080 status = ZwQueryValueKey(hardwareKey,
4081 &unicodeString,
4082 KeyValueFullInformation,
4083 keyData,
4084 VALUE_BUFFER_SIZE,
4085 &length);
4086
4087 if (!NT_SUCCESS(status)) {
4088 DebugPrint((1,
4089 "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
4090 status));
4091 ExFreePool(keyData);
4092 return;
4093 }
4094
4095 //
4096 // Open EISA bus key.
4097 //
4098
4099 RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
4100
4101 InitializeObjectAttributes(&objectAttributes,
4102 &unicodeString,
4103 OBJ_CASE_INSENSITIVE,
4104 hardwareKey,
4105 (PSECURITY_DESCRIPTOR)NULL);
4106
4107 status = ZwOpenKey(&busKey,
4108 KEY_READ,
4109 &objectAttributes);
4110
4111 if (!NT_SUCCESS(status)) {
4112 goto openMultiKey;
4113 }
4114
4115 DebugPrint((3,
4116 "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
4117 if (EnumerateBusKey(DeviceExtension,
4118 busKey,
4119 &diskNumber)) {
4120
4121 ZwClose(hardwareKey);
4122 goto diskMatched;
4123 }
4124
4125 openMultiKey:
4126
4127 //
4128 // Open Multifunction bus key.
4129 //
4130
4131 RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
4132
4133 InitializeObjectAttributes(&objectAttributes,
4134 &unicodeString,
4135 OBJ_CASE_INSENSITIVE,
4136 hardwareKey,
4137 (PSECURITY_DESCRIPTOR)NULL);
4138
4139 status = ZwOpenKey(&busKey,
4140 KEY_READ,
4141 &objectAttributes);
4142
4143 ZwClose(hardwareKey);
4144 if (NT_SUCCESS(status)) {
4145 DebugPrint((3,
4146 "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
4147 if (EnumerateBusKey(DeviceExtension,
4148 busKey,
4149 &diskNumber)) {
4150
4151 goto diskMatched;
4152 }
4153 }
4154
4155 ExFreePool(keyData);
4156 return;
4157
4158 diskMatched:
4159
4160 resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData +
4161 keyData->DataOffset);
4162
4163 //
4164 // Check that the data is long enough to hold a full resource descriptor,
4165 // and that the last resouce list is device-specific and long enough.
4166 //
4167
4168 if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) ||
4169 resourceDescriptor->PartialResourceList.Count == 0 ||
4170 resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type !=
4171 CmResourceTypeDeviceSpecific ||
4172 resourceDescriptor->PartialResourceList.PartialDescriptors[0]
4173 .u.DeviceSpecificData.DataSize < sizeof(ULONG)) {
4174
4175 DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
4176 ExFreePool(keyData);
4177 return;
4178 }
4179
4180 length =
4181 resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize;
4182
4183 //
4184 // Point to the BIOS data. The BIOS data is located after the first
4185 // partial Resource list which should be device specific data.
4186 //
4187
4188 buffer = (PUCHAR) keyData + keyData->DataOffset +
4189 sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
4190
4191
4192 numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
4193
4194 //
4195 // Use the defaults if the drive number is greater than the
4196 // number of drives detected by the BIOS.
4197 //
4198
4199 if (numberOfDrives <= diskNumber) {
4200 ExFreePool(keyData);
4201 return;
4202 }
4203
4204 //
4205 // Point to the array of drive parameters.
4206 //
4207
4208 driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber;
4209 cylinders = driveParameters->MaxCylinders + 1;
4210 sectorsPerTrack = driveParameters->SectorsPerTrack;
4211 tracksPerCylinder = driveParameters->MaxHeads +1;
4212
4213 //
4214 // Calculate the actual number of sectors.
4215 //
4216
4217 sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >>
4218 DeviceExtension->SectorShift);
4219
4220 #if DBG
4221 if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) {
4222 DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
4223 "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
4224 sectors, cylinders, tracksPerCylinder, sectorsPerTrack));
4225 }
4226 #endif
4227
4228 //
4229 // Since the BIOS may not report the full drive, recalculate the drive
4230 // size based on the volume size and the BIOS values for tracks per
4231 // cylinder and sectors per track..
4232 //
4233
4234 length = tracksPerCylinder * sectorsPerTrack;
4235
4236 if (length == 0) {
4237
4238 //
4239 // The BIOS information is bogus.
4240 //
4241
4242 DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
4243 ExFreePool(keyData);
4244 return;
4245 }
4246
4247 cylinders = sectors / length;
4248
4249 //
4250 // Update the actual geometry information.
4251 //
4252
4253 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack;
4254 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder;
4255 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders;
4256 DeviceExtension->DiskGeometry->DiskSize.QuadPart = cylinders * tracksPerCylinder * sectorsPerTrack *
4257 DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4258
4259 DebugPrint((3,
4260 "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
4261 sectorsPerTrack,
4262 tracksPerCylinder,
4263 cylinders));
4264
4265 ExFreePool(keyData);
4266
4267 foundEZHooker = FALSE;
4268
4269 if (!DeviceExtension->DMActive) {
4270
4271 HalExamineMBR(DeviceExtension->DeviceObject,
4272 DeviceExtension->DiskGeometry->Geometry.BytesPerSector,
4273 (ULONG)0x55,
4274 &tmpPtr
4275 );
4276
4277 if (tmpPtr) {
4278
4279 ExFreePool(tmpPtr);
4280 foundEZHooker = TRUE;
4281
4282 }
4283
4284 }
4285
4286 if (DeviceExtension->DMActive || foundEZHooker) {
4287
4288 while (cylinders > 1024) {
4289
4290 tracksPerCylinder = tracksPerCylinder*2;
4291 cylinders = cylinders/2;
4292
4293 }
4294
4295 //
4296 // int 13 values are always 1 less.
4297 //
4298
4299 tracksPerCylinder -= 1;
4300 cylinders -= 1;
4301
4302 //
4303 // DM reserves the CE cylinder
4304 //
4305
4306 cylinders -= 1;
4307
4308 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1;
4309 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1;
4310
4311 DeviceExtension->PartitionLength.QuadPart =
4312 DeviceExtension->DiskGeometry->DiskSize.QuadPart =
4313 DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart *
4314 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack *
4315 DeviceExtension->DiskGeometry->Geometry.BytesPerSector *
4316 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder;
4317
4318 if (DeviceExtension->DMActive) {
4319
4320 DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
4321
4322 }
4323
4324 } else {
4325
4326 DeviceExtension->DMByteSkew = 0;
4327
4328 }
4329
4330 return;
4331
4332 } // end UpdateGeometry()
4333
4334
4335 \f
4336 NTSTATUS
4337 NTAPI
4338 UpdateRemovableGeometry (
4339 IN PDEVICE_OBJECT DeviceObject,
4340 IN PIRP Irp
4341 )
4342
4343 /*++
4344
4345 Routine Description:
4346
4347 This routines updates the size and starting offset of the device. This is
4348 used when the media on the device may have changed thereby changing the
4349 size of the device. If this is the physical device then a
4350 ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
4351
4352 Arguments:
4353
4354 DeviceObject - Supplies the device object whos size needs to be updated.
4355
4356 Irp - Supplies a reference where the status can be updated.
4357
4358 Return Value:
4359
4360 Returns the status of the opertion.
4361
4362 --*/
4363 {
4364
4365 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4366 PDRIVE_LAYOUT_INFORMATION partitionList;
4367 NTSTATUS status;
4368 PDISK_DATA diskData;
4369 ULONG partitionNumber;
4370
4371 //
4372 // Determine if the size of the partition may have changed because
4373 // the media has changed.
4374 //
4375
4376 if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
4377
4378 return(STATUS_SUCCESS);
4379
4380 }
4381
4382 //
4383 // If this request is for partition zero then do a read drive
4384 // capacity otherwise do a I/O read partition table.
4385 //
4386
4387 diskData = (PDISK_DATA) (deviceExtension + 1);
4388
4389 //
4390 // Read the drive capcity. If that fails, give up.
4391 //
4392
4393 status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
4394
4395 if (!NT_SUCCESS(status)) {
4396 return(status);
4397 }
4398
4399 //
4400 // Read the partition table agian.
4401 //
4402
4403 status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
4404 deviceExtension->DiskGeometry->Geometry.BytesPerSector,
4405 TRUE,
4406 &partitionList);
4407
4408
4409 if (!NT_SUCCESS(status)) {
4410
4411 //
4412 // Fail the request.
4413 //
4414
4415 return(status);
4416 }
4417
4418 if (diskData->PartitionNumber != 0 &&
4419 diskData->PartitionNumber <= partitionList->PartitionCount ) {
4420
4421 partitionNumber = diskData->PartitionNumber - 1;
4422
4423 //
4424 // Update the partition information for this parition.
4425 //
4426
4427 diskData->PartitionType =
4428 partitionList->PartitionEntry[partitionNumber].PartitionType;
4429
4430 diskData->BootIndicator =
4431 partitionList->PartitionEntry[partitionNumber].BootIndicator;
4432
4433 deviceExtension->StartingOffset =
4434 partitionList->PartitionEntry[partitionNumber].StartingOffset;
4435
4436 deviceExtension->PartitionLength =
4437 partitionList->PartitionEntry[partitionNumber].PartitionLength;
4438
4439 diskData->HiddenSectors =
4440 partitionList->PartitionEntry[partitionNumber].HiddenSectors;
4441
4442 deviceExtension->SectorShift = ((PDEVICE_EXTENSION)
4443 deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift;
4444
4445 } else if (diskData->PartitionNumber != 0) {
4446
4447 //
4448 // The paritition does not exist. Zero all the data.
4449 //
4450
4451 diskData->PartitionType = 0;
4452 diskData->BootIndicator = 0;
4453 diskData->HiddenSectors = 0;
4454 deviceExtension->StartingOffset.QuadPart = (LONGLONG)0;
4455 deviceExtension->PartitionLength.QuadPart = (LONGLONG)0;
4456 }
4457
4458 //
4459 // Free the parition list allocate by I/O read partition table.
4460 //
4461
4462 ExFreePool(partitionList);
4463
4464
4465 return(STATUS_SUCCESS);
4466 }
4467
4468 \f
4469 VOID
4470 NTAPI
4471 ScsiDiskProcessError(
4472 PDEVICE_OBJECT DeviceObject,
4473 PSCSI_REQUEST_BLOCK Srb,
4474 NTSTATUS *Status,
4475 BOOLEAN *Retry
4476 )
4477 /*++
4478
4479 Routine Description:
4480
4481 This routine checks the type of error. If the error indicates an underrun
4482 then indicate the request should be retried.
4483
4484 Arguments:
4485
4486 DeviceObject - Supplies a pointer to the device object.
4487
4488 Srb - Supplies a pointer to the failing Srb.
4489
4490 Status - Status with which the IRP will be completed.
4491
4492 Retry - Indication of whether the request will be retried.
4493
4494 Return Value:
4495
4496 None.
4497
4498 --*/
4499
4500 {
4501 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4502
4503 if (*Status == STATUS_DATA_OVERRUN &&
4504 ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) {
4505
4506 *Retry = TRUE;
4507
4508 //
4509 // Update the error count for the device.
4510 //
4511
4512 deviceExtension->ErrorCount++;
4513 }
4514
4515 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
4516 Srb->ScsiStatus == SCSISTAT_BUSY) {
4517
4518 //
4519 // The disk drive should never be busy this long. Reset the scsi bus
4520 // maybe this will clear the condition.
4521 //
4522
4523 ResetScsiBus(DeviceObject);
4524
4525 //
4526 // Update the error count for the device.
4527 //
4528
4529 deviceExtension->ErrorCount++;
4530 }
4531 }
4532 \f
4533 VOID
4534 NTAPI
4535 ScanForSpecial(
4536 PDEVICE_OBJECT DeviceObject,
4537 PSCSI_INQUIRY_DATA LunInfo,
4538 PIO_SCSI_CAPABILITIES PortCapabilities
4539 )
4540
4541 /*++
4542
4543 Routine Description:
4544
4545 This function checks to see if an SCSI logical unit requires speical
4546 flags to be set.
4547
4548 Arguments:
4549
4550 DeviceObject - Supplies the device object to be tested.
4551
4552 InquiryData - Supplies the inquiry data returned by the device of interest.
4553
4554 PortCapabilities - Supplies the capabilities of the device object.
4555
4556 Return Value:
4557
4558 None.
4559
4560 --*/
4561
4562 {
4563 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4564 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
4565 BAD_CONTROLLER_INFORMATION const *controller;
4566 ULONG j;
4567
4568 for (j = 0; j < NUMBER_OF_BAD_CONTROLLERS; j++) {
4569
4570 controller = &ScsiDiskBadControllers[j];
4571
4572 if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
4573 continue;
4574 }
4575
4576 DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString));
4577
4578 //
4579 // Found a listed controller. Determine what must be done.
4580 //
4581
4582 if (controller->DisableTaggedQueuing) {
4583
4584 //
4585 // Disable tagged queuing.
4586 //
4587
4588 deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
4589 }
4590
4591 if (controller->DisableSynchronousTransfers) {
4592
4593 //
4594 // Disable synchronous data transfers.
4595 //
4596
4597 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
4598
4599 }
4600
4601 if (controller->DisableDisconnects) {
4602
4603 //
4604 // Disable disconnects.
4605 //
4606
4607 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
4608
4609 }
4610
4611 //
4612 // Found device so exit the loop and return.
4613 //
4614
4615 break;
4616 }
4617
4618 //
4619 // Set the StartUnit flag appropriately.
4620 //
4621
4622 if (DeviceObject->DeviceType == FILE_DEVICE_DISK) {
4623 deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT;
4624
4625 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
4626 if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) {
4627 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT;
4628 }
4629 }
4630 }
4631
4632 return;
4633 }
4634 \f
4635 VOID
4636 NTAPI
4637 ResetScsiBus(
4638 IN PDEVICE_OBJECT DeviceObject
4639 )
4640
4641 /*++
4642
4643 Routine Description:
4644
4645 This command sends a reset bus command to the SCSI port driver.
4646
4647 Arguments:
4648
4649 DeviceObject - The device object for the logical unit with
4650 hardware problem.
4651
4652 Return Value:
4653
4654 None.
4655
4656 --*/
4657 {
4658 PIO_STACK_LOCATION irpStack;
4659 PIRP irp;
4660 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4661 PSCSI_REQUEST_BLOCK srb;
4662 PCOMPLETION_CONTEXT context;
4663
4664 DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
4665
4666 //
4667 // Allocate Srb from nonpaged pool.
4668 //
4669
4670 context = ExAllocatePool(NonPagedPoolMustSucceed,
4671 sizeof(COMPLETION_CONTEXT));
4672
4673 //
4674 // Save the device object in the context for use by the completion
4675 // routine.
4676 //
4677
4678 context->DeviceObject = DeviceObject;
4679 srb = &context->Srb;
4680
4681 //
4682 // Zero out srb.
4683 //
4684
4685 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
4686
4687 //
4688 // Write length to SRB.
4689 //
4690
4691 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4692
4693 //
4694 // Set up SCSI bus address.
4695 //
4696
4697 srb->PathId = deviceExtension->PathId;
4698 srb->TargetId = deviceExtension->TargetId;
4699 srb->Lun = deviceExtension->Lun;
4700
4701 srb->Function = SRB_FUNCTION_RESET_BUS;
4702
4703 //
4704 // Build the asynchronous request to be sent to the port driver.
4705 // Since this routine is called from a DPC the IRP should always be
4706 // available.
4707 //
4708
4709 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4710
4711 IoSetCompletionRoutine(irp,
4712 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
4713 context,
4714 TRUE,
4715 TRUE,
4716 TRUE);
4717
4718 irpStack = IoGetNextIrpStackLocation(irp);
4719
4720 irpStack->MajorFunction = IRP_MJ_SCSI;
4721
4722 srb->OriginalRequest = irp;
4723
4724 //
4725 // Store the SRB address in next stack for port driver.
4726 //
4727
4728 irpStack->Parameters.Scsi.Srb = srb;
4729
4730 //
4731 // Call the port driver with the IRP.
4732 //
4733
4734 IoCallDriver(deviceExtension->PortDeviceObject, irp);
4735
4736 return;
4737
4738 } // end ResetScsiBus()
4739
4740 \f
4741 VOID
4742 NTAPI
4743 UpdateDeviceObjects(
4744 IN PDEVICE_OBJECT PhysicalDisk,
4745 IN PIRP Irp
4746 )
4747
4748 /*++
4749
4750 Routine Description:
4751
4752 This routine creates, deletes and changes device objects when
4753 the IOCTL_SET_DRIVE_LAYOUT is called. This routine also updates
4754 the drive layout information for the user. It is possible to
4755 call this routine even in the GET_LAYOUT case because RewritePartition
4756 will be false.
4757
4758 Arguments:
4759
4760 DeviceObject - Device object for physical disk.
4761 Irp - IO Request Packet (IRP).
4762
4763 Return Value:
4764
4765 None.
4766
4767 --*/
4768 {
4769 PDEVICE_EXTENSION physicalExtension = PhysicalDisk->DeviceExtension;
4770 PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
4771 ULONG partition;
4772 ULONG partitionNumber;
4773 ULONG partitionCount;
4774 ULONG lastPartition;
4775 ULONG partitionOrdinal;
4776 PPARTITION_INFORMATION partitionEntry;
4777 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
4778 STRING ntNameString;
4779 UNICODE_STRING ntUnicodeString;
4780 PDEVICE_OBJECT deviceObject;
4781 PDEVICE_EXTENSION deviceExtension;
4782 PDISK_DATA diskData;
4783 NTSTATUS status;
4784 ULONG numberListElements;
4785 BOOLEAN found;
4786
4787 partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4;
4788
4789 //
4790 // Zero all of the partition numbers.
4791 //
4792
4793 for (partition = 0; partition < partitionCount; partition++) {
4794 partitionEntry = &partitionList->PartitionEntry[partition];
4795 partitionEntry->PartitionNumber = 0;
4796 }
4797
4798 //
4799 // Walk through chain of partitions for this disk to determine
4800 // which existing partitions have no match.
4801 //
4802
4803 deviceExtension = physicalExtension;
4804 diskData = (PDISK_DATA)(deviceExtension + 1);
4805 lastPartition = 0;
4806
4807 do {
4808
4809 deviceExtension = diskData->NextPartition;
4810
4811 //
4812 // Check if this is the last partition in the chain.
4813 //
4814
4815 if (!deviceExtension) {
4816 break;
4817 }
4818
4819 //
4820 // Get the partition device extension from disk data.
4821 //
4822
4823 diskData = (PDISK_DATA)(deviceExtension + 1);
4824
4825 //
4826 // Check for highest partition number this far.
4827 //
4828
4829 if (diskData->PartitionNumber > lastPartition) {
4830 lastPartition = diskData->PartitionNumber;
4831 }
4832
4833 //
4834 // Check if this partition is not currently being used.
4835 //
4836
4837 if (!deviceExtension->PartitionLength.QuadPart) {
4838 continue;
4839 }
4840
4841 //
4842 // Loop through partition information to look for match.
4843 //
4844
4845 found = FALSE;
4846 partitionOrdinal = 0;
4847
4848 for (partition = 0; partition < partitionCount; partition++) {
4849
4850 //
4851 // Get partition descriptor.
4852 //
4853
4854 partitionEntry = &partitionList->PartitionEntry[partition];
4855
4856 //
4857 // Check if empty, or describes extended partiton or hasn't changed.
4858 //
4859
4860 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
4861 IsContainerPartition(partitionEntry->PartitionType)) {
4862 continue;
4863 }
4864
4865 //
4866 // Advance partition ordinal.
4867 //
4868
4869 partitionOrdinal++;
4870
4871 //
4872 // Check if new partition starts where this partition starts.
4873 //
4874
4875 if (partitionEntry->StartingOffset.QuadPart !=
4876 deviceExtension->StartingOffset.QuadPart) {
4877 continue;
4878 }
4879
4880 //
4881 // Check if partition length is the same.
4882 //
4883
4884 if (partitionEntry->PartitionLength.QuadPart ==
4885 deviceExtension->PartitionLength.QuadPart) {
4886
4887 DebugPrint((3,
4888 "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
4889 physicalExtension->DeviceNumber,
4890 diskData->PartitionNumber));
4891
4892 //
4893 // Indicate match is found and set partition number
4894 // in user buffer.
4895 //
4896
4897 found = TRUE;
4898 partitionEntry->PartitionNumber = diskData->PartitionNumber;
4899 break;
4900 }
4901 }
4902
4903 if (found) {
4904
4905 //
4906 // A match is found.
4907 //
4908
4909 diskData = (PDISK_DATA)(deviceExtension + 1);
4910
4911 //
4912 // If this partition is marked for update then update partition type.
4913 //
4914
4915 if (partitionEntry->RewritePartition) {
4916 diskData->PartitionType = partitionEntry->PartitionType;
4917 }
4918
4919 //
4920 // Update partitional ordinal for calls to HAL routine
4921 // IoSetPartitionInformation.
4922 //
4923
4924 diskData->PartitionOrdinal = partitionOrdinal;
4925
4926 DebugPrint((1,
4927 "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
4928 physicalExtension->DeviceNumber,
4929 diskData->PartitionOrdinal,
4930 diskData->PartitionNumber));
4931
4932 } else {
4933
4934 //
4935 // no match was found, indicate this partition is gone.
4936 //
4937
4938 DebugPrint((1,
4939 "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
4940 physicalExtension->DeviceNumber,
4941 diskData->PartitionNumber));
4942
4943 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
4944 }
4945
4946 } while (TRUE);
4947
4948 //
4949 // Walk through partition loop to find new partitions and set up
4950 // device extensions to describe them. In some cases new device
4951 // objects will be created.
4952 //
4953
4954 partitionOrdinal = 0;
4955
4956 for (partition = 0;
4957 partition < partitionCount;
4958 partition++) {
4959
4960 //
4961 // Get partition descriptor.
4962 //
4963
4964 partitionEntry = &partitionList->PartitionEntry[partition];
4965
4966 //
4967 // Check if empty, or describes an extended partiton.
4968 //
4969
4970 if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
4971 IsContainerPartition(partitionEntry->PartitionType)) {
4972 continue;
4973 }
4974
4975 //
4976 // Keep track of position on the disk for calls to IoSetPartitionInformation.
4977 //
4978
4979 partitionOrdinal++;
4980
4981 //
4982 // Check if this entry should be rewritten.
4983 //
4984
4985 if (!partitionEntry->RewritePartition) {
4986 continue;
4987 }
4988
4989 if (partitionEntry->PartitionNumber) {
4990
4991 //
4992 // Partition is an exact match with an existing partition, but is
4993 // being written anyway.
4994 //
4995
4996 continue;
4997 }
4998
4999 //
5000 // Check first if existing device object is available by
5001 // walking partition extension list.
5002 //
5003
5004 partitionNumber = 0;
5005 deviceExtension = physicalExtension;
5006 diskData = (PDISK_DATA)(deviceExtension + 1);
5007
5008 do {
5009
5010 //
5011 // Get next partition device extension from disk data.
5012 //
5013
5014 deviceExtension = diskData->NextPartition;
5015
5016 if (!deviceExtension) {
5017 break;
5018 }
5019
5020 diskData = (PDISK_DATA)(deviceExtension + 1);
5021
5022 //
5023 // A device object is free if the partition length is set to zero.
5024 //
5025
5026 if (!deviceExtension->PartitionLength.QuadPart) {
5027 partitionNumber = diskData->PartitionNumber;
5028 break;
5029 }
5030
5031 } while (TRUE);
5032
5033 //
5034 // If partition number is still zero then a new device object
5035 // must be created.
5036 //
5037
5038 if (partitionNumber == 0) {
5039
5040 lastPartition++;
5041 partitionNumber = lastPartition;
5042
5043 //
5044 // Get or create partition object and set up partition parameters.
5045 //
5046
5047 sprintf(ntNameBuffer,
5048 "\\Device\\Harddisk%lu\\Partition%lu",
5049 physicalExtension->DeviceNumber,
5050 partitionNumber);
5051
5052 RtlInitString(&ntNameString,
5053 ntNameBuffer);
5054
5055 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
5056 &ntNameString,
5057 TRUE);
5058
5059 if (!NT_SUCCESS(status)) {
5060 continue;
5061 }
5062
5063 DebugPrint((3,
5064 "UpdateDeviceObjects: Create device object %s\n",
5065 ntNameBuffer));
5066
5067 //
5068 // This is a new name. Create the device object to represent it.
5069 //
5070
5071 status = IoCreateDevice(PhysicalDisk->DriverObject,
5072 DEVICE_EXTENSION_SIZE,
5073 &ntUnicodeString,
5074 FILE_DEVICE_DISK,
5075 0,
5076 FALSE,
5077 &deviceObject);
5078
5079 if (!NT_SUCCESS(status)) {
5080 DebugPrint((1,
5081 "UpdateDeviceObjects: Can't create device %s\n",
5082 ntNameBuffer));
5083 RtlFreeUnicodeString(&ntUnicodeString);
5084 continue;
5085 }
5086
5087 //
5088 // Set up device object fields.
5089 //
5090
5091 deviceObject->Flags |= DO_DIRECT_IO;
5092 deviceObject->StackSize = PhysicalDisk->StackSize;
5093
5094 //
5095 // Set up device extension fields.
5096 //
5097
5098 deviceExtension = deviceObject->DeviceExtension;
5099
5100 //
5101 // Copy physical disk extension to partition extension.
5102 //
5103
5104 RtlMoveMemory(deviceExtension,
5105 physicalExtension,
5106 sizeof(DEVICE_EXTENSION));
5107
5108 //
5109 // Initialize the new S-List.
5110 //
5111
5112 if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
5113 numberListElements = 30;
5114 } else {
5115 numberListElements = 8;
5116 }
5117
5118 //
5119 // Build the lookaside list for srb's for this partition based on
5120 // whether the adapter and disk can do tagged queueing.
5121 //
5122
5123 ScsiClassInitializeSrbLookasideList(deviceExtension,
5124 numberListElements);
5125
5126 //
5127 // Allocate spinlock for zoning for split-request completion.
5128 //
5129
5130 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
5131
5132 //
5133 // Write back partition number used in creating object name.
5134 //
5135
5136 partitionEntry->PartitionNumber = partitionNumber;
5137
5138 //
5139 // Clear flags initializing bit.
5140 //
5141
5142 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
5143
5144 //
5145 // Point back at device object.
5146 //
5147
5148 deviceExtension->DeviceObject = deviceObject;
5149
5150 RtlFreeUnicodeString(&ntUnicodeString);
5151
5152 //
5153 // Link to end of partition chain using previous disk data.
5154 //
5155
5156 diskData->NextPartition = deviceExtension;
5157
5158 //
5159 // Get new disk data and zero next partition pointer.
5160 //
5161
5162 diskData = (PDISK_DATA)(deviceExtension + 1);
5163 diskData->NextPartition = NULL;
5164
5165 } else {
5166
5167 //
5168 // Set pointer to disk data area that follows device extension.
5169 //
5170
5171 diskData = (PDISK_DATA)(deviceExtension + 1);
5172
5173 DebugPrint((1,
5174 "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
5175 physicalExtension->DeviceNumber,
5176 partitionNumber));
5177 }
5178
5179 //
5180 // Update partition information in partition device extension.
5181 //
5182
5183 diskData->PartitionNumber = partitionNumber;
5184 diskData->PartitionType = partitionEntry->PartitionType;
5185 diskData->BootIndicator = partitionEntry->BootIndicator;
5186 deviceExtension->StartingOffset = partitionEntry->StartingOffset;
5187 deviceExtension->PartitionLength = partitionEntry->PartitionLength;
5188 diskData->HiddenSectors = partitionEntry->HiddenSectors;
5189 diskData->PartitionOrdinal = partitionOrdinal;
5190
5191 DebugPrint((1,
5192 "UpdateDeviceObjects: Ordinal %d is partition %d\n",
5193 diskData->PartitionOrdinal,
5194 diskData->PartitionNumber));
5195
5196 //
5197 // Update partition number passed in to indicate the
5198 // device name for this partition.
5199 //
5200
5201 partitionEntry->PartitionNumber = partitionNumber;
5202 }
5203
5204 } // end UpdateDeviceObjects()