2d68cf862a0606fa3fa4f5fe3a17a9cf57a917c6
[reactos.git] / reactos / drivers / storage / disk / disk.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002, 2003, 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/disk/disk.c
24 * PURPOSE: disk class driver
25 * PROGRAMMER: Eric Kohl
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <ddk/scsi.h>
32 #include <ddk/class2.h>
33 #include <ddk/ntddscsi.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 #define VERSION "0.0.1"
39
40 #define SCSI_DISK_TIMEOUT 10 /* Default timeout: 10 seconds */
41 #define MODE_DATA_SIZE 192
42
43
44 typedef struct _DISK_DATA
45 {
46 PDEVICE_EXTENSION NextPartition;
47 ULONG Signature;
48 ULONG MbrCheckSum;
49 ULONG HiddenSectors;
50 ULONG PartitionNumber;
51 ULONG PartitionOrdinal;
52 UCHAR PartitionType;
53 BOOLEAN BootIndicator;
54 BOOLEAN DriveNotReady;
55 } DISK_DATA, *PDISK_DATA;
56
57 BOOLEAN STDCALL
58 DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
59 PUNICODE_STRING RegistryPath,
60 PCLASS_INIT_DATA InitializationData,
61 PDEVICE_OBJECT PortDeviceObject,
62 ULONG PortNumber);
63
64 BOOLEAN STDCALL
65 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData);
66
67 NTSTATUS STDCALL
68 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
69 IN PIRP Irp);
70
71 static VOID
72 DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
73 IN ULONG DeviceNumber);
74
75 static NTSTATUS
76 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
77 IN PUNICODE_STRING RegistryPath, /* what's this used for? */
78 IN PDEVICE_OBJECT PortDeviceObject,
79 IN ULONG PortNumber,
80 IN ULONG DiskNumber,
81 IN PIO_SCSI_CAPABILITIES Capabilities,
82 IN PSCSI_INQUIRY_DATA InquiryData,
83 IN PCLASS_INIT_DATA InitializationData);
84
85 NTSTATUS STDCALL
86 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
87 IN PIRP Irp);
88
89 NTSTATUS STDCALL
90 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
91 IN PIRP Irp);
92
93 static BOOLEAN
94 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension,
95 IN HANDLE BusKey,
96 OUT PULONG DetectedDiskNumber);
97
98 static VOID
99 DiskClassUpdatePartitionDeviceObjects (IN PDEVICE_OBJECT DeviceObject,
100 IN PIRP Irp);
101
102 static VOID
103 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension);
104
105 static BOOLEAN
106 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension,
107 OUT PULONG Checksum);
108
109
110 static NTSTATUS
111 DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject,
112 IN PIRP Irp);
113
114
115 /* FUNCTIONS ****************************************************************/
116
117 /**********************************************************************
118 * NAME EXPORTED
119 * DriverEntry
120 *
121 * DESCRIPTION
122 * This function initializes the driver, locates and claims
123 * hardware resources, and creates various NT objects needed
124 * to process I/O requests.
125 *
126 * RUN LEVEL
127 * PASSIVE_LEVEL
128 *
129 * ARGUMENTS
130 * DriverObject
131 * System allocated Driver Object for this driver
132 *
133 * RegistryPath
134 * Name of registry driver service key
135 *
136 * RETURN VALUE
137 * Status
138 */
139
140 NTSTATUS STDCALL
141 DriverEntry(IN PDRIVER_OBJECT DriverObject,
142 IN PUNICODE_STRING RegistryPath)
143 {
144 CLASS_INIT_DATA InitData;
145
146 DPRINT("Disk Class Driver %s\n",
147 VERSION);
148 DPRINT("RegistryPath '%wZ'\n",
149 RegistryPath);
150
151 RtlZeroMemory(&InitData,
152 sizeof(CLASS_INIT_DATA));
153
154 InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
155 InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA);
156 InitData.DeviceType = FILE_DEVICE_DISK;
157 InitData.DeviceCharacteristics = 0;
158
159 InitData.ClassError = NULL; // DiskClassProcessError;
160 InitData.ClassReadWriteVerification = DiskClassCheckReadWrite;
161 InitData.ClassFindDeviceCallBack = DiskClassCheckDevice;
162 InitData.ClassFindDevices = DiskClassFindDevices;
163 InitData.ClassDeviceControl = DiskClassDeviceControl;
164 InitData.ClassShutdownFlush = DiskClassShutdownFlush;
165 InitData.ClassCreateClose = NULL;
166 InitData.ClassStartIo = NULL;
167
168 return(ScsiClassInitialize(DriverObject,
169 RegistryPath,
170 &InitData));
171 }
172
173
174 /**********************************************************************
175 * NAME EXPORTED
176 * DiskClassFindDevices
177 *
178 * DESCRIPTION
179 * This function searches for device that are attached to the
180 * given scsi port.
181 *
182 * RUN LEVEL
183 * PASSIVE_LEVEL
184 *
185 * ARGUMENTS
186 * DriverObject
187 * System allocated Driver Object for this driver
188 *
189 * RegistryPath
190 * Name of registry driver service key
191 *
192 * InitializationData
193 * Pointer to the main initialization data
194 *
195 * PortDeviceObject
196 * Pointer to the port Device Object
197 *
198 * PortNumber
199 * Port number
200 *
201 * RETURN VALUE
202 * TRUE: At least one disk drive was found
203 * FALSE: No disk drive found
204 */
205
206 BOOLEAN STDCALL
207 DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
208 PUNICODE_STRING RegistryPath,
209 PCLASS_INIT_DATA InitializationData,
210 PDEVICE_OBJECT PortDeviceObject,
211 ULONG PortNumber)
212 {
213 PCONFIGURATION_INFORMATION ConfigInfo;
214 PIO_SCSI_CAPABILITIES PortCapabilities;
215 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
216 PSCSI_INQUIRY_DATA UnitInfo;
217 PINQUIRYDATA InquiryData;
218 PCHAR Buffer;
219 ULONG Bus;
220 ULONG DeviceCount;
221 BOOLEAN FoundDevice = FALSE;
222 NTSTATUS Status;
223
224 DPRINT("DiskClassFindDevices() called.\n");
225
226 /* Get port capabilities */
227 Status = ScsiClassGetCapabilities(PortDeviceObject,
228 &PortCapabilities);
229 if (!NT_SUCCESS(Status))
230 {
231 DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
232 return(FALSE);
233 }
234
235 DPRINT("PortCapabilities: %p\n", PortCapabilities);
236 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
237 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
238
239 /* Get inquiry data */
240 Status = ScsiClassGetInquiryData(PortDeviceObject,
241 (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
242 if (!NT_SUCCESS(Status))
243 {
244 DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status);
245 return(FALSE);
246 }
247
248 /* Check whether there are unclaimed devices */
249 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
250 DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
251 AdapterBusInfo);
252 if (DeviceCount == 0)
253 {
254 DPRINT("No unclaimed devices!\n");
255 return(FALSE);
256 }
257
258 DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
259
260 ConfigInfo = IoGetConfigurationInformation();
261
262 /* Search each bus of this adapter */
263 for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
264 {
265 DPRINT("Searching bus %lu\n", Bus);
266
267 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
268
269 while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
270 {
271 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
272
273 DPRINT("Device type %u\n", InquiryData->DeviceType);
274
275 if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
276 (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
277 (InquiryData->DeviceTypeQualifier == 0) &&
278 (UnitInfo->DeviceClaimed == FALSE))
279 {
280 DPRINT("Vendor: '%.24s'\n",
281 InquiryData->VendorId);
282
283 /* Create device objects for disk */
284 Status = DiskClassCreateDeviceObject(DriverObject,
285 RegistryPath,
286 PortDeviceObject,
287 PortNumber,
288 ConfigInfo->DiskCount,
289 PortCapabilities,
290 UnitInfo,
291 InitializationData);
292 if (NT_SUCCESS(Status))
293 {
294 ConfigInfo->DiskCount++;
295 FoundDevice = TRUE;
296 }
297 }
298
299 if (UnitInfo->NextInquiryDataOffset == 0)
300 break;
301
302 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
303 }
304 }
305
306 ExFreePool(Buffer);
307
308 DPRINT("DiskClassFindDevices() done\n");
309
310 return(FoundDevice);
311 }
312
313
314 static VOID
315 DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
316 IN ULONG DeviceNumber)
317 {
318 WCHAR NameBuffer[MAX_PATH];
319 UNICODE_STRING Name;
320
321 swprintf (NameBuffer,
322 L"\\Device\\MediaChangeEvent%lu",
323 DeviceNumber);
324 RtlInitUnicodeString (&Name,
325 NameBuffer);
326
327 DeviceExtension->MediaChangeEvent =
328 IoCreateSynchronizationEvent (&Name,
329 &DeviceExtension->MediaChangeEventHandle);
330
331 KeClearEvent (DeviceExtension->MediaChangeEvent);
332 }
333
334
335
336 /**********************************************************************
337 * NAME EXPORTED
338 * DiskClassCheckDevice
339 *
340 * DESCRIPTION
341 * This function checks the InquiryData for the correct device
342 * type and qualifier.
343 *
344 * RUN LEVEL
345 * PASSIVE_LEVEL
346 *
347 * ARGUMENTS
348 * InquiryData
349 * Pointer to the inquiry data for the device in question.
350 *
351 * RETURN VALUE
352 * TRUE: A disk device was found.
353 * FALSE: Otherwise.
354 */
355
356 BOOLEAN STDCALL
357 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData)
358 {
359 return((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE ||
360 InquiryData->DeviceType == OPTICAL_DEVICE) &&
361 InquiryData->DeviceTypeQualifier == 0);
362 }
363
364
365 /**********************************************************************
366 * NAME EXPORTED
367 * DiskClassCheckReadWrite
368 *
369 * DESCRIPTION
370 * This function checks the given IRP for correct data.
371 *
372 * RUN LEVEL
373 * PASSIVE_LEVEL
374 *
375 * ARGUMENTS
376 * DeviceObject
377 * Pointer to the device.
378 *
379 * Irp
380 * Irp to check.
381 *
382 * RETURN VALUE
383 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
384 * Others: Failure.
385 */
386
387 NTSTATUS STDCALL
388 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
389 IN PIRP Irp)
390 {
391 PDEVICE_EXTENSION DeviceExtension;
392 PDISK_DATA DiskData;
393 PIO_STACK_LOCATION IrpStack;
394 ULARGE_INTEGER EndingOffset;
395
396 DPRINT("DiskClassCheckReadWrite() called\n");
397
398 DeviceExtension = DeviceObject->DeviceExtension;
399 DiskData = (PDISK_DATA)(DeviceExtension + 1);
400
401 if (DiskData->DriveNotReady == TRUE)
402 {
403 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
404 IoSetHardErrorOrVerifyDevice(Irp,
405 DeviceObject);
406 return(STATUS_INVALID_PARAMETER);
407 }
408
409 IrpStack = IoGetCurrentIrpStackLocation(Irp);
410 EndingOffset.QuadPart = IrpStack->Parameters.Read.ByteOffset.QuadPart +
411 IrpStack->Parameters.Read.Length;
412
413 if (EndingOffset.QuadPart > DeviceExtension->PartitionLength.QuadPart)
414 {
415 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
416 return(STATUS_INVALID_PARAMETER);
417 }
418
419 return(STATUS_SUCCESS);
420 }
421
422
423 /**********************************************************************
424 * NAME INTERNAL
425 * DiskClassCreateDeviceObject
426 *
427 * DESCRIPTION
428 * Create the raw device and any partition devices on this drive
429 *
430 * RUN LEVEL
431 * PASSIVE_LEVEL
432 *
433 * ARGUMENTS
434 * DriverObject
435 * The system created driver object
436 * RegistryPath
437 * PortDeviceObject
438 * PortNumber
439 * DiskNumber
440 * Capabilities
441 * InquiryData
442 * InitialzationData
443 *
444 * RETURN VALUE
445 * STATUS_SUCCESS: Device objects for disk and partitions were created.
446 * Others: Failure.
447 */
448
449 static NTSTATUS
450 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
451 IN PUNICODE_STRING RegistryPath,
452 IN PDEVICE_OBJECT PortDeviceObject,
453 IN ULONG PortNumber,
454 IN ULONG DiskNumber,
455 IN PIO_SCSI_CAPABILITIES Capabilities,
456 IN PSCSI_INQUIRY_DATA InquiryData,
457 IN PCLASS_INIT_DATA InitializationData)
458 {
459 OBJECT_ATTRIBUTES ObjectAttributes;
460 UNICODE_STRING UnicodeDeviceDirName;
461 WCHAR NameBuffer[80];
462 CHAR NameBuffer2[80];
463 PDEVICE_OBJECT DiskDeviceObject;
464 PDEVICE_OBJECT PartitionDeviceObject;
465 PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
466 PDEVICE_EXTENSION PartitionDeviceExtension; /* defined in class2.h */
467 PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
468 HANDLE Handle;
469 PPARTITION_INFORMATION PartitionEntry;
470 PDISK_DATA DiskData;
471 ULONG PartitionNumber;
472 PVOID MbrBuffer;
473 NTSTATUS Status;
474
475 DPRINT("DiskClassCreateDeviceObject() called\n");
476
477 /* Create the harddisk device directory */
478 swprintf(NameBuffer,
479 L"\\Device\\Harddisk%lu",
480 DiskNumber);
481 RtlInitUnicodeString(&UnicodeDeviceDirName,
482 NameBuffer);
483 InitializeObjectAttributes(&ObjectAttributes,
484 &UnicodeDeviceDirName,
485 0,
486 NULL,
487 NULL);
488 Status = ZwCreateDirectoryObject(&Handle,
489 0,
490 &ObjectAttributes);
491 if (!NT_SUCCESS(Status))
492 {
493 DbgPrint("Could not create device dir object\n");
494 return(Status);
495 }
496
497 /* Claim the disk device */
498 Status = ScsiClassClaimDevice(PortDeviceObject,
499 InquiryData,
500 FALSE,
501 &PortDeviceObject);
502 if (!NT_SUCCESS(Status))
503 {
504 DbgPrint("Could not claim disk device\n");
505
506 ZwMakeTemporaryObject(Handle);
507 ZwClose(Handle);
508
509 return(Status);
510 }
511
512 /* Create disk device (Partition 0) */
513 sprintf(NameBuffer2,
514 "\\Device\\Harddisk%lu\\Partition0",
515 DiskNumber);
516
517 Status = ScsiClassCreateDeviceObject(DriverObject,
518 NameBuffer2,
519 NULL,
520 &DiskDeviceObject,
521 InitializationData);
522 if (!NT_SUCCESS(Status))
523 {
524 DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
525
526 /* Release (unclaim) the disk */
527 ScsiClassClaimDevice(PortDeviceObject,
528 InquiryData,
529 TRUE,
530 NULL);
531
532 /* Delete the harddisk device directory */
533 ZwMakeTemporaryObject(Handle);
534 ZwClose(Handle);
535
536 return(Status);
537 }
538
539 DiskDeviceObject->Flags |= DO_DIRECT_IO;
540 if (((PINQUIRYDATA)InquiryData->InquiryData)->RemovableMedia)
541 {
542 DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
543 }
544 DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
545
546 if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
547 {
548 DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
549 }
550
551 DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
552 DiskDeviceExtension->LockCount = 0;
553 DiskDeviceExtension->DeviceNumber = DiskNumber;
554 DiskDeviceExtension->DeviceObject = DiskDeviceObject;
555 DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
556 DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
557 DiskDeviceExtension->PortCapabilities = Capabilities;
558 DiskDeviceExtension->StartingOffset.QuadPart = 0;
559 DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
560 DiskDeviceExtension->PathId = InquiryData->PathId;
561 DiskDeviceExtension->TargetId = InquiryData->TargetId;
562 DiskDeviceExtension->Lun = InquiryData->Lun;
563 DiskDeviceExtension->SrbFlags = 0;
564
565 /* Enable the command queueing, if it possible */
566 if (Capabilities->TaggedQueuing &&
567 ((PINQUIRYDATA)InquiryData->InquiryData)->CommandQueue)
568 {
569 DiskDeviceExtension->SrbFlags |= SRB_FLAGS_QUEUE_ACTION_ENABLE;
570 }
571
572 /* Get timeout value */
573 DiskDeviceExtension->TimeOutValue =
574 ScsiClassQueryTimeOutRegistryValue(RegistryPath);
575 if (DiskDeviceExtension->TimeOutValue == 0)
576 DiskDeviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
577
578 /* Initialize the lookaside list for SRBs */
579 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
580 4);
581
582 /* zero-out disk data */
583 DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
584 RtlZeroMemory(DiskData,
585 sizeof(DISK_DATA));
586
587 /* Get disk geometry */
588 DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
589 sizeof(DISK_GEOMETRY));
590 if (DiskDeviceExtension->DiskGeometry == NULL)
591 {
592 DPRINT("Failed to allocate geometry buffer!\n");
593
594 ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
595
596 IoDeleteDevice(DiskDeviceObject);
597
598 /* Release (unclaim) the disk */
599 ScsiClassClaimDevice(PortDeviceObject,
600 InquiryData,
601 TRUE,
602 NULL);
603
604 /* Delete the harddisk device directory */
605 ZwMakeTemporaryObject(Handle);
606 ZwClose(Handle);
607
608 return(STATUS_INSUFFICIENT_RESOURCES);
609 }
610
611 /* Allocate sense data buffer */
612 DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPoolCacheAligned,
613 SENSE_BUFFER_SIZE);
614 if (DiskDeviceExtension->SenseData == NULL)
615 {
616 DPRINT("Failed to allocate sense data buffer!\n");
617
618 ExFreePool (DiskDeviceExtension->DiskGeometry);
619
620 ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
621
622 IoDeleteDevice(DiskDeviceObject);
623
624 /* Release (unclaim) the disk */
625 ScsiClassClaimDevice(PortDeviceObject,
626 InquiryData,
627 TRUE,
628 NULL);
629
630 /* Delete the harddisk device directory */
631 ZwMakeTemporaryObject(Handle);
632 ZwClose(Handle);
633
634 return(STATUS_INSUFFICIENT_RESOURCES);
635 }
636
637 /* Read the drive's capacity */
638 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
639 if (!NT_SUCCESS(Status) &&
640 (DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
641 {
642 DPRINT("Failed to retrieve drive capacity!\n");
643 return(STATUS_SUCCESS);
644 }
645 else
646 {
647 /* Clear the verify flag for removable media drives. */
648 DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
649 }
650
651 DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
652
653 if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
654 (DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
655 {
656 DiskClassCreateMediaChangeEvent(DiskDeviceExtension,DiskNumber);
657 if (DiskDeviceExtension->MediaChangeEvent != NULL)
658 {
659 DPRINT("Allocated media change event!\n");
660 }
661 }
662
663 /* Check disk for presence of a disk manager */
664 HalExamineMBR(DiskDeviceObject,
665 DiskDeviceExtension->DiskGeometry->BytesPerSector,
666 0x54,
667 &MbrBuffer);
668 if (MbrBuffer != NULL)
669 {
670 /* Start disk at sector 63 if the Ontrack Disk Manager was found */
671 DPRINT("Found 'Ontrack Disk Manager'!\n");
672
673 DiskDeviceExtension->DMSkew = 63;
674 DiskDeviceExtension->DMByteSkew =
675 63 * DiskDeviceExtension->DiskGeometry->BytesPerSector;
676 DiskDeviceExtension->DMActive = TRUE;
677
678 ExFreePool(MbrBuffer);
679 MbrBuffer = NULL;
680 }
681
682 if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
683 (DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
684 {
685 /* Allocate a partition list for a single entry. */
686 PartitionList = ExAllocatePool(NonPagedPool,
687 sizeof(DRIVE_LAYOUT_INFORMATION));
688 if (PartitionList != NULL)
689 {
690 RtlZeroMemory(PartitionList,
691 sizeof(DRIVE_LAYOUT_INFORMATION));
692 PartitionList->PartitionCount = 1;
693
694 DiskData->DriveNotReady = TRUE;
695 Status = STATUS_SUCCESS;
696 }
697 }
698 else
699 {
700 /* Read partition table */
701 Status = IoReadPartitionTable(DiskDeviceObject,
702 DiskDeviceExtension->DiskGeometry->BytesPerSector,
703 TRUE,
704 &PartitionList);
705
706 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
707
708 if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
709 DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
710 {
711 if (!NT_SUCCESS(Status))
712 {
713 /* Drive is not ready. */
714 DPRINT("Drive not ready\n");
715 DiskData->DriveNotReady = TRUE;
716 }
717 else
718 {
719 ExFreePool(PartitionList);
720 }
721
722 /* Allocate a partition list for a single entry. */
723 PartitionList = ExAllocatePool(NonPagedPool,
724 sizeof(DRIVE_LAYOUT_INFORMATION));
725 if (PartitionList != NULL)
726 {
727 RtlZeroMemory(PartitionList,
728 sizeof(DRIVE_LAYOUT_INFORMATION));
729 PartitionList->PartitionCount = 1;
730
731 Status = STATUS_SUCCESS;
732 }
733 }
734 }
735
736 if (NT_SUCCESS(Status))
737 {
738 DPRINT("Read partition table!\n");
739 DPRINT(" Number of partitions: %u\n", PartitionList->PartitionCount);
740
741 /* Set disk signature */
742 DiskData->Signature = PartitionList->Signature;
743
744 /* Calculate MBR checksum if disk got no signature */
745 if (DiskData->Signature == 0)
746 {
747 if (!ScsiDiskCalcMbrCheckSum(DiskDeviceExtension,
748 &DiskData->MbrCheckSum))
749 {
750 DPRINT("MBR checksum calculation failed for disk %lu\n",
751 DiskDeviceExtension->DeviceNumber);
752 }
753 else
754 {
755 DPRINT("MBR checksum for disk %lu is %lx\n",
756 DiskDeviceExtension->DeviceNumber,
757 DiskData->MbrCheckSum);
758 }
759 }
760 else
761 {
762 DPRINT("Signature on disk %lu is %lx\n",
763 DiskDeviceExtension->DeviceNumber,
764 DiskData->Signature);
765 }
766
767 /* Update disk geometry if disk is visible to the BIOS */
768 ScsiDiskUpdateFixedDiskGeometry(DiskDeviceExtension);
769
770 for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
771 {
772 PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
773
774 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
775 PartitionNumber,
776 PartitionEntry->PartitionNumber,
777 PartitionEntry->BootIndicator,
778 PartitionEntry->PartitionType,
779 PartitionEntry->StartingOffset.QuadPart /
780 DiskDeviceExtension->DiskGeometry->BytesPerSector,
781 PartitionEntry->PartitionLength.QuadPart /
782 DiskDeviceExtension->DiskGeometry->BytesPerSector);
783
784 /* Create partition device object */
785 sprintf(NameBuffer2,
786 "\\Device\\Harddisk%lu\\Partition%lu",
787 DiskNumber,
788 PartitionNumber + 1);
789
790 Status = ScsiClassCreateDeviceObject(DriverObject,
791 NameBuffer2,
792 DiskDeviceObject,
793 &PartitionDeviceObject ,
794 InitializationData);
795 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
796 if (NT_SUCCESS(Status))
797 {
798 PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
799 PartitionDeviceObject->Characteristics = DiskDeviceObject->Characteristics;
800 PartitionDeviceObject->StackSize = DiskDeviceObject->StackSize;
801 PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
802
803 PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
804 PartitionDeviceExtension->SenseData = DiskDeviceExtension->SenseData;
805 PartitionDeviceExtension->LockCount = 0;
806 PartitionDeviceExtension->DeviceNumber = DiskNumber;
807 PartitionDeviceExtension->DeviceObject = PartitionDeviceObject;
808 PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
809 PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
810 PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
811 PartitionDeviceExtension->PortCapabilities = Capabilities;
812 PartitionDeviceExtension->StartingOffset.QuadPart =
813 PartitionEntry->StartingOffset.QuadPart;
814 PartitionDeviceExtension->PartitionLength.QuadPart =
815 PartitionEntry->PartitionLength.QuadPart;
816 PartitionDeviceExtension->DMSkew = DiskDeviceExtension->DMSkew;
817 PartitionDeviceExtension->DMByteSkew = DiskDeviceExtension->DMByteSkew;
818 PartitionDeviceExtension->DMActive = DiskDeviceExtension->DMActive;
819 PartitionDeviceExtension->PortNumber = (UCHAR)PortNumber;
820 PartitionDeviceExtension->PathId = InquiryData->PathId;
821 PartitionDeviceExtension->TargetId = InquiryData->TargetId;
822 PartitionDeviceExtension->Lun = InquiryData->Lun;
823 PartitionDeviceExtension->SectorShift = DiskDeviceExtension->SectorShift;
824 PartitionDeviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
825
826 /* Initialize lookaside list for SRBs */
827 ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension,
828 8);
829
830 /* Link current partition device extension to previous disk data */
831 DiskData->NextPartition = PartitionDeviceExtension;
832
833 /* Initialize current disk data */
834 DiskData = (PDISK_DATA)(PartitionDeviceExtension + 1);
835 DiskData->NextPartition = NULL;
836 DiskData->PartitionType = PartitionEntry->PartitionType;
837 DiskData->PartitionNumber = PartitionNumber + 1;
838 DiskData->PartitionOrdinal = PartitionNumber + 1;
839 DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
840 DiskData->BootIndicator = PartitionEntry->BootIndicator;
841 DiskData->DriveNotReady = FALSE;
842 }
843 else
844 {
845 DPRINT("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
846
847 break;
848 }
849 }
850 }
851
852 if (PartitionList != NULL)
853 ExFreePool(PartitionList);
854
855 DPRINT("DiskClassCreateDeviceObjects() done\n");
856
857 return(STATUS_SUCCESS);
858 }
859
860
861 static NTSTATUS
862 DiskBuildPartitionTable(IN PDEVICE_OBJECT DiskDeviceObject,
863 IN PIRP Irp)
864 {
865 PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
866 PDEVICE_EXTENSION DiskDeviceExtension, DDE;
867 PDISK_DATA DiskData, DD;
868 PPARTITION_INFORMATION PartitionEntry;
869 ULONG PartitionNumber;
870 NTSTATUS Status;
871
872 DPRINT("DiskBuildPartitionTable() start\n");
873
874 DiskDeviceExtension = (PDEVICE_EXTENSION)DiskDeviceObject->DeviceExtension;
875 DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
876
877 DDE = (PDEVICE_EXTENSION) DiskDeviceExtension->PhysicalDevice->DeviceExtension;
878 DD = (PDISK_DATA)(DDE +1);
879
880 /* Clear flag for Partition0, just incase it was set. */
881 DD->DriveNotReady = FALSE;
882
883 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
884 if (!NT_SUCCESS(Status))
885 {
886 /* Drive is not ready. */
887 DPRINT("Drive not ready\n");
888 DiskData->DriveNotReady = TRUE;
889 return Status;
890 }
891
892 /* Read partition table */
893 Status = IoReadPartitionTable(DiskDeviceExtension->PhysicalDevice,
894 DiskDeviceExtension->DiskGeometry->BytesPerSector,
895 TRUE,
896 &PartitionList);
897
898 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
899
900 if (!NT_SUCCESS(Status))
901 {
902 /* Drive is not ready. */
903 DPRINT("Drive not ready\n");
904 DiskData->DriveNotReady = TRUE;
905 if (PartitionList != NULL)
906 ExFreePool(PartitionList);
907 return Status;
908 }
909
910 if (NT_SUCCESS(Status))
911 {
912 DPRINT("Read partition table!\n");
913 DPRINT(" Number of partitions: %u\n", PartitionList->PartitionCount);
914
915 /* Set disk signature */
916 DiskData->Signature = PartitionList->Signature;
917
918 DiskData->NextPartition = NULL;
919
920 if (PartitionList->PartitionCount)
921 {
922 for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
923 {
924 PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
925
926 DiskData->PartitionType = PartitionEntry->PartitionType;
927 DiskData->PartitionNumber = PartitionNumber + 1;
928 DiskData->PartitionOrdinal = PartitionNumber + 1;
929 DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
930 DiskData->BootIndicator = PartitionEntry->BootIndicator;
931 DiskData->DriveNotReady = FALSE;
932 DiskDeviceExtension->StartingOffset = PartitionEntry->StartingOffset;
933 DiskDeviceExtension->PartitionLength = PartitionEntry->PartitionLength;
934
935 DPRINT1("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
936 PartitionNumber,
937 DiskData->PartitionNumber,
938 DiskData->BootIndicator,
939 DiskData->PartitionType,
940 DiskDeviceExtension->StartingOffset.QuadPart /
941 DiskDeviceExtension->DiskGeometry->BytesPerSector,
942 DiskDeviceExtension->PartitionLength.QuadPart /
943 DiskDeviceExtension->DiskGeometry->BytesPerSector);
944 }
945 }
946 else
947 {
948 DiskData->PartitionType = 0;
949 DiskData->PartitionNumber = 1;
950 DiskData->PartitionOrdinal = 0;
951 DiskData->HiddenSectors = 0;
952 DiskData->BootIndicator = 0;
953 DiskData->DriveNotReady = FALSE;
954 DiskDeviceExtension->StartingOffset.QuadPart = 0;
955 DiskDeviceExtension->PartitionLength.QuadPart += DiskDeviceExtension->StartingOffset.QuadPart;
956 }
957 }
958
959 DPRINT("DiskBuildPartitionTable() done\n");
960 if (PartitionList != NULL)
961 ExFreePool(PartitionList);
962 return(STATUS_SUCCESS);
963 }
964
965
966 /**********************************************************************
967 * NAME EXPORTED
968 * DiskClassDeviceControl
969 *
970 * DESCRIPTION
971 * Answer requests for device control calls
972 *
973 * RUN LEVEL
974 * PASSIVE_LEVEL
975 *
976 * ARGUMENTS
977 * Standard dispatch arguments
978 *
979 * RETURNS
980 * Status
981 */
982
983 NTSTATUS STDCALL
984 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
985 IN PIRP Irp)
986 {
987 PDEVICE_EXTENSION DeviceExtension;
988 PIO_STACK_LOCATION IrpStack;
989 ULONG ControlCode, InputLength, OutputLength;
990 PDISK_DATA DiskData;
991 ULONG Information;
992 NTSTATUS Status;
993
994 DPRINT("DiskClassDeviceControl() called!\n");
995
996 Status = STATUS_INVALID_DEVICE_REQUEST;
997 Information = 0;
998 IrpStack = IoGetCurrentIrpStackLocation(Irp);
999 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
1000 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
1001 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
1002 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1003 DiskData = (PDISK_DATA)(DeviceExtension + 1);
1004
1005 switch (ControlCode)
1006 {
1007 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
1008 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
1009 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
1010 {
1011 Status = STATUS_INVALID_PARAMETER;
1012 break;
1013 }
1014
1015 if (DeviceExtension->DiskGeometry == NULL)
1016 {
1017 DPRINT("No disk geometry available!\n");
1018 DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
1019 sizeof(DISK_GEOMETRY));
1020 }
1021
1022 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1023 {
1024 Status = ScsiClassReadDriveCapacity(DeviceObject);
1025 DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status);
1026 if (!NT_SUCCESS(Status))
1027 {
1028 /* Drive is not ready */
1029 DiskData->DriveNotReady = TRUE;
1030 break;
1031 }
1032
1033 /* Drive is ready */
1034 DiskData->DriveNotReady = FALSE;
1035 }
1036
1037 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1038 DeviceExtension->DiskGeometry,
1039 sizeof(DISK_GEOMETRY));
1040
1041 Status = STATUS_SUCCESS;
1042 Information = sizeof(DISK_GEOMETRY);
1043 break;
1044
1045 case IOCTL_DISK_GET_PARTITION_INFO:
1046 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
1047
1048 if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
1049 (DeviceExtension->DiskGeometry->MediaType == RemovableMedia))
1050 {
1051 /* Update a partition list for a single entry. */
1052 Status = DiskBuildPartitionTable(DeviceObject,Irp);
1053 }
1054
1055 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
1056 sizeof(PARTITION_INFORMATION))
1057 {
1058 Status = STATUS_INFO_LENGTH_MISMATCH;
1059 }
1060 else if (DiskData->PartitionNumber == 0)
1061 {
1062 Status = STATUS_INVALID_DEVICE_REQUEST;
1063 }
1064 else
1065 {
1066 PPARTITION_INFORMATION PartitionInfo;
1067
1068 PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
1069
1070 PartitionInfo->PartitionType = DiskData->PartitionType;
1071 PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
1072 PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
1073 PartitionInfo->HiddenSectors = DiskData->HiddenSectors;
1074 PartitionInfo->PartitionNumber = DiskData->PartitionNumber;
1075 PartitionInfo->BootIndicator = DiskData->BootIndicator;
1076 PartitionInfo->RewritePartition = FALSE;
1077 PartitionInfo->RecognizedPartition =
1078 IsRecognizedPartition(DiskData->PartitionType);
1079
1080 Status = STATUS_SUCCESS;
1081 Information = sizeof(PARTITION_INFORMATION);
1082 }
1083 break;
1084
1085 case IOCTL_DISK_SET_PARTITION_INFO:
1086 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
1087 sizeof(SET_PARTITION_INFORMATION))
1088 {
1089 Status = STATUS_INFO_LENGTH_MISMATCH;
1090 }
1091 else if (DiskData->PartitionNumber == 0)
1092 {
1093 Status = STATUS_INVALID_DEVICE_REQUEST;
1094 }
1095 else
1096 {
1097 PSET_PARTITION_INFORMATION PartitionInfo;
1098
1099 PartitionInfo = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
1100
1101 Status = IoSetPartitionInformation(DeviceExtension->PhysicalDevice,
1102 DeviceExtension->DiskGeometry->BytesPerSector,
1103 DiskData->PartitionOrdinal,
1104 PartitionInfo->PartitionType);
1105 if (NT_SUCCESS(Status))
1106 {
1107 DiskData->PartitionType = PartitionInfo->PartitionType;
1108 }
1109 }
1110 break;
1111
1112 case IOCTL_DISK_GET_DRIVE_LAYOUT:
1113 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
1114 sizeof(DRIVE_LAYOUT_INFORMATION))
1115 {
1116 Status = STATUS_BUFFER_TOO_SMALL;
1117 }
1118 else
1119 {
1120 PDRIVE_LAYOUT_INFORMATION PartitionList;
1121
1122 Status = IoReadPartitionTable(DeviceExtension->PhysicalDevice,
1123 DeviceExtension->DiskGeometry->BytesPerSector,
1124 FALSE,
1125 &PartitionList);
1126 if (NT_SUCCESS(Status))
1127 {
1128 ULONG BufferSize;
1129
1130 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
1131 PartitionEntry[0]);
1132 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
1133
1134 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
1135 {
1136 Status = STATUS_BUFFER_TOO_SMALL;
1137 }
1138 else
1139 {
1140 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1141 PartitionList,
1142 BufferSize);
1143 Status = STATUS_SUCCESS;
1144 Information = BufferSize;
1145 }
1146 ExFreePool(PartitionList);
1147 }
1148 }
1149 break;
1150
1151 case IOCTL_DISK_SET_DRIVE_LAYOUT:
1152 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
1153 sizeof(DRIVE_LAYOUT_INFORMATION))
1154 {
1155 Status = STATUS_INFO_LENGTH_MISMATCH;
1156 }
1157 else if (DeviceExtension->PhysicalDevice->DeviceExtension != DeviceExtension)
1158 {
1159 Status = STATUS_INVALID_PARAMETER;
1160 }
1161 else
1162 {
1163 PDRIVE_LAYOUT_INFORMATION PartitionList;
1164 ULONG TableSize;
1165
1166 PartitionList = Irp->AssociatedIrp.SystemBuffer;
1167 TableSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1168 ((PartitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
1169
1170 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < TableSize)
1171 {
1172 Status = STATUS_BUFFER_TOO_SMALL;
1173 }
1174 else
1175 {
1176 /* Update partition device objects */
1177 DiskClassUpdatePartitionDeviceObjects (DeviceObject,
1178 Irp);
1179
1180 /* Write partition table */
1181 Status = IoWritePartitionTable(DeviceExtension->PhysicalDevice,
1182 DeviceExtension->DiskGeometry->BytesPerSector,
1183 DeviceExtension->DiskGeometry->SectorsPerTrack,
1184 DeviceExtension->DiskGeometry->TracksPerCylinder,
1185 PartitionList);
1186 }
1187 }
1188 break;
1189
1190 case IOCTL_DISK_IS_WRITABLE:
1191 {
1192 PMODE_PARAMETER_HEADER ModeData;
1193 ULONG Length;
1194
1195 ModeData = ExAllocatePool (NonPagedPool,
1196 MODE_DATA_SIZE);
1197 if (ModeData == NULL)
1198 {
1199 Status = STATUS_INSUFFICIENT_RESOURCES;
1200 break;
1201 }
1202 RtlZeroMemory (ModeData,
1203 MODE_DATA_SIZE);
1204
1205 Length = ScsiClassModeSense (DeviceObject,
1206 (PVOID)ModeData,
1207 MODE_DATA_SIZE,
1208 MODE_SENSE_RETURN_ALL);
1209 if (Length < sizeof(MODE_PARAMETER_HEADER))
1210 {
1211 /* FIXME: Retry */
1212 Status = STATUS_IO_DEVICE_ERROR;
1213 ExFreePool (ModeData);
1214 break;
1215 }
1216
1217 if (ModeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT)
1218 {
1219 Status = STATUS_MEDIA_WRITE_PROTECTED;
1220 }
1221 else
1222 {
1223 Status = STATUS_SUCCESS;
1224 }
1225 ExFreePool (ModeData);
1226 }
1227 break;
1228
1229 case IOCTL_DISK_VERIFY:
1230 case IOCTL_DISK_FORMAT_TRACKS:
1231 case IOCTL_DISK_PERFORMANCE:
1232 case IOCTL_DISK_LOGGING:
1233 case IOCTL_DISK_FORMAT_TRACKS_EX:
1234 case IOCTL_DISK_HISTOGRAM_STRUCTURE:
1235 case IOCTL_DISK_HISTOGRAM_DATA:
1236 case IOCTL_DISK_HISTOGRAM_RESET:
1237 case IOCTL_DISK_REQUEST_STRUCTURE:
1238 case IOCTL_DISK_REQUEST_DATA:
1239 /* If we get here, something went wrong. Inform the requestor */
1240 DPRINT("Unhandled control code: %lx\n", ControlCode);
1241 Status = STATUS_INVALID_DEVICE_REQUEST;
1242 Information = 0;
1243 break;
1244
1245 default:
1246 /* Call the common device control function */
1247 return(ScsiClassDeviceControl(DeviceObject, Irp));
1248 }
1249
1250 /* Verify the device if the user caused the error */
1251 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
1252 {
1253 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1254 }
1255
1256 Irp->IoStatus.Status = Status;
1257 Irp->IoStatus.Information = Information;
1258 IoCompleteRequest(Irp,
1259 IO_NO_INCREMENT);
1260
1261 return(Status);
1262 }
1263
1264
1265 /**********************************************************************
1266 * NAME EXPORTED
1267 * DiskClassShutdownFlush
1268 *
1269 * DESCRIPTION
1270 * Answer requests for shutdown and flush calls.
1271 *
1272 * RUN LEVEL
1273 * PASSIVE_LEVEL
1274 *
1275 * ARGUMENTS
1276 * DeviceObject
1277 * Pointer to the device.
1278 *
1279 * Irp
1280 * Pointer to the IRP
1281 *
1282 * RETURN VALUE
1283 * Status
1284 */
1285
1286 NTSTATUS STDCALL
1287 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
1288 IN PIRP Irp)
1289 {
1290 PDEVICE_EXTENSION DeviceExtension;
1291 PIO_STACK_LOCATION IrpStack;
1292 PSCSI_REQUEST_BLOCK Srb;
1293
1294 DPRINT("DiskClassShutdownFlush() called!\n");
1295
1296 DeviceExtension = DeviceObject->DeviceExtension;
1297
1298 /* Allocate SRB */
1299 Srb = ExAllocatePool(NonPagedPool,
1300 sizeof(SCSI_REQUEST_BLOCK));
1301 if (Srb == NULL)
1302 {
1303 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1304 Irp->IoStatus.Information = 0;
1305 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1306
1307 return(STATUS_INSUFFICIENT_RESOURCES);
1308 }
1309
1310 /* Initialize SRB */
1311 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
1312 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1313
1314 /* Set device IDs */
1315 Srb->PathId = DeviceExtension->PathId;
1316 Srb->TargetId = DeviceExtension->TargetId;
1317 Srb->Lun = DeviceExtension->Lun;
1318
1319 /* Set timeout */
1320 Srb->TimeOutValue = DeviceExtension->TimeOutValue * 4;
1321
1322 /* Flush write cache */
1323 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1324 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1325 Srb->CdbLength = 10;
1326 Srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
1327 ScsiClassSendSrbSynchronous(DeviceObject,
1328 Srb,
1329 NULL,
1330 0,
1331 TRUE);
1332
1333 /* Get current stack location */
1334 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1335
1336 /* FIXME: Unlock removable media upon shutdown */
1337
1338
1339 /* No retry */
1340 IrpStack->Parameters.Others.Argument4 = (PVOID)0;
1341
1342 /* Send shutdown or flush request to the port driver */
1343 Srb->CdbLength = 0;
1344 if (IrpStack->MajorFunction == IRP_MJ_SHUTDOWN)
1345 Srb->Function = SRB_FUNCTION_SHUTDOWN;
1346 else
1347 Srb->Function = SRB_FUNCTION_FLUSH;
1348
1349 /* Init completion routine */
1350 IoSetCompletionRoutine(Irp,
1351 ScsiClassIoComplete,
1352 Srb,
1353 TRUE,
1354 TRUE,
1355 TRUE);
1356
1357 /* Prepare next stack location for a call to the port driver */
1358 IrpStack = IoGetNextIrpStackLocation(Irp);
1359 IrpStack->MajorFunction = IRP_MJ_SCSI;
1360 IrpStack->Parameters.Scsi.Srb = Srb;
1361 Srb->OriginalRequest = Irp;
1362
1363 /* Call port driver */
1364 return(IoCallDriver(DeviceExtension->PortDeviceObject, Irp));
1365 }
1366
1367
1368 /**********************************************************************
1369 * NAME INTERNAL
1370 * DiskClassUpdatePartitionDeviceObjects
1371 *
1372 * DESCRIPTION
1373 * Deletes, modifies or creates partition device objects.
1374 *
1375 * RUN LEVEL
1376 * PASSIVE_LEVEL
1377 *
1378 * ARGUMENTS
1379 * DeviceObject
1380 * Pointer to the device.
1381 *
1382 * Irp
1383 * Pointer to the IRP
1384 *
1385 * RETURN VALUE
1386 * None
1387 */
1388
1389 static VOID
1390 DiskClassUpdatePartitionDeviceObjects(IN PDEVICE_OBJECT DiskDeviceObject,
1391 IN PIRP Irp)
1392 {
1393 PDRIVE_LAYOUT_INFORMATION PartitionList;
1394 PPARTITION_INFORMATION PartitionEntry;
1395 PDEVICE_EXTENSION DeviceExtension;
1396 PDEVICE_EXTENSION DiskDeviceExtension;
1397 PDISK_DATA DiskData;
1398 ULONG PartitionCount;
1399 ULONG PartitionOrdinal;
1400 ULONG PartitionNumber;
1401 ULONG LastPartitionNumber;
1402 ULONG i;
1403 BOOLEAN Found;
1404 WCHAR NameBuffer[MAX_PATH];
1405 UNICODE_STRING DeviceName;
1406 PDEVICE_OBJECT DeviceObject;
1407 NTSTATUS Status;
1408
1409 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() called\n");
1410
1411 /* Get partition list */
1412 PartitionList = Irp->AssociatedIrp.SystemBuffer;
1413
1414 /* Round partition count up by 4 */
1415 PartitionCount = ((PartitionList->PartitionCount + 3) / 4) * 4;
1416
1417 /* Remove the partition numbers from the partition list */
1418 for (i = 0; i < PartitionCount; i++)
1419 {
1420 PartitionList->PartitionEntry[i].PartitionNumber = 0;
1421 }
1422
1423 DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
1424
1425 /* Traverse on-disk partition list */
1426 LastPartitionNumber = 0;
1427 DeviceExtension = DiskDeviceExtension;
1428 DiskData = (PDISK_DATA)(DeviceExtension + 1);
1429 while (TRUE)
1430 {
1431 DeviceExtension = DiskData->NextPartition;
1432 if (DeviceExtension == NULL)
1433 break;
1434
1435 /* Get disk data */
1436 DiskData = (PDISK_DATA)(DeviceExtension + 1);
1437
1438 /* Update last partition number */
1439 if (DiskData->PartitionNumber > LastPartitionNumber)
1440 LastPartitionNumber = DiskData->PartitionNumber;
1441
1442 /* Ignore unused on-disk partitions */
1443 if (DeviceExtension->PartitionLength.QuadPart == 0ULL)
1444 continue;
1445
1446 Found = FALSE;
1447 PartitionOrdinal = 0;
1448 for (i = 0; i < PartitionCount; i++)
1449 {
1450 /* Get current partition entry */
1451 PartitionEntry = &PartitionList->PartitionEntry[i];
1452
1453 /* Ignore empty (aka unused) or extended partitions */
1454 if (PartitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
1455 IsContainerPartition (PartitionEntry->PartitionType))
1456 continue;
1457
1458 PartitionOrdinal++;
1459
1460 /* Check for matching partition start offset and length */
1461 if ((PartitionEntry->StartingOffset.QuadPart !=
1462 DeviceExtension->StartingOffset.QuadPart) ||
1463 (PartitionEntry->PartitionLength.QuadPart !=
1464 DeviceExtension->PartitionLength.QuadPart))
1465 continue;
1466
1467 DPRINT("Found matching partition entry for partition %lu\n",
1468 DiskData->PartitionNumber);
1469
1470 /* Found matching partition */
1471 Found = TRUE;
1472
1473 /* Update partition number in partition list */
1474 PartitionEntry->PartitionNumber = DiskData->PartitionNumber;
1475 break;
1476 }
1477
1478 if (Found == TRUE)
1479 {
1480 /* Get disk data for current partition */
1481 DiskData = (PDISK_DATA)(DeviceExtension + 1);
1482
1483 /* Update partition type if partiton will be rewritten */
1484 if (PartitionEntry->RewritePartition == TRUE)
1485 DiskData->PartitionType = PartitionEntry->PartitionType;
1486
1487 /* Assign new partiton ordinal */
1488 DiskData->PartitionOrdinal = PartitionOrdinal;
1489
1490 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1491 DiskData->PartitionOrdinal,
1492 DiskData->PartitionNumber);
1493 }
1494 else
1495 {
1496 /* Delete this partition */
1497 DeviceExtension->PartitionLength.QuadPart = 0ULL;
1498
1499 DPRINT("Deleting partition %lu\n",
1500 DiskData->PartitionNumber);
1501 }
1502 }
1503
1504 /* Traverse partiton list and create new partiton devices */
1505 PartitionOrdinal = 0;
1506 for (i = 0; i < PartitionCount; i++)
1507 {
1508 /* Get current partition entry */
1509 PartitionEntry = &PartitionList->PartitionEntry[i];
1510
1511 /* Ignore empty (aka unused) or extended partitions */
1512 if (PartitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
1513 IsContainerPartition (PartitionEntry->PartitionType))
1514 continue;
1515
1516 PartitionOrdinal++;
1517
1518 /* Ignore unchanged partition entries */
1519 if (PartitionEntry->RewritePartition == FALSE)
1520 continue;
1521
1522 /* Check for an unused device object */
1523 PartitionNumber = 0;
1524 DeviceExtension = DiskDeviceExtension;
1525 DiskData = (PDISK_DATA)(DeviceExtension + 1);
1526 while (TRUE)
1527 {
1528 DeviceExtension = DiskData->NextPartition;
1529 if (DeviceExtension == NULL)
1530 break;
1531
1532 /* Get partition disk data */
1533 DiskData = (PDISK_DATA)(DeviceExtension + 1);
1534
1535 /* Found a free (unused) partition (device object) */
1536 if (DeviceExtension->PartitionLength.QuadPart == 0ULL)
1537 {
1538 PartitionNumber = DiskData->PartitionNumber;
1539 break;
1540 }
1541 }
1542
1543 if (PartitionNumber == 0)
1544 {
1545 /* Create a new partition device object */
1546 DPRINT("Create new partition device object\n");
1547
1548 /* Get new partiton number */
1549 LastPartitionNumber++;
1550 PartitionNumber = LastPartitionNumber;
1551
1552 /* Create partition device object */
1553 swprintf(NameBuffer,
1554 L"\\Device\\Harddisk%lu\\Partition%lu",
1555 DiskDeviceExtension->DeviceNumber,
1556 PartitionNumber);
1557 RtlInitUnicodeString(&DeviceName,
1558 NameBuffer);
1559
1560 Status = IoCreateDevice(DiskDeviceObject->DriverObject,
1561 sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA),
1562 &DeviceName,
1563 FILE_DEVICE_DISK,
1564 0,
1565 FALSE,
1566 &DeviceObject);
1567 if (!NT_SUCCESS(Status))
1568 {
1569 DPRINT("IoCreateDevice() failed (Status %lx)\n", Status);
1570 continue;
1571 }
1572
1573 DeviceObject->Flags |= DO_DIRECT_IO;
1574 DeviceObject->StackSize = DiskDeviceObject->StackSize;
1575 DeviceObject->Characteristics = DiskDeviceObject->Characteristics;
1576 DeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
1577
1578 /* Initialize device extension */
1579 DeviceExtension = DeviceObject->DeviceExtension;
1580 RtlCopyMemory(DeviceExtension,
1581 DiskDeviceObject->DeviceExtension,
1582 sizeof(DEVICE_EXTENSION));
1583 DeviceExtension->DeviceObject = DeviceObject;
1584
1585 /* Initialize lookaside list for SRBs */
1586 ScsiClassInitializeSrbLookasideList(DeviceExtension,
1587 8);
1588
1589 /* Link current partition device extension to previous disk data */
1590 DiskData->NextPartition = DeviceExtension;
1591 DiskData = (PDISK_DATA)(DeviceExtension + 1);
1592 DiskData->NextPartition = NULL;
1593 }
1594 else
1595 {
1596 /* Reuse an existing partition device object */
1597 DPRINT("Reuse an exisiting partition device object\n");
1598 DiskData = (PDISK_DATA)(DeviceExtension + 1);
1599 }
1600
1601 /* Update partition data and device extension */
1602 DiskData->PartitionNumber = PartitionNumber;
1603 DiskData->PartitionOrdinal = PartitionOrdinal;
1604 DiskData->PartitionType = PartitionEntry->PartitionType;
1605 DiskData->BootIndicator = PartitionEntry->BootIndicator;
1606 DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
1607 DeviceExtension->StartingOffset = PartitionEntry->StartingOffset;
1608 DeviceExtension->PartitionLength = PartitionEntry->PartitionLength;
1609
1610 /* Update partition number in the partition list */
1611 PartitionEntry->PartitionNumber = PartitionNumber;
1612
1613 DPRINT("Partition ordinal %lu was assigned to partition %lu\n",
1614 DiskData->PartitionOrdinal,
1615 DiskData->PartitionNumber);
1616 }
1617
1618 DPRINT("ScsiDiskUpdatePartitionDeviceObjects() done\n");
1619 }
1620
1621
1622 /**********************************************************************
1623 * NAME INTERNAL
1624 * ScsiDiskSearchForDisk
1625 *
1626 * DESCRIPTION
1627 * Searches the hardware tree for the given disk.
1628 *
1629 * RUN LEVEL
1630 * PASSIVE_LEVEL
1631 *
1632 * ARGUMENTS
1633 * DeviceExtension
1634 * Disk device extension.
1635 *
1636 * BusKey
1637 * Handle to the hardware bus key.
1638 *
1639 * DetectedDiskNumber
1640 * Returned disk number.
1641 *
1642 * RETURN VALUE
1643 * TRUE: Disk was found.
1644 * FALSE: Search failed.
1645 */
1646
1647 static BOOLEAN
1648 ScsiDiskSearchForDisk(IN PDEVICE_EXTENSION DeviceExtension,
1649 IN HANDLE BusKey,
1650 OUT PULONG DetectedDiskNumber)
1651 {
1652 PKEY_VALUE_FULL_INFORMATION ValueData;
1653 OBJECT_ATTRIBUTES ObjectAttributes;
1654 PDISK_DATA DiskData;
1655 UNICODE_STRING IdentifierString;
1656 UNICODE_STRING NameString;
1657 HANDLE BusInstanceKey;
1658 HANDLE ControllerKey;
1659 HANDLE DiskKey;
1660 HANDLE DiskInstanceKey;
1661 ULONG BusNumber;
1662 ULONG ControllerNumber;
1663 ULONG DiskNumber;
1664 ULONG Length;
1665 WCHAR Buffer[32];
1666 BOOLEAN DiskFound;
1667 NTSTATUS Status;
1668
1669 DPRINT("ScsiDiskSearchForDiskData() called\n");
1670
1671 DiskFound = FALSE;
1672
1673 /* Enumerate buses */
1674 for (BusNumber = 0; ; BusNumber++)
1675 {
1676 /* Open bus instance subkey */
1677 swprintf(Buffer,
1678 L"%lu",
1679 BusNumber);
1680
1681 RtlInitUnicodeString(&NameString,
1682 Buffer);
1683
1684 InitializeObjectAttributes(&ObjectAttributes,
1685 &NameString,
1686 OBJ_CASE_INSENSITIVE,
1687 BusKey,
1688 NULL);
1689
1690 Status = ZwOpenKey(&BusInstanceKey,
1691 KEY_READ,
1692 &ObjectAttributes);
1693 if (!NT_SUCCESS(Status))
1694 {
1695 break;
1696 }
1697
1698 /* Open 'DiskController' subkey */
1699 RtlInitUnicodeString(&NameString,
1700 L"DiskController");
1701
1702 InitializeObjectAttributes(&ObjectAttributes,
1703 &NameString,
1704 OBJ_CASE_INSENSITIVE,
1705 BusInstanceKey,
1706 NULL);
1707
1708 Status = ZwOpenKey(&ControllerKey,
1709 KEY_READ,
1710 &ObjectAttributes);
1711 if (!NT_SUCCESS(Status))
1712 {
1713 ZwClose(BusInstanceKey);
1714 continue;
1715 }
1716
1717 /* Enumerate controllers */
1718 for (ControllerNumber = 0; ; ControllerNumber++)
1719 {
1720 /* Open 'DiskPeripheral' subkey */
1721 swprintf(Buffer,
1722 L"%lu\\DiskPeripheral",
1723 ControllerNumber);
1724
1725 RtlInitUnicodeString(&NameString,
1726 Buffer);
1727
1728 InitializeObjectAttributes(&ObjectAttributes,
1729 &NameString,
1730 OBJ_CASE_INSENSITIVE,
1731 ControllerKey,
1732 NULL);
1733
1734 Status = ZwOpenKey(&DiskKey,
1735 KEY_READ,
1736 &ObjectAttributes);
1737 if (!NT_SUCCESS(Status))
1738 {
1739 break;
1740 }
1741
1742 /* Enumerate disks */
1743 for (DiskNumber = 0; ; DiskNumber++)
1744 {
1745 /* Open disk instance subkey */
1746 swprintf(Buffer,
1747 L"%lu",
1748 DiskNumber);
1749
1750 RtlInitUnicodeString(&NameString,
1751 Buffer);
1752
1753 InitializeObjectAttributes(&ObjectAttributes,
1754 &NameString,
1755 OBJ_CASE_INSENSITIVE,
1756 DiskKey,
1757 NULL);
1758
1759 Status = ZwOpenKey(&DiskInstanceKey,
1760 KEY_READ,
1761 &ObjectAttributes);
1762 if (!NT_SUCCESS(Status))
1763 {
1764 break;
1765 }
1766
1767 DPRINT("Found disk key: bus %lu controller %lu disk %lu\n",
1768 BusNumber,
1769 ControllerNumber,
1770 DiskNumber);
1771
1772 /* Allocate data buffer */
1773 ValueData = ExAllocatePool(PagedPool,
1774 2048);
1775 if (ValueData == NULL)
1776 {
1777 ZwClose(DiskInstanceKey);
1778 continue;
1779 }
1780
1781 /* Get the 'Identifier' value */
1782 RtlInitUnicodeString(&NameString,
1783 L"Identifier");
1784 Status = ZwQueryValueKey(DiskInstanceKey,
1785 &NameString,
1786 KeyValueFullInformation,
1787 ValueData,
1788 2048,
1789 &Length);
1790
1791 ZwClose(DiskInstanceKey);
1792 if (!NT_SUCCESS(Status))
1793 {
1794 ExFreePool(ValueData);
1795 continue;
1796 }
1797
1798 IdentifierString.Buffer =
1799 (PWSTR)((PUCHAR)ValueData + ValueData->DataOffset);
1800 IdentifierString.Length = (USHORT)ValueData->DataLength - 2;
1801 IdentifierString.MaximumLength = (USHORT)ValueData->DataLength;
1802
1803 DPRINT("DiskIdentifier: %wZ\n",
1804 &IdentifierString);
1805
1806 DiskData = (PDISK_DATA)(DeviceExtension + 1);
1807 if (DiskData->Signature != 0)
1808 {
1809 /* Comapre disk signature */
1810 swprintf(Buffer,
1811 L"%08lx",
1812 DiskData->Signature);
1813 if (!_wcsnicmp(Buffer, &IdentifierString.Buffer[9], 8))
1814 {
1815 DPRINT("Found disk %lu\n", DiskNumber);
1816 DiskFound = TRUE;
1817 *DetectedDiskNumber = DiskNumber;
1818 }
1819 }
1820 else
1821 {
1822 /* Comapre mbr checksum */
1823 swprintf(Buffer,
1824 L"%08lx",
1825 DiskData->MbrCheckSum);
1826 if (!_wcsnicmp(Buffer, &IdentifierString.Buffer[0], 8))
1827 {
1828 DPRINT("Found disk %lu\n", DiskNumber);
1829 DiskFound = TRUE;
1830 *DetectedDiskNumber = DiskNumber;
1831 }
1832 }
1833
1834 ExFreePool(ValueData);
1835
1836 ZwClose(DiskInstanceKey);
1837
1838 if (DiskFound == TRUE)
1839 break;
1840 }
1841
1842 ZwClose(DiskKey);
1843 }
1844
1845 ZwClose(ControllerKey);
1846 ZwClose(BusInstanceKey);
1847 }
1848
1849 DPRINT("ScsiDiskSearchForDisk() done\n");
1850
1851 return DiskFound;
1852 }
1853
1854
1855 /**********************************************************************
1856 * NAME INTERNAL
1857 * DiskClassUpdateFixedDiskGeometry
1858 *
1859 * DESCRIPTION
1860 * Updated the geometry of a disk if the disk can be accessed
1861 * by the BIOS.
1862 *
1863 * RUN LEVEL
1864 * PASSIVE_LEVEL
1865 *
1866 * ARGUMENTS
1867 * DeviceExtension
1868 * Disk device extension.
1869 *
1870 * RETURN VALUE
1871 * None
1872 */
1873
1874 static VOID
1875 ScsiDiskUpdateFixedDiskGeometry(IN PDEVICE_EXTENSION DeviceExtension)
1876 {
1877 PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor;
1878 PCM_INT13_DRIVE_PARAMETER DriveParameters;
1879 PKEY_VALUE_FULL_INFORMATION ValueBuffer;
1880 OBJECT_ATTRIBUTES ObjectAttributes;
1881 UNICODE_STRING KeyName;
1882 UNICODE_STRING ValueName;
1883 HANDLE SystemKey;
1884 HANDLE BusKey;
1885 ULONG DiskNumber;
1886 ULONG Length;
1887 #if 0
1888 ULONG i;
1889 #endif
1890 ULONG Cylinders;
1891 ULONG Sectors;
1892 ULONG SectorsPerTrack;
1893 ULONG TracksPerCylinder;
1894 NTSTATUS Status;
1895
1896 DPRINT("ScsiDiskUpdateFixedDiskGeometry() called\n");
1897
1898 RtlInitUnicodeString(&KeyName,
1899 L"\\Registry\\Machine\\Hardware\\Description\\System");
1900
1901 InitializeObjectAttributes(&ObjectAttributes,
1902 &KeyName,
1903 OBJ_CASE_INSENSITIVE,
1904 NULL,
1905 NULL);
1906
1907 /* Open the adapter key */
1908 Status = ZwOpenKey(&SystemKey,
1909 KEY_READ,
1910 &ObjectAttributes);
1911 if (!NT_SUCCESS(Status))
1912 {
1913 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
1914 return;
1915 }
1916
1917 /* Allocate value buffer */
1918 ValueBuffer = ExAllocatePool(PagedPool,
1919 1024);
1920 if (ValueBuffer == NULL)
1921 {
1922 DPRINT("Failed to allocate value buffer\n");
1923 ZwClose(SystemKey);
1924 return;
1925 }
1926
1927 RtlInitUnicodeString(&ValueName,
1928 L"Configuration Data");
1929
1930 /* Query 'Configuration Data' value */
1931 Status = ZwQueryValueKey(SystemKey,
1932 &ValueName,
1933 KeyValueFullInformation,
1934 ValueBuffer,
1935 1024,
1936 &Length);
1937 if (!NT_SUCCESS(Status))
1938 {
1939 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
1940 ExFreePool(ValueBuffer);
1941 ZwClose(SystemKey);
1942 return;
1943 }
1944
1945 /* Open the 'MultifunctionAdapter' subkey */
1946 RtlInitUnicodeString(&KeyName,
1947 L"MultifunctionAdapter");
1948
1949 InitializeObjectAttributes(&ObjectAttributes,
1950 &KeyName,
1951 OBJ_CASE_INSENSITIVE,
1952 SystemKey,
1953 NULL);
1954
1955 Status = ZwOpenKey(&BusKey,
1956 KEY_READ,
1957 &ObjectAttributes);
1958 ZwClose(SystemKey);
1959 if (!NT_SUCCESS(Status))
1960 {
1961 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
1962 ExFreePool(ValueBuffer);
1963 return;
1964 }
1965
1966 if (!ScsiDiskSearchForDisk(DeviceExtension, BusKey, &DiskNumber))
1967 {
1968 DPRINT("ScsiDiskSearchForDisk() failed\n");
1969 ZwClose(BusKey);
1970 ExFreePool(ValueBuffer);
1971 return;
1972 }
1973
1974 ZwClose(BusKey);
1975
1976 ResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
1977 ((PUCHAR)ValueBuffer + ValueBuffer->DataOffset);
1978
1979 DriveParameters = (PCM_INT13_DRIVE_PARAMETER)
1980 ((PUCHAR)ResourceDescriptor + sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
1981
1982 #if 0
1983 for (i = 0; i< DriveParameters[0].NumberDrives; i++)
1984 {
1985 DPRINT("Drive %lu: %lu Cylinders %hu Heads %hu Sectors\n",
1986 i,
1987 DriveParameters[i].MaxCylinders,
1988 DriveParameters[i].MaxHeads,
1989 DriveParameters[i].SectorsPerTrack);
1990 }
1991 #endif
1992
1993 Cylinders = DriveParameters[DiskNumber].MaxCylinders + 1;
1994 TracksPerCylinder = DriveParameters[DiskNumber].MaxHeads +1;
1995 SectorsPerTrack = DriveParameters[DiskNumber].SectorsPerTrack;
1996
1997 DPRINT("BIOS geometry: %lu Cylinders %hu Heads %hu Sectors\n",
1998 Cylinders,
1999 TracksPerCylinder,
2000 SectorsPerTrack);
2001
2002 Sectors = (ULONG)
2003 (DeviceExtension->PartitionLength.QuadPart >> DeviceExtension->SectorShift);
2004
2005 DPRINT("Physical sectors: %lu\n",
2006 Sectors);
2007
2008 Length = TracksPerCylinder * SectorsPerTrack;
2009 if (Length == 0)
2010 {
2011 DPRINT("Invalid track length 0\n");
2012 ExFreePool(ValueBuffer);
2013 return;
2014 }
2015
2016 Cylinders = Sectors / Length;
2017
2018 DPRINT("Logical geometry: %lu Cylinders %hu Heads %hu Sectors\n",
2019 Cylinders,
2020 TracksPerCylinder,
2021 SectorsPerTrack);
2022
2023 /* Update the disk geometry */
2024 DeviceExtension->DiskGeometry->SectorsPerTrack = SectorsPerTrack;
2025 DeviceExtension->DiskGeometry->TracksPerCylinder = TracksPerCylinder;
2026 DeviceExtension->DiskGeometry->Cylinders.QuadPart = (ULONGLONG)Cylinders;
2027
2028 if (DeviceExtension->DMActive)
2029 {
2030 DPRINT("FIXME: Update geometry with respect to the installed disk manager!\n");
2031
2032 /* FIXME: Update geometry for disk managers */
2033
2034 }
2035
2036 ExFreePool(ValueBuffer);
2037
2038 DPRINT("ScsiDiskUpdateFixedDiskGeometry() done\n");
2039 }
2040
2041
2042 /**********************************************************************
2043 * NAME INTERNAL
2044 * ScsiDiskCalcMbrCheckSum
2045 *
2046 * DESCRIPTION
2047 * Calculates the Checksum from drives MBR.
2048 *
2049 * RUN LEVEL
2050 * PASSIVE_LEVEL
2051 *
2052 * ARGUMENTS
2053 * DeviceExtension
2054 * Disk device extension.
2055 *
2056 * Checksum
2057 * Pointer to the caller supplied cecksum variable.
2058 *
2059 * RETURN VALUE
2060 * TRUE: Checksum was calculated.
2061 * FALSE: Calculation failed.
2062 */
2063
2064 static BOOLEAN
2065 ScsiDiskCalcMbrCheckSum(IN PDEVICE_EXTENSION DeviceExtension,
2066 OUT PULONG Checksum)
2067 {
2068 IO_STATUS_BLOCK IoStatusBlock;
2069 LARGE_INTEGER SectorOffset;
2070 ULONG SectorSize;
2071 PULONG MbrBuffer;
2072 KEVENT Event;
2073 PIRP Irp;
2074 ULONG i;
2075 ULONG Sum;
2076 NTSTATUS Status;
2077
2078 KeInitializeEvent(&Event,
2079 NotificationEvent,
2080 FALSE);
2081
2082 /* Get the disk sector size */
2083 SectorSize = DeviceExtension->DiskGeometry->BytesPerSector;
2084 if (SectorSize < 512)
2085 {
2086 SectorSize = 512;
2087 }
2088
2089 /* Allocate MBR buffer */
2090 MbrBuffer = ExAllocatePool(NonPagedPool,
2091 SectorSize);
2092 if (MbrBuffer == NULL)
2093 {
2094 return FALSE;
2095 }
2096
2097 /* Allocate an IRP */
2098 SectorOffset.QuadPart = 0ULL;
2099 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
2100 DeviceExtension->DeviceObject,
2101 MbrBuffer,
2102 SectorSize,
2103 &SectorOffset,
2104 &Event,
2105 &IoStatusBlock);
2106 if (Irp == NULL)
2107 {
2108 ExFreePool(MbrBuffer);
2109 return FALSE;
2110 }
2111
2112 /* Call the miniport driver */
2113 Status = IoCallDriver(DeviceExtension->DeviceObject,
2114 Irp);
2115 if (Status == STATUS_PENDING)
2116 {
2117 KeWaitForSingleObject(&Event,
2118 Suspended,
2119 KernelMode,
2120 FALSE,
2121 NULL);
2122 Status = IoStatusBlock.Status;
2123 }
2124
2125 if (!NT_SUCCESS(Status))
2126 {
2127 ExFreePool(MbrBuffer);
2128 return FALSE;
2129 }
2130
2131 /* Calculate MBR checksum */
2132 Sum = 0;
2133 for (i = 0; i < 128; i++)
2134 {
2135 Sum += MbrBuffer[i];
2136 }
2137 *Checksum = ~Sum + 1;
2138
2139 ExFreePool(MbrBuffer);
2140
2141 return TRUE;
2142 }
2143
2144 /* EOF */