1 /* $Id: ide.c,v 1.46 2001/11/01 00:28:57 ekohl Exp $
3 * IDE.C - IDE Disk driver
4 * written by Rex Jolliff
5 * with help from various documentation sources and a few peeks at
6 * linux and freebsd sources.
8 * This driver supports up to 4 controllers with up to 2 drives each.
9 * The device names are assigned as follows:
10 * \Devices\HarddiskX\Partition0
11 * for the raw device, and
12 * \Devices\HarddiskX\PartitionY
15 * X is computed by counting the available drives from the following
16 * sequence: the controller number (0=0x1f0, 1=0x170, 2=0x1e8,
17 * 3=0x168) * 2 plus the drive number (0,1)
18 * Y is the partition number
20 * The driver exports the following function:
22 * DriverEntry() - NT device driver initialization routine
24 * And the following functions are exported implicitly:
26 * IDEStartIo() - called to start an I/O request packet
27 * IDEDispatchOpenClose() - Called to open/close the device. a NOOP
28 * IDEDispatchReadWrite() - Called to read/write the device.
29 * IDEDispatchQueryInformation() - Called to get device information
30 * IDEDispatchSetInformation() - Called to set device information
31 * IDEDispatchDeviceControl() - Called to execute device control requests
33 * Modification History:
34 * 05/25/98 RJJ Created.
35 * 05/30/98 RJJ Removed IRQ handler and inserted busy waits
36 * just to get something working...
37 * 07/18/98 RJJ Made drastic changes so that the driver
38 * resembles a WinNT driver.
39 * 08/05/98 RJJ Changed to .C extension
40 * 09/19/98 RJJ First release (run for cover!)
43 * 09/17/98 RJJ Pri/MST: 14.12X19 WDC AC31000H Test Passed
48 * FIXME: a timer should be used to watch for device timeouts and errors
49 * FIXME: errors should be retried
50 * FIXME: a drive reset/recalibrate should be attempted if errors occur
51 * FIXME: Use DMA for transfers if drives support it
52 * FIXME: should we support unloading of this driver???
53 * FIXME: the device information should come from AUTODETECT (via registry)
54 * FIXME: really big devices need to be handled correctly
55 * FIXME: should get device info from the registry
56 * FIXME: should report hardware usage to iomgr
57 * FIXME: finish implementation of QueryInformation
58 * FIXME: finish implementation of SetInformation
59 * FIXME: finish implementation of DeviceControl
60 * FIXME: bring up to ATA-3 spec
61 * FIXME: add general support for ATAPI devices
62 * FIXME: add support for ATAPI CDROMs
63 * FIXME: add support for ATAPI ZIP drives/RHDs
64 * FIXME: add support for ATAPI tape drives
67 // -------------------------------------------------------------------------
69 #include <ddk/ntddk.h>
77 #define VERSION "V0.1.4"
79 /* remove this to activate the old behaviour of partition chain code (EK) */
82 // ------------------------------------------------------- File Static Data
85 typedef struct _IDE_CONTROLLER_PARAMETERS
94 KINTERRUPT_MODE InterruptMode
;
96 } IDE_CONTROLLER_PARAMETERS
, *PIDE_CONTROLLER_PARAMETERS
;
98 // NOTE: Do not increase max drives above 2
100 #define IDE_MAX_DRIVES 2
102 #define IDE_MAX_CONTROLLERS 2
103 IDE_CONTROLLER_PARAMETERS Controllers
[IDE_MAX_CONTROLLERS
] =
105 {0x01f0, 8, 0x03f6, 1, 14, 14, 15, LevelSensitive
, 0xffff},
106 {0x0170, 8, 0x0376, 1, 15, 15, 15, LevelSensitive
, 0xffff}
107 /* {0x01E8, 8, 0x03ee, 1, 11, 11, 15, LevelSensitive, 0xffff},
108 {0x0168, 8, 0x036e, 1, 10, 10, 15, LevelSensitive, 0xffff}*/
111 static BOOLEAN IDEInitialized
= FALSE
;
113 // ----------------------------------------------- Discardable Declarations
117 // make the initialization routines discardable, so that they
120 #pragma alloc_text(init, DriverEntry)
121 #pragma alloc_text(init, IDECreateController)
122 #pragma alloc_text(init, IDECreateDevices)
123 #pragma alloc_text(init, IDECreateDevice)
124 #pragma alloc_text(init, IDEPolledRead)
126 // make the PASSIVE_LEVEL routines pageable, so that they don't
127 // waste nonpaged memory
129 #pragma alloc_text(page, IDEShutdown)
130 #pragma alloc_text(page, IDEDispatchOpenClose)
131 #pragma alloc_text(page, IDEDispatchRead)
132 #pragma alloc_text(page, IDEDispatchWrite)
134 #endif /* ALLOC_PRAGMA */
136 // ---------------------------------------------------- Forward Declarations
139 IdeFindControllers(IN PDRIVER_OBJECT DriverObject
);
142 IdeCreateController(IN PDRIVER_OBJECT DriverObject
,
143 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
144 IN
int ControllerIdx
);
146 static BOOLEAN
IDEResetController(IN WORD CommandPort
, IN WORD ControlPort
);
147 static BOOLEAN
IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
148 IN PCONTROLLER_OBJECT ControllerObject
,
149 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
152 static BOOLEAN
IDEGetDriveIdentification(IN
int CommandPort
,
154 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
155 static NTSTATUS
IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject
,
156 OUT PDEVICE_OBJECT
*DeviceObject
,
157 IN PCONTROLLER_OBJECT ControllerObject
,
160 IN PIDE_DRIVE_IDENTIFY DrvParms
,
161 IN ULONG SectorCount
);
162 static NTSTATUS
IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject
,
163 OUT PDEVICE_OBJECT
*DeviceObject
,
164 IN PCONTROLLER_OBJECT ControllerObject
,
165 IN PVOID DiskDeviceExtension
,
168 IN PIDE_DRIVE_IDENTIFY DrvParms
,
169 IN PPARTITION_INFORMATION PartitionInfo
);
170 static int IDEPolledRead(IN WORD Address
,
175 IN BYTE CylinderHigh
,
179 static NTSTATUS STDCALL
IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
180 static NTSTATUS STDCALL
IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
181 static NTSTATUS STDCALL
IDEDispatchDeviceControl(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
182 static VOID STDCALL
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
);
183 static IO_ALLOCATION_ACTION STDCALL
184 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
186 IN PVOID MapRegisterBase
,
188 static BOOLEAN STDCALL
189 IDEStartController(IN OUT PVOID Context
);
190 VOID
IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
191 static BOOLEAN STDCALL
IDEIsr(IN PKINTERRUPT Interrupt
, IN PVOID ServiceContext
);
192 static VOID
IDEDpcForIsr(IN PKDPC Dpc
,
193 IN PDEVICE_OBJECT DpcDeviceObject
,
195 IN PVOID DpcContext
);
196 static VOID
IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
197 static VOID STDCALL
IDEIoTimer(PDEVICE_OBJECT DeviceObject
, PVOID Context
);
199 // ---------------------------------------------------------------- Inlines
202 IDESwapBytePairs(char *Buf
,
208 for (i
= 0; i
< Cnt
; i
+= 2)
216 // ------------------------------------------------------- Public Interface
221 // This function initializes the driver, locates and claims
222 // hardware resources, and creates various NT objects needed
223 // to process I/O requests.
229 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
231 // IN PUNICODE_STRING RegistryPath Name of registry driver service
238 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
239 IN PUNICODE_STRING RegistryPath
)
243 DbgPrint("IDE Driver %s\n", VERSION
);
245 // Export other driver entry points...
246 DriverObject
->DriverStartIo
= IDEStartIo
;
247 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = IDEDispatchOpenClose
;
248 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = IDEDispatchOpenClose
;
249 DriverObject
->MajorFunction
[IRP_MJ_READ
] = IDEDispatchReadWrite
;
250 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = IDEDispatchReadWrite
;
251 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
252 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
253 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = IDEDispatchDeviceControl
;
255 Status
= IdeFindControllers(DriverObject
);
256 if (NT_SUCCESS(Status
))
258 IDEInitialized
= TRUE
;
263 // ---------------------------------------------------- Discardable statics
266 IdeFindControllers(IN PDRIVER_OBJECT DriverObject
)
268 PCI_COMMON_CONFIG PciConfig
;
273 NTSTATUS ReturnedStatus
= STATUS_NO_SUCH_DEVICE
;
275 INT ControllerIdx
= 0;
276 PCONFIGURATION_INFORMATION ConfigInfo
;
278 DPRINT("IdeFindControllers() called!\n");
280 ConfigInfo
= IoGetConfigurationInformation();
282 /* Search PCI busses for IDE controllers */
283 for (Bus
= 0; Bus
< 8; Bus
++)
285 for (Slot
= 0; Slot
< 256; Slot
++)
287 Size
= HalGetBusData(PCIConfiguration
,
291 sizeof(PCI_COMMON_CONFIG
));
294 if ((PciConfig
.BaseClass
== 0x01) &&
295 (PciConfig
.SubClass
== 0x01))
297 DPRINT("IDE controller found!\n");
299 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
305 if ((PciConfig
.HeaderType
& 0x7FFFFFFF) == 0)
307 DPRINT(" IPR 0x%X ILR 0x%X\n",
308 PciConfig
.u
.type0
.InterruptPin
,
309 PciConfig
.u
.type0
.InterruptLine
);
312 if (PciConfig
.ProgIf
& 0x01)
314 DPRINT("Primary channel: PCI native mode\n");
318 DPRINT("Primary channel: Compatibility mode\n");
319 if (ConfigInfo
->AtDiskPrimaryAddressClaimed
== FALSE
)
321 Status
= IdeCreateController(DriverObject
,
324 if (NT_SUCCESS(Status
))
327 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
328 ConfigInfo
->ScsiPortCount
++;
329 ReturnedStatus
= Status
;
335 * FIXME: Switch controller to native pci mode
336 * if it is programmable.
340 if (PciConfig
.ProgIf
& 0x02)
342 DPRINT("Primary channel: programmable\n");
346 DPRINT("Primary channel: not programmable\n");
349 if (PciConfig
.ProgIf
& 0x04)
351 DPRINT("Secondary channel: PCI native mode\n");
355 DPRINT("Secondary channel: Compatibility mode\n");
357 Status
= IdeCreateController(DriverObject
,
360 if (NT_SUCCESS(Status
))
363 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
364 ConfigInfo
->ScsiPortCount
++;
365 ReturnedStatus
= Status
;
369 if (PciConfig
.ProgIf
& 0x08)
371 DPRINT("Secondary channel: programmable\n");
375 DPRINT("Secondary channel: not programmable\n");
378 if (PciConfig
.ProgIf
& 0x80)
380 DPRINT("Master IDE device: 1\n");
384 DPRINT("Master IDE device: 0\n");
387 for (i
= 0; i
< PCI_TYPE0_ADDRESSES
; i
++)
389 DPRINT("BaseAddress: 0x%08X\n", PciConfig
.u
.type0
.BaseAddresses
[i
]);
396 /* Search for ISA IDE controller if no primary controller was found */
397 if (ConfigInfo
->AtDiskPrimaryAddressClaimed
== FALSE
)
399 DPRINT("Searching for primary ISA IDE controller!\n");
401 if (IDEResetController(Controllers
[0].CommandPortBase
,
402 Controllers
[0].ControlPortBase
))
404 Status
= IdeCreateController(DriverObject
,
407 if (NT_SUCCESS(Status
))
409 DPRINT(" Found primary ISA IDE controller!\n");
411 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
412 ConfigInfo
->ScsiPortCount
++;
413 ReturnedStatus
= Status
;
419 if (ConfigInfo
->AtDiskSecondaryAddressClaimed
== FALSE
)
421 DPRINT("Searching for secondary ISA IDE controller!\n");
423 if (IDEResetController(Controllers
[1].CommandPortBase
,
424 Controllers
[1].ControlPortBase
))
426 Status
= IdeCreateController(DriverObject
,
429 if (NT_SUCCESS(Status
))
431 DPRINT(" Found secondary ISA IDE controller!\n");
433 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
434 ConfigInfo
->ScsiPortCount
++;
435 ReturnedStatus
= Status
;
441 DPRINT("IdeFindControllers() done!\n");
443 return(ReturnedStatus
);
447 // IdeCreateController
450 // Creates a controller object and a device object for each valid
451 // device on the controller
457 // IN PDRIVER_OBJECT DriverObject The system created driver object
458 // IN PIDE_CONTROLLER_PARAMETERS The parameter block for this
459 // ControllerParams controller
460 // IN int ControllerIdx The index of this controller
463 // TRUE Devices where found on this controller
464 // FALSE The controller does not respond or there are no devices on it
468 IdeCreateController(IN PDRIVER_OBJECT DriverObject
,
469 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
470 IN
int ControllerIdx
)
472 BOOLEAN CreatedDevices
, ThisDriveExists
;
475 PCONTROLLER_OBJECT ControllerObject
;
476 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
478 ControllerObject
= IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION
));
479 if (ControllerObject
== NULL
)
481 DbgPrint ("Could not create controller object for controller %d\n",
483 return STATUS_NO_SUCH_DEVICE
;
486 // Fill out Controller extension data
487 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
488 ControllerObject
->ControllerExtension
;
489 ControllerExtension
->Number
= ControllerIdx
;
490 ControllerExtension
->CommandPortBase
= ControllerParams
->CommandPortBase
;
491 ControllerExtension
->ControlPortBase
= ControllerParams
->ControlPortBase
;
492 ControllerExtension
->Vector
= ControllerParams
->Vector
;
493 ControllerExtension
->DMASupported
= FALSE
;
494 ControllerExtension
->ControllerInterruptBug
= FALSE
;
495 ControllerExtension
->OperationInProgress
= FALSE
;
497 // Initialize the spin lock in the controller extension
498 KeInitializeSpinLock(&ControllerExtension
->SpinLock
);
500 // Register an interrupt handler for this controller
501 RC
= IoConnectInterrupt(&ControllerExtension
->Interrupt
,
504 &ControllerExtension
->SpinLock
,
505 ControllerExtension
->Vector
,
506 ControllerParams
->IrqL
,
507 ControllerParams
->SynchronizeIrqL
,
508 ControllerParams
->InterruptMode
,
510 ControllerParams
->Affinity
,
514 DbgPrint ("Could not Connect Interrupt %d\n",
515 ControllerExtension
->Vector
);
516 IoDeleteController (ControllerObject
);
521 IDEInitialized
= TRUE
;
523 // Create device objects for each raw device (and for partitions)
524 CreatedDevices
= FALSE
;
525 for (DriveIdx
= 0; DriveIdx
< IDE_MAX_DRIVES
; DriveIdx
++)
527 ThisDriveExists
= IDECreateDevices(DriverObject
,
531 ControllerIdx
* 2 + DriveIdx
);
534 CreatedDevices
= TRUE
;
540 DbgPrint ("Did not find any devices for controller %d\n",
542 IoDisconnectInterrupt (ControllerExtension
->Interrupt
);
543 IoDeleteController (ControllerObject
);
547 IDEResetController(ControllerParams
->CommandPortBase
,
548 ControllerParams
->ControlPortBase
);
549 IoStartTimer(ControllerExtension
->TimerDevice
);
552 return((CreatedDevices
== TRUE
)?STATUS_SUCCESS
:STATUS_NO_SUCH_DEVICE
);
556 // IDEResetController
559 // Reset the controller and report completion status
565 // IN WORD CommandPort The address of the command port
566 // IN WORD ControlPort The address of the control port
572 IDEResetController(IN WORD CommandPort
,
577 // Assert drive reset line
578 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
580 // Wait for min. 25 microseconds
581 KeStallExecutionProcessor(IDE_RESET_PULSE_LENGTH
);
583 // Negate drive reset line
584 IDEWriteDriveControl(ControlPort
, 0);
586 // Wait for BUSY negation
587 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
589 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
593 KeStallExecutionProcessor(10);
596 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
601 // return TRUE if controller came back to life. and
602 // the registers are initialized correctly
603 return IDEReadError(CommandPort
) == 1;
610 // Create the raw device and any partition devices on this drive
616 // IN PDRIVER_OBJECT DriverObject The system created driver object
617 // IN PCONTROLLER_OBJECT ControllerObject
618 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
619 // The IDE controller extension for
621 // IN int DriveIdx The index of the drive on this
623 // IN int HarddiskIdx The NT device number for this
627 // TRUE Drive exists and devices were created
628 // FALSE no devices were created for this device
632 IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
633 IN PCONTROLLER_OBJECT ControllerObject
,
634 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
638 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
641 IDE_DRIVE_IDENTIFY DrvParms
;
642 PDEVICE_OBJECT DiskDeviceObject
;
643 PDEVICE_OBJECT PartitionDeviceObject
;
644 PIDE_DEVICE_EXTENSION DiskDeviceExtension
;
645 UNICODE_STRING UnicodeDeviceDirName
;
646 OBJECT_ATTRIBUTES DeviceDirAttributes
;
648 ULONG SectorCount
= 0;
649 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
650 PPARTITION_INFORMATION PartitionEntry
;
653 // Copy I/O port offsets for convenience
654 CommandPort
= ControllerExtension
->CommandPortBase
;
655 // ControlPort = ControllerExtension->ControlPortBase;
656 DPRINT("probing IDE controller %d Addr %04lx Drive %d\n",
657 ControllerExtension
->Number
,
661 /* Get the Drive Identification Data */
662 if (!IDEGetDriveIdentification(CommandPort
, DriveIdx
, &DrvParms
))
665 DbgPrint("Giving up on drive %d on controller %d...\n",
667 ControllerExtension
->Number
);
671 /* Create the harddisk device directory */
672 swprintf (NameBuffer
,
673 L
"\\Device\\Harddisk%d",
675 RtlInitUnicodeString(&UnicodeDeviceDirName
,
677 InitializeObjectAttributes(&DeviceDirAttributes
,
678 &UnicodeDeviceDirName
,
682 Status
= ZwCreateDirectoryObject(&Handle
, 0, &DeviceDirAttributes
);
683 if (!NT_SUCCESS(Status
))
685 DbgPrint("Could not create device dir object\n");
689 /* Create the disk device */
690 if (DrvParms
.Capabilities
& IDE_DRID_LBA_SUPPORTED
)
693 (ULONG
)((DrvParms
.TMSectorCountHi
<< 16) + DrvParms
.TMSectorCountLo
);
698 (ULONG
)(DrvParms
.LogicalCyls
* DrvParms
.LogicalHeads
* DrvParms
.SectorsPerTrack
);
700 DPRINT("SectorCount %lu\n", SectorCount
);
702 Status
= IDECreateDiskDevice(DriverObject
,
709 if (!NT_SUCCESS(Status
))
711 DbgPrint("IDECreateDevice call failed for raw device\n");
715 /* Increase number of available physical disk drives */
716 IoGetConfigurationInformation()->DiskCount
++;
719 * Initialize the controller timer here
720 * (since it has to be tied to a device)
724 ControllerExtension
->TimerState
= IDETimerIdle
;
725 ControllerExtension
->TimerCount
= 0;
726 ControllerExtension
->TimerDevice
= DiskDeviceObject
;
727 IoInitializeTimer(DiskDeviceObject
,
729 ControllerExtension
);
732 DPRINT("DrvParms.BytesPerSector %ld\n",DrvParms
.BytesPerSector
);
734 /* Read partition table */
735 Status
= IoReadPartitionTable(DiskDeviceObject
,
736 DrvParms
.BytesPerSector
,
739 if (!NT_SUCCESS(Status
))
741 DbgPrint("IoReadPartitionTable() failed\n");
745 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
746 for (i
=0;i
< PartitionList
->PartitionCount
; i
++)
748 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
750 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
752 PartitionEntry
->PartitionNumber
,
753 PartitionEntry
->BootIndicator
,
754 PartitionEntry
->PartitionType
,
755 PartitionEntry
->StartingOffset
.QuadPart
/ 512 /*DrvParms.BytesPerSector*/,
756 PartitionEntry
->PartitionLength
.QuadPart
/ 512 /* DrvParms.BytesPerSector*/);
758 /* Create device for partition */
759 Status
= IDECreatePartitionDevice(DriverObject
,
760 &PartitionDeviceObject
,
762 DiskDeviceObject
->DeviceExtension
, //DiskDeviceExtension,
767 if (!NT_SUCCESS(Status
))
769 DbgPrint("IDECreateDevice() failed\n");
774 if (PartitionList
!= NULL
)
775 ExFreePool(PartitionList
);
780 // IDEGetDriveIdentification
783 // Get the identification block from the drive
789 // IN int CommandPort Address of the command port
790 // IN int DriveNum The drive index (0,1)
791 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
794 // TRUE The drive identification block was retrieved successfully
798 IDEGetDriveIdentification(IN
int CommandPort
,
800 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
803 // Get the Drive Identify block from drive or die
804 if (IDEPolledRead(CommandPort
, 0, 0, 0, 0, 0, (DriveNum
? IDE_DH_DRV1
: 0),
805 IDE_CMD_IDENT_DRV
, (BYTE
*)DrvParms
) != 0)
811 // Report on drive parameters if debug mode
812 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
813 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
814 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
815 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
816 DrvParms
->ConfigBits
,
817 DrvParms
->LogicalCyls
,
818 DrvParms
->LogicalHeads
,
819 DrvParms
->SectorsPerTrack
,
820 DrvParms
->InterSectorGap
,
821 DrvParms
->InterSectorGapSize
);
822 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
823 DrvParms
->BytesInPLO
,
824 DrvParms
->VendorUniqueCnt
,
825 DrvParms
->SerialNumber
);
826 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
827 DrvParms
->ControllerType
,
828 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
829 DrvParms
->ECCByteCnt
,
830 DrvParms
->FirmwareRev
);
831 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
832 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
833 (DrvParms
->RWMultImplemented
) & 0xff,
834 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
835 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
836 DrvParms
->MinPIOTransTime
,
837 DrvParms
->MinDMATransTime
);
838 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
839 DrvParms
->TMCylinders
,
841 DrvParms
->TMSectorsPerTrk
,
842 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
843 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
844 DrvParms
->TMSectorCountHi
,
845 DrvParms
->TMSectorCountLo
,
846 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
848 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
849 DrvParms
->BytesPerSector
= 512; /* FIXME !!!*/
854 // IDECreateDiskDevice
857 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
863 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
864 // OUT PDEVICE_OBJECT *DeviceObject The created device object
865 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
866 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
867 // IN BOOLEAN DMASupported Does the drive support DMA?
868 // IN int SectorsPerLogCyl Sectors per cylinder
869 // IN int SectorsPerLogTrk Sectors per track
870 // IN DWORD Offset First valid sector for this device
871 // IN DWORD Size Count of valid sectors for this device
878 IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject
,
879 OUT PDEVICE_OBJECT
*DeviceObject
,
880 IN PCONTROLLER_OBJECT ControllerObject
,
883 IN PIDE_DRIVE_IDENTIFY DrvParms
,
884 IN ULONG SectorCount
)
886 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
887 WCHAR ArcNameBuffer
[IDE_MAX_NAME_LENGTH
+ 15];
888 UNICODE_STRING DeviceName
;
889 UNICODE_STRING ArcName
;
891 PIDE_DEVICE_EXTENSION DeviceExtension
;
893 // Create a unicode device name
895 L
"\\Device\\Harddisk%d\\Partition0",
897 RtlInitUnicodeString(&DeviceName
,
901 RC
= IoCreateDevice(DriverObject
,
902 sizeof(IDE_DEVICE_EXTENSION
),
910 DbgPrint ("IoCreateDevice call failed\n");
914 // Set the buffering strategy here...
915 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
916 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
918 // Fill out Device extension data
919 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) (*DeviceObject
)->DeviceExtension
;
920 DeviceExtension
->DeviceObject
= (*DeviceObject
);
921 DeviceExtension
->ControllerObject
= ControllerObject
;
922 DeviceExtension
->DiskDeviceExtension
= DeviceExtension
;
923 DeviceExtension
->UnitNumber
= UnitNumber
;
924 DeviceExtension
->LBASupported
=
925 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
926 DeviceExtension
->DMASupported
=
927 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
928 // FIXME: deal with bizarre sector sizes
929 DeviceExtension
->BytesPerSector
= 512 /* DrvParms->BytesPerSector */;
930 DeviceExtension
->SectorsPerLogCyl
= DrvParms
->LogicalHeads
*
931 DrvParms
->SectorsPerTrack
;
932 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
933 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
934 DeviceExtension
->LogicalCylinders
=
935 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? DrvParms
->TMCylinders
: DrvParms
->LogicalCyls
;
936 DeviceExtension
->Offset
= 0;
937 DeviceExtension
->Size
= SectorCount
;
938 DPRINT("%wZ: offset %lu size %lu \n",
940 DeviceExtension
->Offset
,
941 DeviceExtension
->Size
);
943 /* Initialize the DPC object here */
944 IoInitializeDpcRequest(*DeviceObject
,
947 /* assign arc name */
948 swprintf(ArcNameBuffer
,
949 L
"\\ArcName\\multi(0)disk(0)rdisk(%d)",
951 RtlInitUnicodeString(&ArcName
,
953 DPRINT("%wZ ==> %wZ\n", &ArcName
, &DeviceName
);
954 RC
= IoAssignArcName(&ArcName
,
958 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName
, RC
);
965 // IDECreatePartitionDevice
968 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
974 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
975 // OUT PDEVICE_OBJECT *DeviceObject The created device object
976 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
977 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
978 // IN BOOLEAN DMASupported Does the drive support DMA?
979 // IN int SectorsPerLogCyl Sectors per cylinder
980 // IN int SectorsPerLogTrk Sectors per track
981 // IN DWORD Offset First valid sector for this device
982 // IN DWORD Size Count of valid sectors for this device
989 IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject
,
990 OUT PDEVICE_OBJECT
*DeviceObject
,
991 IN PCONTROLLER_OBJECT ControllerObject
,
992 IN PVOID DiskDeviceExtension
,
995 IN PIDE_DRIVE_IDENTIFY DrvParms
,
996 IN PPARTITION_INFORMATION PartitionInfo
)
998 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
999 WCHAR ArcNameBuffer
[IDE_MAX_NAME_LENGTH
+ 15];
1000 UNICODE_STRING DeviceName
;
1001 UNICODE_STRING ArcName
;
1003 PIDE_DEVICE_EXTENSION DeviceExtension
;
1005 // Create a unicode device name
1006 swprintf(NameBuffer
,
1007 L
"\\Device\\Harddisk%d\\Partition%d",
1009 PartitionInfo
->PartitionNumber
);
1010 RtlInitUnicodeString(&DeviceName
,
1013 // Create the device
1014 RC
= IoCreateDevice(DriverObject
, sizeof(IDE_DEVICE_EXTENSION
),
1015 &DeviceName
, FILE_DEVICE_DISK
, 0, TRUE
, DeviceObject
);
1016 if (!NT_SUCCESS(RC
))
1018 DbgPrint ("IoCreateDevice call failed\n");
1022 // Set the buffering strategy here...
1023 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
1024 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1026 // Fill out Device extension data
1027 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) (*DeviceObject
)->DeviceExtension
;
1028 DeviceExtension
->DeviceObject
= (*DeviceObject
);
1029 DeviceExtension
->ControllerObject
= ControllerObject
;
1030 DeviceExtension
->DiskDeviceExtension
= DiskDeviceExtension
;
1031 DeviceExtension
->UnitNumber
= UnitNumber
;
1032 DeviceExtension
->LBASupported
=
1033 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
1034 DeviceExtension
->DMASupported
=
1035 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
1036 // FIXME: deal with bizarre sector sizes
1037 DeviceExtension
->BytesPerSector
= 512 /* DrvParms->BytesPerSector */;
1038 DeviceExtension
->SectorsPerLogCyl
= DrvParms
->LogicalHeads
*
1039 DrvParms
->SectorsPerTrack
;
1040 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
1041 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
1042 DeviceExtension
->LogicalCylinders
=
1043 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? DrvParms
->TMCylinders
: DrvParms
->LogicalCyls
;
1044 // DeviceExtension->Offset = Offset;
1045 // DeviceExtension->Size = Size;
1047 DeviceExtension
->Offset
= PartitionInfo
->StartingOffset
.QuadPart
/ 512; /* DrvParms.BytesPerSector*/
1048 DeviceExtension
->Size
= PartitionInfo
->PartitionLength
.QuadPart
/ 512; /*DrvParms.BytesPerSector*/
1050 DPRINT("%wZ: offset %lu size %lu \n",
1052 DeviceExtension
->Offset
,
1053 DeviceExtension
->Size
);
1055 /* Initialize the DPC object here */
1056 IoInitializeDpcRequest(*DeviceObject
, IDEDpcForIsr
);
1058 DbgPrint("%wZ %luMB\n", &DeviceName
, DeviceExtension
->Size
/ 2048);
1060 /* assign arc name */
1061 swprintf(ArcNameBuffer
,
1062 L
"\\ArcName\\multi(0)disk(0)rdisk(%d)partition(%d)",
1064 PartitionInfo
->PartitionNumber
);
1065 RtlInitUnicodeString(&ArcName
,
1067 DPRINT("%wZ ==> %wZ\n", &ArcName
, &DeviceName
);
1068 RC
= IoAssignArcName(&ArcName
,
1070 if (!NT_SUCCESS(RC
))
1072 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName
, RC
);
1082 // Read a sector of data from the drive in a polled fashion.
1088 // IN WORD Address Address of command port for drive
1089 // IN BYTE PreComp Value to write to precomp register
1090 // IN BYTE SectorCnt Value to write to sectorCnt register
1091 // IN BYTE SectorNum Value to write to sectorNum register
1092 // IN BYTE CylinderLow Value to write to CylinderLow register
1093 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1094 // IN BYTE DrvHead Value to write to Drive/Head register
1095 // IN BYTE Command Value to write to Command register
1096 // OUT BYTE *Buffer Buffer for output data
1099 // int 0 is success, non 0 is an error code
1103 IDEPolledRead(IN WORD Address
,
1107 IN BYTE CylinderLow
,
1108 IN BYTE CylinderHigh
,
1116 /* Wait for STATUS.BUSY to clear */
1117 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1119 Status
= IDEReadStatus(Address
);
1120 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1121 // if (!(Status & IDE_SR_BUSY))
1125 KeStallExecutionProcessor(10);
1127 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1132 /* Write Drive/Head to select drive */
1133 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1135 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1136 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1138 Status
= IDEReadStatus(Address
);
1139 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1143 KeStallExecutionProcessor(10);
1145 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1151 /* Issue command to drive */
1152 if (DrvHead
& IDE_DH_LBA
)
1154 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1155 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1156 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1162 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1163 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1172 /* Setup command parameters */
1173 IDEWritePrecomp(Address
, PreComp
);
1174 IDEWriteSectorCount(Address
, SectorCnt
);
1175 IDEWriteSectorNum(Address
, SectorNum
);
1176 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1177 IDEWriteCylinderLow(Address
, CylinderLow
);
1178 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1180 /* Issue the command */
1181 IDEWriteCommand(Address
, Command
);
1182 KeStallExecutionProcessor(50);
1186 /* wait for DRQ or error */
1187 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1189 Status
= IDEReadStatus(Address
);
1190 if (!(Status
& IDE_SR_BUSY
))
1192 if (Status
& IDE_SR_DRQ
)
1201 KeStallExecutionProcessor(10);
1203 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1208 /* Read data into buffer */
1209 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1210 Buffer
+= IDE_SECTOR_BUF_SZ
;
1212 /* Check for more sectors to read */
1213 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1215 Status
= IDEReadStatus(Address
);
1216 if (!(Status
& IDE_SR_BUSY
))
1218 if (Status
& IDE_SR_DRQ
)
1231 // ------------------------------------------- Nondiscardable statics
1233 // IDEDispatchOpenClose
1236 // Answer requests for Open/Close calls: a null operation
1242 // Standard dispatch arguments
1249 STDCALL
IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
,
1252 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1253 Irp
->IoStatus
.Information
= FILE_OPENED
;
1254 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1256 return STATUS_SUCCESS
;
1259 // IDEDispatchReadWrite
1262 // Answer requests for reads and writes
1268 // Standard dispatch arguments
1275 STDCALL
IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
,
1279 LARGE_INTEGER AdjustedOffset
, AdjustedExtent
, PartitionExtent
, InsertKeyLI
;
1280 PIO_STACK_LOCATION IrpStack
;
1281 PIDE_DEVICE_EXTENSION DeviceExtension
;
1283 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1284 DeviceExtension
= (PIDE_DEVICE_EXTENSION
)pDO
->DeviceExtension
;
1286 // Validate operation parameters
1287 AdjustedOffset
= RtlEnlargedIntegerMultiply(DeviceExtension
->Offset
,
1288 DeviceExtension
->BytesPerSector
);
1289 DPRINT("Offset:%ld * BytesPerSector:%ld = AdjOffset:%ld:%ld\n",
1290 DeviceExtension
->Offset
,
1291 DeviceExtension
->BytesPerSector
,
1292 (unsigned long) AdjustedOffset
.u
.HighPart
,
1293 (unsigned long) AdjustedOffset
.u
.LowPart
);
1294 DPRINT("AdjOffset:%ld:%ld + ByteOffset:%ld:%ld\n",
1295 (unsigned long) AdjustedOffset
.u
.HighPart
,
1296 (unsigned long) AdjustedOffset
.u
.LowPart
,
1297 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.u
.HighPart
,
1298 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.u
.LowPart
);
1299 AdjustedOffset
= RtlLargeIntegerAdd(AdjustedOffset
,
1300 IrpStack
->Parameters
.Read
.ByteOffset
);
1301 DPRINT(" = AdjOffset:%ld:%ld\n",
1302 (unsigned long) AdjustedOffset
.u
.HighPart
,
1303 (unsigned long) AdjustedOffset
.u
.LowPart
);
1304 AdjustedExtent
= RtlLargeIntegerAdd(AdjustedOffset
,
1305 RtlConvertLongToLargeInteger(IrpStack
->Parameters
.Read
.Length
));
1306 DPRINT("AdjOffset:%ld:%ld + Length:%ld = AdjExtent:%ld:%ld\n",
1307 (unsigned long) AdjustedOffset
.u
.HighPart
,
1308 (unsigned long) AdjustedOffset
.u
.LowPart
,
1309 IrpStack
->Parameters
.Read
.Length
,
1310 (unsigned long) AdjustedExtent
.u
.HighPart
,
1311 (unsigned long) AdjustedExtent
.u
.LowPart
);
1312 /*FIXME: this assumption will fail on drives bigger than 1TB */
1313 PartitionExtent
.QuadPart
= DeviceExtension
->Offset
+ DeviceExtension
->Size
;
1314 PartitionExtent
= RtlExtendedIntegerMultiply(PartitionExtent
,
1315 DeviceExtension
->BytesPerSector
);
1316 if ((AdjustedExtent
.QuadPart
> PartitionExtent
.QuadPart
) ||
1317 (IrpStack
->Parameters
.Read
.Length
& (DeviceExtension
->BytesPerSector
- 1)))
1319 DPRINT("Request failed on bad parameters\n",0);
1320 DPRINT("AdjustedExtent=%d:%d PartitionExtent=%d:%d ReadLength=%d\n",
1321 (unsigned int) AdjustedExtent
.u
.HighPart
,
1322 (unsigned int) AdjustedExtent
.u
.LowPart
,
1323 (unsigned int) PartitionExtent
.u
.HighPart
,
1324 (unsigned int) PartitionExtent
.u
.LowPart
,
1325 IrpStack
->Parameters
.Read
.Length
);
1326 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1327 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1328 return STATUS_INVALID_PARAMETER
;
1331 // Adjust operation to absolute sector offset
1332 IrpStack
->Parameters
.Read
.ByteOffset
= AdjustedOffset
;
1334 // Start the packet and insert the request in order of sector offset
1335 assert(DeviceExtension
->BytesPerSector
== 512);
1336 InsertKeyLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1337 IrpInsertKey
= InsertKeyLI
.u
.LowPart
;
1338 IoStartPacket(DeviceExtension
->DeviceObject
, Irp
, &IrpInsertKey
, NULL
);
1340 DPRINT("Returning STATUS_PENDING\n");
1341 return STATUS_PENDING
;
1344 // IDEDispatchDeviceControl
1347 // Answer requests for device control calls
1353 // Standard dispatch arguments
1359 static NTSTATUS STDCALL
1360 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1364 ULONG ControlCode
, InputLength
, OutputLength
;
1365 PIO_STACK_LOCATION IrpStack
;
1366 PIDE_DEVICE_EXTENSION DeviceExtension
;
1367 PIDE_DEVICE_EXTENSION DiskDeviceExtension
;
1370 RC
= STATUS_SUCCESS
;
1371 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1372 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1373 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1374 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1375 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1376 DiskDeviceExtension
= (PIDE_DEVICE_EXTENSION
)DeviceExtension
->DiskDeviceExtension
;
1377 Increment
= IO_NO_INCREMENT
;
1379 // A huge switch statement in a Windows program?! who would have thought?
1380 switch (ControlCode
)
1382 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1383 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1385 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1389 PDISK_GEOMETRY Geometry
;
1391 Geometry
= (PDISK_GEOMETRY
) Irp
->AssociatedIrp
.SystemBuffer
;
1393 Geometry
->MediaType
= FixedMedia
;
1394 Geometry
->Cylinders
.QuadPart
= DiskDeviceExtension
->LogicalCylinders
;
1395 Geometry
->TracksPerCylinder
= DiskDeviceExtension
->SectorsPerLogCyl
/
1396 DiskDeviceExtension
->SectorsPerLogTrk
;
1397 Geometry
->SectorsPerTrack
= DiskDeviceExtension
->SectorsPerLogTrk
;
1398 Geometry
->BytesPerSector
= DiskDeviceExtension
->BytesPerSector
;
1400 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1401 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1405 case IOCTL_DISK_GET_PARTITION_INFO
:
1406 case IOCTL_DISK_SET_PARTITION_INFO
:
1407 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1408 Irp
->IoStatus
.Status
= RC
;
1409 Irp
->IoStatus
.Information
= 0;
1412 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1413 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1414 sizeof(DRIVE_LAYOUT_INFORMATION
))
1416 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1420 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1422 RC
= IoReadPartitionTable(DiskDeviceExtension
->DeviceObject
,
1423 DiskDeviceExtension
->BytesPerSector
,
1426 if (!NT_SUCCESS(RC
))
1428 Irp
->IoStatus
.Status
= RC
;
1434 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
1436 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
1438 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1440 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1444 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1447 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1448 Irp
->IoStatus
.Information
= BufferSize
;
1450 ExFreePool(PartitionList
);
1453 Increment
= IO_DISK_INCREMENT
;
1456 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1457 case IOCTL_DISK_VERIFY
:
1458 case IOCTL_DISK_FORMAT_TRACKS
:
1459 case IOCTL_DISK_PERFORMANCE
:
1460 case IOCTL_DISK_IS_WRITABLE
:
1461 case IOCTL_DISK_LOGGING
:
1462 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1463 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1464 case IOCTL_DISK_HISTOGRAM_DATA
:
1465 case IOCTL_DISK_HISTOGRAM_RESET
:
1466 case IOCTL_DISK_REQUEST_STRUCTURE
:
1467 case IOCTL_DISK_REQUEST_DATA
:
1469 // If we get here, something went wrong. inform the requestor
1471 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1472 Irp
->IoStatus
.Status
= RC
;
1473 Irp
->IoStatus
.Information
= 0;
1477 IoCompleteRequest(Irp
, Increment
);
1485 // Get the next requested I/O packet started
1491 // Dispatch routine standard arguments
1498 STDCALL
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
,
1501 LARGE_INTEGER SectorLI
;
1502 PIO_STACK_LOCATION IrpStack
;
1503 PIDE_DEVICE_EXTENSION DeviceExtension
;
1506 DPRINT("IDEStartIo() called!\n");
1508 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1509 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1511 // FIXME: implement the supported functions
1513 switch (IrpStack
->MajorFunction
)
1517 DeviceExtension
->Operation
= IrpStack
->MajorFunction
;
1518 DeviceExtension
->BytesRequested
= IrpStack
->Parameters
.Read
.Length
;
1519 assert(DeviceExtension
->BytesPerSector
== 512);
1520 SectorLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1521 DeviceExtension
->StartingSector
= SectorLI
.u
.LowPart
;
1522 if (DeviceExtension
->BytesRequested
> DeviceExtension
->BytesPerSector
*
1523 IDE_MAX_SECTORS_PER_XFER
)
1525 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesPerSector
*
1526 IDE_MAX_SECTORS_PER_XFER
;
1530 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1532 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1533 DeviceExtension
->SectorsTransferred
= 0;
1534 DeviceExtension
->TargetAddress
= (BYTE
*)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1535 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1536 IoAllocateController(DeviceExtension
->ControllerObject
,
1538 IDEAllocateController
,
1540 KeLowerIrql(OldIrql
);
1544 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1545 Irp
->IoStatus
.Information
= 0;
1546 KeBugCheck((ULONG
)Irp
);
1547 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1548 IoStartNextPacket(DeviceObject
, FALSE
);
1551 DPRINT("IDEStartIo() finished!\n");
1554 // IDEAllocateController
1556 static IO_ALLOCATION_ACTION STDCALL
1557 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
1559 IN PVOID MapRegisterBase
,
1562 PIDE_DEVICE_EXTENSION DeviceExtension
;
1563 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1565 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1566 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1567 DeviceExtension
->ControllerObject
->ControllerExtension
;
1568 ControllerExtension
->CurrentIrp
= Irp
;
1569 ControllerExtension
->Retries
= 0;
1570 return KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1572 DeviceExtension
) ? KeepObject
:
1576 // IDEStartController
1579 IDEStartController(IN OUT PVOID Context
)
1581 BYTE SectorCnt
, SectorNum
, CylinderLow
, CylinderHigh
;
1582 BYTE DrvHead
, Command
;
1585 ULONG StartingSector
;
1586 PIDE_DEVICE_EXTENSION DeviceExtension
;
1587 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1590 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) Context
;
1591 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1592 DeviceExtension
->ControllerObject
->ControllerExtension
;
1593 ControllerExtension
->OperationInProgress
= TRUE
;
1594 ControllerExtension
->DeviceForOperation
= DeviceExtension
;
1596 // Write controller registers to start opteration
1597 StartingSector
= DeviceExtension
->StartingSector
;
1598 SectorCnt
= DeviceExtension
->BytesToTransfer
/
1599 DeviceExtension
->BytesPerSector
;
1600 if (DeviceExtension
->LBASupported
)
1602 SectorNum
= StartingSector
& 0xff;
1603 CylinderLow
= (StartingSector
>> 8) & 0xff;
1604 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1605 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1606 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0) |
1611 SectorNum
= (StartingSector
% DeviceExtension
->SectorsPerLogTrk
) + 1;
1612 StartingSector
/= DeviceExtension
->SectorsPerLogTrk
;
1613 DrvHead
= (StartingSector
% DeviceExtension
->LogicalHeads
) |
1614 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0);
1615 StartingSector
/= DeviceExtension
->LogicalHeads
;
1616 CylinderLow
= StartingSector
& 0xff;
1617 CylinderHigh
= StartingSector
>> 8;
1619 Command
= DeviceExtension
->Operation
== IRP_MJ_READ
?
1620 IDE_CMD_READ
: IDE_CMD_WRITE
;
1621 if (DrvHead
& IDE_DH_LBA
)
1623 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1624 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1625 ControllerExtension
->CommandPortBase
,
1626 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1627 ((DrvHead
& 0x0f) << 24) +
1628 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1634 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1635 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1636 ControllerExtension
->CommandPortBase
,
1637 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1646 /* wait for BUSY to clear */
1647 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1649 Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1650 if (!(Status
& IDE_SR_BUSY
))
1654 KeStallExecutionProcessor(10);
1656 DPRINT ("status=%02x\n", Status
);
1657 DPRINT ("waited %ld usecs for busy to clear\n", Retries
* 10);
1658 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1660 DPRINT ("Drive is BUSY for too long\n");
1661 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1663 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1664 Irp
= ControllerExtension
->CurrentIrp
;
1665 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1666 Irp
->IoStatus
.Information
= 0;
1672 DPRINT ("Beginning drive reset sequence\n");
1673 IDEBeginControllerReset(ControllerExtension
);
1679 /* Select the desired drive */
1680 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1682 /* wait for BUSY to clear and DRDY to assert */
1683 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1685 Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1686 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1690 KeStallExecutionProcessor(10);
1692 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1693 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1695 DPRINT ("Drive is BUSY for too long after drive select\n");
1696 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1698 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1699 Irp
= ControllerExtension
->CurrentIrp
;
1700 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1701 Irp
->IoStatus
.Information
= 0;
1707 DPRINT ("Beginning drive reset sequence\n");
1708 IDEBeginControllerReset(ControllerExtension
);
1714 /* Setup command parameters */
1715 IDEWritePrecomp(ControllerExtension
->CommandPortBase
, 0);
1716 IDEWriteSectorCount(ControllerExtension
->CommandPortBase
, SectorCnt
);
1717 IDEWriteSectorNum(ControllerExtension
->CommandPortBase
, SectorNum
);
1718 IDEWriteCylinderHigh(ControllerExtension
->CommandPortBase
, CylinderHigh
);
1719 IDEWriteCylinderLow(ControllerExtension
->CommandPortBase
, CylinderLow
);
1720 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1722 /* Issue command to drive */
1723 IDEWriteCommand(ControllerExtension
->CommandPortBase
, Command
);
1724 ControllerExtension
->TimerState
= IDETimerCmdWait
;
1725 ControllerExtension
->TimerCount
= IDE_CMD_TIMEOUT
;
1727 if (DeviceExtension
->Operation
== IRP_MJ_WRITE
)
1730 // Wait for controller ready
1731 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
1733 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1734 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
1738 KeStallExecutionProcessor(10);
1740 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1742 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1744 Irp
= ControllerExtension
->CurrentIrp
;
1745 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1746 Irp
->IoStatus
.Information
= 0;
1752 IDEBeginControllerReset(ControllerExtension
);
1758 // Load the first sector of data into the controller
1759 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1760 DeviceExtension
->TargetAddress
,
1762 DeviceExtension
->TargetAddress
+= IDE_SECTOR_BUF_SZ
;
1763 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1764 DeviceExtension
->SectorsTransferred
++;
1766 DPRINT ("Command issued to drive, IDEStartController done\n");
1771 // IDEBeginControllerReset
1774 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1778 DPRINT("Controller Reset initiated on %04x\n",
1779 ControllerExtension
->ControlPortBase
);
1781 /* Assert drive reset line */
1782 DPRINT("Asserting reset line\n");
1783 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, IDE_DC_SRST
);
1785 /* Wait for BSY assertion */
1786 DPRINT("Waiting for BSY assertion\n");
1787 for (Retries
= 0; Retries
< IDE_MAX_RESET_RETRIES
; Retries
++)
1789 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1790 if ((Status
& IDE_SR_BUSY
))
1794 KeStallExecutionProcessor(10);
1796 if (Retries
== IDE_MAX_RESET_RETRIES
)
1798 DPRINT("Timeout on BSY assertion\n");
1801 /* Negate drive reset line */
1802 DPRINT("Negating reset line\n");
1803 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, 0);
1805 // FIXME: handle case of no device 0
1807 /* Set timer to check for end of reset */
1808 ControllerExtension
->TimerState
= IDETimerResetWaitForBusyNegate
;
1809 ControllerExtension
->TimerCount
= IDE_RESET_BUSY_TIMEOUT
;
1815 // Handle interrupts for IDE devices
1821 // IN PKINTERRUPT Interrupt The interrupt level in effect
1822 // IN PVOID ServiceContext The driver supplied context
1823 // (the controller extension)
1825 // TRUE This ISR handled the interrupt
1826 // FALSE Another ISR must handle this interrupt
1828 static BOOLEAN STDCALL
1829 IDEIsr(IN PKINTERRUPT Interrupt
,
1830 IN PVOID ServiceContext
)
1832 BOOLEAN IsLastBlock
, AnErrorOccured
, RequestIsComplete
;
1833 BYTE
*TargetAddress
;
1835 NTSTATUS ErrorStatus
;
1836 ULONG ErrorInformation
;
1838 PIDE_DEVICE_EXTENSION DeviceExtension
;
1839 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1841 if (IDEInitialized
== FALSE
)
1845 DPRINT ("IDEIsr called\n");
1847 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) ServiceContext
;
1849 // Read the status port to clear the interrtupt (even if it's not ours).
1850 ControllerExtension
->DeviceStatus
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1852 // If the interrupt is not ours, get the heck outta dodge.
1853 if (!ControllerExtension
->OperationInProgress
)
1858 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1859 IsLastBlock
= FALSE
;
1860 AnErrorOccured
= FALSE
;
1861 RequestIsComplete
= FALSE
;
1862 ErrorStatus
= STATUS_SUCCESS
;
1863 ErrorInformation
= 0;
1865 // Handle error condition if it exists
1866 if (ControllerExtension
->DeviceStatus
& IDE_SR_ERR
)
1868 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
1872 ErrorReg
= IDEReadError(ControllerExtension
->CommandPortBase
);
1873 CylinderLow
= IDEReadCylinderLow(ControllerExtension
->CommandPortBase
);
1874 CylinderHigh
= IDEReadCylinderHigh(ControllerExtension
->CommandPortBase
);
1875 DriveHead
= IDEReadDriveHead(ControllerExtension
->CommandPortBase
);
1876 SectorCount
= IDEReadSectorCount(ControllerExtension
->CommandPortBase
);
1877 SectorNum
= IDEReadSectorNum(ControllerExtension
->CommandPortBase
);
1878 // FIXME: should use the NT error logging facility
1879 DbgPrint ("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1880 DeviceExtension
->Operation
,
1881 ControllerExtension
->DeviceStatus
,
1888 // FIXME: should retry the command and perhaps recalibrate the drive
1890 // Set error status information
1891 AnErrorOccured
= TRUE
;
1892 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
1894 (((((((CylinderHigh
<< 8) + CylinderLow
) *
1895 DeviceExtension
->LogicalHeads
) +
1896 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
1897 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
1898 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
1903 // Check controller and setup for next transfer
1904 switch (DeviceExtension
->Operation
)
1908 // Update controller/device state variables
1909 TargetAddress
= DeviceExtension
->TargetAddress
;
1910 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1911 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1912 DeviceExtension
->SectorsTransferred
++;
1914 // Remember whether DRQ should be low at end (last block read)
1915 IsLastBlock
= DeviceExtension
->BytesToTransfer
== 0;
1917 // Wait for DRQ assertion
1918 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
1919 !(IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
);
1922 KeStallExecutionProcessor(10);
1925 // Copy the block of data
1926 IDEReadBlock(ControllerExtension
->CommandPortBase
,
1933 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1934 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1937 KeStallExecutionProcessor(10);
1940 // Check for data overrun
1941 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1943 AnErrorOccured
= TRUE
;
1944 ErrorStatus
= STATUS_DATA_OVERRUN
;
1945 ErrorInformation
= 0;
1950 // Setup next transfer or set RequestIsComplete
1951 if (DeviceExtension
->BytesRequested
>
1952 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1954 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1955 DeviceExtension
->SectorsTransferred
= 0;
1956 DeviceExtension
->BytesToTransfer
=
1957 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1958 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1960 else if (DeviceExtension
->BytesRequested
> 0)
1962 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1963 DeviceExtension
->SectorsTransferred
= 0;
1964 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1965 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1969 RequestIsComplete
= TRUE
;
1978 if (DeviceExtension
->BytesToTransfer
== 0)
1980 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1981 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1984 KeStallExecutionProcessor(10);
1987 // Check for data overrun
1988 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1990 AnErrorOccured
= TRUE
;
1991 ErrorStatus
= STATUS_DATA_OVERRUN
;
1992 ErrorInformation
= 0;
1997 // Setup next transfer or set RequestIsComplete
1999 if (DeviceExtension
->BytesRequested
>
2000 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
2002 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
2003 DeviceExtension
->SectorsTransferred
= 0;
2004 DeviceExtension
->BytesToTransfer
=
2005 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
2006 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2008 else if (DeviceExtension
->BytesRequested
> 0)
2010 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
2011 DeviceExtension
->SectorsTransferred
= 0;
2012 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
2013 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2017 RequestIsComplete
= TRUE
;
2024 // Update controller/device state variables
2025 TargetAddress
= DeviceExtension
->TargetAddress
;
2026 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
2027 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
2028 DeviceExtension
->SectorsTransferred
++;
2030 // Write block to controller
2031 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
2039 // If there was an error or the request is done, complete the packet
2040 if (AnErrorOccured
|| RequestIsComplete
)
2042 // Set the return status and info values
2043 Irp
= ControllerExtension
->CurrentIrp
;
2044 Irp
->IoStatus
.Status
= ErrorStatus
;
2045 Irp
->IoStatus
.Information
= ErrorInformation
;
2047 // Clear out controller fields
2048 ControllerExtension
->OperationInProgress
= FALSE
;
2049 ControllerExtension
->DeviceStatus
= 0;
2051 // Queue the Dpc to finish up
2052 IoRequestDpc(DeviceExtension
->DeviceObject
,
2054 ControllerExtension
);
2056 else if (IsLastBlock
)
2058 // Else more data is needed, setup next device I/O
2059 IDEStartController((PVOID
)DeviceExtension
);
2072 // IN PDEVICE_OBJECT DpcDeviceObject
2074 // IN PVOID DpcContext
2077 IDEDpcForIsr(IN PKDPC Dpc
,
2078 IN PDEVICE_OBJECT DpcDeviceObject
,
2080 IN PVOID DpcContext
)
2082 DPRINT("IDEDpcForIsr()\n");
2083 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION
) DpcContext
);
2086 // IDEFinishOperation
2089 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
2091 PIDE_DEVICE_EXTENSION DeviceExtension
;
2095 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
2096 Irp
= ControllerExtension
->CurrentIrp
;
2097 Operation
= DeviceExtension
->Operation
;
2098 ControllerExtension
->OperationInProgress
= FALSE
;
2099 ControllerExtension
->DeviceForOperation
= 0;
2100 ControllerExtension
->CurrentIrp
= 0;
2102 // Deallocate the controller
2103 IoFreeController(DeviceExtension
->ControllerObject
);
2105 // Start the next packet
2106 IoStartNextPacketByKey(DeviceExtension
->DeviceObject
,
2108 DeviceExtension
->StartingSector
);
2110 // Issue completion of the current packet
2111 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2113 // Flush cache if necessary
2114 if (Operation
== IRP_MJ_READ
)
2116 KeFlushIoBuffers(Irp
->MdlAddress
, TRUE
, FALSE
);
2122 // This function handles timeouts and other time delayed processing
2127 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
2128 // IN PVOID Context the Controller extension for the
2129 // controller the device is on
2132 IDEIoTimer(PDEVICE_OBJECT DeviceObject
,
2135 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
2137 // Setup Extension pointer
2138 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) Context
;
2139 DPRINT("Timer activated for %04lx\n", ControllerExtension
->CommandPortBase
);
2141 // Handle state change if necessary
2142 switch (ControllerExtension
->TimerState
)
2144 case IDETimerResetWaitForBusyNegate
:
2145 if (!(IDEReadStatus(ControllerExtension
->CommandPortBase
) &
2148 DPRINT("Busy line has negated, waiting for DRDY assert\n");
2149 ControllerExtension
->TimerState
= IDETimerResetWaitForDrdyAssert
;
2150 ControllerExtension
->TimerCount
= IDE_RESET_DRDY_TIMEOUT
;
2155 case IDETimerResetWaitForDrdyAssert
:
2156 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) &
2159 DPRINT("DRDY has asserted, reset complete\n");
2160 ControllerExtension
->TimerState
= IDETimerIdle
;
2161 ControllerExtension
->TimerCount
= 0;
2163 // FIXME: get diagnostic code from drive 0
2165 /* Start current packet command again */
2166 if (!KeSynchronizeExecution(ControllerExtension
->Interrupt
,
2168 ControllerExtension
->DeviceForOperation
))
2170 IDEFinishOperation(ControllerExtension
);
2180 // If we're counting down, then count.
2181 if (ControllerExtension
->TimerCount
> 0)
2183 ControllerExtension
->TimerCount
--;
2185 // Else we'll check the state and process if necessary
2189 switch (ControllerExtension
->TimerState
)
2194 case IDETimerCmdWait
:
2195 /* Command timed out, reset drive and try again or fail */
2196 DPRINT("Timeout waiting for command completion\n");
2197 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
2199 if (ControllerExtension
->CurrentIrp
!= NULL
)
2201 DbgPrint ("Max retries has been reached, IRP finished with error\n");
2202 ControllerExtension
->CurrentIrp
->IoStatus
.Status
= STATUS_IO_TIMEOUT
;
2203 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2204 IDEFinishOperation(ControllerExtension
);
2206 ControllerExtension
->TimerState
= IDETimerIdle
;
2207 ControllerExtension
->TimerCount
= 0;
2211 IDEBeginControllerReset(ControllerExtension
);
2215 case IDETimerResetWaitForBusyNegate
:
2216 case IDETimerResetWaitForDrdyAssert
:
2217 if (ControllerExtension
->CurrentIrp
!= NULL
)
2219 DbgPrint ("Timeout waiting for drive reset, giving up on IRP\n");
2220 ControllerExtension
->CurrentIrp
->IoStatus
.Status
=
2222 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2223 IDEFinishOperation(ControllerExtension
);
2225 ControllerExtension
->TimerState
= IDETimerIdle
;
2226 ControllerExtension
->TimerCount
= 0;