2 * IDE.C - IDE Disk driver
3 * written by Rex Jolliff
4 * with help from various documentation sources and a few peeks at
5 * linux and freebsd sources.
7 * This driver supports up to 4 controllers with up to 2 drives each.
8 * The device names are assigned as follows:
9 * \Devices\HarddiskX\Partition0
10 * for the raw device, and
11 * \Devices\HarddiskX\PartitionY
14 * X is computed by counting the available drives from the following
15 * sequence: the controller number (0=0x1f0, 1=0x170, 2=0x1e8,
16 * 3=0x168) * 2 plus the drive number (0,1)
17 * Y is the partition number
19 * The driver exports the following function:
21 * DriverEntry() - NT device driver initialization routine
23 * And the following functions are exported implicitly:
25 * IDEStartIo() - called to start an I/O request packet
26 * IDEDispatchOpenClose() - Called to open/close the device. a NOOP
27 * IDEDispatchReadWrite() - Called to read/write the device.
28 * IDEDispatchQueryInformation() - Called to get device information
29 * IDEDispatchSetInformation() - Called to set device information
30 * IDEDispatchDeviceControl() - Called to execute device control requests
32 * Modification History:
33 * 05/25/98 RJJ Created.
34 * 05/30/98 RJJ Removed IRQ handler and inserted busy waits
35 * just to get something working...
36 * 07/18/98 RJJ Made drastic changes so that the driver
37 * resembles a WinNT driver.
38 * 08/05/98 RJJ Changed to .C extension
39 * 09/19/98 RJJ First release (run for cover!)
42 * 09/17/98 RJJ Pri/MST: 14.12X19 WDC AC31000H Test Passed
47 * FIXME: a timer should be used to watch for device timeouts and errors
48 * FIXME: errors should be retried
49 * FIXME: a drive reset/recalibrate should be attempted if errors occur
50 * FIXME: Use DMA for transfers if drives support it
51 * FIXME: should we support unloading of this driver???
52 * FIXME: the device information should come from AUTODETECT (via registry)
53 * FIXME: really big devices need to be handled correctly
54 * FIXME: should get device info from the registry
55 * FIXME: should report hardware usage to iomgr
56 * FIXME: finish implementation of QueryInformation
57 * FIXME: finish implementation of SetInformation
58 * FIXME: finish implementation of DeviceControl
59 * FIXME: bring up to ATA-3 spec
60 * FIXME: add general support for ATAPI devices
61 * FIXME: add support for ATAPI CDROMs
62 * FIXME: add support for ATAPI ZIP drives/RHDs
63 * FIXME: add support for ATAPI tape drives
66 #include <ddk/ntddk.h>
68 // -------------------------------- This stuff should be defined in NTDDK.H
70 typedef DISK_GEOMETRY
*PDISK_GEOMETRY
;
72 // -------------------------------------------------------------------------
74 #include <internal/i386/io.h>
76 #include <internal/string.h>
79 #include <internal/debug.h>
85 #define VERSION "V0.1.4"
87 // ------------------------------------------------------- File Static Data
89 typedef struct _IDE_CONTROLLER_PARAMETERS
98 KINTERRUPT_MODE InterruptMode
;
100 } IDE_CONTROLLER_PARAMETERS
, *PIDE_CONTROLLER_PARAMETERS
;
102 // NOTE: Do not increase max drives above 2
104 #define IDE_MAX_DRIVES 2
106 #define IDE_MAX_CONTROLLERS 4
107 IDE_CONTROLLER_PARAMETERS Controllers
[IDE_MAX_CONTROLLERS
] =
109 {0x01f0, 8, 0x03f6, 1, 14, 14, 15, LevelSensitive
, 0xffff},
110 {0x0170, 8, 0x0376, 1, 15, 15, 15, LevelSensitive
, 0xffff},
111 {0x01E8, 8, 0x03ee, 1, 11, 11, 15, LevelSensitive
, 0xffff},
112 {0x0168, 8, 0x036e, 1, 10, 10, 15, LevelSensitive
, 0xffff}
115 static BOOLEAN IDEInitialized
= FALSE
;
116 static int TotalPartitions
= 0;
118 // ----------------------------------------------- Discardable Declarations
122 // make the initialization routines discardable, so that they
125 #pragma alloc_text(init, DriverEntry)
126 #pragma alloc_text(init, IDECreateController)
127 #pragma alloc_text(init, IDECreateDevices)
128 #pragma alloc_text(init, IDECreateDevice)
129 #pragma alloc_text(init, IDEPolledRead)
131 // make the PASSIVE_LEVEL routines pageable, so that they don't
132 // waste nonpaged memory
134 #pragma alloc_text(page, IDEShutdown)
135 #pragma alloc_text(page, IDEDispatchOpenClose)
136 #pragma alloc_text(page, IDEDispatchRead)
137 #pragma alloc_text(page, IDEDispatchWrite)
139 #endif /* ALLOC_PRAGMA */
141 // ---------------------------------------------------- Forward Declarations
143 static BOOLEAN
IDECreateController(IN PDRIVER_OBJECT DriverObject
,
144 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
145 IN
int ControllerIdx
);
146 static BOOLEAN
IDEResetController(IN WORD CommandPort
, IN WORD ControlPort
);
147 static BOOLEAN
IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
148 IN PCONTROLLER_OBJECT ControllerObject
,
149 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
152 static BOOLEAN
IDEGetDriveIdentification(IN
int CommandPort
,
154 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
155 static BOOLEAN
IDEGetPartitionTable(IN
int CommandPort
,
158 IN PIDE_DRIVE_IDENTIFY DrvParms
,
159 PARTITION
*PartitionTable
);
160 static NTSTATUS
IDECreateDevice(IN PDRIVER_OBJECT DriverObject
,
162 OUT PDEVICE_OBJECT
*DeviceObject
,
163 IN PCONTROLLER_OBJECT ControllerObject
,
166 IN PIDE_DRIVE_IDENTIFY DrvParms
,
169 static int IDEPolledRead(IN WORD Address
,
174 IN BYTE CylinderHigh
,
178 static NTSTATUS
IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
179 static NTSTATUS
IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
180 static NTSTATUS
IDEDispatchDeviceControl(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
181 static VOID
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
);
182 static IO_ALLOCATION_ACTION
IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
184 IN PVOID MapRegisterBase
,
186 static BOOLEAN
IDEStartController(IN OUT PVOID Context
);
187 VOID
IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
188 static BOOLEAN
IDEIsr(IN PKINTERRUPT Interrupt
, IN PVOID ServiceContext
);
189 static VOID
IDEDpcForIsr(IN PKDPC Dpc
,
190 IN PDEVICE_OBJECT DpcDeviceObject
,
192 IN PVOID DpcContext
);
193 static VOID
IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
194 static VOID
IDEIoTimer(PDEVICE_OBJECT DeviceObject
, PVOID Context
);
196 // ---------------------------------------------------------------- Inlines
199 IDESwapBytePairs(char *Buf
,
205 for (i
= 0; i
< Cnt
; i
+= 2)
213 // ------------------------------------------------------- Public Interface
218 // This function initializes the driver, locates and claims
219 // hardware resources, and creates various NT objects needed
220 // to process I/O requests.
226 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
228 // IN PUNICODE_STRING RegistryPath Name of registry driver service
235 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
236 IN PUNICODE_STRING RegistryPath
)
238 BOOLEAN WeGotSomeDisks
;
241 DbgPrint("IDE Driver %s\n", VERSION
);
243 // Export other driver entry points...
244 DriverObject
->DriverStartIo
= IDEStartIo
;
245 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = IDEDispatchOpenClose
;
246 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = IDEDispatchOpenClose
;
247 DriverObject
->MajorFunction
[IRP_MJ_READ
] = IDEDispatchReadWrite
;
248 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = IDEDispatchReadWrite
;
249 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
250 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
251 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = IDEDispatchDeviceControl
;
253 WeGotSomeDisks
= FALSE
;
254 for (ControllerIdx
= 0; ControllerIdx
< IDE_MAX_CONTROLLERS
; ControllerIdx
++)
256 WeGotSomeDisks
|= IDECreateController(DriverObject
,
257 &Controllers
[ControllerIdx
], ControllerIdx
);
262 IDEInitialized
= TRUE
;
265 return WeGotSomeDisks
? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
;
268 // ---------------------------------------------------- Discardable statics
270 // IDECreateController
273 // Creates a controller object and a device object for each valid
274 // device on the controller
280 // IN PDRIVER_OBJECT DriverObject The system created driver object
281 // IN PIDE_CONTROLLER_PARAMETERS The parameter block for this
282 // ControllerParams controller
283 // IN int ControllerIdx The index of this controller
286 // TRUE Devices where found on this controller
287 // FALSE The controller does not respond or there are no devices on it
291 IDECreateController(IN PDRIVER_OBJECT DriverObject
,
292 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
293 IN
int ControllerIdx
)
295 BOOLEAN CreatedDevices
, ThisDriveExists
;
298 PCONTROLLER_OBJECT ControllerObject
;
299 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
301 // Try to reset the controller and return FALSE if it fails
302 if (!IDEResetController(ControllerParams
->CommandPortBase
,
303 ControllerParams
->ControlPortBase
))
305 DPRINT("Could not find controller %d at %04lx\n",
306 ControllerIdx
, ControllerParams
->CommandPortBase
);
310 ControllerObject
= IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION
));
311 if (ControllerObject
== NULL
)
313 DPRINT("Could not create controller object for controller %d\n",
318 // Fill out Controller extension data
319 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
320 ControllerObject
->ControllerExtension
;
321 ControllerExtension
->Number
= ControllerIdx
;
322 ControllerExtension
->CommandPortBase
= ControllerParams
->CommandPortBase
;
323 ControllerExtension
->ControlPortBase
= ControllerParams
->ControlPortBase
;
324 ControllerExtension
->Vector
= ControllerParams
->Vector
;
325 ControllerExtension
->DMASupported
= FALSE
;
326 ControllerExtension
->ControllerInterruptBug
= FALSE
;
327 ControllerExtension
->OperationInProgress
= FALSE
;
329 // Initialize the spin lock in the controller extension
330 KeInitializeSpinLock(&ControllerExtension
->SpinLock
);
332 // Register an interrupt handler for this controller
333 RC
= IoConnectInterrupt(&ControllerExtension
->Interrupt
,
336 &ControllerExtension
->SpinLock
,
337 ControllerExtension
->Vector
,
338 ControllerParams
->IrqL
,
339 ControllerParams
->SynchronizeIrqL
,
340 ControllerParams
->InterruptMode
,
342 ControllerParams
->Affinity
,
346 DPRINT("Could not Connect Interrupt %d\n", ControllerExtension
->Vector
);
347 IoDeleteController(ControllerObject
);
351 // Create device objects for each raw device (and for partitions)
352 CreatedDevices
= FALSE
;
353 for (DriveIdx
= 0; DriveIdx
< IDE_MAX_DRIVES
; DriveIdx
++)
355 ThisDriveExists
= IDECreateDevices(DriverObject
,
359 ControllerIdx
* 2 + DriveIdx
);
362 CreatedDevices
= TRUE
;
368 DPRINT("Did not find any devices for controller %d\n", ControllerIdx
);
369 IoDisconnectInterrupt(ControllerExtension
->Interrupt
);
370 IoDeleteController(ControllerObject
);
374 IoStartTimer(ControllerExtension
->TimerDevice
);
377 return CreatedDevices
;
380 // IDEResetController
383 // Reset the controller and report completion status
389 // IN WORD CommandPort The address of the command port
390 // IN WORD ControlPort The address of the control port
396 IDEResetController(IN WORD CommandPort
,
401 // Assert drive reset line
402 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
404 // Wait for min. 25 microseconds
405 KeStallExecutionProcessor(IDE_RESET_PULSE_LENGTH
);
407 // Negate drive reset line
408 IDEWriteDriveControl(ControlPort
, 0);
410 // Wait for BUSY assertion
411 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
413 if (IDEReadStatus(CommandPort
) & IDE_SR_BUSY
)
417 KeStallExecutionProcessor(10);
419 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
424 // Wait for BUSY negation
425 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
427 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
431 KeStallExecutionProcessor(10);
433 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
438 // return TRUE if controller came back to life. and
439 // the registers are initialized correctly
440 return IDEReadError(CommandPort
) == 1 &&
441 IDEReadSectorCount(CommandPort
) == 1 &&
442 IDEReadSectorNum(CommandPort
) == 1 &&
443 IDEReadCylinderLow(CommandPort
) == 0 &&
444 IDEReadCylinderHigh(CommandPort
) == 0 &&
445 (IDEReadDriveHead(CommandPort
) & 0x1F) == 0;
451 // Create the raw device and any partition devices on this drive
457 // IN PDRIVER_OBJECT DriverObject The system created driver object
458 // IN PCONTROLLER_OBJECT ControllerObject
459 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
460 // The IDE controller extension for
462 // IN int DriveIdx The index of the drive on this
464 // IN int HarddiskIdx The NT device number for this
468 // TRUE Drive exists and devices were created
469 // FALSE no devices were created for this device
473 IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
474 IN PCONTROLLER_OBJECT ControllerObject
,
475 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
479 BOOLEAN CreatedDevices
;
480 char RawDeviceName
[IDE_MAX_NAME_LENGTH
];
481 char PrimaryDeviceName
[IDE_MAX_NAME_LENGTH
];
482 char LogicalDeviceName
[IDE_MAX_NAME_LENGTH
];
483 char Win32AliasName
[IDE_MAX_NAME_LENGTH
];
484 int CommandPort
, PartitionIdx
, PartitionNum
;
485 int ExtPartitionIdx
, ExtOffset
;
487 IDE_DRIVE_IDENTIFY DrvParms
;
488 PDEVICE_OBJECT RawDeviceObject
;
489 PDEVICE_OBJECT PrimaryDeviceObject
;
490 PDEVICE_OBJECT LogicalDeviceObject
;
491 PIDE_DEVICE_EXTENSION RawDeviceExtension
;
492 PARTITION PrimaryPartitionTable
[4], *p
;
493 PARTITION ExtendedPartitionTable
[4], *ep
;
494 char DeviceDirName
[IDE_MAX_NAME_LENGTH
+ 1];
495 ANSI_STRING AnsiDeviceDirName
;
496 UNICODE_STRING UnicodeDeviceDirName
;
497 OBJECT_ATTRIBUTES DeviceDirAttributes
;
500 // Copy I/O port offsets for convenience
501 CommandPort
= ControllerExtension
->CommandPortBase
;
502 // ControlPort = ControllerExtension->ControlPortBase;
503 DPRINT("probing IDE controller %d Addr %04lx Drive %d\n",
504 ControllerExtension
->Number
,
508 // Get the Drive Identification Data
509 if (!IDEGetDriveIdentification(CommandPort
, DriveIdx
, &DrvParms
))
511 DPRINT("Giving up on drive %d on controller %d...\n",
513 ControllerExtension
->Number
);
517 CreatedDevices
= FALSE
;
519 // Create the harddisk device directory
520 strcpy(DeviceDirName
, IDE_NT_ROOTDIR_NAME
);
521 strcat(DeviceDirName
, IDE_NT_DEVICE_NAME
);
522 DeviceDirName
[strlen(DeviceDirName
) + 1] = '\0';
523 DeviceDirName
[strlen(DeviceDirName
)] = '0' + HarddiskIdx
;
524 RtlInitAnsiString(&AnsiDeviceDirName
, DeviceDirName
);
525 RC
= RtlAnsiStringToUnicodeString(&UnicodeDeviceDirName
,
530 DPRINT("Could not convert ansi to unicode for device dir\n", 0);
533 InitializeObjectAttributes(&DeviceDirAttributes
,
534 &UnicodeDeviceDirName
,
538 RC
= ZwCreateDirectoryObject(&Handle
, 0, &DeviceDirAttributes
);
541 DPRINT("Could not create device dir object\n", 0);
544 RtlFreeUnicodeString(&UnicodeDeviceDirName
);
546 // Create the raw device
547 strcpy(RawDeviceName
, IDE_NT_ROOTDIR_NAME
);
548 strcat(RawDeviceName
, IDE_NT_DEVICE_NAME
);
549 RawDeviceName
[strlen(RawDeviceName
) + 1] = '\0';
550 RawDeviceName
[strlen(RawDeviceName
)] = '0' + HarddiskIdx
;
551 strcat(RawDeviceName
, IDE_NT_PARTITION_NAME
);
552 RawDeviceName
[strlen(RawDeviceName
) + 1] = '\0';
553 RawDeviceName
[strlen(RawDeviceName
)] = '0';
554 RC
= IDECreateDevice(DriverObject
,
562 DrvParms
.LogicalCyls
* DrvParms
.LogicalHeads
* DrvParms
.SectorsPerTrack
);
565 DPRINT("IDECreateDevice call failed for raw device\n",0);
569 CreatedDevices
= TRUE
;
570 RawDeviceExtension
= (PIDE_DEVICE_EXTENSION
)
571 RawDeviceObject
->DeviceExtension
;
573 // Initialze the controller timer here (since it has to be
574 // tied to a device)...
577 ControllerExtension
->TimerState
= IDETimerIdle
;
578 ControllerExtension
->TimerCount
= 0;
579 ControllerExtension
->TimerDevice
= RawDeviceObject
;
580 IoInitializeTimer(RawDeviceObject
, IDEIoTimer
, ControllerExtension
);
584 // Get Main partition table for device
586 if (!IDEGetPartitionTable(CommandPort
, DriveIdx
, 0, &DrvParms
, PrimaryPartitionTable
))
588 DPRINT("drive %d controller %d: Could not get primary partition table\n",
590 ControllerExtension
->Number
);
595 // build devices for all partitions in table
596 DPRINT("partitions on %s:\n", DeviceDirName
);
597 for (PartitionIdx
= 0; PartitionIdx
< 4; PartitionIdx
++)
600 // copy partition pointer for convenience
601 p
= &PrimaryPartitionTable
[PartitionIdx
];
603 // if the partition entry is in use, create a device for it
604 if (PartitionIsSupported(p
))
606 DPRINT("%s ptbl entry:%d type:%02x Offset:%d Size:%d\n",
613 // Create Device for partition
614 strcpy(PrimaryDeviceName
, IDE_NT_ROOTDIR_NAME
);
615 strcat(PrimaryDeviceName
, IDE_NT_DEVICE_NAME
);
616 PrimaryDeviceName
[strlen(PrimaryDeviceName
) + 1] = '\0';
617 PrimaryDeviceName
[strlen(PrimaryDeviceName
)] = '0' + HarddiskIdx
;
618 strcat(PrimaryDeviceName
, IDE_NT_PARTITION_NAME
);
619 PrimaryDeviceName
[strlen(PrimaryDeviceName
) + 1] = '\0';
620 PrimaryDeviceName
[strlen(PrimaryDeviceName
)] = '0' + PartitionNum
++;
621 strcpy(Win32AliasName
, "\\??\\ :");
622 Win32AliasName
[4] = 'C' + TotalPartitions
;
624 RC
= IDECreateDevice(DriverObject
,
626 &PrimaryDeviceObject
,
635 DPRINT("IDECreateDevice call failed\n",0);
639 // Create devices for logical partitions within an extended partition
641 else if (PartitionIsExtended(p
))
643 ExtOffset
= p
->StartingBlock
;
645 // Get the Extended partition table
646 if (!IDEGetPartitionTable(CommandPort
,
650 ExtendedPartitionTable
))
652 DPRINT("Harddisk%d: could not get extended partition table at offset %d",
653 HarddiskIdx
, ExtOffset
);
657 for (ExtPartitionIdx
= 0; ExtPartitionIdx
< 4; ExtPartitionIdx
++)
659 ep
= &ExtendedPartitionTable
[ExtPartitionIdx
];
660 if (PartitionIsSupported(ep
))
662 DPRINT("Harddisk%d: Type:%02x Offset:%d Size:%d\n",
665 ep
->StartingBlock
+ ExtOffset
,
668 // Create device for logical partition
669 strcpy(LogicalDeviceName
, IDE_NT_ROOTDIR_NAME
);
670 strcat(LogicalDeviceName
, IDE_NT_DEVICE_NAME
);
671 LogicalDeviceName
[strlen(LogicalDeviceName
) + 1] = '\0';
672 LogicalDeviceName
[strlen(LogicalDeviceName
)] = '0' + HarddiskIdx
;
673 strcat(LogicalDeviceName
, IDE_NT_PARTITION_NAME
);
674 LogicalDeviceName
[strlen(LogicalDeviceName
) + 1] = '\0';
675 LogicalDeviceName
[strlen(LogicalDeviceName
)] = '0' + PartitionNum
++;
676 strcpy(Win32AliasName
, "\\??\\ :");
677 Win32AliasName
[4] = 'C' + TotalPartitions
;
679 RC
= IDECreateDevice(DriverObject
,
681 &LogicalDeviceObject
,
686 ep
->StartingBlock
+ ExtOffset
,
690 DPRINT("IDECreateDevice call failed\n",0);
703 // IDEGetDriveIdentification
706 // Get the identification block from the drive
712 // IN int CommandPort Address of the command port
713 // IN int DriveNum The drive index (0,1)
714 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
717 // TRUE The drive identification block was retrieved successfully
721 IDEGetDriveIdentification(IN
int CommandPort
,
723 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
726 // Get the Drive Identify block from drive or die
727 if (IDEPolledRead(CommandPort
, 0, 0, 0, 0, 0, (DriveNum
? IDE_DH_DRV1
: 0),
728 IDE_CMD_IDENT_DRV
, (BYTE
*)DrvParms
) != 0)
733 // Report on drive parameters if debug mode
734 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
735 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
736 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
737 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
738 DrvParms
->ConfigBits
,
739 DrvParms
->LogicalCyls
,
740 DrvParms
->LogicalHeads
,
741 DrvParms
->SectorsPerTrack
,
742 DrvParms
->InterSectorGap
,
743 DrvParms
->InterSectorGapSize
);
744 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
745 DrvParms
->BytesInPLO
,
746 DrvParms
->VendorUniqueCnt
,
747 DrvParms
->SerialNumber
);
748 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
749 DrvParms
->ControllerType
,
750 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
751 DrvParms
->ECCByteCnt
,
752 DrvParms
->FirmwareRev
);
753 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
754 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
755 (DrvParms
->RWMultImplemented
) & 0xff,
756 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
757 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
758 DrvParms
->MinPIOTransTime
,
759 DrvParms
->MinDMATransTime
);
760 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%d\n",
761 DrvParms
->TMCylinders
,
763 DrvParms
->TMSectorsPerTrk
,
764 DrvParms
->TMCapacity
);
769 // IDEGetPartitionTable
772 // Gets the partition table from the device at the given offset if one exists
778 // IN int CommandPort Address of command port for controller
779 // IN int DriveNum index of drive (0,1)
780 // IN int Offset Block offset (LBA addressing)
781 // OUT PARTITION *PartitionTable address to write partition table
784 // TRUE partition table was retrieved successfully
788 IDEGetPartitionTable(IN
int CommandPort
,
791 IN PIDE_DRIVE_IDENTIFY DrvParms
,
792 OUT PARTITION
*PartitionTable
)
794 BYTE SectorBuf
[512], SectorNum
, DrvHead
, CylinderLow
, CylinderHigh
;
801 // Get sector at offset
803 if (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
805 SectorNum
= Offset
& 0xff;
806 CylinderLow
= (Offset
>> 8) & 0xff;
807 CylinderHigh
= (Offset
>> 16) & 0xff;
808 DrvHead
= ((Offset
>> 24) & 0x0f) |
809 (DriveNum
? IDE_DH_DRV1
: 0) |
814 SectorNum
= (Offset
% DrvParms
->SectorsPerTrack
) + 1;
815 Offset
/= DrvParms
->SectorsPerTrack
;
816 DrvHead
= (Offset
% DrvParms
->LogicalHeads
) |
817 (DriveNum
? IDE_DH_DRV1
: 0);
818 Offset
/= DrvParms
->LogicalHeads
;
819 CylinderLow
= Offset
& 0xff;
820 CylinderHigh
= Offset
>> 8;
824 RC
= IDEPolledRead(CommandPort
,
835 DPRINT("read failed: port %04x drive %d sector %d rc %d\n",
842 else if (*((WORD
*)(SectorBuf
+ PART_MAGIC_OFFSET
)) != PARTITION_MAGIC
)
844 DPRINT("Bad partition magic: port %04x drive %d offset %d magic %d\n",
848 *((short *)(SectorBuf
+ PART_MAGIC_OFFSET
)));
851 RtlCopyMemory(PartitionTable
, SectorBuf
+ PARTITION_OFFSET
, sizeof(PARTITION
) * 4);
854 DPRINT("Partition Table for device %d at offset %d on port %x\n",
858 for (i
= 0; i
< PARTITION_TBL_SIZE
; i
++)
860 DPRINT(" %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
862 PartitionTable
[i
].BootFlags
,
863 PartitionTable
[i
].PartitionType
,
864 PartitionTable
[i
].StartingHead
,
865 PartitionTable
[i
].StartingSector
,
866 PartitionTable
[i
].StartingCylinder
,
867 PartitionTable
[i
].EndingHead
,
868 PartitionTable
[i
].EndingSector
,
869 PartitionTable
[i
].EndingCylinder
,
870 PartitionTable
[i
].StartingBlock
,
871 PartitionTable
[i
].SectorCount
);
881 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
887 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
888 // IN PCHAR DeviceName The name of the device
889 // OUT PDEVICE_OBJECT *DeviceObject The created device object
890 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
891 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
892 // IN BOOLEAN DMASupported Does the drive support DMA?
893 // IN int SectorsPerLogCyl Sectors per cylinder
894 // IN int SectorsPerLogTrk Sectors per track
895 // IN DWORD Offset First valid sector for this device
896 // IN DWORD Size Count of valid sectors for this device
903 IDECreateDevice(IN PDRIVER_OBJECT DriverObject
,
905 OUT PDEVICE_OBJECT
*DeviceObject
,
906 IN PCONTROLLER_OBJECT ControllerObject
,
909 IN PIDE_DRIVE_IDENTIFY DrvParms
,
913 WCHAR UnicodeBuffer
[IDE_MAX_NAME_LENGTH
];
915 ANSI_STRING AnsiName
, AnsiSymLink
;
916 UNICODE_STRING UnicodeName
, SymLink
;
917 PIDE_DEVICE_EXTENSION DeviceExtension
;
919 // Create a unicode device name
920 RtlInitAnsiString(&AnsiName
, DeviceName
);
921 UnicodeName
.MaximumLength
= IDE_MAX_NAME_LENGTH
* sizeof(WCHAR
);
922 UnicodeName
.Buffer
= UnicodeBuffer
;
923 RtlAnsiStringToUnicodeString(&UnicodeName
, &AnsiName
, FALSE
);
926 RC
= IoCreateDevice(DriverObject
, sizeof(IDE_DEVICE_EXTENSION
),
927 &UnicodeName
, FILE_DEVICE_DISK
, 0, TRUE
, DeviceObject
);
930 DPRINT("IoCreateDevice call failed\n",0);
934 // Set the buffering strategy here...
935 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
936 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
938 // Fill out Device extension data
939 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) (*DeviceObject
)->DeviceExtension
;
940 DeviceExtension
->DeviceObject
= (*DeviceObject
);
941 DeviceExtension
->ControllerObject
= ControllerObject
;
942 DeviceExtension
->UnitNumber
= UnitNumber
;
943 DeviceExtension
->LBASupported
=
944 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
945 DeviceExtension
->DMASupported
=
946 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
947 // FIXME: deal with bizarre sector sizes
948 DeviceExtension
->BytesPerSector
= 512 /* DrvParms->BytesPerSector */;
949 DeviceExtension
->SectorsPerLogCyl
= DrvParms
->LogicalHeads
*
950 DrvParms
->SectorsPerTrack
;
951 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
952 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
953 DeviceExtension
->Offset
= Offset
;
954 DeviceExtension
->Size
= Size
;
955 DPRINT("%s: offset %d size %d \n",
957 DeviceExtension
->Offset
,
958 DeviceExtension
->Size
);
960 // FIXME: Create Win32 symbolic link (destroy device if it fails)
962 if (Win32Alias
!= NULL
)
964 DPRINT("Creating SymLink %s --> %s\n", DeviceName
, Win32Alias
);
965 RtlInitAnsiString(&AnsiSymLink
, Win32Alias
);
966 RtlAnsiStringToUnicodeString(&SymLink
, &AnsiSymLink
, TRUE
);
967 IoCreateSymbolicLink(&SymLink
, &UnicodeName
);
968 RtlFreeUnicodeString(&SymLink
);
971 // Initialize the DPC object here
972 IoInitializeDpcRequest(*DeviceObject
, IDEDpcForIsr
);
974 if (Win32Alias
!= NULL
)
976 DbgPrint("%s is %s %dMB\n", DeviceName
, Win32Alias
, Size
/ 2048);
986 // Read a sector of data from the drive in a polled fashion.
992 // IN WORD Address Address of command port for drive
993 // IN BYTE PreComp Value to write to precomp register
994 // IN BYTE SectorCnt Value to write to sectorCnt register
995 // IN BYTE SectorNum Value to write to sectorNum register
996 // IN BYTE CylinderLow Value to write to CylinderLow register
997 // IN BYTE CylinderHigh Value to write to CylinderHigh register
998 // IN BYTE DrvHead Value to write to Drive/Head register
999 // IN BYTE Command Value to write to Command register
1000 // OUT BYTE *Buffer Buffer for output data
1003 // int 0 is success, non 0 is an error code
1007 IDEPolledRead(IN WORD Address
,
1011 IN BYTE CylinderLow
,
1012 IN BYTE CylinderHigh
,
1020 /* Wait for STATUS.BUSY to clear */
1021 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1023 Status
= IDEReadStatus(Address
);
1024 if (!(Status
& IDE_SR_BUSY
))
1028 KeStallExecutionProcessor(10);
1030 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1035 /* Write Drive/Head to select drive */
1036 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1038 /* Wait for STATUS.BUSY to clear and STATUS.DRDY to assert */
1039 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1041 Status
= IDEReadStatus(Address
);
1042 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1046 KeStallExecutionProcessor(10);
1048 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1053 /* Issue command to drive */
1054 if (DrvHead
& IDE_DH_LBA
)
1056 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1057 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1058 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1064 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1065 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1074 /* Setup command parameters */
1075 IDEWritePrecomp(Address
, PreComp
);
1076 IDEWriteSectorCount(Address
, SectorCnt
);
1077 IDEWriteSectorNum(Address
, SectorNum
);
1078 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1079 IDEWriteCylinderLow(Address
, CylinderLow
);
1080 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1082 /* Issue the command */
1083 IDEWriteCommand(Address
, Command
);
1084 KeStallExecutionProcessor(50);
1089 // wait for DRQ or error
1090 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1092 Status
= IDEReadStatus(Address
);
1093 if (!(Status
& IDE_SR_BUSY
))
1095 if (Status
& IDE_SR_ERR
)
1097 BYTE Err
= IDEReadError(Address
);
1100 else if (Status
& IDE_SR_DRQ
)
1105 KeStallExecutionProcessor(10);
1107 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1112 // Read data into buffer
1113 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1114 Buffer
+= IDE_SECTOR_BUF_SZ
;
1116 // Check for more sectors to read
1117 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
&&
1118 (IDEReadStatus(Address
) & IDE_SR_DRQ
); RetryCount
++)
1120 if (!(IDEReadStatus(Address
) & IDE_SR_BUSY
))
1127 // ------------------------------------------- Nondiscardable statics
1129 // IDEDispatchOpenClose
1132 // Answer requests for Open/Close calls: a null operation
1138 // Standard dispatch arguments
1145 IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
,
1148 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1149 Irp
->IoStatus
.Information
= FILE_OPENED
;
1150 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1152 return STATUS_SUCCESS
;
1155 // IDEDispatchReadWrite
1158 // Answer requests for reads and writes
1164 // Standard dispatch arguments
1171 IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
,
1175 LARGE_INTEGER AdjustedOffset
, AdjustedExtent
, PartitionExtent
, InsertKeyLI
;
1176 PIO_STACK_LOCATION IrpStack
;
1177 PIDE_DEVICE_EXTENSION DeviceExtension
;
1179 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1180 DeviceExtension
= (PIDE_DEVICE_EXTENSION
)pDO
->DeviceExtension
;
1182 // Validate operation parameters
1183 AdjustedOffset
= RtlEnlargedIntegerMultiply(DeviceExtension
->Offset
,
1184 DeviceExtension
->BytesPerSector
);
1185 DPRINT("Offset:%ld * BytesPerSector:%ld = AdjOffset:%ld:%ld\n",
1186 DeviceExtension
->Offset
,
1187 DeviceExtension
->BytesPerSector
,
1188 (unsigned long) AdjustedOffset
.HighPart
,
1189 (unsigned long) AdjustedOffset
.LowPart
);
1190 DPRINT("AdjOffset:%ld:%ld + ByteOffset:%ld:%ld = ",
1191 (unsigned long) AdjustedOffset
.HighPart
,
1192 (unsigned long) AdjustedOffset
.LowPart
,
1193 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.HighPart
,
1194 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.LowPart
);
1195 AdjustedOffset
= RtlLargeIntegerAdd(AdjustedOffset
,
1196 IrpStack
->Parameters
.Read
.ByteOffset
);
1197 DPRINT("AdjOffset:%ld:%ld\n",
1198 (unsigned long) AdjustedOffset
.HighPart
,
1199 (unsigned long) AdjustedOffset
.LowPart
);
1200 AdjustedExtent
= RtlLargeIntegerAdd(AdjustedOffset
,
1201 RtlConvertLongToLargeInteger(IrpStack
->Parameters
.Read
.Length
));
1202 DPRINT("AdjOffset:%ld:%ld + Length:%ld = AdjExtent:%ld:%ld\n",
1203 (unsigned long) AdjustedOffset
.HighPart
,
1204 (unsigned long) AdjustedOffset
.LowPart
,
1205 IrpStack
->Parameters
.Read
.Length
,
1206 (unsigned long) AdjustedExtent
.HighPart
,
1207 (unsigned long) AdjustedExtent
.LowPart
);
1208 /* FIXME: this assumption will fail on drives bigger than 1TB */
1209 PartitionExtent
.QuadPart
= DeviceExtension
->Offset
+ DeviceExtension
->Size
;
1210 PartitionExtent
= RtlExtendedIntegerMultiply(PartitionExtent
,
1211 DeviceExtension
->BytesPerSector
);
1212 if (RtlLargeIntegerGreaterThan(AdjustedExtent
, PartitionExtent
) ||
1213 (IrpStack
->Parameters
.Read
.Length
& (DeviceExtension
->BytesPerSector
- 1)))
1215 DPRINT("Request failed on bad parameters\n",0);
1216 DPRINT("AdjustedExtent=%d:%d PartitionExtent=%d:%d ReadLength=%d\n",
1217 (unsigned int) AdjustedExtent
.HighPart
,
1218 (unsigned int) AdjustedExtent
.LowPart
,
1219 (unsigned int) PartitionExtent
.HighPart
,
1220 (unsigned int) PartitionExtent
.LowPart
,
1221 IrpStack
->Parameters
.Read
.Length
);
1222 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1223 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1224 return STATUS_INVALID_PARAMETER
;
1227 // Adjust operation to absolute sector offset
1228 IrpStack
->Parameters
.Read
.ByteOffset
= AdjustedOffset
;
1230 // Start the packet and insert the request in order of sector offset
1231 assert(DeviceExtension
->BytesPerSector
== 512);
1232 InsertKeyLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1233 IrpInsertKey
= InsertKeyLI
.LowPart
;
1234 IoStartPacket(DeviceExtension
->DeviceObject
, Irp
, &IrpInsertKey
, NULL
);
1236 return STATUS_PENDING
;
1239 // IDEDispatchDeviceControl
1242 // Answer requests for device control calls
1248 // Standard dispatch arguments
1255 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1259 ULONG ControlCode
, InputLength
, OutputLength
;
1260 PIO_STACK_LOCATION IrpStack
;
1261 PIDE_DEVICE_EXTENSION DeviceExtension
;
1263 RC
= STATUS_SUCCESS
;
1264 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1265 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1266 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1267 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1268 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1270 // A huge switch statement in a Windows program?! who would have thought?
1271 switch (ControlCode
)
1273 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1274 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1276 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1280 PDISK_GEOMETRY Geometry
;
1282 Geometry
= (PDISK_GEOMETRY
) Irp
->AssociatedIrp
.SystemBuffer
;
1283 Geometry
->MediaType
= FixedMedia
;
1284 // FIXME: should report for RawDevice even on partition
1285 Geometry
->Cylinders
.QuadPart
= DeviceExtension
->Size
/
1286 DeviceExtension
->SectorsPerLogCyl
;
1287 Geometry
->TracksPerCylinder
= DeviceExtension
->SectorsPerLogTrk
/
1288 DeviceExtension
->SectorsPerLogCyl
;
1289 Geometry
->SectorsPerTrack
= DeviceExtension
->SectorsPerLogTrk
;
1290 Geometry
->BytesPerSector
= DeviceExtension
->BytesPerSector
;
1292 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1293 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1297 case IOCTL_DISK_GET_PARTITION_INFO
:
1298 case IOCTL_DISK_SET_PARTITION_INFO
:
1299 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1300 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1301 case IOCTL_DISK_VERIFY
:
1302 case IOCTL_DISK_FORMAT_TRACKS
:
1303 case IOCTL_DISK_PERFORMANCE
:
1304 case IOCTL_DISK_IS_WRITABLE
:
1305 case IOCTL_DISK_LOGGING
:
1306 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1307 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1308 case IOCTL_DISK_HISTOGRAM_DATA
:
1309 case IOCTL_DISK_HISTOGRAM_RESET
:
1310 case IOCTL_DISK_REQUEST_STRUCTURE
:
1311 case IOCTL_DISK_REQUEST_DATA
:
1313 // If we get here, something went wrong. inform the requestor
1315 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1316 Irp
->IoStatus
.Status
= RC
;
1317 Irp
->IoStatus
.Information
= 0;
1321 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1329 // Get the next requested I/O packet started
1335 // Dispatch routine standard arguments
1342 IDEStartIo(IN PDEVICE_OBJECT DeviceObject
,
1345 LARGE_INTEGER SectorLI
;
1346 PIO_STACK_LOCATION IrpStack
;
1347 PIDE_DEVICE_EXTENSION DeviceExtension
;
1350 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1351 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1353 // FIXME: implement the supported functions
1355 switch (IrpStack
->MajorFunction
)
1359 DeviceExtension
->Operation
= IrpStack
->MajorFunction
;
1360 DeviceExtension
->BytesRequested
= IrpStack
->Parameters
.Read
.Length
;
1361 assert(DeviceExtension
->BytesPerSector
== 512);
1362 SectorLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1363 DeviceExtension
->StartingSector
= SectorLI
.LowPart
;
1364 if (DeviceExtension
->BytesRequested
> DeviceExtension
->BytesPerSector
*
1365 IDE_MAX_SECTORS_PER_XFER
)
1367 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesPerSector
*
1368 IDE_MAX_SECTORS_PER_XFER
;
1372 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1374 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1375 DeviceExtension
->SectorsTransferred
= 0;
1376 DeviceExtension
->TargetAddress
= (BYTE
*)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1377 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1378 IoAllocateController(DeviceExtension
->ControllerObject
,
1380 IDEAllocateController
,
1382 KeLowerIrql(OldIrql
);
1386 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1387 Irp
->IoStatus
.Information
= 0;
1388 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1389 IoStartNextPacket(DeviceObject
, FALSE
);
1394 // IDEAllocateController
1396 static IO_ALLOCATION_ACTION
1397 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
1399 IN PVOID MapRegisterBase
,
1402 PIDE_DEVICE_EXTENSION DeviceExtension
;
1403 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1405 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1406 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1407 DeviceExtension
->ControllerObject
->ControllerExtension
;
1408 ControllerExtension
->CurrentIrp
= Irp
;
1409 ControllerExtension
->Retries
= 0;
1410 return KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1412 DeviceExtension
) ? KeepObject
:
1416 // IDEStartController
1419 IDEStartController(IN OUT PVOID Context
)
1421 BYTE SectorCnt
, SectorNum
, CylinderLow
, CylinderHigh
;
1422 BYTE DrvHead
, Command
;
1424 ULONG StartingSector
;
1425 PIDE_DEVICE_EXTENSION DeviceExtension
;
1426 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1429 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) Context
;
1430 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1431 DeviceExtension
->ControllerObject
->ControllerExtension
;
1432 ControllerExtension
->OperationInProgress
= TRUE
;
1433 ControllerExtension
->DeviceForOperation
= DeviceExtension
;
1435 // Write controller registers to start opteration
1436 StartingSector
= DeviceExtension
->StartingSector
;
1437 SectorCnt
= DeviceExtension
->BytesToTransfer
/
1438 DeviceExtension
->BytesPerSector
;
1439 if (DeviceExtension
->LBASupported
)
1441 SectorNum
= StartingSector
& 0xff;
1442 CylinderLow
= (StartingSector
>> 8) & 0xff;
1443 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1444 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1445 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0) |
1450 SectorNum
= (StartingSector
% DeviceExtension
->SectorsPerLogTrk
) + 1;
1451 StartingSector
/= DeviceExtension
->SectorsPerLogTrk
;
1452 DrvHead
= (StartingSector
% DeviceExtension
->LogicalHeads
) |
1453 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0);
1454 StartingSector
/= DeviceExtension
->LogicalHeads
;
1455 CylinderLow
= StartingSector
& 0xff;
1456 CylinderHigh
= StartingSector
>> 8;
1458 Command
= DeviceExtension
->Operation
== IRP_MJ_READ
?
1459 IDE_CMD_READ_RETRY
: IDE_CMD_WRITE_RETRY
;
1460 if (DrvHead
& IDE_DH_LBA
)
1462 DPRINT("%s:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1463 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1464 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1465 ((DrvHead
& 0x0f) << 24) +
1466 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1472 DPRINT("%s:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1473 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1474 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1483 /* wait for BUSY to clear */
1484 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1486 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1487 if (!(Status
& IDE_SR_BUSY
))
1491 KeStallExecutionProcessor(10);
1493 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1495 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1497 Irp
= ControllerExtension
->CurrentIrp
;
1498 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1499 Irp
->IoStatus
.Information
= 0;
1505 IDEBeginControllerReset(ControllerExtension
);
1511 /* Select the desired drive */
1512 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1514 /* wait for BUSY to clear and DRDY to assert */
1515 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1517 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1518 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1522 KeStallExecutionProcessor(10);
1524 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1526 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1528 Irp
= ControllerExtension
->CurrentIrp
;
1529 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1530 Irp
->IoStatus
.Information
= 0;
1536 IDEBeginControllerReset(ControllerExtension
);
1542 /* Setup command parameters */
1543 IDEWritePrecomp(ControllerExtension
->CommandPortBase
, 0);
1544 IDEWriteSectorCount(ControllerExtension
->CommandPortBase
, SectorCnt
);
1545 IDEWriteSectorNum(ControllerExtension
->CommandPortBase
, SectorNum
);
1546 IDEWriteCylinderHigh(ControllerExtension
->CommandPortBase
, CylinderHigh
);
1547 IDEWriteCylinderLow(ControllerExtension
->CommandPortBase
, CylinderLow
);
1548 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1550 /* Issue command to drive */
1551 IDEWriteCommand(ControllerExtension
->CommandPortBase
, Command
);
1552 ControllerExtension
->TimerState
= IDETimerCmdWait
;
1553 ControllerExtension
->TimerCount
= IDE_CMD_TIMEOUT
;
1555 if (DeviceExtension
->Operation
== IRP_MJ_WRITE
)
1558 // Wait for controller ready
1559 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
1561 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1562 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
1566 KeStallExecutionProcessor(10);
1568 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1570 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1572 Irp
= ControllerExtension
->CurrentIrp
;
1573 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1574 Irp
->IoStatus
.Information
= 0;
1580 IDEBeginControllerReset(ControllerExtension
);
1586 // Load the first sector of data into the controller
1587 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1588 DeviceExtension
->TargetAddress
,
1590 DeviceExtension
->TargetAddress
+= IDE_SECTOR_BUF_SZ
;
1591 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1592 DeviceExtension
->SectorsTransferred
++;
1598 // IDEBeginControllerReset
1601 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1605 DPRINT("Controller Reset initiated on %04x\n",
1606 ControllerExtension
->ControlPortBase
);
1608 /* Assert drive reset line */
1609 DPRINT("Asserting reset line\n");
1610 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, IDE_DC_SRST
);
1612 /* Wait for BSY assertion */
1613 DPRINT("Waiting for BSY assertion\n");
1614 for (Retries
= 0; Retries
< IDE_MAX_RESET_RETRIES
; Retries
++)
1616 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1617 if ((Status
& IDE_SR_BUSY
))
1621 KeStallExecutionProcessor(10);
1623 if (Retries
== IDE_MAX_RESET_RETRIES
)
1625 DPRINT("Timeout on BSY assertion\n");
1628 /* Negate drive reset line */
1629 DPRINT("Negating reset line\n");
1630 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, 0);
1632 // FIXME: handle case of no device 0
1634 /* Set timer to check for end of reset */
1635 ControllerExtension
->TimerState
= IDETimerResetWaitForBusyNegate
;
1636 ControllerExtension
->TimerCount
= IDE_RESET_BUSY_TIMEOUT
;
1642 // Handle interrupts for IDE devices
1648 // IN PKINTERRUPT Interrupt The interrupt level in effect
1649 // IN PVOID ServiceContext The driver supplied context
1650 // (the controller extension)
1652 // TRUE This ISR handled the interrupt
1653 // FALSE Another ISR must handle this interrupt
1656 IDEIsr(IN PKINTERRUPT Interrupt
,
1657 IN PVOID ServiceContext
)
1659 BOOLEAN IsLastBlock
, AnErrorOccured
, RequestIsComplete
;
1660 BYTE
*TargetAddress
;
1662 NTSTATUS ErrorStatus
;
1663 ULONG ErrorInformation
;
1665 PIDE_DEVICE_EXTENSION DeviceExtension
;
1666 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1668 if (IDEInitialized
== FALSE
)
1673 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) ServiceContext
;
1675 // Read the status port to clear the interrtupt (even if it's not ours).
1676 ControllerExtension
->DeviceStatus
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1678 // If the interrupt is not ours, get the heck outta dodge.
1679 if (!ControllerExtension
->OperationInProgress
)
1684 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1685 IsLastBlock
= FALSE
;
1686 AnErrorOccured
= FALSE
;
1687 RequestIsComplete
= FALSE
;
1688 ErrorStatus
= STATUS_SUCCESS
;
1689 ErrorInformation
= 0;
1691 // Handle error condition if it exists
1692 if (ControllerExtension
->DeviceStatus
& IDE_SR_ERR
)
1694 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
1698 ErrorReg
= IDEReadError(ControllerExtension
->CommandPortBase
);
1699 CylinderLow
= IDEReadCylinderLow(ControllerExtension
->CommandPortBase
);
1700 CylinderHigh
= IDEReadCylinderHigh(ControllerExtension
->CommandPortBase
);
1701 DriveHead
= IDEReadDriveHead(ControllerExtension
->CommandPortBase
);
1702 SectorCount
= IDEReadSectorCount(ControllerExtension
->CommandPortBase
);
1703 SectorNum
= IDEReadSectorNum(ControllerExtension
->CommandPortBase
);
1704 // FIXME: should use the NT error logging facility
1705 DPRINT("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1706 DeviceExtension
->Operation
,
1707 ControllerExtension
->DeviceStatus
,
1714 // FIXME: should retry the command and perhaps recalibrate the drive
1716 // Set error status information
1717 AnErrorOccured
= TRUE
;
1718 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
1720 (((((((CylinderHigh
<< 8) + CylinderLow
) *
1721 DeviceExtension
->LogicalHeads
) +
1722 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
1723 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
1724 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
1729 // Check controller and setup for next transfer
1730 switch (DeviceExtension
->Operation
)
1734 // Update controller/device state variables
1735 TargetAddress
= DeviceExtension
->TargetAddress
;
1736 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1737 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1738 DeviceExtension
->SectorsTransferred
++;
1740 // Remember whether DRQ should be low at end (last block read)
1741 IsLastBlock
= DeviceExtension
->BytesToTransfer
== 0;
1743 // Wait for DRQ assertion
1744 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
1745 !(IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
);
1748 KeStallExecutionProcessor(10);
1751 // Copy the block of data
1752 IDEReadBlock(ControllerExtension
->CommandPortBase
,
1759 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1760 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1763 KeStallExecutionProcessor(10);
1766 // Check for data overrun
1767 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1769 AnErrorOccured
= TRUE
;
1770 ErrorStatus
= STATUS_DATA_OVERRUN
;
1771 ErrorInformation
= 0;
1776 // Setup next transfer or set RequestIsComplete
1777 if (DeviceExtension
->BytesRequested
>
1778 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1780 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1781 DeviceExtension
->SectorsTransferred
= 0;
1782 DeviceExtension
->BytesToTransfer
=
1783 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1784 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1786 else if (DeviceExtension
->BytesRequested
> 0)
1788 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1789 DeviceExtension
->SectorsTransferred
= 0;
1790 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1791 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1795 RequestIsComplete
= TRUE
;
1804 if (DeviceExtension
->BytesToTransfer
== 0)
1806 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1807 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1810 KeStallExecutionProcessor(10);
1813 // Check for data overrun
1814 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1816 AnErrorOccured
= TRUE
;
1817 ErrorStatus
= STATUS_DATA_OVERRUN
;
1818 ErrorInformation
= 0;
1823 // Setup next transfer or set RequestIsComplete
1825 if (DeviceExtension
->BytesRequested
>
1826 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1828 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1829 DeviceExtension
->SectorsTransferred
= 0;
1830 DeviceExtension
->BytesToTransfer
=
1831 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1832 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1834 else if (DeviceExtension
->BytesRequested
> 0)
1836 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1837 DeviceExtension
->SectorsTransferred
= 0;
1838 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1839 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1843 RequestIsComplete
= TRUE
;
1850 // Update controller/device state variables
1851 TargetAddress
= DeviceExtension
->TargetAddress
;
1852 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1853 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1854 DeviceExtension
->SectorsTransferred
++;
1856 // Write block to controller
1857 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1865 // If there was an error or the request is done, complete the packet
1866 if (AnErrorOccured
|| RequestIsComplete
)
1868 // Set the return status and info values
1869 Irp
= ControllerExtension
->CurrentIrp
;
1870 Irp
->IoStatus
.Status
= ErrorStatus
;
1871 Irp
->IoStatus
.Information
= ErrorInformation
;
1873 // Clear out controller fields
1874 ControllerExtension
->OperationInProgress
= FALSE
;
1875 ControllerExtension
->DeviceStatus
= 0;
1877 // Queue the Dpc to finish up
1878 IoRequestDpc(DeviceExtension
->DeviceObject
,
1880 ControllerExtension
);
1882 else if (IsLastBlock
)
1884 // Else more data is needed, setup next device I/O
1885 IDEStartController((PVOID
)DeviceExtension
);
1898 // IN PDEVICE_OBJECT DpcDeviceObject
1900 // IN PVOID DpcContext
1903 IDEDpcForIsr(IN PKDPC Dpc
,
1904 IN PDEVICE_OBJECT DpcDeviceObject
,
1906 IN PVOID DpcContext
)
1908 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION
) DpcContext
);
1911 // IDEFinishOperation
1914 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1916 PIDE_DEVICE_EXTENSION DeviceExtension
;
1920 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1921 Irp
= ControllerExtension
->CurrentIrp
;
1922 Operation
= DeviceExtension
->Operation
;
1923 ControllerExtension
->OperationInProgress
= FALSE
;
1924 ControllerExtension
->DeviceForOperation
= 0;
1925 ControllerExtension
->CurrentIrp
= 0;
1927 // Deallocate the controller
1928 IoFreeController(DeviceExtension
->ControllerObject
);
1930 // Start the next packet
1931 IoStartNextPacketByKey(DeviceExtension
->DeviceObject
,
1933 DeviceExtension
->StartingSector
);
1935 // Issue completion of the current packet
1936 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1938 // Flush cache if necessary
1939 if (Operation
== IRP_MJ_READ
)
1941 KeFlushIoBuffers(Irp
->MdlAddress
, TRUE
, FALSE
);
1947 // This function handles timeouts and other time delayed processing
1952 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1953 // IN PVOID Context the Controller extension for the
1954 // controller the device is on
1957 IDEIoTimer(PDEVICE_OBJECT DeviceObject
,
1960 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1962 // Setup Extension pointer
1963 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) Context
;
1964 DPRINT("Timer activated for %04lx\n", ControllerExtension
->CommandPortBase
);
1966 // Handle state change if necessary
1967 switch (ControllerExtension
->TimerState
)
1969 case IDETimerResetWaitForBusyNegate
:
1970 if (!(IDEReadStatus(ControllerExtension
->CommandPortBase
) &
1973 DPRINT("Busy line has negated, waiting for DRDY assert\n");
1974 ControllerExtension
->TimerState
= IDETimerResetWaitForDrdyAssert
;
1975 ControllerExtension
->TimerCount
= IDE_RESET_DRDY_TIMEOUT
;
1980 case IDETimerResetWaitForDrdyAssert
:
1981 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) &
1984 DPRINT("DRDY has asserted, reset complete\n");
1985 ControllerExtension
->TimerState
= IDETimerIdle
;
1986 ControllerExtension
->TimerCount
= 0;
1988 // FIXME: get diagnostic code from drive 0
1990 /* Start current packet command again */
1991 if (!KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1993 ControllerExtension
->DeviceForOperation
))
1995 IDEFinishOperation(ControllerExtension
);
2005 // If we're counting down, then count.
2006 if (ControllerExtension
->TimerCount
> 0)
2008 ControllerExtension
->TimerCount
--;
2010 // Else we'll check the state and process if necessary
2014 switch (ControllerExtension
->TimerState
)
2019 case IDETimerCmdWait
:
2020 /* Command timed out, reset drive and try again or fail */
2021 DPRINT("Timeout waiting for command completion\n");
2022 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
2024 DPRINT("Max retries has been reached, IRP finished with error\n");
2025 ControllerExtension
->CurrentIrp
->IoStatus
.Status
= STATUS_IO_TIMEOUT
;
2026 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2027 IDEFinishOperation(ControllerExtension
);
2028 ControllerExtension
->TimerState
= IDETimerIdle
;
2029 ControllerExtension
->TimerCount
= 0;
2033 IDEBeginControllerReset(ControllerExtension
);
2037 case IDETimerResetWaitForBusyNegate
:
2038 case IDETimerResetWaitForDrdyAssert
:
2039 DPRINT("Timeout waiting for drive reset, giving up on IRP\n");
2040 if (ControllerExtension
->CurrentIrp
!= NULL
)
2042 ControllerExtension
->CurrentIrp
->IoStatus
.Status
=
2044 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2045 IDEFinishOperation(ControllerExtension
);
2047 ControllerExtension
->TimerState
= IDETimerIdle
;
2048 ControllerExtension
->TimerCount
= 0;