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