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