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