1 /* $Id: ide.c,v 1.50 2002/01/24 10:04:50 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 /* 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
95 KINTERRUPT_MODE InterruptMode
;
97 } IDE_CONTROLLER_PARAMETERS
, *PIDE_CONTROLLER_PARAMETERS
;
99 // NOTE: Do not increase max drives above 2
101 #define IDE_MAX_DRIVES 2
103 #define IDE_MAX_CONTROLLERS 2
104 IDE_CONTROLLER_PARAMETERS Controllers
[IDE_MAX_CONTROLLERS
] =
106 {0x01f0, 8, 0x03f6, 1, 14, 14, 15, LevelSensitive
, 0xffff},
107 {0x0170, 8, 0x0376, 1, 15, 15, 15, LevelSensitive
, 0xffff}
108 /* {0x01E8, 8, 0x03ee, 1, 11, 11, 15, LevelSensitive, 0xffff},
109 {0x0168, 8, 0x036e, 1, 10, 10, 15, LevelSensitive, 0xffff}*/
112 static BOOLEAN IDEInitialized
= FALSE
;
114 // ----------------------------------------------- Discardable Declarations
118 // make the initialization routines discardable, so that they
121 #pragma alloc_text(init, DriverEntry)
122 #pragma alloc_text(init, IDECreateController)
123 #pragma alloc_text(init, IDECreateDevices)
124 #pragma alloc_text(init, IDECreateDevice)
125 #pragma alloc_text(init, IDEPolledRead)
127 // make the PASSIVE_LEVEL routines pageable, so that they don't
128 // waste nonpaged memory
130 #pragma alloc_text(page, IDEShutdown)
131 #pragma alloc_text(page, IDEDispatchOpenClose)
132 #pragma alloc_text(page, IDEDispatchRead)
133 #pragma alloc_text(page, IDEDispatchWrite)
135 #endif /* ALLOC_PRAGMA */
137 // ---------------------------------------------------- Forward Declarations
140 IdeFindControllers(IN PDRIVER_OBJECT DriverObject
);
143 IdeCreateController(IN PDRIVER_OBJECT DriverObject
,
144 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
145 IN
int ControllerIdx
);
147 static BOOLEAN
IDEResetController(IN WORD CommandPort
, IN WORD ControlPort
);
148 static BOOLEAN
IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
149 IN PCONTROLLER_OBJECT ControllerObject
,
150 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
153 static BOOLEAN
IDEGetDriveIdentification(IN
int CommandPort
,
155 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
156 static NTSTATUS
IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject
,
157 OUT PDEVICE_OBJECT
*DeviceObject
,
158 IN PCONTROLLER_OBJECT ControllerObject
,
161 IN PIDE_DRIVE_IDENTIFY DrvParms
,
162 IN ULONG SectorCount
);
163 static NTSTATUS
IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject
,
164 OUT PDEVICE_OBJECT
*DeviceObject
,
165 IN PCONTROLLER_OBJECT ControllerObject
,
166 IN PVOID DiskDeviceExtension
,
169 IN PIDE_DRIVE_IDENTIFY DrvParms
,
170 IN PPARTITION_INFORMATION PartitionInfo
);
171 static int IDEPolledRead(IN WORD Address
,
176 IN BYTE CylinderHigh
,
180 static NTSTATUS STDCALL
IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
181 static NTSTATUS STDCALL
IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
182 static NTSTATUS STDCALL
IDEDispatchDeviceControl(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
183 static VOID STDCALL
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
);
184 static IO_ALLOCATION_ACTION STDCALL
185 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
187 IN PVOID MapRegisterBase
,
189 static BOOLEAN STDCALL
190 IDEStartController(IN OUT PVOID Context
);
191 VOID
IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
192 static BOOLEAN STDCALL
IDEIsr(IN PKINTERRUPT Interrupt
, IN PVOID ServiceContext
);
193 static VOID
IDEDpcForIsr(IN PKDPC Dpc
,
194 IN PDEVICE_OBJECT DpcDeviceObject
,
196 IN PVOID DpcContext
);
197 static VOID
IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
198 static VOID STDCALL
IDEIoTimer(PDEVICE_OBJECT DeviceObject
, PVOID Context
);
200 // ---------------------------------------------------------------- Inlines
203 IDESwapBytePairs(char *Buf
,
209 for (i
= 0; i
< Cnt
; i
+= 2)
217 // ------------------------------------------------------- Public Interface
222 // This function initializes the driver, locates and claims
223 // hardware resources, and creates various NT objects needed
224 // to process I/O requests.
230 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
232 // IN PUNICODE_STRING RegistryPath Name of registry driver service
239 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
240 IN PUNICODE_STRING RegistryPath
)
244 DbgPrint("IDE Driver %s\n", VERSION
);
246 /* Export other driver entry points... */
247 DriverObject
->DriverStartIo
= IDEStartIo
;
248 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = IDEDispatchOpenClose
;
249 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = IDEDispatchOpenClose
;
250 DriverObject
->MajorFunction
[IRP_MJ_READ
] = IDEDispatchReadWrite
;
251 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = IDEDispatchReadWrite
;
252 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
253 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
254 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = IDEDispatchDeviceControl
;
256 Status
= IdeFindControllers(DriverObject
);
257 if (NT_SUCCESS(Status
))
259 IDEInitialized
= TRUE
;
265 // ---------------------------------------------------- Discardable statics
268 IdeFindControllers(IN PDRIVER_OBJECT DriverObject
)
270 PCI_COMMON_CONFIG PciConfig
;
275 NTSTATUS ReturnedStatus
= STATUS_NO_SUCH_DEVICE
;
277 INT ControllerIdx
= 0;
278 PCONFIGURATION_INFORMATION ConfigInfo
;
280 DPRINT("IdeFindControllers() called!\n");
282 ConfigInfo
= IoGetConfigurationInformation();
284 /* Search PCI busses for IDE controllers */
285 for (Bus
= 0; Bus
< 8; Bus
++)
287 for (Slot
= 0; Slot
< 256; Slot
++)
289 Size
= HalGetBusData(PCIConfiguration
,
293 sizeof(PCI_COMMON_CONFIG
));
296 if ((PciConfig
.BaseClass
== 0x01) &&
297 (PciConfig
.SubClass
== 0x01))
299 DPRINT("IDE controller found!\n");
301 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
307 if ((PciConfig
.HeaderType
& 0x7FFFFFFF) == 0)
309 DPRINT(" IPR 0x%X ILR 0x%X\n",
310 PciConfig
.u
.type0
.InterruptPin
,
311 PciConfig
.u
.type0
.InterruptLine
);
314 if (PciConfig
.ProgIf
& 0x01)
316 DPRINT("Primary channel: PCI native mode\n");
320 DPRINT("Primary channel: Compatibility mode\n");
321 if (ConfigInfo
->AtDiskPrimaryAddressClaimed
== FALSE
)
323 Status
= IdeCreateController(DriverObject
,
326 if (NT_SUCCESS(Status
))
329 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
330 ConfigInfo
->ScsiPortCount
++;
331 ReturnedStatus
= Status
;
337 * FIXME: Switch controller to native pci mode
338 * if it is programmable.
342 if (PciConfig
.ProgIf
& 0x02)
344 DPRINT("Primary channel: programmable\n");
348 DPRINT("Primary channel: not programmable\n");
351 #ifdef ENABLE_SECONDARY_IDE_CHANNEL
352 if (PciConfig
.ProgIf
& 0x04)
354 DPRINT("Secondary channel: PCI native mode\n");
358 DPRINT("Secondary channel: Compatibility mode\n");
359 if (ConfigInfo
->AtDiskSecondaryAddressClaimed
== FALSE
)
361 Status
= IdeCreateController(DriverObject
,
364 if (NT_SUCCESS(Status
))
367 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
368 ConfigInfo
->ScsiPortCount
++;
369 ReturnedStatus
= Status
;
375 * FIXME: Switch controller to native pci mode
376 * if it is programmable.
380 if (PciConfig
.ProgIf
& 0x08)
382 DPRINT("Secondary channel: programmable\n");
386 DPRINT("Secondary channel: not programmable\n");
389 if (PciConfig
.ProgIf
& 0x80)
391 DPRINT("Master IDE device: 1\n");
395 DPRINT("Master IDE device: 0\n");
398 for (i
= 0; i
< PCI_TYPE0_ADDRESSES
; i
++)
400 DPRINT("BaseAddress: 0x%08X\n", PciConfig
.u
.type0
.BaseAddresses
[i
]);
408 /* Search for ISA IDE controller if no primary controller was found */
409 if (ConfigInfo
->AtDiskPrimaryAddressClaimed
== FALSE
)
411 DPRINT("Searching for primary ISA IDE controller!\n");
413 if (IDEResetController(Controllers
[0].CommandPortBase
,
414 Controllers
[0].ControlPortBase
))
416 Status
= IdeCreateController(DriverObject
,
419 if (NT_SUCCESS(Status
))
421 DPRINT(" Found primary ISA IDE controller!\n");
423 ConfigInfo
->AtDiskPrimaryAddressClaimed
= TRUE
;
424 ConfigInfo
->ScsiPortCount
++;
425 ReturnedStatus
= Status
;
430 /* Search for ISA IDE controller if no secondary controller was found */
431 #ifdef ENABLE_SECONDARY_IDE_CHANNEL
432 if (ConfigInfo
->AtDiskSecondaryAddressClaimed
== FALSE
)
434 DPRINT("Searching for secondary ISA IDE controller!\n");
436 if (IDEResetController(Controllers
[1].CommandPortBase
,
437 Controllers
[1].ControlPortBase
))
439 Status
= IdeCreateController(DriverObject
,
442 if (NT_SUCCESS(Status
))
444 DPRINT(" Found secondary ISA IDE controller!\n");
446 ConfigInfo
->AtDiskSecondaryAddressClaimed
= TRUE
;
447 ConfigInfo
->ScsiPortCount
++;
448 ReturnedStatus
= Status
;
454 DPRINT("IdeFindControllers() done!\n");
456 return(ReturnedStatus
);
460 // IdeCreateController
463 // Creates a controller object and a device object for each valid
464 // device on the controller
470 // IN PDRIVER_OBJECT DriverObject The system created driver object
471 // IN PIDE_CONTROLLER_PARAMETERS The parameter block for this
472 // ControllerParams controller
473 // IN int ControllerIdx The index of this controller
476 // TRUE Devices where found on this controller
477 // FALSE The controller does not respond or there are no devices on it
481 IdeCreateController(IN PDRIVER_OBJECT DriverObject
,
482 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
483 IN
int ControllerIdx
)
485 BOOLEAN CreatedDevices
, ThisDriveExists
;
488 PCONTROLLER_OBJECT ControllerObject
;
489 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
491 ControllerObject
= IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION
));
492 if (ControllerObject
== NULL
)
494 DbgPrint ("Could not create controller object for controller %d\n",
496 return STATUS_NO_SUCH_DEVICE
;
499 // Fill out Controller extension data
500 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
501 ControllerObject
->ControllerExtension
;
502 ControllerExtension
->Number
= ControllerIdx
;
503 ControllerExtension
->CommandPortBase
= ControllerParams
->CommandPortBase
;
504 ControllerExtension
->ControlPortBase
= ControllerParams
->ControlPortBase
;
505 ControllerExtension
->Vector
= ControllerParams
->Vector
;
506 ControllerExtension
->DMASupported
= FALSE
;
507 ControllerExtension
->ControllerInterruptBug
= FALSE
;
508 ControllerExtension
->OperationInProgress
= FALSE
;
510 // Initialize the spin lock in the controller extension
511 KeInitializeSpinLock(&ControllerExtension
->SpinLock
);
513 // Register an interrupt handler for this controller
514 RC
= IoConnectInterrupt(&ControllerExtension
->Interrupt
,
517 &ControllerExtension
->SpinLock
,
518 ControllerExtension
->Vector
,
519 ControllerParams
->IrqL
,
520 ControllerParams
->SynchronizeIrqL
,
521 ControllerParams
->InterruptMode
,
523 ControllerParams
->Affinity
,
527 DbgPrint ("Could not Connect Interrupt %d\n",
528 ControllerExtension
->Vector
);
529 IoDeleteController (ControllerObject
);
534 IDEInitialized
= TRUE
;
536 // Create device objects for each raw device (and for partitions)
537 CreatedDevices
= FALSE
;
538 for (DriveIdx
= 0; DriveIdx
< IDE_MAX_DRIVES
; DriveIdx
++)
540 ThisDriveExists
= IDECreateDevices(DriverObject
,
544 ControllerIdx
* 2 + DriveIdx
);
547 CreatedDevices
= TRUE
;
553 DbgPrint ("Did not find any devices for controller %d\n",
555 IoDisconnectInterrupt (ControllerExtension
->Interrupt
);
556 IoDeleteController (ControllerObject
);
560 IDEResetController(ControllerParams
->CommandPortBase
,
561 ControllerParams
->ControlPortBase
);
562 IoStartTimer(ControllerExtension
->TimerDevice
);
565 return((CreatedDevices
== TRUE
)?STATUS_SUCCESS
:STATUS_NO_SUCH_DEVICE
);
569 // IDEResetController
572 // Reset the controller and report completion status
578 // IN WORD CommandPort The address of the command port
579 // IN WORD ControlPort The address of the control port
585 IDEResetController(IN WORD CommandPort
,
590 // Assert drive reset line
591 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
593 // Wait for min. 25 microseconds
594 KeStallExecutionProcessor(IDE_RESET_PULSE_LENGTH
);
596 // Negate drive reset line
597 IDEWriteDriveControl(ControlPort
, 0);
599 // Wait for BUSY negation
600 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
602 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
606 KeStallExecutionProcessor(10);
609 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
614 // return TRUE if controller came back to life. and
615 // the registers are initialized correctly
616 return IDEReadError(CommandPort
) == 1;
623 // Create the raw device and any partition devices on this drive
629 // IN PDRIVER_OBJECT DriverObject The system created driver object
630 // IN PCONTROLLER_OBJECT ControllerObject
631 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
632 // The IDE controller extension for
634 // IN int DriveIdx The index of the drive on this
636 // IN int HarddiskIdx The NT device number for this
640 // TRUE Drive exists and devices were created
641 // FALSE no devices were created for this device
645 IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
646 IN PCONTROLLER_OBJECT ControllerObject
,
647 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
651 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
654 IDE_DRIVE_IDENTIFY DrvParms
;
655 PDEVICE_OBJECT DiskDeviceObject
;
656 PDEVICE_OBJECT PartitionDeviceObject
;
657 PIDE_DEVICE_EXTENSION DiskDeviceExtension
;
658 UNICODE_STRING UnicodeDeviceDirName
;
659 OBJECT_ATTRIBUTES DeviceDirAttributes
;
661 ULONG SectorCount
= 0;
662 PDRIVE_LAYOUT_INFORMATION PartitionList
= NULL
;
663 PPARTITION_INFORMATION PartitionEntry
;
666 /* Copy I/O port offsets for convenience */
667 CommandPort
= ControllerExtension
->CommandPortBase
;
668 // ControlPort = ControllerExtension->ControlPortBase;
669 DPRINT("probing IDE controller %d Addr %04lx Drive %d\n",
670 ControllerExtension
->Number
,
674 /* Get the Drive Identification Data */
675 if (!IDEGetDriveIdentification(CommandPort
, DriveIdx
, &DrvParms
))
677 DbgPrint("No ATA drive %d found on controller %d...\n",
679 ControllerExtension
->Number
);
683 DbgPrint("Found ATA drive %d on controller %d...\n",
685 ControllerExtension
->Number
);
687 /* Create the harddisk device directory */
688 swprintf (NameBuffer
,
689 L
"\\Device\\Harddisk%d",
691 RtlInitUnicodeString(&UnicodeDeviceDirName
,
693 InitializeObjectAttributes(&DeviceDirAttributes
,
694 &UnicodeDeviceDirName
,
698 Status
= ZwCreateDirectoryObject(&Handle
, 0, &DeviceDirAttributes
);
699 if (!NT_SUCCESS(Status
))
701 DbgPrint("Could not create device dir object\n");
705 /* Create the disk device */
706 if (DrvParms
.Capabilities
& IDE_DRID_LBA_SUPPORTED
)
709 (ULONG
)((DrvParms
.TMSectorCountHi
<< 16) + DrvParms
.TMSectorCountLo
);
714 (ULONG
)(DrvParms
.LogicalCyls
* DrvParms
.LogicalHeads
* DrvParms
.SectorsPerTrack
);
716 DPRINT("SectorCount %lu\n", SectorCount
);
718 Status
= IDECreateDiskDevice(DriverObject
,
725 if (!NT_SUCCESS(Status
))
727 DbgPrint("IDECreateDevice call failed for raw device\n");
731 /* Increase number of available physical disk drives */
732 IoGetConfigurationInformation()->DiskCount
++;
735 * Initialize the controller timer here
736 * (since it has to be tied to a device)
740 ControllerExtension
->TimerState
= IDETimerIdle
;
741 ControllerExtension
->TimerCount
= 0;
742 ControllerExtension
->TimerDevice
= DiskDeviceObject
;
743 IoInitializeTimer(DiskDeviceObject
,
745 ControllerExtension
);
748 DPRINT1("DrvParms.BytesPerSector %ld\n",DrvParms
.BytesPerSector
);
750 /* Read partition table */
751 Status
= IoReadPartitionTable(DiskDeviceObject
,
752 DrvParms
.BytesPerSector
,
755 if (!NT_SUCCESS(Status
))
757 DbgPrint("IoReadPartitionTable() failed\n");
761 DPRINT(" Number of partitions: %u\n", PartitionList
->PartitionCount
);
762 for (i
=0;i
< PartitionList
->PartitionCount
; i
++)
764 PartitionEntry
= &PartitionList
->PartitionEntry
[i
];
766 DPRINT("Partition %02ld: nr: %d boot: %1x type: %x offset: %I64d size: %I64d\n",
768 PartitionEntry
->PartitionNumber
,
769 PartitionEntry
->BootIndicator
,
770 PartitionEntry
->PartitionType
,
771 PartitionEntry
->StartingOffset
.QuadPart
/ DrvParms
.BytesPerSector
,
772 PartitionEntry
->PartitionLength
.QuadPart
/ DrvParms
.BytesPerSector
);
774 /* Create device for partition */
775 Status
= IDECreatePartitionDevice(DriverObject
,
776 &PartitionDeviceObject
,
778 DiskDeviceObject
->DeviceExtension
,
783 if (!NT_SUCCESS(Status
))
785 DbgPrint("IDECreateDevice() failed\n");
790 if (PartitionList
!= NULL
)
791 ExFreePool(PartitionList
);
796 // IDEGetDriveIdentification
799 // Get the identification block from the drive
805 // IN int CommandPort Address of the command port
806 // IN int DriveNum The drive index (0,1)
807 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
810 // TRUE The drive identification block was retrieved successfully
814 IDEGetDriveIdentification(IN
int CommandPort
,
816 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
819 /* Get the Drive Identify block from drive or die */
820 if (IDEPolledRead(CommandPort
, 0, 1, 0, 0, 0, (DriveNum
? IDE_DH_DRV1
: 0),
821 IDE_CMD_IDENT_DRV
, (BYTE
*)DrvParms
) != 0)
826 /* Report on drive parameters if debug mode */
827 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
828 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
829 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
830 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
831 DrvParms
->ConfigBits
,
832 DrvParms
->LogicalCyls
,
833 DrvParms
->LogicalHeads
,
834 DrvParms
->SectorsPerTrack
,
835 DrvParms
->InterSectorGap
,
836 DrvParms
->InterSectorGapSize
);
837 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
838 DrvParms
->BytesInPLO
,
839 DrvParms
->VendorUniqueCnt
,
840 DrvParms
->SerialNumber
);
841 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
842 DrvParms
->ControllerType
,
843 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
844 DrvParms
->ECCByteCnt
,
845 DrvParms
->FirmwareRev
);
846 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
847 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
848 (DrvParms
->RWMultImplemented
) & 0xff,
849 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
850 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
851 DrvParms
->MinPIOTransTime
,
852 DrvParms
->MinDMATransTime
);
853 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
854 DrvParms
->TMCylinders
,
856 DrvParms
->TMSectorsPerTrk
,
857 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
858 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
859 DrvParms
->TMSectorCountHi
,
860 DrvParms
->TMSectorCountLo
,
861 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
864 * Fix default ATA sector size.
865 * Attention: Default ATAPI sector size is 2048 bytes!!
867 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
868 DrvParms
->BytesPerSector
= 512;
869 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
875 // IDECreateDiskDevice
878 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
884 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
885 // OUT PDEVICE_OBJECT *DeviceObject The created device object
886 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
887 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
888 // IN BOOLEAN DMASupported Does the drive support DMA?
889 // IN int SectorsPerLogCyl Sectors per cylinder
890 // IN int SectorsPerLogTrk Sectors per track
891 // IN DWORD Offset First valid sector for this device
892 // IN DWORD Size Count of valid sectors for this device
899 IDECreateDiskDevice(IN PDRIVER_OBJECT DriverObject
,
900 OUT PDEVICE_OBJECT
*DeviceObject
,
901 IN PCONTROLLER_OBJECT ControllerObject
,
904 IN PIDE_DRIVE_IDENTIFY DrvParms
,
905 IN ULONG SectorCount
)
907 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
908 WCHAR ArcNameBuffer
[IDE_MAX_NAME_LENGTH
+ 15];
909 UNICODE_STRING DeviceName
;
910 UNICODE_STRING ArcName
;
912 PIDE_DEVICE_EXTENSION DeviceExtension
;
914 /* Create a unicode device name */
916 L
"\\Device\\Harddisk%d\\Partition0",
918 RtlInitUnicodeString(&DeviceName
,
921 /* Create the device */
922 RC
= IoCreateDevice(DriverObject
,
923 sizeof(IDE_DEVICE_EXTENSION
),
931 DbgPrint("IoCreateDevice call failed\n");
935 /* Set the buffering strategy here... */
936 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
937 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
939 /* Fill out Device extension data */
940 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) (*DeviceObject
)->DeviceExtension
;
941 DeviceExtension
->DeviceObject
= (*DeviceObject
);
942 DeviceExtension
->ControllerObject
= ControllerObject
;
943 DeviceExtension
->DiskDeviceExtension
= DeviceExtension
;
944 DeviceExtension
->UnitNumber
= UnitNumber
;
945 DeviceExtension
->LBASupported
=
946 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
947 DeviceExtension
->DMASupported
=
948 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
949 DeviceExtension
->BytesPerSector
= DrvParms
->BytesPerSector
;
950 DeviceExtension
->SectorsPerLogCyl
=
951 DrvParms
->LogicalHeads
* DrvParms
->SectorsPerTrack
;
952 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
953 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
954 DeviceExtension
->LogicalCylinders
=
955 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? DrvParms
->TMCylinders
: DrvParms
->LogicalCyls
;
956 DeviceExtension
->Offset
= 0;
957 DeviceExtension
->Size
= SectorCount
;
958 DPRINT("%wZ: offset %lu size %lu \n",
960 DeviceExtension
->Offset
,
961 DeviceExtension
->Size
);
963 /* Initialize the DPC object here */
964 IoInitializeDpcRequest(*DeviceObject
,
967 /* assign arc name */
968 swprintf(ArcNameBuffer
,
969 L
"\\ArcName\\multi(0)disk(0)rdisk(%d)",
971 RtlInitUnicodeString(&ArcName
,
973 DPRINT("%wZ ==> %wZ\n", &ArcName
, &DeviceName
);
974 RC
= IoAssignArcName(&ArcName
,
978 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName
, RC
);
985 // IDECreatePartitionDevice
988 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
994 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
995 // OUT PDEVICE_OBJECT *DeviceObject The created device object
996 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
997 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
998 // IN BOOLEAN DMASupported Does the drive support DMA?
999 // IN int SectorsPerLogCyl Sectors per cylinder
1000 // IN int SectorsPerLogTrk Sectors per track
1001 // IN DWORD Offset First valid sector for this device
1002 // IN DWORD Size Count of valid sectors for this device
1009 IDECreatePartitionDevice(IN PDRIVER_OBJECT DriverObject
,
1010 OUT PDEVICE_OBJECT
*DeviceObject
,
1011 IN PCONTROLLER_OBJECT ControllerObject
,
1012 IN PVOID DiskDeviceExtension
,
1014 IN ULONG DiskNumber
,
1015 IN PIDE_DRIVE_IDENTIFY DrvParms
,
1016 IN PPARTITION_INFORMATION PartitionInfo
)
1018 WCHAR NameBuffer
[IDE_MAX_NAME_LENGTH
];
1019 WCHAR ArcNameBuffer
[IDE_MAX_NAME_LENGTH
+ 15];
1020 UNICODE_STRING DeviceName
;
1021 UNICODE_STRING ArcName
;
1023 PIDE_DEVICE_EXTENSION DeviceExtension
;
1025 /* Create a unicode device name */
1026 swprintf(NameBuffer
,
1027 L
"\\Device\\Harddisk%d\\Partition%d",
1029 PartitionInfo
->PartitionNumber
);
1030 RtlInitUnicodeString(&DeviceName
,
1033 /* Create the device */
1034 RC
= IoCreateDevice(DriverObject
, sizeof(IDE_DEVICE_EXTENSION
),
1035 &DeviceName
, FILE_DEVICE_DISK
, 0, TRUE
, DeviceObject
);
1036 if (!NT_SUCCESS(RC
))
1038 DbgPrint ("IoCreateDevice call failed\n");
1042 /* Set the buffering strategy here... */
1043 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
1044 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1046 /* Fill out Device extension data */
1047 DeviceExtension
= (PIDE_DEVICE_EXTENSION
)(*DeviceObject
)->DeviceExtension
;
1048 DeviceExtension
->DeviceObject
= (*DeviceObject
);
1049 DeviceExtension
->ControllerObject
= ControllerObject
;
1050 DeviceExtension
->DiskDeviceExtension
= DiskDeviceExtension
;
1051 DeviceExtension
->UnitNumber
= UnitNumber
;
1052 DeviceExtension
->LBASupported
=
1053 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
1054 DeviceExtension
->DMASupported
=
1055 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
1056 DeviceExtension
->BytesPerSector
= DrvParms
->BytesPerSector
;
1057 DeviceExtension
->SectorsPerLogCyl
= DrvParms
->LogicalHeads
*
1058 DrvParms
->SectorsPerTrack
;
1059 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
1060 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
1061 DeviceExtension
->LogicalCylinders
=
1062 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? DrvParms
->TMCylinders
: DrvParms
->LogicalCyls
;
1064 DeviceExtension
->Offset
= PartitionInfo
->StartingOffset
.QuadPart
/ 512; /* DrvParms->BytesPerSector */
1065 DeviceExtension
->Size
= PartitionInfo
->PartitionLength
.QuadPart
/ 512; /* DrvParms->BytesPerSector */
1067 DPRINT("%wZ: offset %lu size %lu \n",
1069 DeviceExtension
->Offset
,
1070 DeviceExtension
->Size
);
1072 /* Initialize the DPC object here */
1073 IoInitializeDpcRequest(*DeviceObject
, IDEDpcForIsr
);
1075 DbgPrint("%wZ %luMB\n", &DeviceName
, DeviceExtension
->Size
/ 2048);
1077 /* assign arc name */
1078 swprintf(ArcNameBuffer
,
1079 L
"\\ArcName\\multi(0)disk(0)rdisk(%d)partition(%d)",
1081 PartitionInfo
->PartitionNumber
);
1082 RtlInitUnicodeString(&ArcName
,
1084 DPRINT("%wZ ==> %wZ\n", &ArcName
, &DeviceName
);
1085 RC
= IoAssignArcName(&ArcName
,
1087 if (!NT_SUCCESS(RC
))
1089 DbgPrint("IoAssignArcName (%wZ) failed (Status %x)\n", &ArcName
, RC
);
1099 // Read a sector of data from the drive in a polled fashion.
1105 // IN WORD Address Address of command port for drive
1106 // IN BYTE PreComp Value to write to precomp register
1107 // IN BYTE SectorCnt Value to write to sectorCnt register
1108 // IN BYTE SectorNum Value to write to sectorNum register
1109 // IN BYTE CylinderLow Value to write to CylinderLow register
1110 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1111 // IN BYTE DrvHead Value to write to Drive/Head register
1112 // IN BYTE Command Value to write to Command register
1113 // OUT BYTE *Buffer Buffer for output data
1116 // int 0 is success, non 0 is an error code
1120 IDEPolledRead(IN WORD Address
,
1124 IN BYTE CylinderLow
,
1125 IN BYTE CylinderHigh
,
1132 BOOLEAN ReadJunk
= FALSE
;
1133 ULONG SectorCount
= 0;
1135 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1136 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1138 Status
= IDEReadStatus(Address
);
1139 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1143 KeStallExecutionProcessor(10);
1145 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1150 /* Write Drive/Head to select drive */
1151 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1153 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1154 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1156 Status
= IDEReadStatus(Address
);
1157 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1161 KeStallExecutionProcessor(10);
1163 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1168 /* Issue command to drive */
1169 if (DrvHead
& IDE_DH_LBA
)
1171 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1172 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1173 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1179 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1180 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1189 /* Setup command parameters */
1190 IDEWritePrecomp(Address
, PreComp
);
1191 IDEWriteSectorCount(Address
, SectorCnt
);
1192 IDEWriteSectorNum(Address
, SectorNum
);
1193 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1194 IDEWriteCylinderLow(Address
, CylinderLow
);
1195 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1197 /* Issue the command */
1198 IDEWriteCommand(Address
, Command
);
1199 KeStallExecutionProcessor(50);
1201 /* wait for DRQ or error */
1202 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1204 Status
= IDEReadStatus(Address
);
1205 if (!(Status
& IDE_SR_BUSY
))
1207 if (Status
& IDE_SR_ERR
)
1209 DPRINT1("IDE_SR_ERR asserted!\n");
1211 if ((Status
& IDE_SR_DRQ
) && !(Status
& IDE_SR_ERR
))
1220 KeStallExecutionProcessor(10);
1222 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1229 /* Read data into buffer */
1230 if (ReadJunk
== TRUE
)
1232 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1233 IDEReadBlock(Address
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1237 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1238 Buffer
+= IDE_SECTOR_BUF_SZ
;
1242 /* Check for more sectors to read */
1243 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1245 Status
= IDEReadStatus(Address
);
1246 if (!(Status
& IDE_SR_BUSY
))
1248 if (Status
& IDE_SR_ERR
)
1250 DPRINT1("IDE_SR_ERR asserted!\n");
1252 if (Status
& IDE_SR_DRQ
)
1254 if (SectorCount
>= SectorCnt
)
1267 // ------------------------------------------- Nondiscardable statics
1269 // IDEDispatchOpenClose
1272 // Answer requests for Open/Close calls: a null operation
1278 // Standard dispatch arguments
1284 static NTSTATUS STDCALL
1285 IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
,
1288 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1289 Irp
->IoStatus
.Information
= FILE_OPENED
;
1290 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1292 return STATUS_SUCCESS
;
1295 // IDEDispatchReadWrite
1298 // Answer requests for reads and writes
1304 // Standard dispatch arguments
1311 STDCALL
IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
,
1315 LARGE_INTEGER AdjustedOffset
, AdjustedExtent
, PartitionExtent
, InsertKeyLI
;
1316 PIO_STACK_LOCATION IrpStack
;
1317 PIDE_DEVICE_EXTENSION DeviceExtension
;
1319 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1320 DeviceExtension
= (PIDE_DEVICE_EXTENSION
)pDO
->DeviceExtension
;
1322 // Validate operation parameters
1323 AdjustedOffset
= RtlEnlargedIntegerMultiply(DeviceExtension
->Offset
,
1324 DeviceExtension
->BytesPerSector
);
1325 DPRINT("Offset:%ld * BytesPerSector:%ld = AdjOffset:%ld:%ld\n",
1326 DeviceExtension
->Offset
,
1327 DeviceExtension
->BytesPerSector
,
1328 (unsigned long) AdjustedOffset
.u
.HighPart
,
1329 (unsigned long) AdjustedOffset
.u
.LowPart
);
1330 DPRINT("AdjOffset:%ld:%ld + ByteOffset:%ld:%ld\n",
1331 (unsigned long) AdjustedOffset
.u
.HighPart
,
1332 (unsigned long) AdjustedOffset
.u
.LowPart
,
1333 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.u
.HighPart
,
1334 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.u
.LowPart
);
1335 AdjustedOffset
= RtlLargeIntegerAdd(AdjustedOffset
,
1336 IrpStack
->Parameters
.Read
.ByteOffset
);
1337 DPRINT(" = AdjOffset:%ld:%ld\n",
1338 (unsigned long) AdjustedOffset
.u
.HighPart
,
1339 (unsigned long) AdjustedOffset
.u
.LowPart
);
1340 AdjustedExtent
= RtlLargeIntegerAdd(AdjustedOffset
,
1341 RtlConvertLongToLargeInteger(IrpStack
->Parameters
.Read
.Length
));
1342 DPRINT("AdjOffset:%ld:%ld + Length:%ld = AdjExtent:%ld:%ld\n",
1343 (unsigned long) AdjustedOffset
.u
.HighPart
,
1344 (unsigned long) AdjustedOffset
.u
.LowPart
,
1345 IrpStack
->Parameters
.Read
.Length
,
1346 (unsigned long) AdjustedExtent
.u
.HighPart
,
1347 (unsigned long) AdjustedExtent
.u
.LowPart
);
1348 /*FIXME: this assumption will fail on drives bigger than 1TB */
1349 PartitionExtent
.QuadPart
= DeviceExtension
->Offset
+ DeviceExtension
->Size
;
1350 PartitionExtent
= RtlExtendedIntegerMultiply(PartitionExtent
,
1351 DeviceExtension
->BytesPerSector
);
1352 if ((AdjustedExtent
.QuadPart
> PartitionExtent
.QuadPart
) ||
1353 (IrpStack
->Parameters
.Read
.Length
& (DeviceExtension
->BytesPerSector
- 1)))
1355 DPRINT("Request failed on bad parameters\n",0);
1356 DPRINT("AdjustedExtent=%d:%d PartitionExtent=%d:%d ReadLength=%d\n",
1357 (unsigned int) AdjustedExtent
.u
.HighPart
,
1358 (unsigned int) AdjustedExtent
.u
.LowPart
,
1359 (unsigned int) PartitionExtent
.u
.HighPart
,
1360 (unsigned int) PartitionExtent
.u
.LowPart
,
1361 IrpStack
->Parameters
.Read
.Length
);
1362 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1363 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1364 return STATUS_INVALID_PARAMETER
;
1367 // Adjust operation to absolute sector offset
1368 IrpStack
->Parameters
.Read
.ByteOffset
= AdjustedOffset
;
1370 // Start the packet and insert the request in order of sector offset
1371 assert(DeviceExtension
->BytesPerSector
== 512);
1372 InsertKeyLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1373 IrpInsertKey
= InsertKeyLI
.u
.LowPart
;
1374 IoStartPacket(DeviceExtension
->DeviceObject
, Irp
, &IrpInsertKey
, NULL
);
1376 DPRINT("Returning STATUS_PENDING\n");
1377 return STATUS_PENDING
;
1380 // IDEDispatchDeviceControl
1383 // Answer requests for device control calls
1389 // Standard dispatch arguments
1395 static NTSTATUS STDCALL
1396 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1400 ULONG ControlCode
, InputLength
, OutputLength
;
1401 PIO_STACK_LOCATION IrpStack
;
1402 PIDE_DEVICE_EXTENSION DeviceExtension
;
1403 PIDE_DEVICE_EXTENSION DiskDeviceExtension
;
1406 RC
= STATUS_SUCCESS
;
1407 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1408 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1409 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1410 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1411 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1412 DiskDeviceExtension
= (PIDE_DEVICE_EXTENSION
)DeviceExtension
->DiskDeviceExtension
;
1413 Increment
= IO_NO_INCREMENT
;
1415 // A huge switch statement in a Windows program?! who would have thought?
1416 switch (ControlCode
)
1418 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1419 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1421 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1425 PDISK_GEOMETRY Geometry
;
1427 Geometry
= (PDISK_GEOMETRY
) Irp
->AssociatedIrp
.SystemBuffer
;
1429 Geometry
->MediaType
= FixedMedia
;
1430 Geometry
->Cylinders
.QuadPart
= DiskDeviceExtension
->LogicalCylinders
;
1431 Geometry
->TracksPerCylinder
= DiskDeviceExtension
->SectorsPerLogCyl
/
1432 DiskDeviceExtension
->SectorsPerLogTrk
;
1433 Geometry
->SectorsPerTrack
= DiskDeviceExtension
->SectorsPerLogTrk
;
1434 Geometry
->BytesPerSector
= DiskDeviceExtension
->BytesPerSector
;
1435 DPRINT1("DiskDeviceExtension->BytesPerSector %lu\n", DiskDeviceExtension
->BytesPerSector
);
1436 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1437 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1441 case IOCTL_DISK_GET_PARTITION_INFO
:
1442 case IOCTL_DISK_SET_PARTITION_INFO
:
1443 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1444 Irp
->IoStatus
.Status
= RC
;
1445 Irp
->IoStatus
.Information
= 0;
1448 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1449 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1450 sizeof(DRIVE_LAYOUT_INFORMATION
))
1452 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1456 PDRIVE_LAYOUT_INFORMATION PartitionList
;
1458 RC
= IoReadPartitionTable(DiskDeviceExtension
->DeviceObject
,
1459 DiskDeviceExtension
->BytesPerSector
,
1462 if (!NT_SUCCESS(RC
))
1464 Irp
->IoStatus
.Status
= RC
;
1470 BufferSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
1472 BufferSize
+= PartitionList
->PartitionCount
* sizeof(PARTITION_INFORMATION
);
1474 if (BufferSize
> IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1476 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1480 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
1483 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1484 Irp
->IoStatus
.Information
= BufferSize
;
1486 ExFreePool(PartitionList
);
1489 Increment
= IO_DISK_INCREMENT
;
1492 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1493 case IOCTL_DISK_VERIFY
:
1494 case IOCTL_DISK_FORMAT_TRACKS
:
1495 case IOCTL_DISK_PERFORMANCE
:
1496 case IOCTL_DISK_IS_WRITABLE
:
1497 case IOCTL_DISK_LOGGING
:
1498 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1499 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1500 case IOCTL_DISK_HISTOGRAM_DATA
:
1501 case IOCTL_DISK_HISTOGRAM_RESET
:
1502 case IOCTL_DISK_REQUEST_STRUCTURE
:
1503 case IOCTL_DISK_REQUEST_DATA
:
1505 // If we get here, something went wrong. inform the requestor
1507 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1508 Irp
->IoStatus
.Status
= RC
;
1509 Irp
->IoStatus
.Information
= 0;
1513 IoCompleteRequest(Irp
, Increment
);
1521 // Get the next requested I/O packet started
1527 // Dispatch routine standard arguments
1534 STDCALL
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
,
1537 LARGE_INTEGER SectorLI
;
1538 PIO_STACK_LOCATION IrpStack
;
1539 PIDE_DEVICE_EXTENSION DeviceExtension
;
1542 DPRINT("IDEStartIo() called!\n");
1544 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1545 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1547 // FIXME: implement the supported functions
1549 switch (IrpStack
->MajorFunction
)
1553 DeviceExtension
->Operation
= IrpStack
->MajorFunction
;
1554 DeviceExtension
->BytesRequested
= IrpStack
->Parameters
.Read
.Length
;
1555 assert(DeviceExtension
->BytesPerSector
== 512);
1556 SectorLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1557 DeviceExtension
->StartingSector
= SectorLI
.u
.LowPart
;
1558 if (DeviceExtension
->BytesRequested
> DeviceExtension
->BytesPerSector
*
1559 IDE_MAX_SECTORS_PER_XFER
)
1561 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesPerSector
*
1562 IDE_MAX_SECTORS_PER_XFER
;
1566 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1568 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1569 DeviceExtension
->SectorsTransferred
= 0;
1570 DeviceExtension
->TargetAddress
= (BYTE
*)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1571 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1572 IoAllocateController(DeviceExtension
->ControllerObject
,
1574 IDEAllocateController
,
1576 KeLowerIrql(OldIrql
);
1580 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1581 Irp
->IoStatus
.Information
= 0;
1582 KeBugCheck((ULONG
)Irp
);
1583 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1584 IoStartNextPacket(DeviceObject
, FALSE
);
1587 DPRINT("IDEStartIo() finished!\n");
1590 // IDEAllocateController
1592 static IO_ALLOCATION_ACTION STDCALL
1593 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
1595 IN PVOID MapRegisterBase
,
1598 PIDE_DEVICE_EXTENSION DeviceExtension
;
1599 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1601 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1602 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1603 DeviceExtension
->ControllerObject
->ControllerExtension
;
1604 ControllerExtension
->CurrentIrp
= Irp
;
1605 ControllerExtension
->Retries
= 0;
1606 return KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1608 DeviceExtension
) ? KeepObject
:
1612 // IDEStartController
1615 IDEStartController(IN OUT PVOID Context
)
1617 BYTE SectorCnt
, SectorNum
, CylinderLow
, CylinderHigh
;
1618 BYTE DrvHead
, Command
;
1621 ULONG StartingSector
;
1622 PIDE_DEVICE_EXTENSION DeviceExtension
;
1623 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1626 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) Context
;
1627 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1628 DeviceExtension
->ControllerObject
->ControllerExtension
;
1629 ControllerExtension
->OperationInProgress
= TRUE
;
1630 ControllerExtension
->DeviceForOperation
= DeviceExtension
;
1632 // Write controller registers to start opteration
1633 StartingSector
= DeviceExtension
->StartingSector
;
1634 SectorCnt
= DeviceExtension
->BytesToTransfer
/
1635 DeviceExtension
->BytesPerSector
;
1636 if (DeviceExtension
->LBASupported
)
1638 SectorNum
= StartingSector
& 0xff;
1639 CylinderLow
= (StartingSector
>> 8) & 0xff;
1640 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1641 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1642 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0) |
1647 SectorNum
= (StartingSector
% DeviceExtension
->SectorsPerLogTrk
) + 1;
1648 StartingSector
/= DeviceExtension
->SectorsPerLogTrk
;
1649 DrvHead
= (StartingSector
% DeviceExtension
->LogicalHeads
) |
1650 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0);
1651 StartingSector
/= DeviceExtension
->LogicalHeads
;
1652 CylinderLow
= StartingSector
& 0xff;
1653 CylinderHigh
= StartingSector
>> 8;
1655 Command
= DeviceExtension
->Operation
== IRP_MJ_READ
?
1656 IDE_CMD_READ
: IDE_CMD_WRITE
;
1657 if (DrvHead
& IDE_DH_LBA
)
1659 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1660 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1661 ControllerExtension
->CommandPortBase
,
1662 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1663 ((DrvHead
& 0x0f) << 24) +
1664 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1670 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1671 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1672 ControllerExtension
->CommandPortBase
,
1673 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1682 /* wait for BUSY to clear */
1683 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1685 Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1686 if (!(Status
& IDE_SR_BUSY
))
1690 KeStallExecutionProcessor(10);
1692 DPRINT ("status=%02x\n", Status
);
1693 DPRINT ("waited %ld usecs for busy to clear\n", Retries
* 10);
1694 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1696 DPRINT ("Drive is BUSY for too long\n");
1697 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1699 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1700 Irp
= ControllerExtension
->CurrentIrp
;
1701 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1702 Irp
->IoStatus
.Information
= 0;
1708 DPRINT ("Beginning drive reset sequence\n");
1709 IDEBeginControllerReset(ControllerExtension
);
1715 /* Select the desired drive */
1716 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1718 /* wait for BUSY to clear and DRDY to assert */
1719 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1721 Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1722 // if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1723 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1727 KeStallExecutionProcessor(10);
1729 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1730 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1732 DPRINT ("Drive is BUSY for too long after drive select\n");
1733 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1735 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1736 Irp
= ControllerExtension
->CurrentIrp
;
1737 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1738 Irp
->IoStatus
.Information
= 0;
1744 DPRINT ("Beginning drive reset sequence\n");
1745 IDEBeginControllerReset(ControllerExtension
);
1751 /* Setup command parameters */
1752 IDEWritePrecomp(ControllerExtension
->CommandPortBase
, 0);
1753 IDEWriteSectorCount(ControllerExtension
->CommandPortBase
, SectorCnt
);
1754 IDEWriteSectorNum(ControllerExtension
->CommandPortBase
, SectorNum
);
1755 IDEWriteCylinderHigh(ControllerExtension
->CommandPortBase
, CylinderHigh
);
1756 IDEWriteCylinderLow(ControllerExtension
->CommandPortBase
, CylinderLow
);
1757 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1759 /* Issue command to drive */
1760 IDEWriteCommand(ControllerExtension
->CommandPortBase
, Command
);
1761 ControllerExtension
->TimerState
= IDETimerCmdWait
;
1762 ControllerExtension
->TimerCount
= IDE_CMD_TIMEOUT
;
1764 if (DeviceExtension
->Operation
== IRP_MJ_WRITE
)
1767 // Wait for controller ready
1768 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
1770 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1771 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
1775 KeStallExecutionProcessor(10);
1777 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1779 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1781 Irp
= ControllerExtension
->CurrentIrp
;
1782 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1783 Irp
->IoStatus
.Information
= 0;
1789 IDEBeginControllerReset(ControllerExtension
);
1795 // Load the first sector of data into the controller
1796 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1797 DeviceExtension
->TargetAddress
,
1799 DeviceExtension
->TargetAddress
+= IDE_SECTOR_BUF_SZ
;
1800 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1801 DeviceExtension
->SectorsTransferred
++;
1803 DPRINT ("Command issued to drive, IDEStartController done\n");
1808 // IDEBeginControllerReset
1811 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1815 DPRINT("Controller Reset initiated on %04x\n",
1816 ControllerExtension
->ControlPortBase
);
1818 /* Assert drive reset line */
1819 DPRINT("Asserting reset line\n");
1820 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, IDE_DC_SRST
);
1822 /* Wait for BSY assertion */
1823 DPRINT("Waiting for BSY assertion\n");
1824 for (Retries
= 0; Retries
< IDE_MAX_RESET_RETRIES
; Retries
++)
1826 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1827 if ((Status
& IDE_SR_BUSY
))
1831 KeStallExecutionProcessor(10);
1833 if (Retries
== IDE_MAX_RESET_RETRIES
)
1835 DPRINT("Timeout on BSY assertion\n");
1838 /* Negate drive reset line */
1839 DPRINT("Negating reset line\n");
1840 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, 0);
1842 // FIXME: handle case of no device 0
1844 /* Set timer to check for end of reset */
1845 ControllerExtension
->TimerState
= IDETimerResetWaitForBusyNegate
;
1846 ControllerExtension
->TimerCount
= IDE_RESET_BUSY_TIMEOUT
;
1852 // Handle interrupts for IDE devices
1858 // IN PKINTERRUPT Interrupt The interrupt level in effect
1859 // IN PVOID ServiceContext The driver supplied context
1860 // (the controller extension)
1862 // TRUE This ISR handled the interrupt
1863 // FALSE Another ISR must handle this interrupt
1865 static BOOLEAN STDCALL
1866 IDEIsr(IN PKINTERRUPT Interrupt
,
1867 IN PVOID ServiceContext
)
1869 BOOLEAN IsLastBlock
, AnErrorOccured
, RequestIsComplete
;
1870 BYTE
*TargetAddress
;
1872 NTSTATUS ErrorStatus
;
1873 ULONG ErrorInformation
;
1875 PIDE_DEVICE_EXTENSION DeviceExtension
;
1876 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1878 if (IDEInitialized
== FALSE
)
1882 DPRINT ("IDEIsr called\n");
1884 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) ServiceContext
;
1886 // Read the status port to clear the interrtupt (even if it's not ours).
1887 ControllerExtension
->DeviceStatus
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1889 // If the interrupt is not ours, get the heck outta dodge.
1890 if (!ControllerExtension
->OperationInProgress
)
1895 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1896 IsLastBlock
= FALSE
;
1897 AnErrorOccured
= FALSE
;
1898 RequestIsComplete
= FALSE
;
1899 ErrorStatus
= STATUS_SUCCESS
;
1900 ErrorInformation
= 0;
1902 // Handle error condition if it exists
1903 if (ControllerExtension
->DeviceStatus
& IDE_SR_ERR
)
1905 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
1909 ErrorReg
= IDEReadError(ControllerExtension
->CommandPortBase
);
1910 CylinderLow
= IDEReadCylinderLow(ControllerExtension
->CommandPortBase
);
1911 CylinderHigh
= IDEReadCylinderHigh(ControllerExtension
->CommandPortBase
);
1912 DriveHead
= IDEReadDriveHead(ControllerExtension
->CommandPortBase
);
1913 SectorCount
= IDEReadSectorCount(ControllerExtension
->CommandPortBase
);
1914 SectorNum
= IDEReadSectorNum(ControllerExtension
->CommandPortBase
);
1915 // FIXME: should use the NT error logging facility
1916 DbgPrint ("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1917 DeviceExtension
->Operation
,
1918 ControllerExtension
->DeviceStatus
,
1925 // FIXME: should retry the command and perhaps recalibrate the drive
1927 // Set error status information
1928 AnErrorOccured
= TRUE
;
1929 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
1931 (((((((CylinderHigh
<< 8) + CylinderLow
) *
1932 DeviceExtension
->LogicalHeads
) +
1933 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
1934 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
1935 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
1940 // Check controller and setup for next transfer
1941 switch (DeviceExtension
->Operation
)
1945 // Update controller/device state variables
1946 TargetAddress
= DeviceExtension
->TargetAddress
;
1947 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1948 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1949 DeviceExtension
->SectorsTransferred
++;
1951 // Remember whether DRQ should be low at end (last block read)
1952 IsLastBlock
= DeviceExtension
->BytesToTransfer
== 0;
1954 // Wait for DRQ assertion
1955 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
1956 !(IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
);
1959 KeStallExecutionProcessor(10);
1962 // Copy the block of data
1963 IDEReadBlock(ControllerExtension
->CommandPortBase
,
1970 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1971 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1974 KeStallExecutionProcessor(10);
1977 // Check for data overrun
1978 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1980 AnErrorOccured
= TRUE
;
1981 ErrorStatus
= STATUS_DATA_OVERRUN
;
1982 ErrorInformation
= 0;
1987 // Setup next transfer or set RequestIsComplete
1988 if (DeviceExtension
->BytesRequested
>
1989 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1991 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1992 DeviceExtension
->SectorsTransferred
= 0;
1993 DeviceExtension
->BytesToTransfer
=
1994 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1995 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1997 else if (DeviceExtension
->BytesRequested
> 0)
1999 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
2000 DeviceExtension
->SectorsTransferred
= 0;
2001 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
2002 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2006 RequestIsComplete
= TRUE
;
2015 if (DeviceExtension
->BytesToTransfer
== 0)
2017 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
2018 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
2021 KeStallExecutionProcessor(10);
2024 // Check for data overrun
2025 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
2027 AnErrorOccured
= TRUE
;
2028 ErrorStatus
= STATUS_DATA_OVERRUN
;
2029 ErrorInformation
= 0;
2034 // Setup next transfer or set RequestIsComplete
2036 if (DeviceExtension
->BytesRequested
>
2037 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
2039 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
2040 DeviceExtension
->SectorsTransferred
= 0;
2041 DeviceExtension
->BytesToTransfer
=
2042 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
2043 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2045 else if (DeviceExtension
->BytesRequested
> 0)
2047 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
2048 DeviceExtension
->SectorsTransferred
= 0;
2049 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
2050 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
2054 RequestIsComplete
= TRUE
;
2061 // Update controller/device state variables
2062 TargetAddress
= DeviceExtension
->TargetAddress
;
2063 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
2064 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
2065 DeviceExtension
->SectorsTransferred
++;
2067 // Write block to controller
2068 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
2076 // If there was an error or the request is done, complete the packet
2077 if (AnErrorOccured
|| RequestIsComplete
)
2079 // Set the return status and info values
2080 Irp
= ControllerExtension
->CurrentIrp
;
2081 Irp
->IoStatus
.Status
= ErrorStatus
;
2082 Irp
->IoStatus
.Information
= ErrorInformation
;
2084 // Clear out controller fields
2085 ControllerExtension
->OperationInProgress
= FALSE
;
2086 ControllerExtension
->DeviceStatus
= 0;
2088 // Queue the Dpc to finish up
2089 IoRequestDpc(DeviceExtension
->DeviceObject
,
2091 ControllerExtension
);
2093 else if (IsLastBlock
)
2095 // Else more data is needed, setup next device I/O
2096 IDEStartController((PVOID
)DeviceExtension
);
2109 // IN PDEVICE_OBJECT DpcDeviceObject
2111 // IN PVOID DpcContext
2114 IDEDpcForIsr(IN PKDPC Dpc
,
2115 IN PDEVICE_OBJECT DpcDeviceObject
,
2117 IN PVOID DpcContext
)
2119 DPRINT("IDEDpcForIsr()\n");
2120 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION
) DpcContext
);
2123 // IDEFinishOperation
2126 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
2128 PIDE_DEVICE_EXTENSION DeviceExtension
;
2132 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
2133 Irp
= ControllerExtension
->CurrentIrp
;
2134 Operation
= DeviceExtension
->Operation
;
2135 ControllerExtension
->OperationInProgress
= FALSE
;
2136 ControllerExtension
->DeviceForOperation
= 0;
2137 ControllerExtension
->CurrentIrp
= 0;
2139 // Deallocate the controller
2140 IoFreeController(DeviceExtension
->ControllerObject
);
2142 // Start the next packet
2143 IoStartNextPacketByKey(DeviceExtension
->DeviceObject
,
2145 DeviceExtension
->StartingSector
);
2147 // Issue completion of the current packet
2148 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2150 // Flush cache if necessary
2151 if (Operation
== IRP_MJ_READ
)
2153 KeFlushIoBuffers(Irp
->MdlAddress
, TRUE
, FALSE
);
2159 // This function handles timeouts and other time delayed processing
2164 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
2165 // IN PVOID Context the Controller extension for the
2166 // controller the device is on
2169 IDEIoTimer(PDEVICE_OBJECT DeviceObject
,
2172 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
2174 // Setup Extension pointer
2175 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) Context
;
2176 DPRINT("Timer activated for %04lx\n", ControllerExtension
->CommandPortBase
);
2178 // Handle state change if necessary
2179 switch (ControllerExtension
->TimerState
)
2181 case IDETimerResetWaitForBusyNegate
:
2182 if (!(IDEReadStatus(ControllerExtension
->CommandPortBase
) &
2185 DPRINT("Busy line has negated, waiting for DRDY assert\n");
2186 ControllerExtension
->TimerState
= IDETimerResetWaitForDrdyAssert
;
2187 ControllerExtension
->TimerCount
= IDE_RESET_DRDY_TIMEOUT
;
2192 case IDETimerResetWaitForDrdyAssert
:
2193 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) &
2196 DPRINT("DRDY has asserted, reset complete\n");
2197 ControllerExtension
->TimerState
= IDETimerIdle
;
2198 ControllerExtension
->TimerCount
= 0;
2200 // FIXME: get diagnostic code from drive 0
2202 /* Start current packet command again */
2203 if (!KeSynchronizeExecution(ControllerExtension
->Interrupt
,
2205 ControllerExtension
->DeviceForOperation
))
2207 IDEFinishOperation(ControllerExtension
);
2217 // If we're counting down, then count.
2218 if (ControllerExtension
->TimerCount
> 0)
2220 ControllerExtension
->TimerCount
--;
2222 // Else we'll check the state and process if necessary
2226 switch (ControllerExtension
->TimerState
)
2231 case IDETimerCmdWait
:
2232 /* Command timed out, reset drive and try again or fail */
2233 DPRINT("Timeout waiting for command completion\n");
2234 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
2236 if (ControllerExtension
->CurrentIrp
!= NULL
)
2238 DbgPrint ("Max retries has been reached, IRP finished with error\n");
2239 ControllerExtension
->CurrentIrp
->IoStatus
.Status
= STATUS_IO_TIMEOUT
;
2240 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2241 IDEFinishOperation(ControllerExtension
);
2243 ControllerExtension
->TimerState
= IDETimerIdle
;
2244 ControllerExtension
->TimerCount
= 0;
2248 IDEBeginControllerReset(ControllerExtension
);
2252 case IDETimerResetWaitForBusyNegate
:
2253 case IDETimerResetWaitForDrdyAssert
:
2254 if (ControllerExtension
->CurrentIrp
!= NULL
)
2256 DbgPrint ("Timeout waiting for drive reset, giving up on IRP\n");
2257 ControllerExtension
->CurrentIrp
->IoStatus
.Status
=
2259 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2260 IDEFinishOperation(ControllerExtension
);
2262 ControllerExtension
->TimerState
= IDETimerIdle
;
2263 ControllerExtension
->TimerCount
= 0;