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