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