Detect disk manager software.
[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.22 2003/02/26 16:25:40 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 PVOID MbrBuffer;
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 /* Initialize the lookaside list for SRBs */
496 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
497 4);
498
499 /* zero-out disk data */
500 DiskData = (PDISK_DATA)(DiskDeviceExtension + 1);
501 RtlZeroMemory(DiskData,
502 sizeof(DISK_DATA));
503
504 /* Get disk geometry */
505 DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
506 sizeof(DISK_GEOMETRY));
507 if (DiskDeviceExtension->DiskGeometry == NULL)
508 {
509 DPRINT("Failed to allocate geometry buffer!\n");
510
511 ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
512
513 IoDeleteDevice(DiskDeviceObject);
514
515 /* Release (unclaim) the disk */
516 ScsiClassClaimDevice(PortDeviceObject,
517 InquiryData,
518 TRUE,
519 NULL);
520
521 /* Delete the harddisk device directory */
522 ZwMakeTemporaryObject(Handle);
523 ZwClose(Handle);
524
525 return(STATUS_INSUFFICIENT_RESOURCES);
526 }
527
528 /* Read the drive's capacity */
529 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
530 if (!NT_SUCCESS(Status) &&
531 (DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) == 0)
532 {
533 DPRINT1("Failed to retrieve drive capacity!\n");
534 return(STATUS_SUCCESS);
535 }
536 else
537 {
538 /* Clear the verify flag for removable media drives. */
539 DiskDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
540 }
541
542 DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
543
544 /* Check disk for presence of a disk manager */
545 HalExamineMBR(DiskDeviceObject,
546 DiskDeviceExtension->DiskGeometry->BytesPerSector,
547 0x54,
548 &MbrBuffer);
549 if (MbrBuffer != NULL)
550 {
551 DPRINT1("Found 'Ontrack Disk Manager'!\n");
552 KeBugCheck(0);
553
554 ExFreePool(MbrBuffer);
555 MbrBuffer = NULL;
556 }
557
558 HalExamineMBR(DiskDeviceObject,
559 DiskDeviceExtension->DiskGeometry->BytesPerSector,
560 0x55,
561 &MbrBuffer);
562 if (MbrBuffer != NULL)
563 {
564 DPRINT1("Found 'EZ-Drive' disk manager!\n");
565 KeBugCheck(0);
566
567 ExFreePool(MbrBuffer);
568 MbrBuffer = NULL;
569 }
570
571
572 if ((DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
573 (DiskDeviceExtension->DiskGeometry->MediaType == RemovableMedia))
574 {
575 /* Allocate a partition list for a single entry. */
576 PartitionList = ExAllocatePool(NonPagedPool,
577 sizeof(DRIVE_LAYOUT_INFORMATION));
578 if (PartitionList != NULL)
579 {
580 RtlZeroMemory(PartitionList,
581 sizeof(DRIVE_LAYOUT_INFORMATION));
582 PartitionList->PartitionCount = 1;
583
584 DiskData->DriveNotReady = TRUE;
585 Status = STATUS_SUCCESS;
586 }
587 }
588 else
589 {
590 /* Read partition table */
591 Status = IoReadPartitionTable(DiskDeviceObject,
592 DiskDeviceExtension->DiskGeometry->BytesPerSector,
593 TRUE,
594 &PartitionList);
595
596 DPRINT("IoReadPartitionTable(): Status: %lx\n", Status);
597
598 if ((!NT_SUCCESS(Status) || PartitionList->PartitionCount == 0) &&
599 DiskDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
600 {
601 if (!NT_SUCCESS(Status))
602 {
603 /* Drive is not ready. */
604 DPRINT("Drive not ready\n");
605 DiskData->DriveNotReady = TRUE;
606 }
607 else
608 {
609 ExFreePool(PartitionList);
610 }
611
612 /* Allocate a partition list for a single entry. */
613 PartitionList = ExAllocatePool(NonPagedPool,
614 sizeof(DRIVE_LAYOUT_INFORMATION));
615 if (PartitionList != NULL)
616 {
617 RtlZeroMemory(PartitionList,
618 sizeof(DRIVE_LAYOUT_INFORMATION));
619 PartitionList->PartitionCount = 1;
620
621 Status = STATUS_SUCCESS;
622 }
623 }
624 }
625
626 if (NT_SUCCESS(Status))
627 {
628 DPRINT("Read partition table!\n");
629
630 DPRINT(" Number of partitions: %u\n", PartitionList->PartitionCount);
631
632 for (PartitionNumber = 0; PartitionNumber < PartitionList->PartitionCount; PartitionNumber++)
633 {
634 PartitionEntry = &PartitionList->PartitionEntry[PartitionNumber];
635
636 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
637 PartitionNumber,
638 PartitionEntry->PartitionNumber,
639 PartitionEntry->BootIndicator,
640 PartitionEntry->PartitionType,
641 PartitionEntry->StartingOffset.QuadPart / 512 /*DrvParms.BytesPerSector*/,
642 PartitionEntry->PartitionLength.QuadPart / 512 /* DrvParms.BytesPerSector*/);
643
644 /* Create partition device object */
645 sprintf(NameBuffer2,
646 "\\Device\\Harddisk%lu\\Partition%lu",
647 DiskNumber,
648 PartitionNumber + 1);
649
650 Status = ScsiClassCreateDeviceObject(DriverObject,
651 NameBuffer2,
652 DiskDeviceObject,
653 &PartitionDeviceObject,
654 InitializationData);
655 DPRINT("ScsiClassCreateDeviceObject(): Status %x\n", Status);
656 if (NT_SUCCESS(Status))
657 {
658 PartitionDeviceObject->Flags = DiskDeviceObject->Flags;
659 PartitionDeviceObject->Characteristics = DiskDeviceObject->Characteristics;
660 PartitionDeviceObject->StackSize = DiskDeviceObject->StackSize;
661 PartitionDeviceObject->AlignmentRequirement = DiskDeviceObject->AlignmentRequirement;
662
663 PartitionDeviceExtension = PartitionDeviceObject->DeviceExtension;
664 PartitionDeviceExtension->LockCount = 0;
665 PartitionDeviceExtension->DeviceNumber = DiskNumber;
666 PartitionDeviceExtension->PortDeviceObject = PortDeviceObject;
667 PartitionDeviceExtension->DiskGeometry = DiskDeviceExtension->DiskGeometry;
668 PartitionDeviceExtension->PhysicalDevice = DiskDeviceExtension->PhysicalDevice;
669 PartitionDeviceExtension->PortCapabilities = Capabilities;
670 PartitionDeviceExtension->StartingOffset.QuadPart =
671 PartitionEntry->StartingOffset.QuadPart;
672 PartitionDeviceExtension->PartitionLength.QuadPart =
673 PartitionEntry->PartitionLength.QuadPart;
674 PartitionDeviceExtension->PortNumber = (UCHAR)PortNumber;
675 PartitionDeviceExtension->PathId = InquiryData->PathId;
676 PartitionDeviceExtension->TargetId = InquiryData->TargetId;
677 PartitionDeviceExtension->Lun = InquiryData->Lun;
678 PartitionDeviceExtension->SectorShift = DiskDeviceExtension->SectorShift;
679
680 /* Initialize lookaside list for SRBs */
681 ScsiClassInitializeSrbLookasideList(PartitionDeviceExtension,
682 8);
683
684 DiskData = (PDISK_DATA)(PartitionDeviceExtension + 1);
685 DiskData->PartitionType = PartitionEntry->PartitionType;
686 DiskData->PartitionNumber = PartitionNumber + 1;
687 DiskData->PartitionOrdinal = PartitionNumber + 1;
688 DiskData->HiddenSectors = PartitionEntry->HiddenSectors;
689 DiskData->BootIndicator = PartitionEntry->BootIndicator;
690 DiskData->DriveNotReady = FALSE;
691 }
692 else
693 {
694 DPRINT1("ScsiClassCreateDeviceObject() failed to create partition device object (Status %x)\n", Status);
695
696 break;
697 }
698 }
699 }
700
701 if (PartitionList != NULL)
702 ExFreePool(PartitionList);
703
704 DPRINT("DiskClassCreateDeviceObjects() done\n");
705
706 return(STATUS_SUCCESS);
707 }
708
709
710 /**********************************************************************
711 * NAME EXPORTED
712 * DiskClassDeviceControl
713 *
714 * DESCRIPTION
715 * Answer requests for device control calls
716 *
717 * RUN LEVEL
718 * PASSIVE_LEVEL
719 *
720 * ARGUMENTS
721 * Standard dispatch arguments
722 *
723 * RETURNS
724 * Status
725 */
726
727 NTSTATUS STDCALL
728 DiskClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
729 IN PIRP Irp)
730 {
731 PDEVICE_EXTENSION DeviceExtension;
732 PIO_STACK_LOCATION IrpStack;
733 ULONG ControlCode, InputLength, OutputLength;
734 PDISK_DATA DiskData;
735 ULONG Information;
736 NTSTATUS Status;
737
738 DPRINT("DiskClassDeviceControl() called!\n");
739
740 Status = STATUS_INVALID_DEVICE_REQUEST;
741 Information = 0;
742 IrpStack = IoGetCurrentIrpStackLocation(Irp);
743 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
744 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
745 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
746 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
747 DiskData = (PDISK_DATA)(DeviceExtension + 1);
748
749 switch (ControlCode)
750 {
751 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
752 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY\n");
753 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
754 {
755 Status = STATUS_INVALID_PARAMETER;
756 }
757 else
758 {
759 PDISK_GEOMETRY Geometry;
760
761 if (DeviceExtension->DiskGeometry == NULL)
762 {
763 DPRINT("No disk geometry available!\n");
764 DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
765 sizeof(DISK_GEOMETRY));
766 }
767 Status = ScsiClassReadDriveCapacity(DeviceObject);
768 DPRINT("ScsiClassReadDriveCapacity() returned (Status %lx)\n", Status);
769 if (NT_SUCCESS(Status))
770 {
771 Geometry = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
772 RtlMoveMemory(Geometry,
773 DeviceExtension->DiskGeometry,
774 sizeof(DISK_GEOMETRY));
775
776 Status = STATUS_SUCCESS;
777 Information = sizeof(DISK_GEOMETRY);
778 }
779 }
780 break;
781
782 case IOCTL_DISK_GET_PARTITION_INFO:
783 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
784 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
785 sizeof(PARTITION_INFORMATION))
786 {
787 Status = STATUS_INFO_LENGTH_MISMATCH;
788 }
789 else if (DiskData->PartitionNumber == 0)
790 {
791 Status = STATUS_INVALID_DEVICE_REQUEST;
792 }
793 else
794 {
795 PPARTITION_INFORMATION PartitionInfo;
796
797 PartitionInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
798
799 PartitionInfo->PartitionType = DiskData->PartitionType;
800 PartitionInfo->StartingOffset = DeviceExtension->StartingOffset;
801 PartitionInfo->PartitionLength = DeviceExtension->PartitionLength;
802 PartitionInfo->HiddenSectors = DiskData->HiddenSectors;
803 PartitionInfo->PartitionNumber = DiskData->PartitionNumber;
804 PartitionInfo->BootIndicator = DiskData->BootIndicator;
805 PartitionInfo->RewritePartition = FALSE;
806 PartitionInfo->RecognizedPartition =
807 IsRecognizedPartition(DiskData->PartitionType);
808
809 Status = STATUS_SUCCESS;
810 Information = sizeof(PARTITION_INFORMATION);
811 }
812 break;
813
814 case IOCTL_DISK_SET_PARTITION_INFO:
815 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
816 sizeof(SET_PARTITION_INFORMATION))
817 {
818 Status = STATUS_INFO_LENGTH_MISMATCH;
819 }
820 else if (DiskData->PartitionNumber == 0)
821 {
822 Status = STATUS_INVALID_DEVICE_REQUEST;
823 }
824 else
825 {
826 PSET_PARTITION_INFORMATION PartitionInfo;
827
828 PartitionInfo = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
829
830 Status = IoSetPartitionInformation(DeviceExtension->PhysicalDevice,
831 DeviceExtension->DiskGeometry->BytesPerSector,
832 DiskData->PartitionOrdinal,
833 PartitionInfo->PartitionType);
834 if (NT_SUCCESS(Status))
835 {
836 DiskData->PartitionType = PartitionInfo->PartitionType;
837 }
838 }
839 break;
840
841 case IOCTL_DISK_GET_DRIVE_LAYOUT:
842 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
843 sizeof(DRIVE_LAYOUT_INFORMATION))
844 {
845 Status = STATUS_BUFFER_TOO_SMALL;
846 }
847 else
848 {
849 PDRIVE_LAYOUT_INFORMATION PartitionList;
850
851 Status = IoReadPartitionTable(DeviceExtension->PhysicalDevice,
852 DeviceExtension->DiskGeometry->BytesPerSector,
853 FALSE,
854 &PartitionList);
855 if (NT_SUCCESS(Status))
856 {
857 ULONG BufferSize;
858
859 BufferSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
860 PartitionEntry[0]);
861 BufferSize += PartitionList->PartitionCount * sizeof(PARTITION_INFORMATION);
862
863 if (BufferSize > IrpStack->Parameters.DeviceIoControl.OutputBufferLength)
864 {
865 Status = STATUS_BUFFER_TOO_SMALL;
866 }
867 else
868 {
869 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
870 PartitionList,
871 BufferSize);
872 Status = STATUS_SUCCESS;
873 Information = BufferSize;
874 }
875 ExFreePool(PartitionList);
876 }
877 }
878 break;
879
880 case IOCTL_DISK_SET_DRIVE_LAYOUT:
881 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
882 sizeof(DRIVE_LAYOUT_INFORMATION))
883 {
884 Status = STATUS_INFO_LENGTH_MISMATCH;
885 }
886 else if (DeviceExtension->PhysicalDevice->DeviceExtension != DeviceExtension)
887 {
888 Status = STATUS_INVALID_PARAMETER;
889 }
890 else
891 {
892 PDRIVE_LAYOUT_INFORMATION PartitionList;
893 ULONG TableSize;
894
895 PartitionList = Irp->AssociatedIrp.SystemBuffer;
896 TableSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
897 ((PartitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
898
899 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < TableSize)
900 {
901 Status = STATUS_BUFFER_TOO_SMALL;
902 }
903 else
904 {
905 Status = IoWritePartitionTable(DeviceExtension->DeviceObject,
906 DeviceExtension->DiskGeometry->BytesPerSector,
907 DeviceExtension->DiskGeometry->SectorsPerTrack,
908 DeviceExtension->DiskGeometry->TracksPerCylinder,
909 PartitionList);
910 if (NT_SUCCESS(Status))
911 {
912 /* FIXME: Update partition device objects */
913
914 Information = TableSize;
915 }
916 }
917 }
918 break;
919
920 case IOCTL_DISK_VERIFY:
921 case IOCTL_DISK_FORMAT_TRACKS:
922 case IOCTL_DISK_PERFORMANCE:
923 case IOCTL_DISK_IS_WRITABLE:
924 case IOCTL_DISK_LOGGING:
925 case IOCTL_DISK_FORMAT_TRACKS_EX:
926 case IOCTL_DISK_HISTOGRAM_STRUCTURE:
927 case IOCTL_DISK_HISTOGRAM_DATA:
928 case IOCTL_DISK_HISTOGRAM_RESET:
929 case IOCTL_DISK_REQUEST_STRUCTURE:
930 case IOCTL_DISK_REQUEST_DATA:
931 /* If we get here, something went wrong. Inform the requestor */
932 DPRINT1("Unhandled control code: %lx\n", ControlCode);
933 Status = STATUS_INVALID_DEVICE_REQUEST;
934 Information = 0;
935 break;
936
937 default:
938 /* Call the common device control function */
939 return(ScsiClassDeviceControl(DeviceObject, Irp));
940 }
941
942 /* Verify the device if the user caused the error */
943 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
944 {
945 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
946 }
947
948 Irp->IoStatus.Status = Status;
949 Irp->IoStatus.Information = Information;
950 IoCompleteRequest(Irp,
951 IO_NO_INCREMENT);
952
953 return(Status);
954 }
955
956
957 /**********************************************************************
958 * NAME EXPORTED
959 * DiskClassShutdownFlush
960 *
961 * DESCRIPTION
962 * Answer requests for shutdown and flush calls.
963 *
964 * RUN LEVEL
965 * PASSIVE_LEVEL
966 *
967 * ARGUMENTS
968 * DeviceObject
969 * Pointer to the device.
970 *
971 * Irp
972 * Pointer to the IRP
973 *
974 * RETURN VALUE
975 * Status
976 */
977
978 NTSTATUS STDCALL
979 DiskClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
980 IN PIRP Irp)
981 {
982 PDEVICE_EXTENSION DeviceExtension;
983 PIO_STACK_LOCATION IrpStack;
984 PSCSI_REQUEST_BLOCK Srb;
985
986 DPRINT("DiskClassShutdownFlush() called!\n");
987
988 DeviceExtension = DeviceObject->DeviceExtension;
989
990 /* Allocate SRB */
991 Srb = ExAllocatePool(NonPagedPool,
992 sizeof(SCSI_REQUEST_BLOCK));
993 if (Srb == NULL)
994 {
995 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
996 Irp->IoStatus.Information = 0;
997 IoCompleteRequest(Irp, IO_NO_INCREMENT);
998
999 return(STATUS_INSUFFICIENT_RESOURCES);
1000 }
1001
1002 /* Initialize SRB */
1003 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
1004 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1005
1006 /* Set device IDs */
1007 Srb->PathId = DeviceExtension->PathId;
1008 Srb->TargetId = DeviceExtension->TargetId;
1009 Srb->Lun = DeviceExtension->Lun;
1010
1011 /* Flush write cache */
1012 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1013 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1014 Srb->CdbLength = 10;
1015 Srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
1016 ScsiClassSendSrbSynchronous(DeviceObject,
1017 Srb,
1018 NULL,
1019 0,
1020 TRUE);
1021
1022 /* Get current stack location */
1023 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1024
1025 /* FIXME: Unlock removable media upon shutdown */
1026
1027
1028 /* No retry */
1029 IrpStack->Parameters.Others.Argument4 = (PVOID)0;
1030
1031 /* Send shutdown or flush request to the port driver */
1032 Srb->CdbLength = 0;
1033 if (IrpStack->MajorFunction == IRP_MJ_SHUTDOWN)
1034 Srb->Function = SRB_FUNCTION_SHUTDOWN;
1035 else
1036 Srb->Function = SRB_FUNCTION_FLUSH;
1037
1038 /* Init completion routine */
1039 IoSetCompletionRoutine(Irp,
1040 ScsiClassIoComplete,
1041 Srb,
1042 TRUE,
1043 TRUE,
1044 TRUE);
1045
1046 /* Prepare next stack location for a call to the port driver */
1047 IrpStack = IoGetNextIrpStackLocation(Irp);
1048 IrpStack->MajorFunction = IRP_MJ_SCSI;
1049 IrpStack->Parameters.Scsi.Srb = Srb;
1050 Srb->OriginalRequest = Irp;
1051
1052 /* Call port driver */
1053 return(IoCallDriver(DeviceExtension->PortDeviceObject, Irp));
1054 }
1055
1056 /* EOF */