Relative include path fixed to absolute path.
[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.19 2002/09/19 16:18:14 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 #include <ddk/scsi.h>
32 #include <ddk/class2.h>
33 #include <ddk/ntddscsi.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 #define VERSION "0.0.1"
39
40
41 typedef struct _DISK_DATA
42 {
43 ULONG HiddenSectors;
44 ULONG PartitionNumber;
45 ULONG PartitionOrdinal;
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 DPRINT("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("PortCapabilities: %p\n", PortCapabilities);
204 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
205 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
206
207 /* Get inquiry data */
208 Status = ScsiClassGetInquiryData(PortDeviceObject,
209 (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
210 if (!NT_SUCCESS(Status))
211 {
212 DPRINT("ScsiClassGetInquiryData() failed! (Status %x)\n", Status);
213 return(FALSE);
214 }
215
216 /* Check whether there are unclaimed devices */
217 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
218 DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
219 AdapterBusInfo);
220 if (DeviceCount == 0)
221 {
222 DPRINT("No unclaimed devices!\n");
223 return(FALSE);
224 }
225
226 DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
227
228 ConfigInfo = IoGetConfigurationInformation();
229
230 /* Search each bus of this adapter */
231 for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
232 {
233 DPRINT("Searching bus %lu\n", Bus);
234
235 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
236
237 while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
238 {
239 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
240
241 if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
242 (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
243 (InquiryData->DeviceTypeQualifier == 0) &&
244 (UnitInfo->DeviceClaimed == FALSE))
245 {
246 DPRINT("Vendor: '%.24s'\n",
247 InquiryData->VendorId);
248
249 /* Create device objects for disk */
250 Status = DiskClassCreateDeviceObject(DriverObject,
251 RegistryPath,
252 PortDeviceObject,
253 PortNumber,
254 ConfigInfo->DiskCount,
255 PortCapabilities,
256 UnitInfo,
257 InitializationData);
258 if (NT_SUCCESS(Status))
259 {
260 ConfigInfo->DiskCount++;
261 FoundDevice = TRUE;
262 }
263 }
264
265 if (UnitInfo->NextInquiryDataOffset == 0)
266 break;
267
268 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
269 }
270 }
271
272 ExFreePool(Buffer);
273
274 DPRINT("DiskClassFindDevices() done\n");
275
276 return(FoundDevice);
277 }
278
279
280 /**********************************************************************
281 * NAME EXPORTED
282 * DiskClassCheckDevice
283 *
284 * DESCRIPTION
285 * This function checks the InquiryData for the correct device
286 * type and qualifier.
287 *
288 * RUN LEVEL
289 * PASSIVE_LEVEL
290 *
291 * ARGUMENTS
292 * InquiryData
293 * Pointer to the inquiry data for the device in question.
294 *
295 * RETURN VALUE
296 * TRUE: A disk device was found.
297 * FALSE: Otherwise.
298 */
299
300 BOOLEAN STDCALL
301 DiskClassCheckDevice(IN PINQUIRYDATA InquiryData)
302 {
303 return((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE ||
304 InquiryData->DeviceType == OPTICAL_DEVICE) &&
305 InquiryData->DeviceTypeQualifier == 0);
306 }
307
308
309 /**********************************************************************
310 * NAME EXPORTED
311 * DiskClassCheckReadWrite
312 *
313 * DESCRIPTION
314 * This function checks the given IRP for correct data.
315 *
316 * RUN LEVEL
317 * PASSIVE_LEVEL
318 *
319 * ARGUMENTS
320 * DeviceObject
321 * Pointer to the device.
322 *
323 * Irp
324 * Irp to check.
325 *
326 * RETURN VALUE
327 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
328 * Others: Failure.
329 */
330
331 NTSTATUS STDCALL
332 DiskClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
333 IN PIRP Irp)
334 {
335 PDEVICE_EXTENSION DeviceExtension;
336 PDISK_DATA DiskData;
337
338 DPRINT("DiskClassCheckReadWrite() called\n");
339
340 DeviceExtension = DeviceObject->DeviceExtension;
341 DiskData = (PDISK_DATA)(DeviceExtension + 1);
342
343 if (DiskData->DriveNotReady == TRUE)
344 {
345 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
346 IoSetHardErrorOrVerifyDevice(Irp,
347 DeviceObject);
348 return(STATUS_INVALID_PARAMETER);
349 }
350
351 return(STATUS_SUCCESS);
352 }
353
354
355 /**********************************************************************
356 * NAME EXPORTED
357 * DiskClassCreateDeviceObject
358 *
359 * DESCRIPTION
360 * Create the raw device and any partition devices on this drive
361 *
362 * RUN LEVEL
363 * PASSIVE_LEVEL
364 *
365 * ARGUMENTS
366 * DriverObject
367 * The system created driver object
368 * RegistryPath
369 * PortDeviceObject
370 * PortNumber
371 * DiskNumber
372 * Capabilities
373 * InquiryData
374 * InitialzationData
375 *
376 * RETURN VALUE
377 * STATUS_SUCCESS: Device objects for disk and partitions were created.
378 * Others: Failure.
379 */
380
381 static NTSTATUS
382 DiskClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
383 IN PUNICODE_STRING RegistryPath, /* what's this used for? */
384 IN PDEVICE_OBJECT PortDeviceObject,
385 IN ULONG PortNumber,
386 IN ULONG DiskNumber,
387 IN PIO_SCSI_CAPABILITIES Capabilities,
388 IN PSCSI_INQUIRY_DATA InquiryData,
389 IN PCLASS_INIT_DATA InitializationData)
390 {
391 OBJECT_ATTRIBUTES ObjectAttributes;
392 UNICODE_STRING UnicodeDeviceDirName;
393 WCHAR NameBuffer[80];
394 CHAR NameBuffer2[80];
395 PDEVICE_OBJECT DiskDeviceObject;
396 PDEVICE_OBJECT PartitionDeviceObject;
397 PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
398 PDEVICE_EXTENSION PartitionDeviceExtension; /* defined in class2.h */
399 PDRIVE_LAYOUT_INFORMATION PartitionList = NULL;
400 HANDLE Handle;
401 PPARTITION_INFORMATION PartitionEntry;
402 PDISK_DATA DiskData;
403 ULONG PartitionNumber;
404 NTSTATUS Status;
405
406 DPRINT("DiskClassCreateDeviceObject() called\n");
407
408 /* Create the harddisk device directory */
409 swprintf(NameBuffer,
410 L"\\Device\\Harddisk%lu",
411 DiskNumber);
412 RtlInitUnicodeString(&UnicodeDeviceDirName,
413 NameBuffer);
414 InitializeObjectAttributes(&ObjectAttributes,
415 &UnicodeDeviceDirName,
416 0,
417 NULL,
418 NULL);
419 Status = ZwCreateDirectoryObject(&Handle,
420 0,
421 &ObjectAttributes);
422 if (!NT_SUCCESS(Status))
423 {
424 DbgPrint("Could not create device dir object\n");
425 return(Status);
426 }
427
428 /* Claim the disk device */
429 Status = ScsiClassClaimDevice(PortDeviceObject,
430 InquiryData,
431 FALSE,
432 &PortDeviceObject);
433 if (!NT_SUCCESS(Status))
434 {
435 DbgPrint("Could not claim disk device\n");
436
437 ZwMakeTemporaryObject(Handle);
438 ZwClose(Handle);
439
440 return(Status);
441 }
442
443 /* Create disk device (Partition 0) */
444 sprintf(NameBuffer2,
445 "\\Device\\Harddisk%lu\\Partition0",
446 DiskNumber);
447
448 Status = ScsiClassCreateDeviceObject(DriverObject,
449 NameBuffer2,
450 NULL,
451 &DiskDeviceObject,
452 InitializationData);
453 if (!NT_SUCCESS(Status))
454 {
455 DPRINT("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
456
457 /* Release (unclaim) the disk */
458 ScsiClassClaimDevice(PortDeviceObject,
459 InquiryData,
460 TRUE,
461 NULL);
462
463 /* Delete the harddisk device directory */
464 ZwMakeTemporaryObject(Handle);
465 ZwClose(Handle);
466
467 return(Status);
468 }
469
470 DiskDeviceObject->Flags |= DO_DIRECT_IO;
471 if (((PINQUIRYDATA)InquiryData->InquiryData)->RemovableMedia)
472 {
473 DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
474 }
475 DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
476
477 if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
478 {
479 DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
480 }
481
482 DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
483 DiskDeviceExtension->LockCount = 0;
484 DiskDeviceExtension->DeviceNumber = DiskNumber;
485 DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
486 DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
487 DiskDeviceExtension->PortCapabilities = Capabilities;
488 DiskDeviceExtension->StartingOffset.QuadPart = 0;
489 DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
490 DiskDeviceExtension->PathId = InquiryData->PathId;
491 DiskDeviceExtension->TargetId = InquiryData->TargetId;
492 DiskDeviceExtension->Lun = InquiryData->Lun;
493
494 /* zero-out disk data */
495 DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
496 RtlZeroMemory(DiskData,
497 sizeof(DISK_DATA));
498
499 /* Get disk geometry */
500 DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
501 sizeof(DISK_GEOMETRY));
502 if (DiskDeviceExtension->DiskGeometry == NULL)
503 {
504 DPRINT("Failed to allocate geometry buffer!\n");
505
506 IoDeleteDevice(DiskDeviceObject);
507
508 /* Release (unclaim) the disk */
509 ScsiClassClaimDevice(PortDeviceObject,
510 InquiryData,
511 TRUE,
512 NULL);
513
514 /* Delete the harddisk device directory */
515 ZwMakeTemporaryObject(Handle);
516 ZwClose(Handle);
517
518 return(STATUS_INSUFFICIENT_RESOURCES);
519 }
520
521 /* Read the drive's capacity */
522 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
523 if (!NT_SUCCESS(Status) &&
524 (DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
525 {
526 DPRINT1("Failed to retrieve drive capacity!\n");
527 return(STATUS_SUCCESS);
528 }
529 else
530 {
531 /* Clear the verify flag for removable media drives. */
532 DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
533 }
534
535 DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
536
537 if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
538 (DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
539 {
540 /* Allocate a partition list for a single entry. */
541 PartitionList = ExAllocatePool(NonPagedPool,
542 sizeof(DRIVE_LAYOUT_INFORMATION));
543 if (PartitionList != NULL)
544 {
545 RtlZeroMemory(PartitionList,
546 sizeof(DRIVE_LAYOUT_INFORMATION));
547 PartitionList->PartitionCount = 1;
548
549 DiskData->DriveNotReady = TRUE;
550 Status = STATUS_SUCCESS;
551 }
552 }
553 else
554 {
555 /* Read partition table */
556 Status = IoReadPartitionTable(DiskDeviceObject,
557 DiskDeviceExtension->DiskGeometry->BytesPerSector,
558 TRUE,
559 &PartitionList);
560
561 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
562
563 if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
564 DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
565 {
566 if (!NT_SUCCESS(Status))
567 {
568 /* Drive is not ready. */
569 DPRINT("Drive not ready\n");
570 DiskData->DriveNotReady = TRUE;
571 }
572 else
573 {
574 ExFreePool(PartitionList);
575 }
576
577 /* Allocate a partition list for a single entry. */
578 PartitionList = ExAllocatePool(NonPagedPool,
579 sizeof(DRIVE_LAYOUT_INFORMATION));
580 if (PartitionList != NULL)
581 {
582 RtlZeroMemory(PartitionList,
583 sizeof(DRIVE_LAYOUT_INFORMATION));
584 PartitionList->PartitionCount = 1;
585
586 Status = STATUS_SUCCESS;
587 }
588 }
589 }
590
591 if (NT_SUCCESS(Status))
592 {
593 DPRINT("Read partition table!\n");
594
595 DPRINT(" Number of partitions: %u\n", PartitionList->PartitionCount);
596
597 for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
598 {
599 PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
600
601 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
602 PartitionNumber,
603 PartitionEntry->PartitionNumber,
604 PartitionEntry->BootIndicator,
605 PartitionEntry->PartitionType,
606 PartitionEntry->StartingOffset.QuadPart / 512 /*DrvParms.BytesPerSector*/,
607 PartitionEntry->PartitionLength.QuadPart / 512 /* DrvParms.BytesPerSector*/);
608
609 /* Create partition device object */
610 sprintf(NameBuffer2,
611 "\\Device\\Harddisk%lu\\Partition%lu",
612 DiskNumber,
613 PartitionNumber + 1);
614
615 Status = ScsiClassCreateDeviceObject(DriverObject,
616 NameBuffer2,
617 DiskDeviceObject,
618 &PartitionDeviceObject,
619 InitializationData);
620 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
621 if (NT_SUCCESS(Status))
622 {
623 PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
624 PartitionDeviceObject->Characteristics = DiskDeviceObject->Characteristics;
625 PartitionDeviceObject->StackSize = DiskDeviceObject->StackSize;
626 PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
627
628 PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
629 PartitionDeviceExtension->LockCount = 0;
630 PartitionDeviceExtension->DeviceNumber = DiskNumber;
631 PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
632 PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
633 PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
634 PartitionDeviceExtension->PortCapabilities = Capabilities;
635 PartitionDeviceExtension->StartingOffset.QuadPart =
636 PartitionEntry->StartingOffset.QuadPart;
637 PartitionDeviceExtension->PartitionLength.QuadPart =
638 PartitionEntry->PartitionLength.QuadPart;
639 PartitionDeviceExtension->PortNumber = (UCHAR)PortNumber;
640 PartitionDeviceExtension->PathId = InquiryData->PathId;
641 PartitionDeviceExtension->TargetId = InquiryData->TargetId;
642 PartitionDeviceExtension->Lun = InquiryData->Lun;
643 PartitionDeviceExtension->SectorShift = DiskDeviceExtension->SectorShift;
644
645 DiskData = (PDISK_DATA)(PartitionDeviceExtension + 1);
646 DiskData->PartitionType = PartitionEntry->PartitionType;
647 DiskData->PartitionNumber = PartitionNumber + 1;
648 DiskData->PartitionOrdinal = PartitionNumber + 1;
649 DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
650 DiskData->BootIndicator = PartitionEntry->BootIndicator;
651 DiskData->DriveNotReady = FALSE;
652 }
653 else
654 {
655 DPRINT1("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
656
657 break;
658 }
659 }
660 }
661
662 if (PartitionList != NULL)
663 ExFreePool(PartitionList);
664
665 DPRINT("DiskClassCreateDeviceObjects() done\n");
666
667 return(STATUS_SUCCESS);
668 }
669
670
671 /**********************************************************************
672 * NAME EXPORTED
673 * DiskClassDeviceControl
674 *
675 * DESCRIPTION
676 * Answer requests for device control calls
677 *
678 * RUN LEVEL
679 * PASSIVE_LEVEL
680 *
681 * ARGUMENTS
682 * Standard dispatch arguments
683 *
684 * RETURNS
685 * Status
686 */
687
688 NTSTATUS STDCALL
689 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
690 IN PIRP Irp)
691 {
692 PDEVICE_EXTENSION DeviceExtension;
693 PIO_STACK_LOCATION IrpStack;
694 ULONG ControlCode, InputLength, OutputLength;
695 PDISK_DATA DiskData;
696 ULONG Information;
697 NTSTATUS Status;
698
699 DPRINT("DiskClassDeviceControl() called!\n");
700
701 Status = STATUS_INVALID_DEVICE_REQUEST;
702 Information = 0;
703 IrpStack = IoGetCurrentIrpStackLocation(Irp);
704 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
705 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
706 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
707 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
708 DiskData = (PDISK_DATA)(DeviceExtension + 1);
709
710 switch (ControlCode)
711 {
712 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
713 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
714 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
715 {
716 Status = STATUS_INVALID_PARAMETER;
717 }
718 else
719 {
720 PDISK_GEOMETRY Geometry;
721
722 if (DeviceExtension->DiskGeometry == NULL)
723 {
724 DPRINT("No disk geometry available!\n");
725 DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
726 sizeof(DISK_GEOMETRY));
727 }
728 Status = ScsiClassReadDriveCapacity(DeviceObject);
729 DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status);
730 if (NT_SUCCESS(Status))
731 {
732 Geometry = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
733 RtlMoveMemory(Geometry,
734 DeviceExtension->DiskGeometry,
735 sizeof(DISK_GEOMETRY));
736
737 Status = STATUS_SUCCESS;
738 Information = sizeof(DISK_GEOMETRY);
739 }
740 }
741 break;
742
743 case IOCTL_DISK_GET_PARTITION_INFO:
744 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
745 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
746 sizeof(PARTITION_INFORMATION))
747 {
748 Status = STATUS_INFO_LENGTH_MISMATCH;
749 }
750 else if (DiskData->PartitionNumber == 0)
751 {
752 Status = STATUS_INVALID_DEVICE_REQUEST;
753 }
754 else
755 {
756 PPARTITION_INFORMATION PartitionInfo;
757
758 PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
759
760 PartitionInfo->PartitionType = DiskData->PartitionType;
761 PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
762 PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
763 PartitionInfo->HiddenSectors = DiskData->HiddenSectors;
764 PartitionInfo->PartitionNumber = DiskData->PartitionNumber;
765 PartitionInfo->BootIndicator = DiskData->BootIndicator;
766 PartitionInfo->RewritePartition = FALSE;
767 PartitionInfo->RecognizedPartition =
768 IsRecognizedPartition(DiskData->PartitionType);
769
770 Status = STATUS_SUCCESS;
771 Information = sizeof(PARTITION_INFORMATION);
772 }
773 break;
774
775 case IOCTL_DISK_SET_PARTITION_INFO:
776 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
777 sizeof(SET_PARTITION_INFORMATION))
778 {
779 Status = STATUS_INFO_LENGTH_MISMATCH;
780 }
781 else if (DiskData->PartitionNumber == 0)
782 {
783 Status = STATUS_INVALID_DEVICE_REQUEST;
784 }
785 else
786 {
787 PSET_PARTITION_INFORMATION PartitionInfo;
788
789 PartitionInfo = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
790
791 Status = IoSetPartitionInformation(DeviceExtension->PhysicalDevice,
792 DeviceExtension->DiskGeometry->BytesPerSector,
793 DiskData->PartitionOrdinal,
794 PartitionInfo->PartitionType);
795 if (NT_SUCCESS(Status))
796 {
797 DiskData->PartitionType = PartitionInfo->PartitionType;
798 }
799 }
800 break;
801
802 case IOCTL_DISK_GET_DRIVE_LAYOUT:
803 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
804 sizeof(DRIVE_LAYOUT_INFORMATION))
805 {
806 Status = STATUS_BUFFER_TOO_SMALL;
807 }
808 else
809 {
810 PDRIVE_LAYOUT_INFORMATION PartitionList;
811
812 Status = IoReadPartitionTable(DeviceExtension->PhysicalDevice,
813 DeviceExtension->DiskGeometry->BytesPerSector,
814 FALSE,
815 &PartitionList);
816 if (NT_SUCCESS(Status))
817 {
818 ULONG BufferSize;
819
820 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
821 PartitionEntry[0]);
822 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
823
824 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
825 {
826 Status = STATUS_BUFFER_TOO_SMALL;
827 }
828 else
829 {
830 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
831 PartitionList,
832 BufferSize);
833 Status = STATUS_SUCCESS;
834 Information = BufferSize;
835 }
836 ExFreePool(PartitionList);
837 }
838 }
839 break;
840
841 case IOCTL_DISK_SET_DRIVE_LAYOUT:
842 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
843 sizeof(DRIVE_LAYOUT_INFORMATION))
844 {
845 Status = STATUS_INFO_LENGTH_MISMATCH;
846 }
847 else if (DeviceExtension->PhysicalDevice->DeviceExtension != DeviceExtension)
848 {
849 Status = STATUS_INVALID_PARAMETER;
850 }
851 else
852 {
853 PDRIVE_LAYOUT_INFORMATION PartitionList;
854 ULONG TableSize;
855
856 PartitionList = Irp->AssociatedIrp.SystemBuffer;
857 TableSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
858 ((PartitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
859
860 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < TableSize)
861 {
862 Status = STATUS_BUFFER_TOO_SMALL;
863 }
864 else
865 {
866 Status = IoWritePartitionTable(DeviceExtension->DeviceObject,
867 DeviceExtension->DiskGeometry->BytesPerSector,
868 DeviceExtension->DiskGeometry->SectorsPerTrack,
869 DeviceExtension->DiskGeometry->TracksPerCylinder,
870 PartitionList);
871 if (NT_SUCCESS(Status))
872 {
873 /* FIXME: Update partition device objects */
874
875 Information = TableSize;
876 }
877 }
878 }
879 break;
880
881 case IOCTL_DISK_VERIFY:
882 case IOCTL_DISK_FORMAT_TRACKS:
883 case IOCTL_DISK_PERFORMANCE:
884 case IOCTL_DISK_IS_WRITABLE:
885 case IOCTL_DISK_LOGGING:
886 case IOCTL_DISK_FORMAT_TRACKS_EX:
887 case IOCTL_DISK_HISTOGRAM_STRUCTURE:
888 case IOCTL_DISK_HISTOGRAM_DATA:
889 case IOCTL_DISK_HISTOGRAM_RESET:
890 case IOCTL_DISK_REQUEST_STRUCTURE:
891 case IOCTL_DISK_REQUEST_DATA:
892 /* If we get here, something went wrong. Inform the requestor */
893 DPRINT1("Unhandled control code: %lx\n", ControlCode);
894 Status = STATUS_INVALID_DEVICE_REQUEST;
895 Information = 0;
896 break;
897
898 default:
899 /* Call the common device control function */
900 return(ScsiClassDeviceControl(DeviceObject, Irp));
901 }
902
903 /* Verify the device if the user caused the error */
904 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
905 {
906 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
907 }
908
909 Irp->IoStatus.Status = Status;
910 Irp->IoStatus.Information = Information;
911 IoCompleteRequest(Irp,
912 IO_NO_INCREMENT);
913
914 return(Status);
915 }
916
917
918 /**********************************************************************
919 * NAME EXPORTED
920 * DiskClassShutdownFlush
921 *
922 * DESCRIPTION
923 * Answer requests for shutdown and flush calls.
924 *
925 * RUN LEVEL
926 * PASSIVE_LEVEL
927 *
928 * ARGUMENTS
929 * DeviceObject
930 * Pointer to the device.
931 *
932 * Irp
933 * Pointer to the IRP
934 *
935 * RETURN VALUE
936 * Status
937 */
938
939 NTSTATUS STDCALL
940 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
941 IN PIRP Irp)
942 {
943 PDEVICE_EXTENSION DeviceExtension;
944 PIO_STACK_LOCATION IrpStack;
945 PSCSI_REQUEST_BLOCK Srb;
946
947 DPRINT("DiskClassShutdownFlush() called!\n");
948
949 DeviceExtension = DeviceObject->DeviceExtension;
950
951 /* Allocate SRB */
952 Srb = ExAllocatePool(NonPagedPool,
953 sizeof(SCSI_REQUEST_BLOCK));
954 if (Srb == NULL)
955 {
956 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
957 Irp->IoStatus.Information = 0;
958 IoCompleteRequest(Irp, IO_NO_INCREMENT);
959
960 return(STATUS_INSUFFICIENT_RESOURCES);
961 }
962
963 /* Initialize SRB */
964 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
965 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
966
967 /* Set device IDs */
968 Srb->PathId = DeviceExtension->PathId;
969 Srb->TargetId = DeviceExtension->TargetId;
970 Srb->Lun = DeviceExtension->Lun;
971
972
973 /* FIXME: Flush write cache */
974
975
976 /* Get current stack location */
977 IrpStack = IoGetCurrentIrpStackLocation(Irp);
978
979
980 /* FIXME: Unlock removable media upon shutdown */
981
982
983 /* No retry */
984 IrpStack->Parameters.Others.Argument4 = (PVOID)0;
985
986 /* Send shutdown or flush request to the port driver */
987 Srb->CdbLength = 0;
988 if (IrpStack->MajorFunction == IRP_MJ_SHUTDOWN)
989 Srb->Function = SRB_FUNCTION_SHUTDOWN;
990 else
991 Srb->Function = SRB_FUNCTION_FLUSH;
992
993 /* Init completion routine */
994 IoSetCompletionRoutine(Irp,
995 ScsiClassIoComplete,
996 Srb,
997 TRUE,
998 TRUE,
999 TRUE);
1000
1001 /* Prepare next stack location for a call to the port driver */
1002 IrpStack = IoGetNextIrpStackLocation(Irp);
1003 IrpStack->MajorFunction = IRP_MJ_SCSI;
1004 IrpStack->Parameters.Scsi.Srb = Srb;
1005 Srb->OriginalRequest = Irp;
1006
1007 /* Call port driver */
1008 return(IoCallDriver(DeviceExtension->PortDeviceObject, Irp));
1009 }
1010
1011 /* EOF */