Added IOCTL_DISK_GET_PARTITION_INFO.
[reactos.git] / reactos / drivers / storage / disk / disk.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: disk.c,v 1.8 2002/03/08 12:01:26 ekohl Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/disk/disk.c
24 * PURPOSE: disk class driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31
32 #include "../include/scsi.h"
33 #include "../include/class2.h"
34 #include "../include/ntddscsi.h"
35
36 #define NDEBUG
37 #include <debug.h>
38
39 #define VERSION "0.0.1"
40
41
42 typedef struct _DISK_DATA
43 {
44 ULONG HiddenSectors;
45 ULONG PartitionNumber;
46 UCHAR PartitionType;
47 BOOLEAN BootIndicator;
48 BOOLEAN DriveNotReady;
49 } DISK_DATA, *PDISK_DATA;
50
51
52 BOOLEAN STDCALL
53 DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
54 PUNICODE_STRING RegistryPath,
55 PCLASS_INIT_DATA InitializationData,
56 PDEVICE_OBJECT PortDeviceObject,
57 ULONG PortNumber);
58
59 BOOLEAN STDCALL
60 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData);
61
62 NTSTATUS STDCALL
63 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
64 IN PIRP Irp);
65
66
67 static NTSTATUS
68 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
69 IN PUNICODE_STRING RegistryPath, /* what's this used for? */
70 IN PDEVICE_OBJECT PortDeviceObject,
71 IN ULONG PortNumber,
72 IN ULONG DiskNumber,
73 IN PIO_SCSI_CAPABILITIES Capabilities,
74 IN PSCSI_INQUIRY_DATA InquiryData,
75 IN PCLASS_INIT_DATA InitializationData);
76
77 NTSTATUS STDCALL
78 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
79 IN PIRP Irp);
80
81 NTSTATUS STDCALL
82 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
83 IN PIRP Irp);
84
85
86
87 /* FUNCTIONS ****************************************************************/
88
89 // DriverEntry
90 //
91 // DESCRIPTION:
92 // This function initializes the driver, locates and claims
93 // hardware resources, and creates various NT objects needed
94 // to process I/O requests.
95 //
96 // RUN LEVEL:
97 // PASSIVE_LEVEL
98 //
99 // ARGUMENTS:
100 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
101 // for this driver
102 // IN PUNICODE_STRING RegistryPath Name of registry driver service
103 // key
104 //
105 // RETURNS:
106 // NTSTATUS
107
108 NTSTATUS STDCALL
109 DriverEntry(IN PDRIVER_OBJECT DriverObject,
110 IN PUNICODE_STRING RegistryPath)
111 {
112 CLASS_INIT_DATA InitData;
113
114 DbgPrint("Disk Class Driver %s\n",
115 VERSION);
116 DPRINT("RegistryPath '%wZ'\n",
117 RegistryPath);
118
119 RtlZeroMemory(&InitData,
120 sizeof(CLASS_INIT_DATA));
121
122 InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
123 InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA);
124 InitData.DeviceType = FILE_DEVICE_DISK;
125 InitData.DeviceCharacteristics = 0;
126
127 InitData.ClassError = NULL; // DiskClassProcessError;
128 InitData.ClassReadWriteVerification = DiskClassCheckReadWrite;
129 InitData.ClassFindDeviceCallBack = DiskClassCheckDevice;
130 InitData.ClassFindDevices = DiskClassFindDevices;
131 InitData.ClassDeviceControl = DiskClassDeviceControl;
132 InitData.ClassShutdownFlush = DiskClassShutdownFlush;
133 InitData.ClassCreateClose = NULL;
134 InitData.ClassStartIo = NULL;
135
136 return(ScsiClassInitialize(DriverObject,
137 RegistryPath,
138 &InitData));
139 }
140
141
142 /**********************************************************************
143 * NAME EXPORTED
144 * DiskClassFindDevices
145 *
146 * DESCRIPTION
147 * This function searches for device that are attached to the
148 * given scsi port.
149 *
150 * RUN LEVEL
151 * PASSIVE_LEVEL
152 *
153 * ARGUMENTS
154 * DriverObject
155 * System allocated Driver Object for this driver
156 *
157 * RegistryPath
158 * Name of registry driver service key
159 *
160 * InitializationData
161 * Pointer to the main initialization data
162 *
163 * PortDeviceObject
164 * Pointer to the port Device Object
165 *
166 * PortNumber
167 * Port number
168 *
169 * RETURN VALUE
170 * TRUE: At least one disk drive was found
171 * FALSE: No disk drive found
172 */
173
174 BOOLEAN STDCALL
175 DiskClassFindDevices(PDRIVER_OBJECT DriverObject,
176 PUNICODE_STRING RegistryPath,
177 PCLASS_INIT_DATA InitializationData,
178 PDEVICE_OBJECT PortDeviceObject,
179 ULONG PortNumber)
180 {
181 PCONFIGURATION_INFORMATION ConfigInfo;
182 PIO_SCSI_CAPABILITIES PortCapabilities;
183 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
184 PSCSI_INQUIRY_DATA UnitInfo;
185 PINQUIRYDATA InquiryData;
186 PCHAR Buffer;
187 ULONG Bus;
188 ULONG DeviceCount;
189 BOOLEAN FoundDevice;
190 NTSTATUS Status;
191
192 DPRINT("DiskClassFindDevices() called.\n");
193
194 /* Get port capabilities */
195 Status = ScsiClassGetCapabilities(PortDeviceObject,
196 &PortCapabilities);
197 if (!NT_SUCCESS(Status))
198 {
199 DPRINT("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
200 return(FALSE);
201 }
202
203 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
204
205 /* Get inquiry data */
206 Status = ScsiClassGetInquiryData(PortDeviceObject,
207 (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
208 if (!NT_SUCCESS(Status))
209 {
210 DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status);
211 return(FALSE);
212 }
213
214 /* Check whether there are unclaimed devices */
215 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
216 DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
217 AdapterBusInfo);
218 if (DeviceCount == 0)
219 {
220 DPRINT1("No unclaimed devices!\n");
221 return(FALSE);
222 }
223
224 DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
225
226 ConfigInfo = IoGetConfigurationInformation();
227
228 /* Search each bus of this adapter */
229 for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
230 {
231 DPRINT("Searching bus %lu\n", Bus);
232
233 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
234
235 while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
236 {
237 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
238
239 if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
240 (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
241 (InquiryData->DeviceTypeQualifier == 0) &&
242 (UnitInfo->DeviceClaimed == FALSE))
243 {
244 DPRINT("Vendor: '%.24s'\n",
245 InquiryData->VendorId);
246
247 /* Create device objects for disk */
248 Status = DiskClassCreateDeviceObject(DriverObject,
249 RegistryPath,
250 PortDeviceObject,
251 PortNumber,
252 ConfigInfo->DiskCount,
253 PortCapabilities,
254 UnitInfo,
255 InitializationData);
256 if (NT_SUCCESS(Status))
257 {
258 ConfigInfo->DiskCount++;
259 FoundDevice = TRUE;
260 }
261 }
262
263 if (UnitInfo->NextInquiryDataOffset == 0)
264 break;
265
266 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
267 }
268 }
269
270 ExFreePool(Buffer);
271 ExFreePool(PortCapabilities);
272
273 DPRINT("DiskClassFindDevices() done\n");
274
275 return(FoundDevice);
276 }
277
278
279 /**********************************************************************
280 * NAME EXPORTED
281 * DiskClassCheckDevice
282 *
283 * DESCRIPTION
284 * This function checks the InquiryData for the correct device
285 * type and qualifier.
286 *
287 * RUN LEVEL
288 * PASSIVE_LEVEL
289 *
290 * ARGUMENTS
291 * InquiryData
292 * Pointer to the inquiry data for the device in question.
293 *
294 * RETURN VALUE
295 * TRUE: A disk device was found.
296 * FALSE: Otherwise.
297 */
298
299 BOOLEAN STDCALL
300 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData)
301 {
302 return((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE ||
303 InquiryData->DeviceType == OPTICAL_DEVICE) &&
304 InquiryData->DeviceTypeQualifier == 0);
305 }
306
307
308 /**********************************************************************
309 * NAME EXPORTED
310 * DiskClassCheckReadWrite
311 *
312 * DESCRIPTION
313 * This function checks the given IRP for correct data.
314 *
315 * RUN LEVEL
316 * PASSIVE_LEVEL
317 *
318 * ARGUMENTS
319 * DeviceObject
320 * Pointer to the device.
321 *
322 * Irp
323 * Irp to check.
324 *
325 * RETURN VALUE
326 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
327 * Others: Failure.
328 */
329
330 NTSTATUS STDCALL
331 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
332 IN PIRP Irp)
333 {
334 DPRINT1("DiskClassCheckReadWrite() called\n");
335
336 return(STATUS_SUCCESS);
337 }
338
339
340 // DiskClassCreateDeviceObject
341 //
342 // DESCRIPTION:
343 // Create the raw device and any partition devices on this drive
344 //
345 // RUN LEVEL:
346 // PASSIVE_LEVEL
347 //
348 // ARGUMENTS:
349 // IN PDRIVER_OBJECT DriverObject The system created driver object
350 // IN PCONTROLLER_OBJECT ControllerObject
351 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
352 // The IDE controller extension for
353 // this device
354 // IN int DriveIdx The index of the drive on this
355 // controller
356 // IN int HarddiskIdx The NT device number for this
357 // drive
358 //
359 // RETURNS:
360 // TRUE Drive exists and devices were created
361 // FALSE no devices were created for this device
362 //
363
364 static NTSTATUS
365 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
366 IN PUNICODE_STRING RegistryPath, /* what's this used for? */
367 IN PDEVICE_OBJECT PortDeviceObject,
368 IN ULONG PortNumber,
369 IN ULONG DiskNumber,
370 IN PIO_SCSI_CAPABILITIES Capabilities,
371 IN PSCSI_INQUIRY_DATA InquiryData,
372 IN PCLASS_INIT_DATA InitializationData)
373 {
374 OBJECT_ATTRIBUTES ObjectAttributes;
375 UNICODE_STRING UnicodeDeviceDirName;
376 WCHAR NameBuffer[80];
377 CHAR NameBuffer2[80];
378 PDEVICE_OBJECT DiskDeviceObject;
379 PDEVICE_OBJECT PartitionDeviceObject;
380 PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
381 PDEVICE_EXTENSION PartitionDeviceExtension; /* defined in class2.h */
382 PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
383 HANDLE Handle;
384 PPARTITION_INFORMATION PartitionEntry;
385 PDISK_DATA DiskData;
386 ULONG PartitionNumber;
387 NTSTATUS Status;
388
389 WCHAR ArcNameBuffer[120];
390 UNICODE_STRING ArcName;
391 ANSI_STRING DeviceNameA;
392 UNICODE_STRING DeviceName;
393
394 DPRINT("DiskClassCreateDeviceObject() called\n");
395
396 /* Create the harddisk device directory */
397 swprintf(NameBuffer,
398 L"\\Device\\Harddisk%lu",
399 DiskNumber);
400 RtlInitUnicodeString(&UnicodeDeviceDirName,
401 NameBuffer);
402 InitializeObjectAttributes(&ObjectAttributes,
403 &UnicodeDeviceDirName,
404 0,
405 NULL,
406 NULL);
407 Status = ZwCreateDirectoryObject(&Handle,
408 0,
409 &ObjectAttributes);
410 if (!NT_SUCCESS(Status))
411 {
412 DbgPrint("Could not create device dir object\n");
413 return(Status);
414 }
415
416 /* Claim the disk device */
417 Status = ScsiClassClaimDevice(PortDeviceObject,
418 InquiryData,
419 FALSE,
420 &PortDeviceObject);
421 if (!NT_SUCCESS(Status))
422 {
423 DbgPrint("Could not claim disk device\n");
424
425 ZwMakeTemporaryObject(Handle);
426 ZwClose(Handle);
427
428 return(Status);
429 }
430
431 /* Create disk device (Partition 0) */
432 sprintf(NameBuffer2,
433 "\\Device\\Harddisk%lu\\Partition0",
434 DiskNumber);
435
436 Status = ScsiClassCreateDeviceObject(DriverObject,
437 NameBuffer2,
438 NULL,
439 &DiskDeviceObject,
440 InitializationData);
441 if (!NT_SUCCESS(Status))
442 {
443 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
444
445 /* Release (unclaim) the disk */
446 ScsiClassClaimDevice(PortDeviceObject,
447 InquiryData,
448 TRUE,
449 NULL);
450
451 /* Delete the harddisk device directory */
452 ZwMakeTemporaryObject(Handle);
453 ZwClose(Handle);
454
455 return(Status);
456 }
457
458 DiskDeviceObject->Flags |= DO_DIRECT_IO;
459 if (((PINQUIRYDATA)InquiryData->InquiryData)->RemovableMedia)
460 {
461 DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
462 }
463 DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
464
465 if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
466 {
467 DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
468 }
469
470 DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
471 DiskDeviceExtension->LockCount = 0;
472 DiskDeviceExtension->DeviceNumber = DiskNumber;
473 DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
474 DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
475
476 /* FIXME: Not yet! Will cause pointer corruption! */
477 // DiskDeviceExtension->PortCapabilities = PortCapabilities;
478
479 DiskDeviceExtension->StartingOffset.QuadPart = 0;
480 DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
481 DiskDeviceExtension->PathId = InquiryData->PathId;
482 DiskDeviceExtension->TargetId = InquiryData->TargetId;
483 DiskDeviceExtension->Lun = InquiryData->Lun;
484
485 /* zero-out disk data */
486 DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
487 RtlZeroMemory(DiskData,
488 sizeof(DISK_DATA));
489
490 /* Get disk geometry */
491 DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
492 sizeof(DISK_GEOMETRY));
493 if (DiskDeviceExtension->DiskGeometry == NULL)
494 {
495 DPRINT1("Failed to allocate geometry buffer!\n");
496
497 IoDeleteDevice(DiskDeviceObject);
498
499 /* Release (unclaim) the disk */
500 ScsiClassClaimDevice(PortDeviceObject,
501 InquiryData,
502 TRUE,
503 NULL);
504
505 /* Delete the harddisk device directory */
506 ZwMakeTemporaryObject(Handle);
507 ZwClose(Handle);
508
509 return(STATUS_INSUFFICIENT_RESOURCES);
510 }
511
512 /* Read the drive's capacity */
513 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
514 if (!NT_SUCCESS(Status) &&
515 (DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
516 {
517 DPRINT1("Failed to retrieve drive capacity!\n");
518 return(STATUS_SUCCESS);
519 }
520 else
521 {
522 /* Clear the verify flag for non-removable media drives. */
523 DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
524 }
525
526 DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
527
528 /* assign arc name */
529 RtlInitAnsiString(&DeviceNameA,
530 NameBuffer2);
531 RtlAnsiStringToUnicodeString(&DeviceName,
532 &DeviceNameA,
533 TRUE);
534 swprintf(ArcNameBuffer,
535 L"\\ArcName\\multi(0)disk(0)rdisk(%lu)",
536 DiskNumber);
537 RtlInitUnicodeString(&ArcName,
538 ArcNameBuffer);
539 DPRINT("ArcNameBuffer '%S'\n", ArcNameBuffer);
540 DPRINT("%wZ ==> %wZ\n", &ArcName, &DeviceName);
541 Status = IoAssignArcName(&ArcName,
542 &DeviceName);
543 RtlFreeUnicodeString(&DeviceName);
544
545 if (!NT_SUCCESS(Status))
546 {
547 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName, Status);
548 KeBugCheck(0);
549 }
550
551
552 /* Read partition table */
553 Status = IoReadPartitionTable(DiskDeviceObject,
554 DiskDeviceExtension->DiskGeometry->BytesPerSector,
555 TRUE,
556 &PartitionList);
557
558 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
559
560 if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
561 DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
562 {
563 if (!NT_SUCCESS(Status))
564 {
565 /* Drive is not ready. */
566 DPRINT1("Drive not ready\n");
567 DiskData->DriveNotReady = TRUE;
568 }
569 else
570 {
571 ExFreePool(PartitionList);
572 }
573
574 /* Allocate a partition list for a single entry. */
575 PartitionList = ExAllocatePool(NonPagedPool,
576 sizeof(DRIVE_LAYOUT_INFORMATION));
577 if (PartitionList != NULL)
578 {
579 RtlZeroMemory(PartitionList,
580 sizeof(DRIVE_LAYOUT_INFORMATION));
581 PartitionList->PartitionCount = 1;
582
583 Status = STATUS_SUCCESS;
584 }
585 }
586
587 if (NT_SUCCESS(Status))
588 {
589 DPRINT("Read partition table!\n");
590
591 DPRINT(" Number of partitions: %u\n", PartitionList->PartitionCount);
592
593 for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
594 {
595 PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
596
597 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
598 PartitionNumber,
599 PartitionEntry->PartitionNumber,
600 PartitionEntry->BootIndicator,
601 PartitionEntry->PartitionType,
602 PartitionEntry->StartingOffset.QuadPart / 512 /*DrvParms.BytesPerSector*/,
603 PartitionEntry->PartitionLength.QuadPart / 512 /* DrvParms.BytesPerSector*/);
604
605 /* Create partition device (Partition 0) */
606 sprintf(NameBuffer2,
607 "\\Device\\Harddisk%lu\\Partition%lu",
608 DiskNumber,
609 PartitionNumber + 1);
610
611 Status = ScsiClassCreateDeviceObject(DriverObject,
612 NameBuffer2,
613 DiskDeviceObject,
614 &PartitionDeviceObject,
615 InitializationData);
616 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
617 if (NT_SUCCESS(Status))
618 {
619 PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
620 PartitionDeviceObject->Characteristics = DiskDeviceObject->Characteristics;
621 PartitionDeviceObject->StackSize = DiskDeviceObject->StackSize;
622 PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
623
624 PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
625 PartitionDeviceExtension->LockCount = 0;
626 PartitionDeviceExtension->DeviceNumber = DiskNumber;
627 PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
628 PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
629 PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
630
631 /* FIXME: Not yet! Will cause pointer corruption! */
632 // PartitionDeviceExtension->PortCapabilities = PortCapabilities;
633
634 PartitionDeviceExtension->StartingOffset.QuadPart =
635 PartitionEntry->StartingOffset.QuadPart;
636 PartitionDeviceExtension->PartitionLength.QuadPart =
637 PartitionEntry->PartitionLength.QuadPart;
638 PartitionDeviceExtension->PortNumber = (UCHAR)PortNumber;
639 PartitionDeviceExtension->PathId = InquiryData->PathId;
640 PartitionDeviceExtension->TargetId = InquiryData->TargetId;
641 PartitionDeviceExtension->Lun = InquiryData->Lun;
642
643 DiskData = (PDISK_DATA)(PartitionDeviceExtension + 1);
644 DiskData->PartitionType = PartitionEntry->PartitionType;
645 DiskData->PartitionNumber = PartitionNumber + 1;
646 DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
647 DiskData->BootIndicator = PartitionEntry->BootIndicator;
648 DiskData->DriveNotReady = FALSE;
649
650
651 /* assign arc name */
652 RtlInitAnsiString(&DeviceNameA,
653 NameBuffer2);
654 RtlAnsiStringToUnicodeString(&DeviceName,
655 &DeviceNameA,
656 TRUE);
657 swprintf(ArcNameBuffer,
658 L"\\ArcName\\multi(0)disk(0)rdisk(%lu)partition(%lu)",
659 DiskNumber,
660 PartitionNumber + 1);
661 RtlInitUnicodeString(&ArcName,
662 ArcNameBuffer);
663 DPRINT("ArcNameBuffer '%S'\n", ArcNameBuffer);
664 DPRINT("%wZ ==> %wZ\n", &ArcName, &DeviceName);
665 Status = IoAssignArcName(&ArcName,
666 &DeviceName);
667 RtlFreeUnicodeString(&DeviceName);
668
669 if (!NT_SUCCESS(Status))
670 {
671 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName, Status);
672 KeBugCheck(0);
673 }
674
675 }
676 else
677 {
678 DPRINT1("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
679
680 break;
681 }
682 }
683
684
685 }
686
687 if (PartitionList != NULL)
688 ExFreePool(PartitionList);
689
690 DPRINT("DiskClassCreateDeviceObjects() done\n");
691
692 return(STATUS_SUCCESS);
693 }
694
695
696
697
698
699 // DiskClassDeviceControl
700 //
701 // DESCRIPTION:
702 // Answer requests for device control calls
703 //
704 // RUN LEVEL:
705 // PASSIVE_LEVEL
706 //
707 // ARGUMENTS:
708 // Standard dispatch arguments
709 //
710 // RETURNS:
711 // NTSTATUS
712 //
713
714 NTSTATUS STDCALL
715 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
716 IN PIRP Irp)
717 {
718 PDEVICE_EXTENSION DeviceExtension;
719 PIO_STACK_LOCATION IrpStack;
720 ULONG ControlCode, InputLength, OutputLength;
721 PDISK_DATA DiskData;
722 ULONG Information;
723 NTSTATUS Status;
724
725 DPRINT("DiskClassDeviceControl() called!\n");
726
727 Status = STATUS_INVALID_DEVICE_REQUEST;
728 Information = 0;
729 IrpStack = IoGetCurrentIrpStackLocation(Irp);
730 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
731 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
732 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
733 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
734 DiskData = (PDISK_DATA)(DeviceExtension + 1);
735
736 /* A huge switch statement in a Windows program?! who would have thought? */
737 switch (ControlCode)
738 {
739 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
740 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
741 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
742 {
743 Status = STATUS_INVALID_PARAMETER;
744 }
745 else if (DeviceExtension->DiskGeometry == NULL)
746 {
747 DPRINT1("No disk geometry available!\n");
748 Status = STATUS_NO_SUCH_DEVICE;
749 }
750 else
751 {
752 PDISK_GEOMETRY Geometry;
753
754 Geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
755 RtlMoveMemory(Geometry,
756 DeviceExtension->DiskGeometry,
757 sizeof(DISK_GEOMETRY));
758
759 Status = STATUS_SUCCESS;
760 Information = sizeof(DISK_GEOMETRY);
761 }
762 break;
763
764 case IOCTL_DISK_GET_PARTITION_INFO:
765 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
766 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
767 sizeof(PARTITION_INFORMATION))
768 {
769 Status = STATUS_INFO_LENGTH_MISMATCH;
770 }
771 else if (DiskData->PartitionNumber == 0)
772 {
773 Status = STATUS_INVALID_DEVICE_REQUEST;
774 }
775 else
776 {
777 PPARTITION_INFORMATION PartitionInfo;
778
779 PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
780
781 PartitionInfo->PartitionType = DiskData->PartitionType;
782 PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
783 PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
784 PartitionInfo->HiddenSectors = DiskData->HiddenSectors;
785 PartitionInfo->PartitionNumber = DiskData->PartitionNumber;
786 PartitionInfo->BootIndicator = DiskData->BootIndicator;
787 PartitionInfo->RewritePartition = FALSE;
788 PartitionInfo->RecognizedPartition =
789 IsRecognizedPartition(DiskData->PartitionType);
790
791 Status = STATUS_SUCCESS;
792 Information = sizeof(PARTITION_INFORMATION);
793 }
794 break;
795
796 case IOCTL_DISK_SET_PARTITION_INFO:
797 DPRINT1("Unhandled IOCTL_DISK_SET_PARTITION_INFO\n");
798 break;
799
800 case IOCTL_DISK_GET_DRIVE_LAYOUT:
801 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
802 sizeof(DRIVE_LAYOUT_INFORMATION))
803 {
804 Status = STATUS_BUFFER_TOO_SMALL;
805 }
806 else
807 {
808 PDRIVE_LAYOUT_INFORMATION PartitionList;
809
810 Status = IoReadPartitionTable(DeviceExtension->PhysicalDevice,
811 DeviceExtension->DiskGeometry->BytesPerSector,
812 FALSE,
813 &PartitionList);
814 if (NT_SUCCESS(Status))
815 {
816 ULONG BufferSize;
817
818 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
819 PartitionEntry[0]);
820 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
821
822 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
823 {
824 Status = STATUS_BUFFER_TOO_SMALL;
825 }
826 else
827 {
828 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
829 PartitionList,
830 BufferSize);
831 Status = STATUS_SUCCESS;
832 Information = BufferSize;
833 }
834 ExFreePool(PartitionList);
835 }
836 }
837 break;
838
839 case IOCTL_DISK_SET_DRIVE_LAYOUT:
840 case IOCTL_DISK_VERIFY:
841 case IOCTL_DISK_FORMAT_TRACKS:
842 case IOCTL_DISK_PERFORMANCE:
843 case IOCTL_DISK_IS_WRITABLE:
844 case IOCTL_DISK_LOGGING:
845 case IOCTL_DISK_FORMAT_TRACKS_EX:
846 case IOCTL_DISK_HISTOGRAM_STRUCTURE:
847 case IOCTL_DISK_HISTOGRAM_DATA:
848 case IOCTL_DISK_HISTOGRAM_RESET:
849 case IOCTL_DISK_REQUEST_STRUCTURE:
850 case IOCTL_DISK_REQUEST_DATA:
851
852 /* If we get here, something went wrong. inform the requestor */
853 default:
854 DPRINT1("Unhandled control code: %lx\n", ControlCode);
855 Status = STATUS_INVALID_DEVICE_REQUEST;
856 Information = 0;
857 break;
858 }
859
860 Irp->IoStatus.Status = Status;
861 Irp->IoStatus.Information = Information;
862 IoCompleteRequest(Irp,
863 IO_NO_INCREMENT);
864
865 return(Status);
866 }
867
868
869 // DiskClassShutdownFlush
870 //
871 // DESCRIPTION:
872 // Answer requests for shutdown and flush calls
873 //
874 // RUN LEVEL:
875 // PASSIVE_LEVEL
876 //
877 // ARGUMENTS:
878 // Standard dispatch arguments
879 //
880 // RETURNS:
881 // NTSTATUS
882 //
883
884 NTSTATUS STDCALL
885 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
886 IN PIRP Irp)
887 {
888 DPRINT("DiskClassShutdownFlush() called!\n");
889
890 Irp->IoStatus.Status = STATUS_SUCCESS;
891 Irp->IoStatus.Information = 0;
892 IoCompleteRequest(Irp, IO_NO_INCREMENT);
893
894 return(STATUS_SUCCESS);
895 }
896
897
898 /* EOF */