1 /* $Id: ide.c,v 1.60 2004/02/10 16:22:55 navaraf 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 /* uncomment the following line to enable the secondary ide channel */
81 //#define ENABLE_SECONDARY_IDE_CHANNEL
83 // ------------------------------------------------------- File Static Data
86 typedef struct _IDE_CONTROLLER_PARAMETERS
93 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, Latched
},
104 {0x0170, 8, 0x0376, 1, 15, Latched
}
105 /* {0x01E8, 8, 0x03ee, 1, 11, LevelSensitive},
106 {0x0168, 8, 0x036e, 1, 10, LevelSensitive}*/
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 DPRINT("IDE Driver %s\n", VERSION
);
243 /* Export other driver entry points... */
244 DriverObject
->DriverStartIo
= IDEStartIo
;
245 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = (PDRIVER_DISPATCH
)IDEDispatchOpenClose
;
246 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = (PDRIVER_DISPATCH
)IDEDispatchOpenClose
;
247 DriverObject
->MajorFunction
[IRP_MJ_READ
] = (PDRIVER_DISPATCH
)IDEDispatchReadWrite
;
248 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = (PDRIVER_DISPATCH
)IDEDispatchReadWrite
;
249 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)IDEDispatchQueryInformation;
250 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)IDEDispatchSetInformation;
251 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = (PDRIVER_DISPATCH
)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
;
271 NTSTATUS ReturnedStatus
= STATUS_NO_SUCH_DEVICE
;
273 INT ControllerIdx
= 0;
274 PCONFIGURATION_INFORMATION ConfigInfo
;
276 DPRINT("IdeFindControllers() called!\n");
278 ConfigInfo
= IoGetConfigurationInformation();
280 /* Search PCI busses for IDE controllers */
281 for (Bus
= 0; Bus
< 8; Bus
++)
283 for (Slot
= 0; Slot
< 256; Slot
++)
285 Size
= HalGetBusData(PCIConfiguration
,
289 sizeof(PCI_COMMON_CONFIG
));
292 if ((PciConfig
.BaseClass
== 0x01) &&
293 (PciConfig
.SubClass
== 0x01))
295 DPRINT("IDE controller found!\n");
297 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
303 if ((PciConfig
.HeaderType
& 0x7FFFFFFF) == 0)
305 DPRINT(" IPR 0x%X ILR 0x%X\n",
306 PciConfig
.u
.type0
.InterruptPin
,
307 PciConfig
.u
.type0
.InterruptLine
);
310 if (PciConfig
.ProgIf
& 0x01)
312 DPRINT("Primary channel: PCI native mode\n");
316 DPRINT("Primary channel: Compatibility mode\n");
317 if (ConfigInfo
->AtDiskPrimaryAddressClaimed
== FALSE
)
319 Status
= IdeCreateController(DriverObject
,
322 if (NT_SUCCESS(Status
))
325 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
326 ConfigInfo
->ScsiPortCount
++;
327 ReturnedStatus
= Status
;
333 * FIXME: Switch controller to native pci mode
334 * if it is programmable.
338 if (PciConfig
.ProgIf
& 0x02)
340 DPRINT("Primary channel: programmable\n");
344 DPRINT("Primary channel: not programmable\n");
347 #ifdef ENABLE_SECONDARY_IDE_CHANNEL
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
]);
404 /* Search for ISA IDE controller if no primary controller was found */
405 if (ConfigInfo
->AtDiskPrimaryAddressClaimed
== FALSE
)
407 DPRINT("Searching for primary ISA IDE controller!\n");
409 if (IDEResetController(Controllers
[0].CommandPortBase
,
410 Controllers
[0].ControlPortBase
))
412 Status
= IdeCreateController(DriverObject
,
415 if (NT_SUCCESS(Status
))
417 DPRINT(" Found primary ISA IDE controller!\n");
419 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
420 ConfigInfo
->ScsiPortCount
++;
421 ReturnedStatus
= Status
;
426 /* Search for ISA IDE controller if no secondary controller was found */
427 #ifdef ENABLE_SECONDARY_IDE_CHANNEL
428 if (ConfigInfo
->AtDiskSecondaryAddressClaimed
== FALSE
)
430 DPRINT("Searching for secondary ISA IDE controller!\n");
432 if (IDEResetController(Controllers
[1].CommandPortBase
,
433 Controllers
[1].ControlPortBase
))
435 Status
= IdeCreateController(DriverObject
,
438 if (NT_SUCCESS(Status
))
440 DPRINT(" Found secondary ISA IDE controller!\n");
442 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
443 ConfigInfo
->ScsiPortCount
++;
444 ReturnedStatus
= Status
;
450 DPRINT("IdeFindControllers() done!\n");
452 return(ReturnedStatus
);
456 // IdeCreateController
459 // Creates a controller object and a device object for each valid
460 // device on the controller
466 // IN PDRIVER_OBJECT DriverObject The system created driver object
467 // IN PIDE_CONTROLLER_PARAMETERS The parameter block for this
468 // ControllerParams controller
469 // IN int ControllerIdx The index of this controller
472 // TRUE Devices where found on this controller
473 // FALSE The controller does not respond or there are no devices on it
477 IdeCreateController(IN PDRIVER_OBJECT DriverObject
,
478 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
479 IN
int ControllerIdx
)
481 BOOLEAN CreatedDevices
, ThisDriveExists
;
484 PCONTROLLER_OBJECT ControllerObject
;
485 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
490 ControllerObject
= IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION
));
491 if (ControllerObject
== NULL
)
493 DbgPrint ("Could not create controller object for controller %d\n",
495 return STATUS_NO_SUCH_DEVICE
;
498 MappedIrq
= HalGetInterruptVector(Isa
,
500 ControllerParams
->Vector
,
501 ControllerParams
->Vector
,
505 // Fill out Controller extension data
506 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
507 ControllerObject
->ControllerExtension
;
508 ControllerExtension
->Number
= ControllerIdx
;
509 ControllerExtension
->CommandPortBase
= ControllerParams
->CommandPortBase
;
510 ControllerExtension
->ControlPortBase
= ControllerParams
->ControlPortBase
;
511 ControllerExtension
->Vector
= MappedIrq
;
512 ControllerExtension
->DMASupported
= FALSE
;
513 ControllerExtension
->ControllerInterruptBug
= FALSE
;
514 ControllerExtension
->OperationInProgress
= FALSE
;
516 // Initialize the spin lock in the controller extension
517 KeInitializeSpinLock(&ControllerExtension
->SpinLock
);
519 // Register an interrupt handler for this controller
520 RC
= IoConnectInterrupt(&ControllerExtension
->Interrupt
,
523 &ControllerExtension
->SpinLock
,
524 ControllerExtension
->Vector
,
527 ControllerParams
->InterruptMode
,
533 DbgPrint ("Could not Connect Interrupt %d\n",
534 ControllerExtension
->Vector
);
535 IoDeleteController (ControllerObject
);
540 IDEInitialized
= TRUE
;
542 // Create device objects for each raw device (and for partitions)
543 CreatedDevices
= FALSE
;
544 for (DriveIdx
= 0; DriveIdx
< IDE_MAX_DRIVES
; DriveIdx
++)
546 ThisDriveExists
= IDECreateDevices(DriverObject
,
550 ControllerIdx
* 2 + DriveIdx
);
553 CreatedDevices
= TRUE
;
559 DbgPrint ("Did not find any devices for controller %d\n",
561 IoDisconnectInterrupt (ControllerExtension
->Interrupt
);
562 IoDeleteController (ControllerObject
);
566 IDEResetController(ControllerParams
->CommandPortBase
,
567 ControllerParams
->ControlPortBase
);
568 IoStartTimer(ControllerExtension
->TimerDevice
);
571 return((CreatedDevices
== TRUE
)?STATUS_SUCCESS
:STATUS_NO_SUCH_DEVICE
);
575 // IDEResetController
578 // Reset the controller and report completion status
584 // IN WORD CommandPort The address of the command port
585 // IN WORD ControlPort The address of the control port
591 IDEResetController(IN WORD CommandPort
,
596 // Assert drive reset line
597 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
599 // Wait for min. 25 microseconds
600 KeStallExecutionProcessor(IDE_RESET_PULSE_LENGTH
);
602 // Negate drive reset line
603 IDEWriteDriveControl(ControlPort
, 0);
605 // Wait for BUSY negation
606 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
608 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
612 KeStallExecutionProcessor(10);
615 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
620 // return TRUE if controller came back to life. and
621 // the registers are initialized correctly
622 return IDEReadError(CommandPort
) == 1;
629 // Create the raw device and any partition devices on this drive
635 // IN PDRIVER_OBJECT DriverObject The system created driver object
636 // IN PCONTROLLER_OBJECT ControllerObject
637 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
638 // The IDE controller extension for
640 // IN int DriveIdx The index of the drive on this
642 // IN int HarddiskIdx The NT device number for this
646 // TRUE Drive exists and devices were created
647 // FALSE no devices were created for this device
651 IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
652 IN PCONTROLLER_OBJECT ControllerObject
,
653 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
657 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
660 IDE_DRIVE_IDENTIFY DrvParms
;
661 PDEVICE_OBJECT DiskDeviceObject
;
662 PDEVICE_OBJECT PartitionDeviceObject
;
663 UNICODE_STRING UnicodeDeviceDirName
;
664 OBJECT_ATTRIBUTES DeviceDirAttributes
;
666 ULONG SectorCount
= 0;
667 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
668 PPARTITION_INFORMATION PartitionEntry
;
671 /* Copy I/O port offsets for convenience */
672 CommandPort
= ControllerExtension
->CommandPortBase
;
673 // ControlPort = ControllerExtension->ControlPortBase;
674 DPRINT("probing IDE controller %d Addr %04lx Drive %d\n",
675 ControllerExtension
->Number
,
679 /* Get the Drive Identification Data */
680 if (!IDEGetDriveIdentification(CommandPort
, DriveIdx
, &DrvParms
))
682 DPRINT("No ATA drive %d found on controller %d...\n",
684 ControllerExtension
->Number
);
688 DPRINT("Found ATA drive %d on controller %d...\n",
690 ControllerExtension
->Number
);
692 /* Create the harddisk device directory */
693 swprintf (NameBuffer
,
694 L
"\\Device\\Harddisk%d",
696 RtlInitUnicodeString(&UnicodeDeviceDirName
,
698 InitializeObjectAttributes(&DeviceDirAttributes
,
699 &UnicodeDeviceDirName
,
703 Status
= ZwCreateDirectoryObject(&Handle
, 0, &DeviceDirAttributes
);
704 if (!NT_SUCCESS(Status
))
706 DbgPrint("Could not create device dir object\n");
710 /* Create the disk device */
711 if (DrvParms
.Capabilities
& IDE_DRID_LBA_SUPPORTED
)
714 (ULONG
)((DrvParms
.TMSectorCountHi
<< 16) + DrvParms
.TMSectorCountLo
);
719 (ULONG
)(DrvParms
.LogicalCyls
* DrvParms
.LogicalHeads
* DrvParms
.SectorsPerTrack
);
721 DPRINT("SectorCount %lu\n", SectorCount
);
723 Status
= IDECreateDiskDevice(DriverObject
,
730 if (!NT_SUCCESS(Status
))
732 DbgPrint("IDECreateDevice call failed for raw device\n");
736 /* Increase number of available physical disk drives */
737 IoGetConfigurationInformation()->DiskCount
++;
740 * Initialize the controller timer here
741 * (since it has to be tied to a device)
745 ControllerExtension
->TimerState
= IDETimerIdle
;
746 ControllerExtension
->TimerCount
= 0;
747 ControllerExtension
->TimerDevice
= DiskDeviceObject
;
748 IoInitializeTimer(DiskDeviceObject
,
750 ControllerExtension
);
753 DPRINT("DrvParms.BytesPerSector %ld\n",DrvParms
.BytesPerSector
);
755 /* Read partition table */
756 Status
= IoReadPartitionTable(DiskDeviceObject
,
757 DrvParms
.BytesPerSector
,
760 if (!NT_SUCCESS(Status
))
762 DbgPrint("IoReadPartitionTable() failed\n");
766 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
767 for (i
=0;i
< PartitionList
->PartitionCount
; i
++)
769 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
771 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
773 PartitionEntry
->PartitionNumber
,
774 PartitionEntry
->BootIndicator
,
775 PartitionEntry
->PartitionType
,
776 PartitionEntry
->StartingOffset
.QuadPart
/ DrvParms
.BytesPerSector
,
777 PartitionEntry
->PartitionLength
.QuadPart
/ DrvParms
.BytesPerSector
);
779 /* Create device for partition */
780 Status
= IDECreatePartitionDevice(DriverObject
,
781 &PartitionDeviceObject
,
783 DiskDeviceObject
->DeviceExtension
,
788 if (!NT_SUCCESS(Status
))
790 DbgPrint("IDECreateDevice() failed\n");
795 if (PartitionList
!= NULL
)
796 ExFreePool(PartitionList
);
801 // IDEGetDriveIdentification
804 // Get the identification block from the drive
810 // IN int CommandPort Address of the command port
811 // IN int DriveNum The drive index (0,1)
812 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
815 // TRUE The drive identification block was retrieved successfully
819 IDEGetDriveIdentification(IN
int CommandPort
,
821 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
824 /* Get the Drive Identify block from drive or die */
825 if (IDEPolledRead(CommandPort
, 0, 1, 0, 0, 0, (DriveNum
? IDE_DH_DRV1
: 0),
826 IDE_CMD_IDENT_DRV
, (BYTE
*)DrvParms
) != 0)
831 /* Report on drive parameters if debug mode */
832 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
833 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
834 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
835 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
836 DrvParms
->ConfigBits
,
837 DrvParms
->LogicalCyls
,
838 DrvParms
->LogicalHeads
,
839 DrvParms
->SectorsPerTrack
,
840 DrvParms
->InterSectorGap
,
841 DrvParms
->InterSectorGapSize
);
842 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
843 DrvParms
->BytesInPLO
,
844 DrvParms
->VendorUniqueCnt
,
845 DrvParms
->SerialNumber
);
846 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
847 DrvParms
->ControllerType
,
848 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
849 DrvParms
->ECCByteCnt
,
850 DrvParms
->FirmwareRev
);
851 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
852 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
853 (DrvParms
->RWMultImplemented
) & 0xff,
854 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
855 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
856 DrvParms
->MinPIOTransTime
,
857 DrvParms
->MinDMATransTime
);
858 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
859 DrvParms
->TMCylinders
,
861 DrvParms
->TMSectorsPerTrk
,
862 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
863 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
864 DrvParms
->TMSectorCountHi
,
865 DrvParms
->TMSectorCountLo
,
866 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
869 * Fix default ATA sector size.
870 * Attention: Default ATAPI sector size is 2048 bytes!!
872 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
873 DrvParms
->BytesPerSector
= 512;
874 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
880 // IDECreateDiskDevice
883 // Creates the disk device object
889 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
890 // OUT PDEVICE_OBJECT *DeviceObject The created device object
891 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
892 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
893 // IN BOOLEAN DMASupported Does the drive support DMA?
894 // IN int SectorsPerLogCyl Sectors per cylinder
895 // IN int SectorsPerLogTrk Sectors per track
896 // IN DWORD Offset First valid sector for this device
897 // IN DWORD Size Count of valid sectors for this device
904 IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject
,
905 OUT PDEVICE_OBJECT
*DeviceObject
,
906 IN PCONTROLLER_OBJECT ControllerObject
,
909 IN PIDE_DRIVE_IDENTIFY DrvParms
,
910 IN ULONG SectorCount
)
912 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
913 UNICODE_STRING DeviceName
;
915 PIDE_DEVICE_EXTENSION DeviceExtension
;
917 /* Create a unicode device name */
919 L
"\\Device\\Harddisk%d\\Partition0",
921 RtlInitUnicodeString(&DeviceName
,
924 /* Create the device */
925 RC
= IoCreateDevice(DriverObject
,
926 sizeof(IDE_DEVICE_EXTENSION
),
934 DbgPrint("IoCreateDevice call failed\n");
938 /* Set the buffering strategy here... */
939 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
940 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
942 /* Fill out Device extension data */
943 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) (*DeviceObject
)->DeviceExtension
;
944 DeviceExtension
->DeviceObject
= (*DeviceObject
);
945 DeviceExtension
->ControllerObject
= ControllerObject
;
946 DeviceExtension
->DiskDeviceExtension
= DeviceExtension
;
947 DeviceExtension
->UnitNumber
= UnitNumber
;
948 DeviceExtension
->LBASupported
=
949 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
950 DeviceExtension
->DMASupported
=
951 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
952 DeviceExtension
->BytesPerSector
= DrvParms
->BytesPerSector
;
953 DeviceExtension
->SectorsPerLogCyl
=
954 DrvParms
->LogicalHeads
* DrvParms
->SectorsPerTrack
;
955 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
956 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
957 DeviceExtension
->LogicalCylinders
=
958 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? DrvParms
->TMCylinders
: DrvParms
->LogicalCyls
;
960 DeviceExtension
->StartingOffset
.QuadPart
= 0;
961 DeviceExtension
->PartitionLength
.QuadPart
= (ULONGLONG
)SectorCount
*
962 (ULONGLONG
)DrvParms
->BytesPerSector
;
963 DeviceExtension
->HiddenSectors
= 0;
964 DeviceExtension
->PartitionNumber
= 0;
965 DeviceExtension
->PartitionType
= 0;
966 DeviceExtension
->BootIndicator
= FALSE
;
968 DPRINT("%wZ: offset %I64d length %I64d\n",
970 DeviceExtension
->StartingOffset
.QuadPart
,
971 DeviceExtension
->PartitionLength
.QuadPart
);
973 /* Initialize the DPC object here */
974 IoInitializeDpcRequest(*DeviceObject
,
981 // IDECreatePartitionDevice
984 // Creates a partition device object
990 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
991 // OUT PDEVICE_OBJECT *DeviceObject The created device object
992 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
993 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
994 // IN BOOLEAN DMASupported Does the drive support DMA?
995 // IN int SectorsPerLogCyl Sectors per cylinder
996 // IN int SectorsPerLogTrk Sectors per track
997 // IN DWORD Offset First valid sector for this device
998 // IN DWORD Size Count of valid sectors for this device
1005 IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject
,
1006 OUT PDEVICE_OBJECT
*DeviceObject
,
1007 IN PCONTROLLER_OBJECT ControllerObject
,
1008 IN PVOID DiskDeviceExtension
,
1010 IN ULONG DiskNumber
,
1011 IN PIDE_DRIVE_IDENTIFY DrvParms
,
1012 IN PPARTITION_INFORMATION PartitionInfo
)
1014 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
1015 UNICODE_STRING DeviceName
;
1017 PIDE_DEVICE_EXTENSION DeviceExtension
;
1019 /* Create a unicode device name */
1020 swprintf(NameBuffer
,
1021 L
"\\Device\\Harddisk%d\\Partition%d",
1023 PartitionInfo
->PartitionNumber
);
1024 RtlInitUnicodeString(&DeviceName
,
1027 /* Create the device */
1028 RC
= IoCreateDevice(DriverObject
, sizeof(IDE_DEVICE_EXTENSION
),
1029 &DeviceName
, FILE_DEVICE_DISK
, 0, TRUE
, DeviceObject
);
1030 if (!NT_SUCCESS(RC
))
1032 DbgPrint ("IoCreateDevice call failed\n");
1036 /* Set the buffering strategy here... */
1037 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
1038 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1040 /* Fill out Device extension data */
1041 DeviceExtension
= (PIDE_DEVICE_EXTENSION
)(*DeviceObject
)->DeviceExtension
;
1042 DeviceExtension
->DeviceObject
= (*DeviceObject
);
1043 DeviceExtension
->ControllerObject
= ControllerObject
;
1044 DeviceExtension
->DiskDeviceExtension
= DiskDeviceExtension
;
1045 DeviceExtension
->UnitNumber
= UnitNumber
;
1046 DeviceExtension
->LBASupported
=
1047 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
1048 DeviceExtension
->DMASupported
=
1049 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
1050 DeviceExtension
->BytesPerSector
= DrvParms
->BytesPerSector
;
1051 DeviceExtension
->SectorsPerLogCyl
= DrvParms
->LogicalHeads
*
1052 DrvParms
->SectorsPerTrack
;
1053 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
1054 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
1055 DeviceExtension
->LogicalCylinders
=
1056 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? DrvParms
->TMCylinders
: DrvParms
->LogicalCyls
;
1058 DeviceExtension
->StartingOffset
= PartitionInfo
->StartingOffset
;
1059 DeviceExtension
->PartitionLength
= PartitionInfo
->PartitionLength
;
1060 DeviceExtension
->HiddenSectors
= PartitionInfo
->HiddenSectors
;
1061 DeviceExtension
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
1062 DeviceExtension
->PartitionType
= PartitionInfo
->PartitionType
;
1063 DeviceExtension
->BootIndicator
= PartitionInfo
->BootIndicator
;
1065 DPRINT("%wZ: offset %I64d size %I64d\n",
1067 DeviceExtension
->StartingOffset
.QuadPart
,
1068 DeviceExtension
->PartitionLength
.QuadPart
);
1070 /* Initialize the DPC object here */
1071 IoInitializeDpcRequest(*DeviceObject
, IDEDpcForIsr
);
1073 DPRINT("%wZ %I64dMB\n",
1075 DeviceExtension
->PartitionLength
.QuadPart
>> 20);
1084 // Read a sector of data from the drive in a polled fashion.
1090 // IN WORD Address Address of command port for drive
1091 // IN BYTE PreComp Value to write to precomp register
1092 // IN BYTE SectorCnt Value to write to sectorCnt register
1093 // IN BYTE SectorNum Value to write to sectorNum register
1094 // IN BYTE CylinderLow Value to write to CylinderLow register
1095 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1096 // IN BYTE DrvHead Value to write to Drive/Head register
1097 // IN BYTE Command Value to write to Command register
1098 // OUT BYTE *Buffer Buffer for output data
1101 // int 0 is success, non 0 is an error code
1105 IDEPolledRead(IN WORD Address
,
1109 IN BYTE CylinderLow
,
1110 IN BYTE CylinderHigh
,
1117 BOOLEAN ReadJunk
= FALSE
;
1118 ULONG SectorCount
= 0;
1120 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1121 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1123 Status
= IDEReadStatus(Address
);
1124 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1128 KeStallExecutionProcessor(10);
1130 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1135 /* Write Drive/Head to select drive */
1136 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1138 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1139 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1141 Status
= IDEReadStatus(Address
);
1142 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1146 KeStallExecutionProcessor(10);
1148 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1153 /* Issue command to drive */
1154 if (DrvHead
& IDE_DH_LBA
)
1156 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1157 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1158 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1164 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1165 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1174 /* Setup command parameters */
1175 IDEWritePrecomp(Address
, PreComp
);
1176 IDEWriteSectorCount(Address
, SectorCnt
);
1177 IDEWriteSectorNum(Address
, SectorNum
);
1178 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1179 IDEWriteCylinderLow(Address
, CylinderLow
);
1180 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1182 /* Issue the command */
1183 IDEWriteCommand(Address
, Command
);
1184 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_ERR
)
1194 DPRINT("IDE_SR_ERR asserted!\n");
1196 if ((Status
& IDE_SR_DRQ
) && !(Status
& IDE_SR_ERR
))
1205 KeStallExecutionProcessor(10);
1207 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1214 /* Read data into buffer */
1215 if (ReadJunk
== TRUE
)
1217 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1218 IDEReadBlock(Address
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1222 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1223 Buffer
+= IDE_SECTOR_BUF_SZ
;
1227 /* Check for more sectors to read */
1228 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1230 Status
= IDEReadStatus(Address
);
1231 if (!(Status
& IDE_SR_BUSY
))
1233 if (Status
& IDE_SR_ERR
)
1235 DPRINT("IDE_SR_ERR asserted!\n");
1237 if (Status
& IDE_SR_DRQ
)
1239 if (SectorCount
>= SectorCnt
)
1252 // ------------------------------------------- Nondiscardable statics
1254 // IDEDispatchOpenClose
1257 // Answer requests for Open/Close calls: a null operation
1263 // Standard dispatch arguments
1269 static NTSTATUS STDCALL
1270 IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
,
1273 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1274 Irp
->IoStatus
.Information
= FILE_OPENED
;
1275 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1277 return STATUS_SUCCESS
;
1280 // IDEDispatchReadWrite
1283 // Answer requests for reads and writes
1289 // Standard dispatch arguments
1295 static NTSTATUS STDCALL
1296 IDEDispatchReadWrite(IN PDEVICE_OBJECT DeviceObject
,
1300 LARGE_INTEGER AdjustedOffset
, AdjustedExtent
, PartitionExtent
, InsertKeyLI
;
1301 PIO_STACK_LOCATION IrpStack
;
1302 PIDE_DEVICE_EXTENSION DeviceExtension
;
1304 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1305 DeviceExtension
= (PIDE_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1307 // Validate operation parameters
1308 AdjustedOffset
.QuadPart
= DeviceExtension
->StartingOffset
.QuadPart
+
1309 IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
;
1310 DPRINT("AdjustedOffset: %I64x\n", AdjustedOffset
.QuadPart
);
1312 AdjustedExtent
.QuadPart
= AdjustedOffset
.QuadPart
+
1313 (ULONGLONG
)IrpStack
->Parameters
.Read
.Length
;
1314 DPRINT("AdjustedExtent: %I64x\n", AdjustedExtent
.QuadPart
);
1316 PartitionExtent
.QuadPart
= DeviceExtension
->StartingOffset
.QuadPart
+
1317 DeviceExtension
->PartitionLength
.QuadPart
;
1318 DPRINT("PartitionExtent: %I64x\n", PartitionExtent
.QuadPart
);
1320 if ((AdjustedExtent
.QuadPart
> PartitionExtent
.QuadPart
) ||
1321 (IrpStack
->Parameters
.Read
.Length
& (DeviceExtension
->BytesPerSector
- 1)))
1323 DPRINT("Request failed on bad parameters\n",0);
1324 DPRINT("AdjustedExtent=%I64x PartitionExtent=%I64x ReadLength=%lx\n",
1325 AdjustedExtent
.QuadPart
,
1326 PartitionExtent
.QuadPart
,
1327 IrpStack
->Parameters
.Read
.Length
);
1328 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1329 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1330 return STATUS_INVALID_PARAMETER
;
1333 // Adjust operation to absolute sector offset
1334 IrpStack
->Parameters
.Read
.ByteOffset
= AdjustedOffset
;
1336 // Start the packet and insert the request in order of sector offset
1337 assert(DeviceExtension
->BytesPerSector
== 512);
1338 InsertKeyLI
.QuadPart
= IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
>> 9;
1339 IrpInsertKey
= InsertKeyLI
.u
.LowPart
;
1340 IoStartPacket(DeviceObject
, Irp
, &IrpInsertKey
, NULL
);
1342 DPRINT("Returning STATUS_PENDING\n");
1343 return STATUS_PENDING
;
1346 // IDEDispatchDeviceControl
1349 // Answer requests for device control calls
1355 // Standard dispatch arguments
1361 static NTSTATUS STDCALL
1362 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1366 ULONG ControlCode
, InputLength
, OutputLength
;
1367 PIO_STACK_LOCATION IrpStack
;
1368 PIDE_DEVICE_EXTENSION DeviceExtension
;
1369 PIDE_DEVICE_EXTENSION DiskDeviceExtension
;
1372 RC
= STATUS_SUCCESS
;
1373 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1374 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1375 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1376 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1377 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1378 DiskDeviceExtension
= (PIDE_DEVICE_EXTENSION
)DeviceExtension
->DiskDeviceExtension
;
1379 Increment
= IO_NO_INCREMENT
;
1381 // A huge switch statement in a Windows program?! who would have thought?
1382 switch (ControlCode
)
1384 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1385 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1387 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1391 PDISK_GEOMETRY Geometry
;
1393 Geometry
= (PDISK_GEOMETRY
) Irp
->AssociatedIrp
.SystemBuffer
;
1395 Geometry
->MediaType
= FixedMedia
;
1396 Geometry
->Cylinders
.QuadPart
= DiskDeviceExtension
->LogicalCylinders
;
1397 Geometry
->TracksPerCylinder
= DiskDeviceExtension
->SectorsPerLogCyl
/
1398 DiskDeviceExtension
->SectorsPerLogTrk
;
1399 Geometry
->SectorsPerTrack
= DiskDeviceExtension
->SectorsPerLogTrk
;
1400 Geometry
->BytesPerSector
= DiskDeviceExtension
->BytesPerSector
;
1401 DPRINT("DiskDeviceExtension->BytesPerSector %lu\n", DiskDeviceExtension
->BytesPerSector
);
1402 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1403 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1407 case IOCTL_DISK_GET_PARTITION_INFO
:
1408 DPRINT("IOCTL_DISK_GET_PARTITION_INFO\n");
1409 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1410 sizeof(PARTITION_INFORMATION
))
1412 Irp
->IoStatus
.Status
= STATUS_INFO_LENGTH_MISMATCH
;
1414 else if (DeviceExtension
->PartitionNumber
== 0)
1416 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1420 PPARTITION_INFORMATION PartitionInfo
;
1422 PartitionInfo
= (PPARTITION_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1424 PartitionInfo
->PartitionType
= DeviceExtension
->PartitionType
;
1425 PartitionInfo
->StartingOffset
= DeviceExtension
->StartingOffset
;
1426 PartitionInfo
->PartitionLength
= DeviceExtension
->PartitionLength
;
1427 PartitionInfo
->HiddenSectors
= DeviceExtension
->HiddenSectors
;
1428 PartitionInfo
->PartitionNumber
= DeviceExtension
->PartitionNumber
;
1429 PartitionInfo
->BootIndicator
= DeviceExtension
->BootIndicator
;
1430 PartitionInfo
->RewritePartition
= FALSE
;
1431 PartitionInfo
->RecognizedPartition
=
1432 IsRecognizedPartition(DeviceExtension
->PartitionType
);
1434 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1435 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
1439 case IOCTL_DISK_SET_PARTITION_INFO
:
1440 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1441 Irp
->IoStatus
.Status
= RC
;
1442 Irp
->IoStatus
.Information
= 0;
1445 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1446 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1447 sizeof(DRIVE_LAYOUT_INFORMATION
))
1449 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1453 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1455 RC
= IoReadPartitionTable(DiskDeviceExtension
->DeviceObject
,
1456 DiskDeviceExtension
->BytesPerSector
,
1459 if (!NT_SUCCESS(RC
))
1461 Irp
->IoStatus
.Status
= RC
;
1467 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
1469 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
1471 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1473 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1477 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1480 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1481 Irp
->IoStatus
.Information
= BufferSize
;
1483 ExFreePool(PartitionList
);
1486 Increment
= IO_DISK_INCREMENT
;
1489 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1490 case IOCTL_DISK_VERIFY
:
1491 case IOCTL_DISK_FORMAT_TRACKS
:
1492 case IOCTL_DISK_PERFORMANCE
:
1493 case IOCTL_DISK_IS_WRITABLE
:
1494 case IOCTL_DISK_LOGGING
:
1495 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1496 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1497 case IOCTL_DISK_HISTOGRAM_DATA
:
1498 case IOCTL_DISK_HISTOGRAM_RESET
:
1499 case IOCTL_DISK_REQUEST_STRUCTURE
:
1500 case IOCTL_DISK_REQUEST_DATA
:
1502 // If we get here, something went wrong. inform the requestor
1504 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1505 Irp
->IoStatus
.Status
= RC
;
1506 Irp
->IoStatus
.Information
= 0;
1510 IoCompleteRequest(Irp
, Increment
);
1518 // Get the next requested I/O packet started
1524 // Dispatch routine standard arguments
1531 STDCALL
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
,
1534 LARGE_INTEGER SectorLI
;
1535 PIO_STACK_LOCATION IrpStack
;
1536 PIDE_DEVICE_EXTENSION DeviceExtension
;
1539 DPRINT("IDEStartIo() called!\n");
1541 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1542 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1544 // FIXME: implement the supported functions
1546 switch (IrpStack
->MajorFunction
)
1550 DeviceExtension
->Operation
= IrpStack
->MajorFunction
;
1551 DeviceExtension
->BytesRequested
= IrpStack
->Parameters
.Read
.Length
;
1552 assert(DeviceExtension
->BytesPerSector
== 512);
1553 SectorLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1554 DeviceExtension
->StartingSector
= SectorLI
.u
.LowPart
;
1555 if (DeviceExtension
->BytesRequested
> DeviceExtension
->BytesPerSector
*
1556 IDE_MAX_SECTORS_PER_XFER
)
1558 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesPerSector
*
1559 IDE_MAX_SECTORS_PER_XFER
;
1563 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1565 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1566 DeviceExtension
->SectorsTransferred
= 0;
1567 DeviceExtension
->TargetAddress
= (BYTE
*)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1568 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1569 IoAllocateController(DeviceExtension
->ControllerObject
,
1571 IDEAllocateController
,
1573 KeLowerIrql(OldIrql
);
1577 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1578 Irp
->IoStatus
.Information
= 0;
1579 KeBugCheck((ULONG
)Irp
);
1580 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1581 IoStartNextPacket(DeviceObject
, FALSE
);
1584 DPRINT("IDEStartIo() finished!\n");
1587 // IDEAllocateController
1589 static IO_ALLOCATION_ACTION STDCALL
1590 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
1592 IN PVOID MapRegisterBase
,
1595 PIDE_DEVICE_EXTENSION DeviceExtension
;
1596 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1598 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1599 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1600 DeviceExtension
->ControllerObject
->ControllerExtension
;
1601 ControllerExtension
->CurrentIrp
= Irp
;
1602 ControllerExtension
->Retries
= 0;
1603 return KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1605 DeviceExtension
) ? KeepObject
:
1609 // IDEStartController
1612 IDEStartController(IN OUT PVOID Context
)
1614 BYTE SectorCnt
, SectorNum
, CylinderLow
, CylinderHigh
;
1615 BYTE DrvHead
, Command
;
1618 ULONG StartingSector
;
1619 PIDE_DEVICE_EXTENSION DeviceExtension
;
1620 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1623 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) Context
;
1624 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1625 DeviceExtension
->ControllerObject
->ControllerExtension
;
1626 ControllerExtension
->OperationInProgress
= TRUE
;
1627 ControllerExtension
->DeviceForOperation
= DeviceExtension
;
1629 // Write controller registers to start opteration
1630 StartingSector
= DeviceExtension
->StartingSector
;
1631 SectorCnt
= DeviceExtension
->BytesToTransfer
/
1632 DeviceExtension
->BytesPerSector
;
1633 if (DeviceExtension
->LBASupported
)
1635 SectorNum
= StartingSector
& 0xff;
1636 CylinderLow
= (StartingSector
>> 8) & 0xff;
1637 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1638 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1639 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0) |
1644 SectorNum
= (StartingSector
% DeviceExtension
->SectorsPerLogTrk
) + 1;
1645 StartingSector
/= DeviceExtension
->SectorsPerLogTrk
;
1646 DrvHead
= (StartingSector
% DeviceExtension
->LogicalHeads
) |
1647 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0);
1648 StartingSector
/= DeviceExtension
->LogicalHeads
;
1649 CylinderLow
= StartingSector
& 0xff;
1650 CylinderHigh
= StartingSector
>> 8;
1652 Command
= DeviceExtension
->Operation
== IRP_MJ_READ
?
1653 IDE_CMD_READ
: IDE_CMD_WRITE
;
1654 if (DrvHead
& IDE_DH_LBA
)
1656 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1657 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1658 ControllerExtension
->CommandPortBase
,
1659 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1660 ((DrvHead
& 0x0f) << 24) +
1661 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1667 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1668 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1669 ControllerExtension
->CommandPortBase
,
1670 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1679 /* wait for BUSY to clear */
1680 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1682 Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1683 if (!(Status
& IDE_SR_BUSY
))
1687 KeStallExecutionProcessor(10);
1689 DPRINT ("status=%02x\n", Status
);
1690 DPRINT ("waited %ld usecs for busy to clear\n", Retries
* 10);
1691 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1693 DPRINT ("Drive is BUSY for too long\n");
1694 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1696 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1697 Irp
= ControllerExtension
->CurrentIrp
;
1698 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1699 Irp
->IoStatus
.Information
= 0;
1705 DPRINT ("Beginning drive reset sequence\n");
1706 IDEBeginControllerReset(ControllerExtension
);
1712 /* Select the desired drive */
1713 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1715 /* wait for BUSY to clear and DRDY to assert */
1716 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1718 Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1719 // if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1720 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1724 KeStallExecutionProcessor(10);
1726 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1727 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1729 DPRINT ("Drive is BUSY for too long after drive select\n");
1730 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1732 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1733 Irp
= ControllerExtension
->CurrentIrp
;
1734 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1735 Irp
->IoStatus
.Information
= 0;
1741 DPRINT ("Beginning drive reset sequence\n");
1742 IDEBeginControllerReset(ControllerExtension
);
1748 /* Setup command parameters */
1749 IDEWritePrecomp(ControllerExtension
->CommandPortBase
, 0);
1750 IDEWriteSectorCount(ControllerExtension
->CommandPortBase
, SectorCnt
);
1751 IDEWriteSectorNum(ControllerExtension
->CommandPortBase
, SectorNum
);
1752 IDEWriteCylinderHigh(ControllerExtension
->CommandPortBase
, CylinderHigh
);
1753 IDEWriteCylinderLow(ControllerExtension
->CommandPortBase
, CylinderLow
);
1754 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1756 /* Issue command to drive */
1757 IDEWriteCommand(ControllerExtension
->CommandPortBase
, Command
);
1758 ControllerExtension
->TimerState
= IDETimerCmdWait
;
1759 ControllerExtension
->TimerCount
= IDE_CMD_TIMEOUT
;
1761 if (DeviceExtension
->Operation
== IRP_MJ_WRITE
)
1764 // Wait for controller ready
1765 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
1767 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1768 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
1772 KeStallExecutionProcessor(10);
1774 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1776 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1778 Irp
= ControllerExtension
->CurrentIrp
;
1779 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1780 Irp
->IoStatus
.Information
= 0;
1786 IDEBeginControllerReset(ControllerExtension
);
1792 // Load the first sector of data into the controller
1793 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1794 DeviceExtension
->TargetAddress
,
1796 DeviceExtension
->TargetAddress
+= IDE_SECTOR_BUF_SZ
;
1797 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1798 DeviceExtension
->SectorsTransferred
++;
1800 DPRINT ("Command issued to drive, IDEStartController done\n");
1805 // IDEBeginControllerReset
1808 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1812 DPRINT("Controller Reset initiated on %04x\n",
1813 ControllerExtension
->ControlPortBase
);
1815 /* Assert drive reset line */
1816 DPRINT("Asserting reset line\n");
1817 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, IDE_DC_SRST
);
1819 /* Wait for BSY assertion */
1820 DPRINT("Waiting for BSY assertion\n");
1821 for (Retries
= 0; Retries
< IDE_MAX_RESET_RETRIES
; Retries
++)
1823 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1824 if ((Status
& IDE_SR_BUSY
))
1828 KeStallExecutionProcessor(10);
1830 if (Retries
== IDE_MAX_RESET_RETRIES
)
1832 DPRINT("Timeout on BSY assertion\n");
1835 /* Negate drive reset line */
1836 DPRINT("Negating reset line\n");
1837 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, 0);
1839 // FIXME: handle case of no device 0
1841 /* Set timer to check for end of reset */
1842 ControllerExtension
->TimerState
= IDETimerResetWaitForBusyNegate
;
1843 ControllerExtension
->TimerCount
= IDE_RESET_BUSY_TIMEOUT
;
1849 // Handle interrupts for IDE devices
1855 // IN PKINTERRUPT Interrupt The interrupt level in effect
1856 // IN PVOID ServiceContext The driver supplied context
1857 // (the controller extension)
1859 // TRUE This ISR handled the interrupt
1860 // FALSE Another ISR must handle this interrupt
1862 static BOOLEAN STDCALL
1863 IDEIsr(IN PKINTERRUPT Interrupt
,
1864 IN PVOID ServiceContext
)
1866 BOOLEAN IsLastBlock
, AnErrorOccured
, RequestIsComplete
;
1867 BYTE
*TargetAddress
;
1869 NTSTATUS ErrorStatus
;
1870 ULONG ErrorInformation
;
1872 PIDE_DEVICE_EXTENSION DeviceExtension
;
1873 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1875 if (IDEInitialized
== FALSE
)
1879 DPRINT ("IDEIsr called\n");
1881 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) ServiceContext
;
1883 // Read the status port to clear the interrtupt (even if it's not ours).
1884 ControllerExtension
->DeviceStatus
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1886 // If the interrupt is not ours, get the heck outta dodge.
1887 if (!ControllerExtension
->OperationInProgress
)
1892 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1893 IsLastBlock
= FALSE
;
1894 AnErrorOccured
= FALSE
;
1895 RequestIsComplete
= FALSE
;
1896 ErrorStatus
= STATUS_SUCCESS
;
1897 ErrorInformation
= 0;
1899 // Handle error condition if it exists
1900 if (ControllerExtension
->DeviceStatus
& IDE_SR_ERR
)
1902 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
1906 ErrorReg
= IDEReadError(ControllerExtension
->CommandPortBase
);
1907 CylinderLow
= IDEReadCylinderLow(ControllerExtension
->CommandPortBase
);
1908 CylinderHigh
= IDEReadCylinderHigh(ControllerExtension
->CommandPortBase
);
1909 DriveHead
= IDEReadDriveHead(ControllerExtension
->CommandPortBase
);
1910 SectorCount
= IDEReadSectorCount(ControllerExtension
->CommandPortBase
);
1911 SectorNum
= IDEReadSectorNum(ControllerExtension
->CommandPortBase
);
1912 // FIXME: should use the NT error logging facility
1913 DbgPrint ("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1914 DeviceExtension
->Operation
,
1915 ControllerExtension
->DeviceStatus
,
1922 // FIXME: should retry the command and perhaps recalibrate the drive
1924 // Set error status information
1925 AnErrorOccured
= TRUE
;
1926 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
1928 (((((((CylinderHigh
<< 8) + CylinderLow
) *
1929 DeviceExtension
->LogicalHeads
) +
1930 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
1931 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
1932 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
1937 // Check controller and setup for next transfer
1938 switch (DeviceExtension
->Operation
)
1942 // Update controller/device state variables
1943 TargetAddress
= DeviceExtension
->TargetAddress
;
1944 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1945 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1946 DeviceExtension
->SectorsTransferred
++;
1948 // Remember whether DRQ should be low at end (last block read)
1949 IsLastBlock
= DeviceExtension
->BytesToTransfer
== 0;
1951 // Wait for DRQ assertion
1952 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
1953 !(IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
);
1956 KeStallExecutionProcessor(10);
1959 // Copy the block of data
1960 IDEReadBlock(ControllerExtension
->CommandPortBase
,
1967 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1968 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1971 KeStallExecutionProcessor(10);
1974 // Check for data overrun
1975 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1977 AnErrorOccured
= TRUE
;
1978 ErrorStatus
= STATUS_DATA_OVERRUN
;
1979 ErrorInformation
= 0;
1984 // Setup next transfer or set RequestIsComplete
1985 if (DeviceExtension
->BytesRequested
>
1986 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1988 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1989 DeviceExtension
->SectorsTransferred
= 0;
1990 DeviceExtension
->BytesToTransfer
=
1991 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1992 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1994 else if (DeviceExtension
->BytesRequested
> 0)
1996 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1997 DeviceExtension
->SectorsTransferred
= 0;
1998 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1999 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2003 RequestIsComplete
= TRUE
;
2012 if (DeviceExtension
->BytesToTransfer
== 0)
2014 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
2015 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
2018 KeStallExecutionProcessor(10);
2021 // Check for data overrun
2022 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
2024 AnErrorOccured
= TRUE
;
2025 ErrorStatus
= STATUS_DATA_OVERRUN
;
2026 ErrorInformation
= 0;
2031 // Setup next transfer or set RequestIsComplete
2033 if (DeviceExtension
->BytesRequested
>
2034 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
2036 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
2037 DeviceExtension
->SectorsTransferred
= 0;
2038 DeviceExtension
->BytesToTransfer
=
2039 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
2040 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2042 else if (DeviceExtension
->BytesRequested
> 0)
2044 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
2045 DeviceExtension
->SectorsTransferred
= 0;
2046 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
2047 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2051 RequestIsComplete
= TRUE
;
2058 // Update controller/device state variables
2059 TargetAddress
= DeviceExtension
->TargetAddress
;
2060 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
2061 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
2062 DeviceExtension
->SectorsTransferred
++;
2064 // Write block to controller
2065 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
2073 // If there was an error or the request is done, complete the packet
2074 if (AnErrorOccured
|| RequestIsComplete
)
2076 // Set the return status and info values
2077 Irp
= ControllerExtension
->CurrentIrp
;
2078 Irp
->IoStatus
.Status
= ErrorStatus
;
2079 Irp
->IoStatus
.Information
= ErrorInformation
;
2081 // Clear out controller fields
2082 ControllerExtension
->OperationInProgress
= FALSE
;
2083 ControllerExtension
->DeviceStatus
= 0;
2085 // Queue the Dpc to finish up
2086 IoRequestDpc(DeviceExtension
->DeviceObject
,
2088 ControllerExtension
);
2090 else if (IsLastBlock
)
2092 // Else more data is needed, setup next device I/O
2093 IDEStartController((PVOID
)DeviceExtension
);
2106 // IN PDEVICE_OBJECT DpcDeviceObject
2108 // IN PVOID DpcContext
2111 IDEDpcForIsr(IN PKDPC Dpc
,
2112 IN PDEVICE_OBJECT DpcDeviceObject
,
2114 IN PVOID DpcContext
)
2116 DPRINT("IDEDpcForIsr()\n");
2117 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION
) DpcContext
);
2120 // IDEFinishOperation
2123 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
2125 PIDE_DEVICE_EXTENSION DeviceExtension
;
2129 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
2130 Irp
= ControllerExtension
->CurrentIrp
;
2131 Operation
= DeviceExtension
->Operation
;
2132 ControllerExtension
->OperationInProgress
= FALSE
;
2133 ControllerExtension
->DeviceForOperation
= 0;
2134 ControllerExtension
->CurrentIrp
= 0;
2136 // Deallocate the controller
2137 IoFreeController(DeviceExtension
->ControllerObject
);
2139 // Start the next packet
2140 IoStartNextPacketByKey(DeviceExtension
->DeviceObject
,
2142 DeviceExtension
->StartingSector
);
2144 // Flush cache if necessary
2145 if (Operation
== IRP_MJ_READ
)
2147 KeFlushIoBuffers(Irp
->MdlAddress
, TRUE
, FALSE
);
2149 // Issue completion of the current packet
2150 // return status information too
2151 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2152 Irp
->IoStatus
.Information
= DeviceExtension
->SectorsTransferred
* DeviceExtension
->BytesPerSector
;
2153 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2158 // This function handles timeouts and other time delayed processing
2163 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
2164 // IN PVOID Context the Controller extension for the
2165 // controller the device is on
2168 IDEIoTimer(PDEVICE_OBJECT DeviceObject
,
2171 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
2173 // Setup Extension pointer
2174 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) Context
;
2175 DPRINT("Timer activated for %04lx\n", ControllerExtension
->CommandPortBase
);
2177 // Handle state change if necessary
2178 switch (ControllerExtension
->TimerState
)
2180 case IDETimerResetWaitForBusyNegate
:
2181 if (!(IDEReadStatus(ControllerExtension
->CommandPortBase
) &
2184 DPRINT("Busy line has negated, waiting for DRDY assert\n");
2185 ControllerExtension
->TimerState
= IDETimerResetWaitForDrdyAssert
;
2186 ControllerExtension
->TimerCount
= IDE_RESET_DRDY_TIMEOUT
;
2191 case IDETimerResetWaitForDrdyAssert
:
2192 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) &
2195 DPRINT("DRDY has asserted, reset complete\n");
2196 ControllerExtension
->TimerState
= IDETimerIdle
;
2197 ControllerExtension
->TimerCount
= 0;
2199 // FIXME: get diagnostic code from drive 0
2201 /* Start current packet command again */
2202 if (!KeSynchronizeExecution(ControllerExtension
->Interrupt
,
2204 ControllerExtension
->DeviceForOperation
))
2206 IDEFinishOperation(ControllerExtension
);
2216 // If we're counting down, then count.
2217 if (ControllerExtension
->TimerCount
> 0)
2219 ControllerExtension
->TimerCount
--;
2221 // Else we'll check the state and process if necessary
2225 switch (ControllerExtension
->TimerState
)
2230 case IDETimerCmdWait
:
2231 /* Command timed out, reset drive and try again or fail */
2232 DPRINT("Timeout waiting for command completion\n");
2233 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
2235 if (ControllerExtension
->CurrentIrp
!= NULL
)
2237 DbgPrint ("Max retries has been reached, IRP finished with error\n");
2238 ControllerExtension
->CurrentIrp
->IoStatus
.Status
= STATUS_IO_TIMEOUT
;
2239 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2240 IDEFinishOperation(ControllerExtension
);
2242 ControllerExtension
->TimerState
= IDETimerIdle
;
2243 ControllerExtension
->TimerCount
= 0;
2247 IDEBeginControllerReset(ControllerExtension
);
2251 case IDETimerResetWaitForBusyNegate
:
2252 case IDETimerResetWaitForDrdyAssert
:
2253 if (ControllerExtension
->CurrentIrp
!= NULL
)
2255 DbgPrint ("Timeout waiting for drive reset, giving up on IRP\n");
2256 ControllerExtension
->CurrentIrp
->IoStatus
.Status
=
2258 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2259 IDEFinishOperation(ControllerExtension
);
2261 ControllerExtension
->TimerState
= IDETimerIdle
;
2262 ControllerExtension
->TimerCount
= 0;