1 /* $Id: ide.c,v 1.47 2001/11/01 14:51: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 PCI controllers and up to 4 ISA controllers
9 * with up to 2 drives each.
10 * The device names are assigned as follows:
11 * \Devices\HarddiskX\Partition0
12 * for the raw device, and
13 * \Devices\HarddiskX\PartitionY
16 * X is computed by counting the available drives from the following
17 * sequence: the controller number (0=0x1f0, 1=0x170, 2=0x1e8,
18 * 3=0x168) * 2 plus the drive number (0,1)
19 * Y is the partition number
21 * The driver exports the following function:
23 * DriverEntry() - NT device driver initialization routine
25 * And the following functions are exported implicitly:
27 * IDEStartIo() - called to start an I/O request packet
28 * IDEDispatchOpenClose() - Called to open/close the device. a NOOP
29 * IDEDispatchReadWrite() - Called to read/write the device.
30 * IDEDispatchQueryInformation() - Called to get device information
31 * IDEDispatchSetInformation() - Called to set device information
32 * IDEDispatchDeviceControl() - Called to execute device control requests
34 * Modification History:
35 * 05/25/98 RJJ Created.
36 * 05/30/98 RJJ Removed IRQ handler and inserted busy waits
37 * just to get something working...
38 * 07/18/98 RJJ Made drastic changes so that the driver
39 * resembles a WinNT driver.
40 * 08/05/98 RJJ Changed to .C extension
41 * 09/19/98 RJJ First release (run for cover!)
44 * 09/17/98 RJJ Pri/MST: 14.12X19 WDC AC31000H Test Passed
49 * FIXME: a timer should be used to watch for device timeouts and errors
50 * FIXME: errors should be retried
51 * FIXME: a drive reset/recalibrate should be attempted if errors occur
52 * FIXME: Use DMA for transfers if drives support it
53 * FIXME: should we support unloading of this driver???
54 * FIXME: the device information should come from AUTODETECT (via registry)
55 * FIXME: really big devices need to be handled correctly
56 * FIXME: should get device info from the registry
57 * FIXME: should report hardware usage to iomgr
58 * FIXME: finish implementation of QueryInformation
59 * FIXME: finish implementation of SetInformation
60 * FIXME: finish implementation of DeviceControl
61 * FIXME: bring up to ATA-3 spec
62 * FIXME: add general support for ATAPI devices
63 * FIXME: add support for ATAPI CDROMs
64 * FIXME: add support for ATAPI ZIP drives/RHDs
65 * FIXME: add support for ATAPI tape drives
68 // -------------------------------------------------------------------------
70 #include <ddk/ntddk.h>
78 #define VERSION "V0.1.5"
80 // ------------------------------------------------------- File Static Data
83 typedef struct _IDE_CONTROLLER_PARAMETERS
92 KINTERRUPT_MODE InterruptMode
;
94 } IDE_CONTROLLER_PARAMETERS
, *PIDE_CONTROLLER_PARAMETERS
;
96 // NOTE: Do not increase max drives above 2
98 #define IDE_MAX_DRIVES 2
100 #define IDE_MAX_CONTROLLERS 2
101 IDE_CONTROLLER_PARAMETERS Controllers
[IDE_MAX_CONTROLLERS
] =
103 {0x01f0, 8, 0x03f6, 1, 14, 14, 15, LevelSensitive
, 0xffff},
104 {0x0170, 8, 0x0376, 1, 15, 15, 15, LevelSensitive
, 0xffff}
105 /* {0x01E8, 8, 0x03ee, 1, 11, 11, 15, LevelSensitive, 0xffff},
106 {0x0168, 8, 0x036e, 1, 10, 10, 15, LevelSensitive, 0xffff}*/
109 static BOOLEAN IDEInitialized
= FALSE
;
111 // ----------------------------------------------- Discardable Declarations
115 // make the initialization routines discardable, so that they
118 #pragma alloc_text(init, DriverEntry)
119 #pragma alloc_text(init, IDECreateController)
120 #pragma alloc_text(init, IDECreateDevices)
121 #pragma alloc_text(init, IDECreateDevice)
122 #pragma alloc_text(init, IDEPolledRead)
124 // make the PASSIVE_LEVEL routines pageable, so that they don't
125 // waste nonpaged memory
127 #pragma alloc_text(page, IDEShutdown)
128 #pragma alloc_text(page, IDEDispatchOpenClose)
129 #pragma alloc_text(page, IDEDispatchRead)
130 #pragma alloc_text(page, IDEDispatchWrite)
132 #endif /* ALLOC_PRAGMA */
134 // ---------------------------------------------------- Forward Declarations
137 IdeFindControllers(IN PDRIVER_OBJECT DriverObject
);
140 IdeCreateController(IN PDRIVER_OBJECT DriverObject
,
141 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
142 IN
int ControllerIdx
);
144 static BOOLEAN
IDEResetController(IN WORD CommandPort
, IN WORD ControlPort
);
145 static BOOLEAN
IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
146 IN PCONTROLLER_OBJECT ControllerObject
,
147 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
150 static BOOLEAN
IDEGetDriveIdentification(IN
int CommandPort
,
152 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
153 static NTSTATUS
IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject
,
154 OUT PDEVICE_OBJECT
*DeviceObject
,
155 IN PCONTROLLER_OBJECT ControllerObject
,
158 IN PIDE_DRIVE_IDENTIFY DrvParms
,
159 IN ULONG SectorCount
);
160 static NTSTATUS
IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject
,
161 OUT PDEVICE_OBJECT
*DeviceObject
,
162 IN PCONTROLLER_OBJECT ControllerObject
,
163 IN PVOID DiskDeviceExtension
,
166 IN PIDE_DRIVE_IDENTIFY DrvParms
,
167 IN PPARTITION_INFORMATION PartitionInfo
);
168 static int IDEPolledRead(IN WORD Address
,
173 IN BYTE CylinderHigh
,
177 static NTSTATUS STDCALL
IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
178 static NTSTATUS STDCALL
IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
179 static NTSTATUS STDCALL
IDEDispatchDeviceControl(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
180 static VOID STDCALL
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
);
181 static IO_ALLOCATION_ACTION STDCALL
182 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
184 IN PVOID MapRegisterBase
,
186 static BOOLEAN STDCALL
187 IDEStartController(IN OUT PVOID Context
);
188 VOID
IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
189 static BOOLEAN STDCALL
IDEIsr(IN PKINTERRUPT Interrupt
, IN PVOID ServiceContext
);
190 static VOID
IDEDpcForIsr(IN PKDPC Dpc
,
191 IN PDEVICE_OBJECT DpcDeviceObject
,
193 IN PVOID DpcContext
);
194 static VOID
IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
195 static VOID STDCALL
IDEIoTimer(PDEVICE_OBJECT DeviceObject
, PVOID Context
);
197 // ---------------------------------------------------------------- Inlines
200 IDESwapBytePairs(char *Buf
,
206 for (i
= 0; i
< Cnt
; i
+= 2)
214 // ------------------------------------------------------- Public Interface
219 // This function initializes the driver, locates and claims
220 // hardware resources, and creates various NT objects needed
221 // to process I/O requests.
227 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
229 // IN PUNICODE_STRING RegistryPath Name of registry driver service
236 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
237 IN PUNICODE_STRING RegistryPath
)
241 DbgPrint("IDE Driver %s\n", VERSION
);
243 /* Export other driver entry points... */
244 DriverObject
->DriverStartIo
= IDEStartIo
;
245 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = IDEDispatchOpenClose
;
246 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = IDEDispatchOpenClose
;
247 DriverObject
->MajorFunction
[IRP_MJ_READ
] = IDEDispatchReadWrite
;
248 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = IDEDispatchReadWrite
;
249 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
250 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
251 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = IDEDispatchDeviceControl
;
253 Status
= IdeFindControllers(DriverObject
);
254 if (NT_SUCCESS(Status
))
256 IDEInitialized
= TRUE
;
262 // ---------------------------------------------------- Discardable statics
265 IdeFindControllers(IN PDRIVER_OBJECT DriverObject
)
267 PCI_COMMON_CONFIG PciConfig
;
272 NTSTATUS ReturnedStatus
= STATUS_NO_SUCH_DEVICE
;
274 INT ControllerIdx
= 0;
275 PCONFIGURATION_INFORMATION ConfigInfo
;
277 DPRINT("IdeFindControllers() called!\n");
279 ConfigInfo
= IoGetConfigurationInformation();
281 /* Search PCI busses for IDE controllers */
282 for (Bus
= 0; Bus
< 8; Bus
++)
284 for (Slot
= 0; Slot
< 256; Slot
++)
286 Size
= HalGetBusData(PCIConfiguration
,
290 sizeof(PCI_COMMON_CONFIG
));
293 if ((PciConfig
.BaseClass
== 0x01) &&
294 (PciConfig
.SubClass
== 0x01))
296 DPRINT("IDE controller found!\n");
298 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
304 if ((PciConfig
.HeaderType
& 0x7FFFFFFF) == 0)
306 DPRINT(" IPR 0x%X ILR 0x%X\n",
307 PciConfig
.u
.type0
.InterruptPin
,
308 PciConfig
.u
.type0
.InterruptLine
);
311 if (PciConfig
.ProgIf
& 0x01)
313 DPRINT("Primary channel: PCI native mode\n");
317 DPRINT("Primary channel: Compatibility mode\n");
318 if (ConfigInfo
->AtDiskPrimaryAddressClaimed
== FALSE
)
320 Status
= IdeCreateController(DriverObject
,
323 if (NT_SUCCESS(Status
))
326 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
327 ConfigInfo
->ScsiPortCount
++;
328 ReturnedStatus
= Status
;
334 * FIXME: Switch controller to native pci mode
335 * if it is programmable.
339 if (PciConfig
.ProgIf
& 0x02)
341 DPRINT("Primary channel: programmable\n");
345 DPRINT("Primary channel: not programmable\n");
348 if (PciConfig
.ProgIf
& 0x04)
350 DPRINT("Secondary channel: PCI native mode\n");
354 DPRINT("Secondary channel: Compatibility mode\n");
355 if (ConfigInfo
->AtDiskSecondaryAddressClaimed
== FALSE
)
357 Status
= IdeCreateController(DriverObject
,
360 if (NT_SUCCESS(Status
))
363 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
364 ConfigInfo
->ScsiPortCount
++;
365 ReturnedStatus
= Status
;
371 * FIXME: Switch controller to native pci mode
372 * if it is programmable.
376 if (PciConfig
.ProgIf
& 0x08)
378 DPRINT("Secondary channel: programmable\n");
382 DPRINT("Secondary channel: not programmable\n");
385 if (PciConfig
.ProgIf
& 0x80)
387 DPRINT("Master IDE device: 1\n");
391 DPRINT("Master IDE device: 0\n");
394 for (i
= 0; i
< PCI_TYPE0_ADDRESSES
; i
++)
396 DPRINT("BaseAddress: 0x%08X\n", PciConfig
.u
.type0
.BaseAddresses
[i
]);
403 /* Search for ISA IDE controller if no primary controller was found */
404 if (ConfigInfo
->AtDiskPrimaryAddressClaimed
== FALSE
)
406 DPRINT("Searching for primary ISA IDE controller!\n");
408 if (IDEResetController(Controllers
[0].CommandPortBase
,
409 Controllers
[0].ControlPortBase
))
411 Status
= IdeCreateController(DriverObject
,
414 if (NT_SUCCESS(Status
))
416 DPRINT(" Found primary ISA IDE controller!\n");
418 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
419 ConfigInfo
->ScsiPortCount
++;
420 ReturnedStatus
= Status
;
425 /* Search for ISA IDE controller if no secondary controller was found */
426 if (ConfigInfo
->AtDiskSecondaryAddressClaimed
== FALSE
)
428 DPRINT("Searching for secondary ISA IDE controller!\n");
430 if (IDEResetController(Controllers
[1].CommandPortBase
,
431 Controllers
[1].ControlPortBase
))
433 Status
= IdeCreateController(DriverObject
,
436 if (NT_SUCCESS(Status
))
438 DPRINT(" Found secondary ISA IDE controller!\n");
440 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
441 ConfigInfo
->ScsiPortCount
++;
442 ReturnedStatus
= Status
;
447 DPRINT("IdeFindControllers() done!\n");
449 return(ReturnedStatus
);
453 // IdeCreateController
456 // Creates a controller object and a device object for each valid
457 // device on the controller
463 // IN PDRIVER_OBJECT DriverObject The system created driver object
464 // IN PIDE_CONTROLLER_PARAMETERS The parameter block for this
465 // ControllerParams controller
466 // IN int ControllerIdx The index of this controller
469 // TRUE Devices where found on this controller
470 // FALSE The controller does not respond or there are no devices on it
474 IdeCreateController(IN PDRIVER_OBJECT DriverObject
,
475 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
476 IN
int ControllerIdx
)
478 BOOLEAN CreatedDevices
, ThisDriveExists
;
481 PCONTROLLER_OBJECT ControllerObject
;
482 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
484 ControllerObject
= IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION
));
485 if (ControllerObject
== NULL
)
487 DbgPrint ("Could not create controller object for controller %d\n",
489 return STATUS_NO_SUCH_DEVICE
;
492 // Fill out Controller extension data
493 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
494 ControllerObject
->ControllerExtension
;
495 ControllerExtension
->Number
= ControllerIdx
;
496 ControllerExtension
->CommandPortBase
= ControllerParams
->CommandPortBase
;
497 ControllerExtension
->ControlPortBase
= ControllerParams
->ControlPortBase
;
498 ControllerExtension
->Vector
= ControllerParams
->Vector
;
499 ControllerExtension
->DMASupported
= FALSE
;
500 ControllerExtension
->ControllerInterruptBug
= FALSE
;
501 ControllerExtension
->OperationInProgress
= FALSE
;
503 // Initialize the spin lock in the controller extension
504 KeInitializeSpinLock(&ControllerExtension
->SpinLock
);
506 // Register an interrupt handler for this controller
507 RC
= IoConnectInterrupt(&ControllerExtension
->Interrupt
,
510 &ControllerExtension
->SpinLock
,
511 ControllerExtension
->Vector
,
512 ControllerParams
->IrqL
,
513 ControllerParams
->SynchronizeIrqL
,
514 ControllerParams
->InterruptMode
,
516 ControllerParams
->Affinity
,
520 DbgPrint ("Could not Connect Interrupt %d\n",
521 ControllerExtension
->Vector
);
522 IoDeleteController (ControllerObject
);
527 IDEInitialized
= TRUE
;
529 // Create device objects for each raw device (and for partitions)
530 CreatedDevices
= FALSE
;
531 for (DriveIdx
= 0; DriveIdx
< IDE_MAX_DRIVES
; DriveIdx
++)
533 ThisDriveExists
= IDECreateDevices(DriverObject
,
537 ControllerIdx
* 2 + DriveIdx
);
540 CreatedDevices
= TRUE
;
546 DbgPrint ("Did not find any devices for controller %d\n",
548 IoDisconnectInterrupt (ControllerExtension
->Interrupt
);
549 IoDeleteController (ControllerObject
);
553 IDEResetController(ControllerParams
->CommandPortBase
,
554 ControllerParams
->ControlPortBase
);
555 IoStartTimer(ControllerExtension
->TimerDevice
);
558 return((CreatedDevices
== TRUE
)?STATUS_SUCCESS
:STATUS_NO_SUCH_DEVICE
);
562 // IDEResetController
565 // Reset the controller and report completion status
571 // IN WORD CommandPort The address of the command port
572 // IN WORD ControlPort The address of the control port
578 IDEResetController(IN WORD CommandPort
,
583 // Assert drive reset line
584 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
586 // Wait for min. 25 microseconds
587 KeStallExecutionProcessor(IDE_RESET_PULSE_LENGTH
);
589 // Negate drive reset line
590 IDEWriteDriveControl(ControlPort
, 0);
592 // Wait for BUSY negation
593 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
595 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
599 KeStallExecutionProcessor(10);
602 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
607 // return TRUE if controller came back to life. and
608 // the registers are initialized correctly
609 return IDEReadError(CommandPort
) == 1;
616 // Create the raw device and any partition devices on this drive
622 // IN PDRIVER_OBJECT DriverObject The system created driver object
623 // IN PCONTROLLER_OBJECT ControllerObject
624 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
625 // The IDE controller extension for
627 // IN int DriveIdx The index of the drive on this
629 // IN int HarddiskIdx The NT device number for this
633 // TRUE Drive exists and devices were created
634 // FALSE no devices were created for this device
638 IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
639 IN PCONTROLLER_OBJECT ControllerObject
,
640 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
644 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
647 IDE_DRIVE_IDENTIFY DrvParms
;
648 PDEVICE_OBJECT DiskDeviceObject
;
649 PDEVICE_OBJECT PartitionDeviceObject
;
650 PIDE_DEVICE_EXTENSION DiskDeviceExtension
;
651 UNICODE_STRING UnicodeDeviceDirName
;
652 OBJECT_ATTRIBUTES DeviceDirAttributes
;
654 ULONG SectorCount
= 0;
655 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
656 PPARTITION_INFORMATION PartitionEntry
;
659 /* Copy I/O port offsets for convenience */
660 CommandPort
= ControllerExtension
->CommandPortBase
;
661 // ControlPort = ControllerExtension->ControlPortBase;
662 DPRINT("probing IDE controller %d Addr %04lx Drive %d\n",
663 ControllerExtension
->Number
,
667 /* Get the Drive Identification Data */
668 if (!IDEGetDriveIdentification(CommandPort
, DriveIdx
, &DrvParms
))
670 DbgPrint("No ATA drive %d found on controller %d...\n",
672 ControllerExtension
->Number
);
676 /* Create the harddisk device directory */
677 swprintf (NameBuffer
,
678 L
"\\Device\\Harddisk%d",
680 RtlInitUnicodeString(&UnicodeDeviceDirName
,
682 InitializeObjectAttributes(&DeviceDirAttributes
,
683 &UnicodeDeviceDirName
,
687 Status
= ZwCreateDirectoryObject(&Handle
, 0, &DeviceDirAttributes
);
688 if (!NT_SUCCESS(Status
))
690 DbgPrint("Could not create device dir object\n");
694 /* Create the disk device */
695 if (DrvParms
.Capabilities
& IDE_DRID_LBA_SUPPORTED
)
698 (ULONG
)((DrvParms
.TMSectorCountHi
<< 16) + DrvParms
.TMSectorCountLo
);
703 (ULONG
)(DrvParms
.LogicalCyls
* DrvParms
.LogicalHeads
* DrvParms
.SectorsPerTrack
);
705 DPRINT("SectorCount %lu\n", SectorCount
);
707 Status
= IDECreateDiskDevice(DriverObject
,
714 if (!NT_SUCCESS(Status
))
716 DbgPrint("IDECreateDevice call failed for raw device\n");
720 /* Increase number of available physical disk drives */
721 IoGetConfigurationInformation()->DiskCount
++;
724 * Initialize the controller timer here
725 * (since it has to be tied to a device)
729 ControllerExtension
->TimerState
= IDETimerIdle
;
730 ControllerExtension
->TimerCount
= 0;
731 ControllerExtension
->TimerDevice
= DiskDeviceObject
;
732 IoInitializeTimer(DiskDeviceObject
,
734 ControllerExtension
);
737 DPRINT("DrvParms.BytesPerSector %ld\n",DrvParms
.BytesPerSector
);
739 /* Read partition table */
740 Status
= IoReadPartitionTable(DiskDeviceObject
,
741 DrvParms
.BytesPerSector
,
744 if (!NT_SUCCESS(Status
))
746 DbgPrint("IoReadPartitionTable() failed\n");
750 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
751 for (i
=0;i
< PartitionList
->PartitionCount
; i
++)
753 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
755 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
757 PartitionEntry
->PartitionNumber
,
758 PartitionEntry
->BootIndicator
,
759 PartitionEntry
->PartitionType
,
760 PartitionEntry
->StartingOffset
.QuadPart
/ DrvParms
.BytesPerSector
,
761 PartitionEntry
->PartitionLength
.QuadPart
/ DrvParms
.BytesPerSector
);
763 /* Create device for partition */
764 Status
= IDECreatePartitionDevice(DriverObject
,
765 &PartitionDeviceObject
,
767 DiskDeviceObject
->DeviceExtension
,
772 if (!NT_SUCCESS(Status
))
774 DbgPrint("IDECreateDevice() failed\n");
779 if (PartitionList
!= NULL
)
780 ExFreePool(PartitionList
);
785 // IDEGetDriveIdentification
788 // Get the identification block from the drive
794 // IN int CommandPort Address of the command port
795 // IN int DriveNum The drive index (0,1)
796 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
799 // TRUE The drive identification block was retrieved successfully
803 IDEGetDriveIdentification(IN
int CommandPort
,
805 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
808 /* Get the Drive Identify block from drive or die */
809 if (IDEPolledRead(CommandPort
, 0, 0, 0, 0, 0, (DriveNum
? IDE_DH_DRV1
: 0),
810 IDE_CMD_IDENT_DRV
, (BYTE
*)DrvParms
) != 0)
815 /* Report on drive parameters if debug mode */
816 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
817 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
818 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
819 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
820 DrvParms
->ConfigBits
,
821 DrvParms
->LogicalCyls
,
822 DrvParms
->LogicalHeads
,
823 DrvParms
->SectorsPerTrack
,
824 DrvParms
->InterSectorGap
,
825 DrvParms
->InterSectorGapSize
);
826 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
827 DrvParms
->BytesInPLO
,
828 DrvParms
->VendorUniqueCnt
,
829 DrvParms
->SerialNumber
);
830 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
831 DrvParms
->ControllerType
,
832 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
833 DrvParms
->ECCByteCnt
,
834 DrvParms
->FirmwareRev
);
835 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
836 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
837 (DrvParms
->RWMultImplemented
) & 0xff,
838 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
839 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
840 DrvParms
->MinPIOTransTime
,
841 DrvParms
->MinDMATransTime
);
842 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
843 DrvParms
->TMCylinders
,
845 DrvParms
->TMSectorsPerTrk
,
846 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
847 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
848 DrvParms
->TMSectorCountHi
,
849 DrvParms
->TMSectorCountLo
,
850 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
853 * Fix default ATA sector size.
854 * Attention: Default ATAPI sector size is 2048 bytes!!
856 if (DrvParms
->BytesPerSector
== 0)
857 DrvParms
->BytesPerSector
= 512;
858 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
864 // IDECreateDiskDevice
867 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
873 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
874 // OUT PDEVICE_OBJECT *DeviceObject The created device object
875 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
876 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
877 // IN BOOLEAN DMASupported Does the drive support DMA?
878 // IN int SectorsPerLogCyl Sectors per cylinder
879 // IN int SectorsPerLogTrk Sectors per track
880 // IN DWORD Offset First valid sector for this device
881 // IN DWORD Size Count of valid sectors for this device
888 IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject
,
889 OUT PDEVICE_OBJECT
*DeviceObject
,
890 IN PCONTROLLER_OBJECT ControllerObject
,
893 IN PIDE_DRIVE_IDENTIFY DrvParms
,
894 IN ULONG SectorCount
)
896 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
897 WCHAR ArcNameBuffer
[IDE_MAX_NAME_LENGTH
+ 15];
898 UNICODE_STRING DeviceName
;
899 UNICODE_STRING ArcName
;
901 PIDE_DEVICE_EXTENSION DeviceExtension
;
903 /* Create a unicode device name */
905 L
"\\Device\\Harddisk%d\\Partition0",
907 RtlInitUnicodeString(&DeviceName
,
910 /* Create the device */
911 RC
= IoCreateDevice(DriverObject
,
912 sizeof(IDE_DEVICE_EXTENSION
),
920 DbgPrint("IoCreateDevice call failed\n");
924 /* Set the buffering strategy here... */
925 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
926 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
928 /* Fill out Device extension data */
929 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) (*DeviceObject
)->DeviceExtension
;
930 DeviceExtension
->DeviceObject
= (*DeviceObject
);
931 DeviceExtension
->ControllerObject
= ControllerObject
;
932 DeviceExtension
->DiskDeviceExtension
= DeviceExtension
;
933 DeviceExtension
->UnitNumber
= UnitNumber
;
934 DeviceExtension
->LBASupported
=
935 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
936 DeviceExtension
->DMASupported
=
937 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
938 DeviceExtension
->BytesPerSector
= DrvParms
->BytesPerSector
;
939 DeviceExtension
->SectorsPerLogCyl
=
940 DrvParms
->LogicalHeads
* DrvParms
->SectorsPerTrack
;
941 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
942 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
943 DeviceExtension
->LogicalCylinders
=
944 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? DrvParms
->TMCylinders
: DrvParms
->LogicalCyls
;
945 DeviceExtension
->Offset
= 0;
946 DeviceExtension
->Size
= SectorCount
;
947 DPRINT("%wZ: offset %lu size %lu \n",
949 DeviceExtension
->Offset
,
950 DeviceExtension
->Size
);
952 /* Initialize the DPC object here */
953 IoInitializeDpcRequest(*DeviceObject
,
956 /* assign arc name */
957 swprintf(ArcNameBuffer
,
958 L
"\\ArcName\\multi(0)disk(0)rdisk(%d)",
960 RtlInitUnicodeString(&ArcName
,
962 DPRINT("%wZ ==> %wZ\n", &ArcName
, &DeviceName
);
963 RC
= IoAssignArcName(&ArcName
,
967 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName
, RC
);
974 // IDECreatePartitionDevice
977 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
983 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
984 // OUT PDEVICE_OBJECT *DeviceObject The created device object
985 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
986 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
987 // IN BOOLEAN DMASupported Does the drive support DMA?
988 // IN int SectorsPerLogCyl Sectors per cylinder
989 // IN int SectorsPerLogTrk Sectors per track
990 // IN DWORD Offset First valid sector for this device
991 // IN DWORD Size Count of valid sectors for this device
998 IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject
,
999 OUT PDEVICE_OBJECT
*DeviceObject
,
1000 IN PCONTROLLER_OBJECT ControllerObject
,
1001 IN PVOID DiskDeviceExtension
,
1003 IN ULONG DiskNumber
,
1004 IN PIDE_DRIVE_IDENTIFY DrvParms
,
1005 IN PPARTITION_INFORMATION PartitionInfo
)
1007 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
1008 WCHAR ArcNameBuffer
[IDE_MAX_NAME_LENGTH
+ 15];
1009 UNICODE_STRING DeviceName
;
1010 UNICODE_STRING ArcName
;
1012 PIDE_DEVICE_EXTENSION DeviceExtension
;
1014 // Create a unicode device name
1015 swprintf(NameBuffer
,
1016 L
"\\Device\\Harddisk%d\\Partition%d",
1018 PartitionInfo
->PartitionNumber
);
1019 RtlInitUnicodeString(&DeviceName
,
1022 // Create the device
1023 RC
= IoCreateDevice(DriverObject
, sizeof(IDE_DEVICE_EXTENSION
),
1024 &DeviceName
, FILE_DEVICE_DISK
, 0, TRUE
, DeviceObject
);
1025 if (!NT_SUCCESS(RC
))
1027 DbgPrint ("IoCreateDevice call failed\n");
1031 // Set the buffering strategy here...
1032 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
1033 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1035 // Fill out Device extension data
1036 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) (*DeviceObject
)->DeviceExtension
;
1037 DeviceExtension
->DeviceObject
= (*DeviceObject
);
1038 DeviceExtension
->ControllerObject
= ControllerObject
;
1039 DeviceExtension
->DiskDeviceExtension
= DiskDeviceExtension
;
1040 DeviceExtension
->UnitNumber
= UnitNumber
;
1041 DeviceExtension
->LBASupported
=
1042 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
1043 DeviceExtension
->DMASupported
=
1044 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
1045 // FIXME: deal with bizarre sector sizes
1046 DeviceExtension
->BytesPerSector
= 512 /* DrvParms->BytesPerSector */;
1047 DeviceExtension
->SectorsPerLogCyl
= DrvParms
->LogicalHeads
*
1048 DrvParms
->SectorsPerTrack
;
1049 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
1050 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
1051 DeviceExtension
->LogicalCylinders
=
1052 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? DrvParms
->TMCylinders
: DrvParms
->LogicalCyls
;
1053 // DeviceExtension->Offset = Offset;
1054 // DeviceExtension->Size = Size;
1056 DeviceExtension
->Offset
= PartitionInfo
->StartingOffset
.QuadPart
/ 512; /* DrvParms.BytesPerSector*/
1057 DeviceExtension
->Size
= PartitionInfo
->PartitionLength
.QuadPart
/ 512; /*DrvParms.BytesPerSector*/
1059 DPRINT("%wZ: offset %lu size %lu \n",
1061 DeviceExtension
->Offset
,
1062 DeviceExtension
->Size
);
1064 /* Initialize the DPC object here */
1065 IoInitializeDpcRequest(*DeviceObject
, IDEDpcForIsr
);
1067 DbgPrint("%wZ %luMB\n", &DeviceName
, DeviceExtension
->Size
/ 2048);
1069 /* assign arc name */
1070 swprintf(ArcNameBuffer
,
1071 L
"\\ArcName\\multi(0)disk(0)rdisk(%d)partition(%d)",
1073 PartitionInfo
->PartitionNumber
);
1074 RtlInitUnicodeString(&ArcName
,
1076 DPRINT("%wZ ==> %wZ\n", &ArcName
, &DeviceName
);
1077 RC
= IoAssignArcName(&ArcName
,
1079 if (!NT_SUCCESS(RC
))
1081 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName
, RC
);
1091 // Read a sector of data from the drive in a polled fashion.
1097 // IN WORD Address Address of command port for drive
1098 // IN BYTE PreComp Value to write to precomp register
1099 // IN BYTE SectorCnt Value to write to sectorCnt register
1100 // IN BYTE SectorNum Value to write to sectorNum register
1101 // IN BYTE CylinderLow Value to write to CylinderLow register
1102 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1103 // IN BYTE DrvHead Value to write to Drive/Head register
1104 // IN BYTE Command Value to write to Command register
1105 // OUT BYTE *Buffer Buffer for output data
1108 // int 0 is success, non 0 is an error code
1112 IDEPolledRead(IN WORD Address
,
1116 IN BYTE CylinderLow
,
1117 IN BYTE CylinderHigh
,
1125 /* Wait for STATUS.BUSY to clear */
1126 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1128 Status
= IDEReadStatus(Address
);
1129 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1133 KeStallExecutionProcessor(10);
1135 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1140 /* Write Drive/Head to select drive */
1141 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1143 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1144 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1146 Status
= IDEReadStatus(Address
);
1147 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1151 KeStallExecutionProcessor(10);
1153 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1158 /* Issue command to drive */
1159 if (DrvHead
& IDE_DH_LBA
)
1161 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1162 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1163 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1169 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1170 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1179 /* Setup command parameters */
1180 IDEWritePrecomp(Address
, PreComp
);
1181 IDEWriteSectorCount(Address
, SectorCnt
);
1182 IDEWriteSectorNum(Address
, SectorNum
);
1183 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1184 IDEWriteCylinderLow(Address
, CylinderLow
);
1185 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1187 /* Issue the command */
1188 IDEWriteCommand(Address
, Command
);
1189 KeStallExecutionProcessor(50);
1193 /* wait for DRQ or error */
1194 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1196 Status
= IDEReadStatus(Address
);
1197 if (!(Status
& IDE_SR_BUSY
))
1199 if (Status
& IDE_SR_DRQ
)
1208 KeStallExecutionProcessor(10);
1210 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1215 /* Read data into buffer */
1216 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1217 Buffer
+= IDE_SECTOR_BUF_SZ
;
1219 /* Check for more sectors to read */
1220 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1222 Status
= IDEReadStatus(Address
);
1223 if (!(Status
& IDE_SR_BUSY
))
1225 if (Status
& IDE_SR_DRQ
)
1238 // ------------------------------------------- Nondiscardable statics
1240 // IDEDispatchOpenClose
1243 // Answer requests for Open/Close calls: a null operation
1249 // Standard dispatch arguments
1255 static NTSTATUS STDCALL
1256 IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
,
1259 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1260 Irp
->IoStatus
.Information
= FILE_OPENED
;
1261 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1263 return STATUS_SUCCESS
;
1266 // IDEDispatchReadWrite
1269 // Answer requests for reads and writes
1275 // Standard dispatch arguments
1282 STDCALL
IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
,
1286 LARGE_INTEGER AdjustedOffset
, AdjustedExtent
, PartitionExtent
, InsertKeyLI
;
1287 PIO_STACK_LOCATION IrpStack
;
1288 PIDE_DEVICE_EXTENSION DeviceExtension
;
1290 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1291 DeviceExtension
= (PIDE_DEVICE_EXTENSION
)pDO
->DeviceExtension
;
1293 // Validate operation parameters
1294 AdjustedOffset
= RtlEnlargedIntegerMultiply(DeviceExtension
->Offset
,
1295 DeviceExtension
->BytesPerSector
);
1296 DPRINT("Offset:%ld * BytesPerSector:%ld = AdjOffset:%ld:%ld\n",
1297 DeviceExtension
->Offset
,
1298 DeviceExtension
->BytesPerSector
,
1299 (unsigned long) AdjustedOffset
.u
.HighPart
,
1300 (unsigned long) AdjustedOffset
.u
.LowPart
);
1301 DPRINT("AdjOffset:%ld:%ld + ByteOffset:%ld:%ld\n",
1302 (unsigned long) AdjustedOffset
.u
.HighPart
,
1303 (unsigned long) AdjustedOffset
.u
.LowPart
,
1304 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.u
.HighPart
,
1305 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.u
.LowPart
);
1306 AdjustedOffset
= RtlLargeIntegerAdd(AdjustedOffset
,
1307 IrpStack
->Parameters
.Read
.ByteOffset
);
1308 DPRINT(" = AdjOffset:%ld:%ld\n",
1309 (unsigned long) AdjustedOffset
.u
.HighPart
,
1310 (unsigned long) AdjustedOffset
.u
.LowPart
);
1311 AdjustedExtent
= RtlLargeIntegerAdd(AdjustedOffset
,
1312 RtlConvertLongToLargeInteger(IrpStack
->Parameters
.Read
.Length
));
1313 DPRINT("AdjOffset:%ld:%ld + Length:%ld = AdjExtent:%ld:%ld\n",
1314 (unsigned long) AdjustedOffset
.u
.HighPart
,
1315 (unsigned long) AdjustedOffset
.u
.LowPart
,
1316 IrpStack
->Parameters
.Read
.Length
,
1317 (unsigned long) AdjustedExtent
.u
.HighPart
,
1318 (unsigned long) AdjustedExtent
.u
.LowPart
);
1319 /*FIXME: this assumption will fail on drives bigger than 1TB */
1320 PartitionExtent
.QuadPart
= DeviceExtension
->Offset
+ DeviceExtension
->Size
;
1321 PartitionExtent
= RtlExtendedIntegerMultiply(PartitionExtent
,
1322 DeviceExtension
->BytesPerSector
);
1323 if ((AdjustedExtent
.QuadPart
> PartitionExtent
.QuadPart
) ||
1324 (IrpStack
->Parameters
.Read
.Length
& (DeviceExtension
->BytesPerSector
- 1)))
1326 DPRINT("Request failed on bad parameters\n",0);
1327 DPRINT("AdjustedExtent=%d:%d PartitionExtent=%d:%d ReadLength=%d\n",
1328 (unsigned int) AdjustedExtent
.u
.HighPart
,
1329 (unsigned int) AdjustedExtent
.u
.LowPart
,
1330 (unsigned int) PartitionExtent
.u
.HighPart
,
1331 (unsigned int) PartitionExtent
.u
.LowPart
,
1332 IrpStack
->Parameters
.Read
.Length
);
1333 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1334 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1335 return STATUS_INVALID_PARAMETER
;
1338 // Adjust operation to absolute sector offset
1339 IrpStack
->Parameters
.Read
.ByteOffset
= AdjustedOffset
;
1341 // Start the packet and insert the request in order of sector offset
1342 assert(DeviceExtension
->BytesPerSector
== 512);
1343 InsertKeyLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1344 IrpInsertKey
= InsertKeyLI
.u
.LowPart
;
1345 IoStartPacket(DeviceExtension
->DeviceObject
, Irp
, &IrpInsertKey
, NULL
);
1347 DPRINT("Returning STATUS_PENDING\n");
1348 return STATUS_PENDING
;
1351 // IDEDispatchDeviceControl
1354 // Answer requests for device control calls
1360 // Standard dispatch arguments
1366 static NTSTATUS STDCALL
1367 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1371 ULONG ControlCode
, InputLength
, OutputLength
;
1372 PIO_STACK_LOCATION IrpStack
;
1373 PIDE_DEVICE_EXTENSION DeviceExtension
;
1374 PIDE_DEVICE_EXTENSION DiskDeviceExtension
;
1377 RC
= STATUS_SUCCESS
;
1378 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1379 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1380 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1381 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1382 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1383 DiskDeviceExtension
= (PIDE_DEVICE_EXTENSION
)DeviceExtension
->DiskDeviceExtension
;
1384 Increment
= IO_NO_INCREMENT
;
1386 // A huge switch statement in a Windows program?! who would have thought?
1387 switch (ControlCode
)
1389 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1390 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1392 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1396 PDISK_GEOMETRY Geometry
;
1398 Geometry
= (PDISK_GEOMETRY
) Irp
->AssociatedIrp
.SystemBuffer
;
1400 Geometry
->MediaType
= FixedMedia
;
1401 Geometry
->Cylinders
.QuadPart
= DiskDeviceExtension
->LogicalCylinders
;
1402 Geometry
->TracksPerCylinder
= DiskDeviceExtension
->SectorsPerLogCyl
/
1403 DiskDeviceExtension
->SectorsPerLogTrk
;
1404 Geometry
->SectorsPerTrack
= DiskDeviceExtension
->SectorsPerLogTrk
;
1405 Geometry
->BytesPerSector
= DiskDeviceExtension
->BytesPerSector
;
1407 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1408 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1412 case IOCTL_DISK_GET_PARTITION_INFO
:
1413 case IOCTL_DISK_SET_PARTITION_INFO
:
1414 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1415 Irp
->IoStatus
.Status
= RC
;
1416 Irp
->IoStatus
.Information
= 0;
1419 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1420 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1421 sizeof(DRIVE_LAYOUT_INFORMATION
))
1423 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1427 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1429 RC
= IoReadPartitionTable(DiskDeviceExtension
->DeviceObject
,
1430 DiskDeviceExtension
->BytesPerSector
,
1433 if (!NT_SUCCESS(RC
))
1435 Irp
->IoStatus
.Status
= RC
;
1441 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
1443 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
1445 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1447 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1451 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1454 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1455 Irp
->IoStatus
.Information
= BufferSize
;
1457 ExFreePool(PartitionList
);
1460 Increment
= IO_DISK_INCREMENT
;
1463 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1464 case IOCTL_DISK_VERIFY
:
1465 case IOCTL_DISK_FORMAT_TRACKS
:
1466 case IOCTL_DISK_PERFORMANCE
:
1467 case IOCTL_DISK_IS_WRITABLE
:
1468 case IOCTL_DISK_LOGGING
:
1469 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1470 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1471 case IOCTL_DISK_HISTOGRAM_DATA
:
1472 case IOCTL_DISK_HISTOGRAM_RESET
:
1473 case IOCTL_DISK_REQUEST_STRUCTURE
:
1474 case IOCTL_DISK_REQUEST_DATA
:
1476 // If we get here, something went wrong. inform the requestor
1478 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1479 Irp
->IoStatus
.Status
= RC
;
1480 Irp
->IoStatus
.Information
= 0;
1484 IoCompleteRequest(Irp
, Increment
);
1492 // Get the next requested I/O packet started
1498 // Dispatch routine standard arguments
1505 STDCALL
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
,
1508 LARGE_INTEGER SectorLI
;
1509 PIO_STACK_LOCATION IrpStack
;
1510 PIDE_DEVICE_EXTENSION DeviceExtension
;
1513 DPRINT("IDEStartIo() called!\n");
1515 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1516 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1518 // FIXME: implement the supported functions
1520 switch (IrpStack
->MajorFunction
)
1524 DeviceExtension
->Operation
= IrpStack
->MajorFunction
;
1525 DeviceExtension
->BytesRequested
= IrpStack
->Parameters
.Read
.Length
;
1526 assert(DeviceExtension
->BytesPerSector
== 512);
1527 SectorLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1528 DeviceExtension
->StartingSector
= SectorLI
.u
.LowPart
;
1529 if (DeviceExtension
->BytesRequested
> DeviceExtension
->BytesPerSector
*
1530 IDE_MAX_SECTORS_PER_XFER
)
1532 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesPerSector
*
1533 IDE_MAX_SECTORS_PER_XFER
;
1537 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1539 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1540 DeviceExtension
->SectorsTransferred
= 0;
1541 DeviceExtension
->TargetAddress
= (BYTE
*)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1542 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1543 IoAllocateController(DeviceExtension
->ControllerObject
,
1545 IDEAllocateController
,
1547 KeLowerIrql(OldIrql
);
1551 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1552 Irp
->IoStatus
.Information
= 0;
1553 KeBugCheck((ULONG
)Irp
);
1554 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1555 IoStartNextPacket(DeviceObject
, FALSE
);
1558 DPRINT("IDEStartIo() finished!\n");
1561 // IDEAllocateController
1563 static IO_ALLOCATION_ACTION STDCALL
1564 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
1566 IN PVOID MapRegisterBase
,
1569 PIDE_DEVICE_EXTENSION DeviceExtension
;
1570 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1572 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1573 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1574 DeviceExtension
->ControllerObject
->ControllerExtension
;
1575 ControllerExtension
->CurrentIrp
= Irp
;
1576 ControllerExtension
->Retries
= 0;
1577 return KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1579 DeviceExtension
) ? KeepObject
:
1583 // IDEStartController
1586 IDEStartController(IN OUT PVOID Context
)
1588 BYTE SectorCnt
, SectorNum
, CylinderLow
, CylinderHigh
;
1589 BYTE DrvHead
, Command
;
1592 ULONG StartingSector
;
1593 PIDE_DEVICE_EXTENSION DeviceExtension
;
1594 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1597 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) Context
;
1598 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1599 DeviceExtension
->ControllerObject
->ControllerExtension
;
1600 ControllerExtension
->OperationInProgress
= TRUE
;
1601 ControllerExtension
->DeviceForOperation
= DeviceExtension
;
1603 // Write controller registers to start opteration
1604 StartingSector
= DeviceExtension
->StartingSector
;
1605 SectorCnt
= DeviceExtension
->BytesToTransfer
/
1606 DeviceExtension
->BytesPerSector
;
1607 if (DeviceExtension
->LBASupported
)
1609 SectorNum
= StartingSector
& 0xff;
1610 CylinderLow
= (StartingSector
>> 8) & 0xff;
1611 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1612 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1613 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0) |
1618 SectorNum
= (StartingSector
% DeviceExtension
->SectorsPerLogTrk
) + 1;
1619 StartingSector
/= DeviceExtension
->SectorsPerLogTrk
;
1620 DrvHead
= (StartingSector
% DeviceExtension
->LogicalHeads
) |
1621 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0);
1622 StartingSector
/= DeviceExtension
->LogicalHeads
;
1623 CylinderLow
= StartingSector
& 0xff;
1624 CylinderHigh
= StartingSector
>> 8;
1626 Command
= DeviceExtension
->Operation
== IRP_MJ_READ
?
1627 IDE_CMD_READ
: IDE_CMD_WRITE
;
1628 if (DrvHead
& IDE_DH_LBA
)
1630 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1631 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1632 ControllerExtension
->CommandPortBase
,
1633 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1634 ((DrvHead
& 0x0f) << 24) +
1635 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1641 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1642 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1643 ControllerExtension
->CommandPortBase
,
1644 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1653 /* wait for BUSY to clear */
1654 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1656 Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1657 if (!(Status
& IDE_SR_BUSY
))
1661 KeStallExecutionProcessor(10);
1663 DPRINT ("status=%02x\n", Status
);
1664 DPRINT ("waited %ld usecs for busy to clear\n", Retries
* 10);
1665 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1667 DPRINT ("Drive is BUSY for too long\n");
1668 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1670 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1671 Irp
= ControllerExtension
->CurrentIrp
;
1672 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1673 Irp
->IoStatus
.Information
= 0;
1679 DPRINT ("Beginning drive reset sequence\n");
1680 IDEBeginControllerReset(ControllerExtension
);
1686 /* Select the desired drive */
1687 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1689 /* wait for BUSY to clear and DRDY to assert */
1690 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1692 Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1693 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1697 KeStallExecutionProcessor(10);
1699 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1700 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1702 DPRINT ("Drive is BUSY for too long after drive select\n");
1703 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1705 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1706 Irp
= ControllerExtension
->CurrentIrp
;
1707 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1708 Irp
->IoStatus
.Information
= 0;
1714 DPRINT ("Beginning drive reset sequence\n");
1715 IDEBeginControllerReset(ControllerExtension
);
1721 /* Setup command parameters */
1722 IDEWritePrecomp(ControllerExtension
->CommandPortBase
, 0);
1723 IDEWriteSectorCount(ControllerExtension
->CommandPortBase
, SectorCnt
);
1724 IDEWriteSectorNum(ControllerExtension
->CommandPortBase
, SectorNum
);
1725 IDEWriteCylinderHigh(ControllerExtension
->CommandPortBase
, CylinderHigh
);
1726 IDEWriteCylinderLow(ControllerExtension
->CommandPortBase
, CylinderLow
);
1727 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1729 /* Issue command to drive */
1730 IDEWriteCommand(ControllerExtension
->CommandPortBase
, Command
);
1731 ControllerExtension
->TimerState
= IDETimerCmdWait
;
1732 ControllerExtension
->TimerCount
= IDE_CMD_TIMEOUT
;
1734 if (DeviceExtension
->Operation
== IRP_MJ_WRITE
)
1737 // Wait for controller ready
1738 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
1740 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1741 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
1745 KeStallExecutionProcessor(10);
1747 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1749 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1751 Irp
= ControllerExtension
->CurrentIrp
;
1752 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1753 Irp
->IoStatus
.Information
= 0;
1759 IDEBeginControllerReset(ControllerExtension
);
1765 // Load the first sector of data into the controller
1766 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1767 DeviceExtension
->TargetAddress
,
1769 DeviceExtension
->TargetAddress
+= IDE_SECTOR_BUF_SZ
;
1770 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1771 DeviceExtension
->SectorsTransferred
++;
1773 DPRINT ("Command issued to drive, IDEStartController done\n");
1778 // IDEBeginControllerReset
1781 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1785 DPRINT("Controller Reset initiated on %04x\n",
1786 ControllerExtension
->ControlPortBase
);
1788 /* Assert drive reset line */
1789 DPRINT("Asserting reset line\n");
1790 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, IDE_DC_SRST
);
1792 /* Wait for BSY assertion */
1793 DPRINT("Waiting for BSY assertion\n");
1794 for (Retries
= 0; Retries
< IDE_MAX_RESET_RETRIES
; Retries
++)
1796 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1797 if ((Status
& IDE_SR_BUSY
))
1801 KeStallExecutionProcessor(10);
1803 if (Retries
== IDE_MAX_RESET_RETRIES
)
1805 DPRINT("Timeout on BSY assertion\n");
1808 /* Negate drive reset line */
1809 DPRINT("Negating reset line\n");
1810 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, 0);
1812 // FIXME: handle case of no device 0
1814 /* Set timer to check for end of reset */
1815 ControllerExtension
->TimerState
= IDETimerResetWaitForBusyNegate
;
1816 ControllerExtension
->TimerCount
= IDE_RESET_BUSY_TIMEOUT
;
1822 // Handle interrupts for IDE devices
1828 // IN PKINTERRUPT Interrupt The interrupt level in effect
1829 // IN PVOID ServiceContext The driver supplied context
1830 // (the controller extension)
1832 // TRUE This ISR handled the interrupt
1833 // FALSE Another ISR must handle this interrupt
1835 static BOOLEAN STDCALL
1836 IDEIsr(IN PKINTERRUPT Interrupt
,
1837 IN PVOID ServiceContext
)
1839 BOOLEAN IsLastBlock
, AnErrorOccured
, RequestIsComplete
;
1840 BYTE
*TargetAddress
;
1842 NTSTATUS ErrorStatus
;
1843 ULONG ErrorInformation
;
1845 PIDE_DEVICE_EXTENSION DeviceExtension
;
1846 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1848 if (IDEInitialized
== FALSE
)
1852 DPRINT ("IDEIsr called\n");
1854 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) ServiceContext
;
1856 // Read the status port to clear the interrtupt (even if it's not ours).
1857 ControllerExtension
->DeviceStatus
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1859 // If the interrupt is not ours, get the heck outta dodge.
1860 if (!ControllerExtension
->OperationInProgress
)
1865 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1866 IsLastBlock
= FALSE
;
1867 AnErrorOccured
= FALSE
;
1868 RequestIsComplete
= FALSE
;
1869 ErrorStatus
= STATUS_SUCCESS
;
1870 ErrorInformation
= 0;
1872 // Handle error condition if it exists
1873 if (ControllerExtension
->DeviceStatus
& IDE_SR_ERR
)
1875 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
1879 ErrorReg
= IDEReadError(ControllerExtension
->CommandPortBase
);
1880 CylinderLow
= IDEReadCylinderLow(ControllerExtension
->CommandPortBase
);
1881 CylinderHigh
= IDEReadCylinderHigh(ControllerExtension
->CommandPortBase
);
1882 DriveHead
= IDEReadDriveHead(ControllerExtension
->CommandPortBase
);
1883 SectorCount
= IDEReadSectorCount(ControllerExtension
->CommandPortBase
);
1884 SectorNum
= IDEReadSectorNum(ControllerExtension
->CommandPortBase
);
1885 // FIXME: should use the NT error logging facility
1886 DbgPrint ("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1887 DeviceExtension
->Operation
,
1888 ControllerExtension
->DeviceStatus
,
1895 // FIXME: should retry the command and perhaps recalibrate the drive
1897 // Set error status information
1898 AnErrorOccured
= TRUE
;
1899 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
1901 (((((((CylinderHigh
<< 8) + CylinderLow
) *
1902 DeviceExtension
->LogicalHeads
) +
1903 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
1904 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
1905 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
1910 // Check controller and setup for next transfer
1911 switch (DeviceExtension
->Operation
)
1915 // Update controller/device state variables
1916 TargetAddress
= DeviceExtension
->TargetAddress
;
1917 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1918 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1919 DeviceExtension
->SectorsTransferred
++;
1921 // Remember whether DRQ should be low at end (last block read)
1922 IsLastBlock
= DeviceExtension
->BytesToTransfer
== 0;
1924 // Wait for DRQ assertion
1925 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
1926 !(IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
);
1929 KeStallExecutionProcessor(10);
1932 // Copy the block of data
1933 IDEReadBlock(ControllerExtension
->CommandPortBase
,
1940 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1941 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1944 KeStallExecutionProcessor(10);
1947 // Check for data overrun
1948 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1950 AnErrorOccured
= TRUE
;
1951 ErrorStatus
= STATUS_DATA_OVERRUN
;
1952 ErrorInformation
= 0;
1957 // Setup next transfer or set RequestIsComplete
1958 if (DeviceExtension
->BytesRequested
>
1959 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1961 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1962 DeviceExtension
->SectorsTransferred
= 0;
1963 DeviceExtension
->BytesToTransfer
=
1964 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1965 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1967 else if (DeviceExtension
->BytesRequested
> 0)
1969 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1970 DeviceExtension
->SectorsTransferred
= 0;
1971 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1972 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1976 RequestIsComplete
= TRUE
;
1985 if (DeviceExtension
->BytesToTransfer
== 0)
1987 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1988 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1991 KeStallExecutionProcessor(10);
1994 // Check for data overrun
1995 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1997 AnErrorOccured
= TRUE
;
1998 ErrorStatus
= STATUS_DATA_OVERRUN
;
1999 ErrorInformation
= 0;
2004 // Setup next transfer or set RequestIsComplete
2006 if (DeviceExtension
->BytesRequested
>
2007 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
2009 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
2010 DeviceExtension
->SectorsTransferred
= 0;
2011 DeviceExtension
->BytesToTransfer
=
2012 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
2013 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2015 else if (DeviceExtension
->BytesRequested
> 0)
2017 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
2018 DeviceExtension
->SectorsTransferred
= 0;
2019 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
2020 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2024 RequestIsComplete
= TRUE
;
2031 // Update controller/device state variables
2032 TargetAddress
= DeviceExtension
->TargetAddress
;
2033 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
2034 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
2035 DeviceExtension
->SectorsTransferred
++;
2037 // Write block to controller
2038 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
2046 // If there was an error or the request is done, complete the packet
2047 if (AnErrorOccured
|| RequestIsComplete
)
2049 // Set the return status and info values
2050 Irp
= ControllerExtension
->CurrentIrp
;
2051 Irp
->IoStatus
.Status
= ErrorStatus
;
2052 Irp
->IoStatus
.Information
= ErrorInformation
;
2054 // Clear out controller fields
2055 ControllerExtension
->OperationInProgress
= FALSE
;
2056 ControllerExtension
->DeviceStatus
= 0;
2058 // Queue the Dpc to finish up
2059 IoRequestDpc(DeviceExtension
->DeviceObject
,
2061 ControllerExtension
);
2063 else if (IsLastBlock
)
2065 // Else more data is needed, setup next device I/O
2066 IDEStartController((PVOID
)DeviceExtension
);
2079 // IN PDEVICE_OBJECT DpcDeviceObject
2081 // IN PVOID DpcContext
2084 IDEDpcForIsr(IN PKDPC Dpc
,
2085 IN PDEVICE_OBJECT DpcDeviceObject
,
2087 IN PVOID DpcContext
)
2089 DPRINT("IDEDpcForIsr()\n");
2090 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION
) DpcContext
);
2093 // IDEFinishOperation
2096 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
2098 PIDE_DEVICE_EXTENSION DeviceExtension
;
2102 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
2103 Irp
= ControllerExtension
->CurrentIrp
;
2104 Operation
= DeviceExtension
->Operation
;
2105 ControllerExtension
->OperationInProgress
= FALSE
;
2106 ControllerExtension
->DeviceForOperation
= 0;
2107 ControllerExtension
->CurrentIrp
= 0;
2109 // Deallocate the controller
2110 IoFreeController(DeviceExtension
->ControllerObject
);
2112 // Start the next packet
2113 IoStartNextPacketByKey(DeviceExtension
->DeviceObject
,
2115 DeviceExtension
->StartingSector
);
2117 // Issue completion of the current packet
2118 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2120 // Flush cache if necessary
2121 if (Operation
== IRP_MJ_READ
)
2123 KeFlushIoBuffers(Irp
->MdlAddress
, TRUE
, FALSE
);
2129 // This function handles timeouts and other time delayed processing
2134 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
2135 // IN PVOID Context the Controller extension for the
2136 // controller the device is on
2139 IDEIoTimer(PDEVICE_OBJECT DeviceObject
,
2142 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
2144 // Setup Extension pointer
2145 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) Context
;
2146 DPRINT("Timer activated for %04lx\n", ControllerExtension
->CommandPortBase
);
2148 // Handle state change if necessary
2149 switch (ControllerExtension
->TimerState
)
2151 case IDETimerResetWaitForBusyNegate
:
2152 if (!(IDEReadStatus(ControllerExtension
->CommandPortBase
) &
2155 DPRINT("Busy line has negated, waiting for DRDY assert\n");
2156 ControllerExtension
->TimerState
= IDETimerResetWaitForDrdyAssert
;
2157 ControllerExtension
->TimerCount
= IDE_RESET_DRDY_TIMEOUT
;
2162 case IDETimerResetWaitForDrdyAssert
:
2163 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) &
2166 DPRINT("DRDY has asserted, reset complete\n");
2167 ControllerExtension
->TimerState
= IDETimerIdle
;
2168 ControllerExtension
->TimerCount
= 0;
2170 // FIXME: get diagnostic code from drive 0
2172 /* Start current packet command again */
2173 if (!KeSynchronizeExecution(ControllerExtension
->Interrupt
,
2175 ControllerExtension
->DeviceForOperation
))
2177 IDEFinishOperation(ControllerExtension
);
2187 // If we're counting down, then count.
2188 if (ControllerExtension
->TimerCount
> 0)
2190 ControllerExtension
->TimerCount
--;
2192 // Else we'll check the state and process if necessary
2196 switch (ControllerExtension
->TimerState
)
2201 case IDETimerCmdWait
:
2202 /* Command timed out, reset drive and try again or fail */
2203 DPRINT("Timeout waiting for command completion\n");
2204 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
2206 if (ControllerExtension
->CurrentIrp
!= NULL
)
2208 DbgPrint ("Max retries has been reached, IRP finished with error\n");
2209 ControllerExtension
->CurrentIrp
->IoStatus
.Status
= STATUS_IO_TIMEOUT
;
2210 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2211 IDEFinishOperation(ControllerExtension
);
2213 ControllerExtension
->TimerState
= IDETimerIdle
;
2214 ControllerExtension
->TimerCount
= 0;
2218 IDEBeginControllerReset(ControllerExtension
);
2222 case IDETimerResetWaitForBusyNegate
:
2223 case IDETimerResetWaitForDrdyAssert
:
2224 if (ControllerExtension
->CurrentIrp
!= NULL
)
2226 DbgPrint ("Timeout waiting for drive reset, giving up on IRP\n");
2227 ControllerExtension
->CurrentIrp
->IoStatus
.Status
=
2229 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2230 IDEFinishOperation(ControllerExtension
);
2232 ControllerExtension
->TimerState
= IDETimerIdle
;
2233 ControllerExtension
->TimerCount
= 0;