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