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