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