1 /* $Id: ide.c,v 1.23 1999/12/04 20:58:36 ea Exp $
3 * IDE.C - IDE Disk driver
4 * written by Rex Jolliff
5 * with help from various documentation sources and a few peeks at
6 * linux and freebsd sources.
8 * This driver supports up to 4 controllers with up to 2 drives each.
9 * The device names are assigned as follows:
10 * \Devices\HarddiskX\Partition0
11 * for the raw device, and
12 * \Devices\HarddiskX\PartitionY
15 * X is computed by counting the available drives from the following
16 * sequence: the controller number (0=0x1f0, 1=0x170, 2=0x1e8,
17 * 3=0x168) * 2 plus the drive number (0,1)
18 * Y is the partition number
20 * The driver exports the following function:
22 * DriverEntry() - NT device driver initialization routine
24 * And the following functions are exported implicitly:
26 * IDEStartIo() - called to start an I/O request packet
27 * IDEDispatchOpenClose() - Called to open/close the device. a NOOP
28 * IDEDispatchReadWrite() - Called to read/write the device.
29 * IDEDispatchQueryInformation() - Called to get device information
30 * IDEDispatchSetInformation() - Called to set device information
31 * IDEDispatchDeviceControl() - Called to execute device control requests
33 * Modification History:
34 * 05/25/98 RJJ Created.
35 * 05/30/98 RJJ Removed IRQ handler and inserted busy waits
36 * just to get something working...
37 * 07/18/98 RJJ Made drastic changes so that the driver
38 * resembles a WinNT driver.
39 * 08/05/98 RJJ Changed to .C extension
40 * 09/19/98 RJJ First release (run for cover!)
43 * 09/17/98 RJJ Pri/MST: 14.12X19 WDC AC31000H Test Passed
48 * FIXME: a timer should be used to watch for device timeouts and errors
49 * FIXME: errors should be retried
50 * FIXME: a drive reset/recalibrate should be attempted if errors occur
51 * FIXME: Use DMA for transfers if drives support it
52 * FIXME: should we support unloading of this driver???
53 * FIXME: the device information should come from AUTODETECT (via registry)
54 * FIXME: really big devices need to be handled correctly
55 * FIXME: should get device info from the registry
56 * FIXME: should report hardware usage to iomgr
57 * FIXME: finish implementation of QueryInformation
58 * FIXME: finish implementation of SetInformation
59 * FIXME: finish implementation of DeviceControl
60 * FIXME: bring up to ATA-3 spec
61 * FIXME: add general support for ATAPI devices
62 * FIXME: add support for ATAPI CDROMs
63 * FIXME: add support for ATAPI ZIP drives/RHDs
64 * FIXME: add support for ATAPI tape drives
67 #include <ddk/ntddk.h>
69 // -------------------------------- This stuff should be defined in NTDDK.H
71 typedef DISK_GEOMETRY
*PDISK_GEOMETRY
;
73 // -------------------------------------------------------------------------
75 #include <internal/i386/io.h>
77 #include <internal/string.h>
80 #include <internal/debug.h>
86 #define VERSION "V0.1.4"
88 // ------------------------------------------------------- File Static Data
90 typedef struct _IDE_CONTROLLER_PARAMETERS
99 KINTERRUPT_MODE InterruptMode
;
101 } IDE_CONTROLLER_PARAMETERS
, *PIDE_CONTROLLER_PARAMETERS
;
103 // NOTE: Do not increase max drives above 2
105 #define IDE_MAX_DRIVES 2
107 #define IDE_MAX_CONTROLLERS 1
108 IDE_CONTROLLER_PARAMETERS Controllers
[IDE_MAX_CONTROLLERS
] =
110 {0x01f0, 8, 0x03f6, 1, 14, 14, 15, LevelSensitive
, 0xffff}
111 /*{0x0170, 8, 0x0376, 1, 15, 15, 15, LevelSensitive, 0xffff},
112 {0x01E8, 8, 0x03ee, 1, 11, 11, 15, LevelSensitive, 0xffff},
113 {0x0168, 8, 0x036e, 1, 10, 10, 15, LevelSensitive, 0xffff}*/
116 static BOOLEAN IDEInitialized
= FALSE
;
117 static int TotalPartitions
= 0;
119 // ----------------------------------------------- Discardable Declarations
123 // make the initialization routines discardable, so that they
126 #pragma alloc_text(init, DriverEntry)
127 #pragma alloc_text(init, IDECreateController)
128 #pragma alloc_text(init, IDECreateDevices)
129 #pragma alloc_text(init, IDECreateDevice)
130 #pragma alloc_text(init, IDEPolledRead)
132 // make the PASSIVE_LEVEL routines pageable, so that they don't
133 // waste nonpaged memory
135 #pragma alloc_text(page, IDEShutdown)
136 #pragma alloc_text(page, IDEDispatchOpenClose)
137 #pragma alloc_text(page, IDEDispatchRead)
138 #pragma alloc_text(page, IDEDispatchWrite)
140 #endif /* ALLOC_PRAGMA */
142 // ---------------------------------------------------- Forward Declarations
144 static BOOLEAN
IDECreateController(IN PDRIVER_OBJECT DriverObject
,
145 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
146 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 BOOLEAN
IDEGetPartitionTable(IN
int CommandPort
,
159 IN PIDE_DRIVE_IDENTIFY DrvParms
,
160 PARTITION
*PartitionTable
);
161 static NTSTATUS
IDECreateDevice(IN PDRIVER_OBJECT DriverObject
,
163 OUT PDEVICE_OBJECT
*DeviceObject
,
164 IN PCONTROLLER_OBJECT ControllerObject
,
167 IN PIDE_DRIVE_IDENTIFY DrvParms
,
170 static int IDEPolledRead(IN WORD Address
,
175 IN BYTE CylinderHigh
,
179 static NTSTATUS
IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
180 static NTSTATUS
IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
181 static NTSTATUS
IDEDispatchDeviceControl(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
182 static VOID
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
);
183 static IO_ALLOCATION_ACTION
IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
185 IN PVOID MapRegisterBase
,
187 static BOOLEAN
IDEStartController(IN OUT PVOID Context
);
188 VOID
IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
189 static BOOLEAN
IDEIsr(IN PKINTERRUPT Interrupt
, IN PVOID ServiceContext
);
190 static VOID
IDEDpcForIsr(IN PKDPC Dpc
,
191 IN PDEVICE_OBJECT DpcDeviceObject
,
193 IN PVOID DpcContext
);
194 static VOID
IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
195 static VOID
IDEIoTimer(PDEVICE_OBJECT DeviceObject
, PVOID Context
);
197 // ---------------------------------------------------------------- Inlines
200 IDESwapBytePairs(char *Buf
,
206 for (i
= 0; i
< Cnt
; i
+= 2)
214 // ------------------------------------------------------- Public Interface
219 // This function initializes the driver, locates and claims
220 // hardware resources, and creates various NT objects needed
221 // to process I/O requests.
227 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
229 // IN PUNICODE_STRING RegistryPath Name of registry driver service
236 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
237 IN PUNICODE_STRING RegistryPath
)
239 BOOLEAN WeGotSomeDisks
;
242 DbgPrint("IDE Driver %s\n", VERSION
);
244 // Export other driver entry points...
245 DriverObject
->DriverStartIo
= IDEStartIo
;
246 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = IDEDispatchOpenClose
;
247 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = IDEDispatchOpenClose
;
248 DriverObject
->MajorFunction
[IRP_MJ_READ
] = IDEDispatchReadWrite
;
249 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = IDEDispatchReadWrite
;
250 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
251 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
252 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = IDEDispatchDeviceControl
;
254 WeGotSomeDisks
= FALSE
;
255 for (ControllerIdx
= 0; ControllerIdx
< IDE_MAX_CONTROLLERS
; ControllerIdx
++)
257 WeGotSomeDisks
|= IDECreateController(DriverObject
,
258 &Controllers
[ControllerIdx
], ControllerIdx
);
263 IDEInitialized
= TRUE
;
265 DPRINT( "Returning from DriverEntry\n" );
266 return WeGotSomeDisks
? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
;
269 // ---------------------------------------------------- Discardable statics
271 // IDECreateController
274 // Creates a controller object and a device object for each valid
275 // device on the controller
281 // IN PDRIVER_OBJECT DriverObject The system created driver object
282 // IN PIDE_CONTROLLER_PARAMETERS The parameter block for this
283 // ControllerParams controller
284 // IN int ControllerIdx The index of this controller
287 // TRUE Devices where found on this controller
288 // FALSE The controller does not respond or there are no devices on it
292 IDECreateController(IN PDRIVER_OBJECT DriverObject
,
293 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
294 IN
int ControllerIdx
)
296 BOOLEAN CreatedDevices
, ThisDriveExists
;
299 PCONTROLLER_OBJECT ControllerObject
;
300 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
302 // Try to reset the controller and return FALSE if it fails
303 if (!IDEResetController(ControllerParams
->CommandPortBase
,
304 ControllerParams
->ControlPortBase
))
306 DPRINT("Could not find controller %d at %04lx\n",
307 ControllerIdx
, ControllerParams
->CommandPortBase
);
311 ControllerObject
= IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION
));
312 if (ControllerObject
== NULL
)
314 DPRINT("Could not create controller object for controller %d\n",
319 // Fill out Controller extension data
320 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
321 ControllerObject
->ControllerExtension
;
322 ControllerExtension
->Number
= ControllerIdx
;
323 ControllerExtension
->CommandPortBase
= ControllerParams
->CommandPortBase
;
324 ControllerExtension
->ControlPortBase
= ControllerParams
->ControlPortBase
;
325 ControllerExtension
->Vector
= ControllerParams
->Vector
;
326 ControllerExtension
->DMASupported
= FALSE
;
327 ControllerExtension
->ControllerInterruptBug
= FALSE
;
328 ControllerExtension
->OperationInProgress
= FALSE
;
330 // Initialize the spin lock in the controller extension
331 KeInitializeSpinLock(&ControllerExtension
->SpinLock
);
333 // Register an interrupt handler for this controller
334 RC
= IoConnectInterrupt(&ControllerExtension
->Interrupt
,
337 &ControllerExtension
->SpinLock
,
338 ControllerExtension
->Vector
,
339 ControllerParams
->IrqL
,
340 ControllerParams
->SynchronizeIrqL
,
341 ControllerParams
->InterruptMode
,
343 ControllerParams
->Affinity
,
347 DPRINT("Could not Connect Interrupt %d\n", ControllerExtension
->Vector
);
348 IoDeleteController(ControllerObject
);
352 // Create device objects for each raw device (and for partitions)
353 CreatedDevices
= FALSE
;
354 for (DriveIdx
= 0; DriveIdx
< IDE_MAX_DRIVES
; DriveIdx
++)
356 ThisDriveExists
= IDECreateDevices(DriverObject
,
360 ControllerIdx
* 2 + DriveIdx
);
363 CreatedDevices
= TRUE
;
369 DPRINT("Did not find any devices for controller %d\n", ControllerIdx
);
370 IoDisconnectInterrupt(ControllerExtension
->Interrupt
);
371 IoDeleteController(ControllerObject
);
375 IoStartTimer(ControllerExtension
->TimerDevice
);
378 return CreatedDevices
;
381 // IDEResetController
384 // Reset the controller and report completion status
390 // IN WORD CommandPort The address of the command port
391 // IN WORD ControlPort The address of the control port
397 IDEResetController(IN WORD CommandPort
,
402 // Assert drive reset line
403 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
405 // Wait for min. 25 microseconds
406 KeStallExecutionProcessor(IDE_RESET_PULSE_LENGTH
);
408 // Negate drive reset line
409 IDEWriteDriveControl(ControlPort
, 0);
411 // Wait for BUSY assertion
412 /*for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
414 if (IDEReadStatus(CommandPort) & IDE_SR_BUSY)
418 KeStallExecutionProcessor(10);
421 if (Retries >= IDE_MAX_BUSY_RETRIES)
426 // Wait for BUSY negation
427 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
429 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
433 KeStallExecutionProcessor(10);
436 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
441 // return TRUE if controller came back to life. and
442 // the registers are initialized correctly
443 return IDEReadError(CommandPort
) == 1;
449 // Create the raw device and any partition devices on this drive
455 // IN PDRIVER_OBJECT DriverObject The system created driver object
456 // IN PCONTROLLER_OBJECT ControllerObject
457 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
458 // The IDE controller extension for
460 // IN int DriveIdx The index of the drive on this
462 // IN int HarddiskIdx The NT device number for this
466 // TRUE Drive exists and devices were created
467 // FALSE no devices were created for this device
471 IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
472 IN PCONTROLLER_OBJECT ControllerObject
,
473 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
477 BOOLEAN CreatedDevices
;
478 char RawDeviceName
[IDE_MAX_NAME_LENGTH
];
479 char PrimaryDeviceName
[IDE_MAX_NAME_LENGTH
];
480 char LogicalDeviceName
[IDE_MAX_NAME_LENGTH
];
481 char Win32AliasName
[IDE_MAX_NAME_LENGTH
];
482 int CommandPort
, PartitionIdx
, PartitionNum
;
483 int ExtPartitionIdx
, ExtOffset
;
485 IDE_DRIVE_IDENTIFY DrvParms
;
486 PDEVICE_OBJECT RawDeviceObject
;
487 PDEVICE_OBJECT PrimaryDeviceObject
;
488 PDEVICE_OBJECT LogicalDeviceObject
;
489 PIDE_DEVICE_EXTENSION RawDeviceExtension
;
490 PARTITION PrimaryPartitionTable
[4], *p
;
491 PARTITION ExtendedPartitionTable
[4], *ep
;
492 char DeviceDirName
[IDE_MAX_NAME_LENGTH
+ 1];
493 ANSI_STRING AnsiDeviceDirName
;
494 UNICODE_STRING UnicodeDeviceDirName
;
495 OBJECT_ATTRIBUTES DeviceDirAttributes
;
498 // Copy I/O port offsets for convenience
499 CommandPort
= ControllerExtension
->CommandPortBase
;
500 // ControlPort = ControllerExtension->ControlPortBase;
501 DPRINT("probing IDE controller %d Addr %04lx Drive %d\n",
502 ControllerExtension
->Number
,
506 // Get the Drive Identification Data
507 if (!IDEGetDriveIdentification(CommandPort
, DriveIdx
, &DrvParms
))
509 DPRINT("Giving up on drive %d on controller %d...\n",
511 ControllerExtension
->Number
);
515 CreatedDevices
= FALSE
;
517 // Create the harddisk device directory
518 strcpy(DeviceDirName
, IDE_NT_ROOTDIR_NAME
);
519 strcat(DeviceDirName
, IDE_NT_DEVICE_NAME
);
520 DeviceDirName
[strlen(DeviceDirName
) + 1] = '\0';
521 DeviceDirName
[strlen(DeviceDirName
)] = '0' + HarddiskIdx
;
522 RtlInitAnsiString(&AnsiDeviceDirName
, DeviceDirName
);
523 RC
= RtlAnsiStringToUnicodeString(&UnicodeDeviceDirName
,
528 DPRINT("Could not convert ansi to unicode for device dir\n", 0);
531 InitializeObjectAttributes(&DeviceDirAttributes
,
532 &UnicodeDeviceDirName
,
536 RC
= ZwCreateDirectoryObject(&Handle
, 0, &DeviceDirAttributes
);
539 DPRINT("Could not create device dir object\n", 0);
542 RtlFreeUnicodeString(&UnicodeDeviceDirName
);
544 // Create the raw device
545 strcpy(RawDeviceName
, IDE_NT_ROOTDIR_NAME
);
546 strcat(RawDeviceName
, IDE_NT_DEVICE_NAME
);
547 RawDeviceName
[strlen(RawDeviceName
) + 1] = '\0';
548 RawDeviceName
[strlen(RawDeviceName
)] = '0' + HarddiskIdx
;
549 strcat(RawDeviceName
, IDE_NT_PARTITION_NAME
);
550 RawDeviceName
[strlen(RawDeviceName
) + 1] = '\0';
551 RawDeviceName
[strlen(RawDeviceName
)] = '0';
552 RC
= IDECreateDevice(DriverObject
,
560 DrvParms
.LogicalCyls
* DrvParms
.LogicalHeads
* DrvParms
.SectorsPerTrack
);
563 DPRINT("IDECreateDevice call failed for raw device\n",0);
567 CreatedDevices
= TRUE
;
568 RawDeviceExtension
= (PIDE_DEVICE_EXTENSION
)
569 RawDeviceObject
->DeviceExtension
;
571 // Initialze the controller timer here (since it has to be
572 // tied to a device)...
575 ControllerExtension
->TimerState
= IDETimerIdle
;
576 ControllerExtension
->TimerCount
= 0;
577 ControllerExtension
->TimerDevice
= RawDeviceObject
;
578 IoInitializeTimer(RawDeviceObject
, IDEIoTimer
, ControllerExtension
);
582 // Get Main partition table for device
584 if (!IDEGetPartitionTable(CommandPort
, DriveIdx
, 0, &DrvParms
, PrimaryPartitionTable
))
586 DPRINT("drive %d controller %d: Could not get primary partition table\n",
588 ControllerExtension
->Number
);
593 // build devices for all partitions in table
594 DPRINT("partitions on %s:\n", DeviceDirName
);
595 for (PartitionIdx
= 0; PartitionIdx
< 4; PartitionIdx
++)
598 // copy partition pointer for convenience
599 p
= &PrimaryPartitionTable
[PartitionIdx
];
601 // if the partition entry is in use, create a device for it
602 if (PartitionIsSupported(p
))
604 DPRINT("%s ptbl entry:%d type:%02x Offset:%d Size:%d\n",
611 // Create Device for partition
612 strcpy(PrimaryDeviceName
, IDE_NT_ROOTDIR_NAME
);
613 strcat(PrimaryDeviceName
, IDE_NT_DEVICE_NAME
);
614 PrimaryDeviceName
[strlen(PrimaryDeviceName
) + 1] = '\0';
615 PrimaryDeviceName
[strlen(PrimaryDeviceName
)] = '0' + HarddiskIdx
;
616 strcat(PrimaryDeviceName
, IDE_NT_PARTITION_NAME
);
617 PrimaryDeviceName
[strlen(PrimaryDeviceName
) + 1] = '\0';
618 PrimaryDeviceName
[strlen(PrimaryDeviceName
)] = '0' + PartitionNum
++;
619 strcpy(Win32AliasName
, "\\??\\ :");
620 Win32AliasName
[4] = 'C' + TotalPartitions
;
622 RC
= IDECreateDevice(DriverObject
,
624 &PrimaryDeviceObject
,
633 DPRINT("IDECreateDevice call failed\n",0);
637 // Create devices for logical partitions within an extended partition
639 else if (PartitionIsExtended(p
))
641 ExtOffset
= p
->StartingBlock
;
643 // Get the Extended partition table
644 if (!IDEGetPartitionTable(CommandPort
,
648 ExtendedPartitionTable
))
650 DPRINT("Harddisk%d: could not get extended partition table at offset %d",
651 HarddiskIdx
, ExtOffset
);
655 for (ExtPartitionIdx
= 0; ExtPartitionIdx
< 4; ExtPartitionIdx
++)
657 ep
= &ExtendedPartitionTable
[ExtPartitionIdx
];
658 if (PartitionIsSupported(ep
))
660 DPRINT("Harddisk%d: Type:%02x Offset:%d Size:%d\n",
663 ep
->StartingBlock
+ ExtOffset
,
666 // Create device for logical partition
667 strcpy(LogicalDeviceName
, IDE_NT_ROOTDIR_NAME
);
668 strcat(LogicalDeviceName
, IDE_NT_DEVICE_NAME
);
669 LogicalDeviceName
[strlen(LogicalDeviceName
) + 1] = '\0';
670 LogicalDeviceName
[strlen(LogicalDeviceName
)] = '0' + HarddiskIdx
;
671 strcat(LogicalDeviceName
, IDE_NT_PARTITION_NAME
);
672 LogicalDeviceName
[strlen(LogicalDeviceName
) + 1] = '\0';
673 LogicalDeviceName
[strlen(LogicalDeviceName
)] = '0' + PartitionNum
++;
674 strcpy(Win32AliasName
, "\\??\\ :");
675 Win32AliasName
[4] = 'C' + TotalPartitions
;
677 RC
= IDECreateDevice(DriverObject
,
679 &LogicalDeviceObject
,
684 ep
->StartingBlock
+ ExtOffset
,
688 DPRINT("IDECreateDevice call failed\n",0);
701 // IDEGetDriveIdentification
704 // Get the identification block from the drive
710 // IN int CommandPort Address of the command port
711 // IN int DriveNum The drive index (0,1)
712 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
715 // TRUE The drive identification block was retrieved successfully
719 IDEGetDriveIdentification(IN
int CommandPort
,
721 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
724 // Get the Drive Identify block from drive or die
725 if (IDEPolledRead(CommandPort
, 0, 0, 0, 0, 0, (DriveNum
? IDE_DH_DRV1
: 0),
726 IDE_CMD_IDENT_DRV
, (BYTE
*)DrvParms
) != 0)
731 // Report on drive parameters if debug mode
732 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
733 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
734 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
735 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
736 DrvParms
->ConfigBits
,
737 DrvParms
->LogicalCyls
,
738 DrvParms
->LogicalHeads
,
739 DrvParms
->SectorsPerTrack
,
740 DrvParms
->InterSectorGap
,
741 DrvParms
->InterSectorGapSize
);
742 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
743 DrvParms
->BytesInPLO
,
744 DrvParms
->VendorUniqueCnt
,
745 DrvParms
->SerialNumber
);
746 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
747 DrvParms
->ControllerType
,
748 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
749 DrvParms
->ECCByteCnt
,
750 DrvParms
->FirmwareRev
);
751 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
752 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
753 (DrvParms
->RWMultImplemented
) & 0xff,
754 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
755 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
756 DrvParms
->MinPIOTransTime
,
757 DrvParms
->MinDMATransTime
);
758 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%d\n",
759 DrvParms
->TMCylinders
,
761 DrvParms
->TMSectorsPerTrk
,
762 DrvParms
->TMCapacity
);
767 // IDEGetPartitionTable
770 // Gets the partition table from the device at the given offset if one exists
776 // IN int CommandPort Address of command port for controller
777 // IN int DriveNum index of drive (0,1)
778 // IN int Offset Block offset (LBA addressing)
779 // OUT PARTITION *PartitionTable address to write partition table
782 // TRUE partition table was retrieved successfully
786 IDEGetPartitionTable(IN
int CommandPort
,
789 IN PIDE_DRIVE_IDENTIFY DrvParms
,
790 OUT PARTITION
*PartitionTable
)
792 BYTE SectorBuf
[512], SectorNum
, DrvHead
, CylinderLow
, CylinderHigh
;
799 // Get sector at offset
801 if (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
803 SectorNum
= Offset
& 0xff;
804 CylinderLow
= (Offset
>> 8) & 0xff;
805 CylinderHigh
= (Offset
>> 16) & 0xff;
806 DrvHead
= ((Offset
>> 24) & 0x0f) |
807 (DriveNum
? IDE_DH_DRV1
: 0) |
812 SectorNum
= (Offset
% DrvParms
->SectorsPerTrack
) + 1;
813 Offset
/= DrvParms
->SectorsPerTrack
;
814 DrvHead
= (Offset
% DrvParms
->LogicalHeads
) |
815 (DriveNum
? IDE_DH_DRV1
: 0);
816 Offset
/= DrvParms
->LogicalHeads
;
817 CylinderLow
= Offset
& 0xff;
818 CylinderHigh
= Offset
>> 8;
822 RC
= IDEPolledRead(CommandPort
,
833 DPRINT("read failed: port %04x drive %d sector %d rc %d\n",
840 else if (*((WORD
*)(SectorBuf
+ PART_MAGIC_OFFSET
)) != PARTITION_MAGIC
)
842 DPRINT("Bad partition magic: port %04x drive %d offset %d magic %d\n",
846 *((short *)(SectorBuf
+ PART_MAGIC_OFFSET
)));
849 RtlCopyMemory(PartitionTable
, SectorBuf
+ PARTITION_OFFSET
, sizeof(PARTITION
) * 4);
852 DPRINT("Partition Table for device %d at offset %d on port %x\n",
856 for (i
= 0; i
< PARTITION_TBL_SIZE
; i
++)
858 DPRINT(" %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
860 PartitionTable
[i
].BootFlags
,
861 PartitionTable
[i
].PartitionType
,
862 PartitionTable
[i
].StartingHead
,
863 PartitionTable
[i
].StartingSector
,
864 PartitionTable
[i
].StartingCylinder
,
865 PartitionTable
[i
].EndingHead
,
866 PartitionTable
[i
].EndingSector
,
867 PartitionTable
[i
].EndingCylinder
,
868 PartitionTable
[i
].StartingBlock
,
869 PartitionTable
[i
].SectorCount
);
879 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
885 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
886 // IN PCHAR DeviceName The name of the device
887 // OUT PDEVICE_OBJECT *DeviceObject The created device object
888 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
889 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
890 // IN BOOLEAN DMASupported Does the drive support DMA?
891 // IN int SectorsPerLogCyl Sectors per cylinder
892 // IN int SectorsPerLogTrk Sectors per track
893 // IN DWORD Offset First valid sector for this device
894 // IN DWORD Size Count of valid sectors for this device
901 IDECreateDevice(IN PDRIVER_OBJECT DriverObject
,
903 OUT PDEVICE_OBJECT
*DeviceObject
,
904 IN PCONTROLLER_OBJECT ControllerObject
,
907 IN PIDE_DRIVE_IDENTIFY DrvParms
,
911 WCHAR UnicodeBuffer
[IDE_MAX_NAME_LENGTH
];
913 ANSI_STRING AnsiName
, AnsiSymLink
;
914 UNICODE_STRING UnicodeName
, SymLink
;
915 PIDE_DEVICE_EXTENSION DeviceExtension
;
917 // Create a unicode device name
918 RtlInitAnsiString(&AnsiName
, DeviceName
);
919 UnicodeName
.MaximumLength
= IDE_MAX_NAME_LENGTH
* sizeof(WCHAR
);
920 UnicodeName
.Buffer
= UnicodeBuffer
;
921 RtlAnsiStringToUnicodeString(&UnicodeName
, &AnsiName
, FALSE
);
924 RC
= IoCreateDevice(DriverObject
, sizeof(IDE_DEVICE_EXTENSION
),
925 &UnicodeName
, FILE_DEVICE_DISK
, 0, TRUE
, DeviceObject
);
928 DPRINT("IoCreateDevice call failed\n",0);
932 // Set the buffering strategy here...
933 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
934 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
936 // Fill out Device extension data
937 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) (*DeviceObject
)->DeviceExtension
;
938 DeviceExtension
->DeviceObject
= (*DeviceObject
);
939 DeviceExtension
->ControllerObject
= ControllerObject
;
940 DeviceExtension
->UnitNumber
= UnitNumber
;
941 DeviceExtension
->LBASupported
=
942 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
943 DeviceExtension
->DMASupported
=
944 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
945 // FIXME: deal with bizarre sector sizes
946 DeviceExtension
->BytesPerSector
= 512 /* DrvParms->BytesPerSector */;
947 DeviceExtension
->SectorsPerLogCyl
= DrvParms
->LogicalHeads
*
948 DrvParms
->SectorsPerTrack
;
949 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
950 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
951 DeviceExtension
->Offset
= Offset
;
952 DeviceExtension
->Size
= Size
;
953 DPRINT("%s: offset %d size %d \n",
955 DeviceExtension
->Offset
,
956 DeviceExtension
->Size
);
958 // FIXME: Create Win32 symbolic link (destroy device if it fails)
960 if (Win32Alias
!= NULL
)
962 DPRINT("Creating SymLink %s --> %s\n", DeviceName
, Win32Alias
);
963 RtlInitAnsiString(&AnsiSymLink
, Win32Alias
);
964 RtlAnsiStringToUnicodeString(&SymLink
, &AnsiSymLink
, TRUE
);
965 IoCreateSymbolicLink(&SymLink
, &UnicodeName
);
966 RtlFreeUnicodeString(&SymLink
);
969 // Initialize the DPC object here
970 IoInitializeDpcRequest(*DeviceObject
, IDEDpcForIsr
);
972 if (Win32Alias
!= NULL
)
974 DbgPrint("%s is %s %dMB\n", DeviceName
, Win32Alias
, Size
/ 2048);
984 // Read a sector of data from the drive in a polled fashion.
990 // IN WORD Address Address of command port for drive
991 // IN BYTE PreComp Value to write to precomp register
992 // IN BYTE SectorCnt Value to write to sectorCnt register
993 // IN BYTE SectorNum Value to write to sectorNum register
994 // IN BYTE CylinderLow Value to write to CylinderLow register
995 // IN BYTE CylinderHigh Value to write to CylinderHigh register
996 // IN BYTE DrvHead Value to write to Drive/Head register
997 // IN BYTE Command Value to write to Command register
998 // OUT BYTE *Buffer Buffer for output data
1001 // int 0 is success, non 0 is an error code
1005 IDEPolledRead(IN WORD Address
,
1009 IN BYTE CylinderLow
,
1010 IN BYTE CylinderHigh
,
1018 /* Wait for STATUS.BUSY to clear */
1019 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1021 Status
= IDEReadStatus(Address
);
1022 if (!(Status
& IDE_SR_BUSY
))
1026 KeStallExecutionProcessor(10);
1028 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1033 /* Write Drive/Head to select drive */
1034 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1036 /* Wait for STATUS.BUSY to clear and STATUS.DRDY to assert */
1037 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1039 Status
= IDEReadStatus(Address
);
1040 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1044 KeStallExecutionProcessor(10);
1046 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1051 /* Issue command to drive */
1052 if (DrvHead
& IDE_DH_LBA
)
1054 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1055 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1056 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1062 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1063 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1072 /* Setup command parameters */
1073 IDEWritePrecomp(Address
, PreComp
);
1074 IDEWriteSectorCount(Address
, SectorCnt
);
1075 IDEWriteSectorNum(Address
, SectorNum
);
1076 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1077 IDEWriteCylinderLow(Address
, CylinderLow
);
1078 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1080 /* Issue the command */
1081 IDEWriteCommand(Address
, Command
);
1082 KeStallExecutionProcessor(50);
1087 // wait for DRQ or error
1088 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1090 Status
= IDEReadStatus(Address
);
1091 if (!(Status
& IDE_SR_BUSY
))
1093 if (Status
& IDE_SR_ERR
)
1095 BYTE Err
= IDEReadError(Address
);
1098 else if (Status
& IDE_SR_DRQ
)
1103 KeStallExecutionProcessor(10);
1105 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1110 // Read data into buffer
1111 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1112 Buffer
+= IDE_SECTOR_BUF_SZ
;
1114 // Check for more sectors to read
1115 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
&&
1116 (IDEReadStatus(Address
) & IDE_SR_DRQ
); RetryCount
++)
1118 if (!(IDEReadStatus(Address
) & IDE_SR_BUSY
))
1125 // ------------------------------------------- Nondiscardable statics
1127 // IDEDispatchOpenClose
1130 // Answer requests for Open/Close calls: a null operation
1136 // Standard dispatch arguments
1143 IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
,
1146 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1147 Irp
->IoStatus
.Information
= FILE_OPENED
;
1148 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1150 return STATUS_SUCCESS
;
1153 // IDEDispatchReadWrite
1156 // Answer requests for reads and writes
1162 // Standard dispatch arguments
1169 IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
,
1173 LARGE_INTEGER AdjustedOffset
, AdjustedExtent
, PartitionExtent
, InsertKeyLI
;
1174 PIO_STACK_LOCATION IrpStack
;
1175 PIDE_DEVICE_EXTENSION DeviceExtension
;
1177 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1178 DeviceExtension
= (PIDE_DEVICE_EXTENSION
)pDO
->DeviceExtension
;
1180 // Validate operation parameters
1181 AdjustedOffset
= RtlEnlargedIntegerMultiply(DeviceExtension
->Offset
,
1182 DeviceExtension
->BytesPerSector
);
1183 DPRINT("Offset:%ld * BytesPerSector:%ld = AdjOffset:%ld:%ld\n",
1184 DeviceExtension
->Offset
,
1185 DeviceExtension
->BytesPerSector
,
1186 (unsigned long) AdjustedOffset
.u
.HighPart
,
1187 (unsigned long) AdjustedOffset
.u
.LowPart
);
1188 DPRINT("AdjOffset:%ld:%ld + ByteOffset:%ld:%ld = ",
1189 (unsigned long) AdjustedOffset
.u
.HighPart
,
1190 (unsigned long) AdjustedOffset
.u
.LowPart
,
1191 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.u
.HighPart
,
1192 (unsigned long) IrpStack
->Parameters
.Read
.ByteOffset
.u
.LowPart
);
1193 AdjustedOffset
= RtlLargeIntegerAdd(AdjustedOffset
,
1194 IrpStack
->Parameters
.Read
.ByteOffset
);
1195 DPRINT("AdjOffset:%ld:%ld\n",
1196 (unsigned long) AdjustedOffset
.u
.HighPart
,
1197 (unsigned long) AdjustedOffset
.u
.LowPart
);
1198 AdjustedExtent
= RtlLargeIntegerAdd(AdjustedOffset
,
1199 RtlConvertLongToLargeInteger(IrpStack
->Parameters
.Read
.Length
));
1200 DPRINT("AdjOffset:%ld:%ld + Length:%ld = AdjExtent:%ld:%ld\n",
1201 (unsigned long) AdjustedOffset
.u
.HighPart
,
1202 (unsigned long) AdjustedOffset
.u
.LowPart
,
1203 IrpStack
->Parameters
.Read
.Length
,
1204 (unsigned long) AdjustedExtent
.u
.HighPart
,
1205 (unsigned long) AdjustedExtent
.u
.LowPart
);
1206 /* FIXME: this assumption will fail on drives bigger than 1TB */
1207 PartitionExtent
.QuadPart
= DeviceExtension
->Offset
+ DeviceExtension
->Size
;
1208 PartitionExtent
= RtlExtendedIntegerMultiply(PartitionExtent
,
1209 DeviceExtension
->BytesPerSector
);
1210 if ((AdjustedExtent
.QuadPart
> PartitionExtent
.QuadPart
) ||
1211 (IrpStack
->Parameters
.Read
.Length
& (DeviceExtension
->BytesPerSector
- 1)))
1213 DPRINT("Request failed on bad parameters\n",0);
1214 DPRINT("AdjustedExtent=%d:%d PartitionExtent=%d:%d ReadLength=%d\n",
1215 (unsigned int) AdjustedExtent
.u
.HighPart
,
1216 (unsigned int) AdjustedExtent
.u
.LowPart
,
1217 (unsigned int) PartitionExtent
.u
.HighPart
,
1218 (unsigned int) PartitionExtent
.u
.LowPart
,
1219 IrpStack
->Parameters
.Read
.Length
);
1220 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1221 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1222 return STATUS_INVALID_PARAMETER
;
1225 // Adjust operation to absolute sector offset
1226 IrpStack
->Parameters
.Read
.ByteOffset
= AdjustedOffset
;
1228 // Start the packet and insert the request in order of sector offset
1229 assert(DeviceExtension
->BytesPerSector
== 512);
1230 InsertKeyLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1231 IrpInsertKey
= InsertKeyLI
.u
.LowPart
;
1232 IoStartPacket(DeviceExtension
->DeviceObject
, Irp
, &IrpInsertKey
, NULL
);
1234 return STATUS_PENDING
;
1237 // IDEDispatchDeviceControl
1240 // Answer requests for device control calls
1246 // Standard dispatch arguments
1253 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1257 ULONG ControlCode
, InputLength
, OutputLength
;
1258 PIO_STACK_LOCATION IrpStack
;
1259 PIDE_DEVICE_EXTENSION DeviceExtension
;
1261 RC
= STATUS_SUCCESS
;
1262 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1263 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1264 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1265 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1266 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1268 // A huge switch statement in a Windows program?! who would have thought?
1269 switch (ControlCode
)
1271 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1272 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1274 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1278 PDISK_GEOMETRY Geometry
;
1280 Geometry
= (PDISK_GEOMETRY
) Irp
->AssociatedIrp
.SystemBuffer
;
1281 Geometry
->MediaType
= FixedMedia
;
1282 // FIXME: should report for RawDevice even on partition
1283 Geometry
->Cylinders
.QuadPart
= DeviceExtension
->Size
/
1284 DeviceExtension
->SectorsPerLogCyl
;
1285 Geometry
->TracksPerCylinder
= DeviceExtension
->SectorsPerLogTrk
/
1286 DeviceExtension
->SectorsPerLogCyl
;
1287 Geometry
->SectorsPerTrack
= DeviceExtension
->SectorsPerLogTrk
;
1288 Geometry
->BytesPerSector
= DeviceExtension
->BytesPerSector
;
1290 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1291 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1295 case IOCTL_DISK_GET_PARTITION_INFO
:
1296 case IOCTL_DISK_SET_PARTITION_INFO
:
1297 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1298 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1299 case IOCTL_DISK_VERIFY
:
1300 case IOCTL_DISK_FORMAT_TRACKS
:
1301 case IOCTL_DISK_PERFORMANCE
:
1302 case IOCTL_DISK_IS_WRITABLE
:
1303 case IOCTL_DISK_LOGGING
:
1304 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1305 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1306 case IOCTL_DISK_HISTOGRAM_DATA
:
1307 case IOCTL_DISK_HISTOGRAM_RESET
:
1308 case IOCTL_DISK_REQUEST_STRUCTURE
:
1309 case IOCTL_DISK_REQUEST_DATA
:
1311 // If we get here, something went wrong. inform the requestor
1313 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1314 Irp
->IoStatus
.Status
= RC
;
1315 Irp
->IoStatus
.Information
= 0;
1319 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1327 // Get the next requested I/O packet started
1333 // Dispatch routine standard arguments
1340 IDEStartIo(IN PDEVICE_OBJECT DeviceObject
,
1343 LARGE_INTEGER SectorLI
;
1344 PIO_STACK_LOCATION IrpStack
;
1345 PIDE_DEVICE_EXTENSION DeviceExtension
;
1348 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1349 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1351 // FIXME: implement the supported functions
1353 switch (IrpStack
->MajorFunction
)
1357 DeviceExtension
->Operation
= IrpStack
->MajorFunction
;
1358 DeviceExtension
->BytesRequested
= IrpStack
->Parameters
.Read
.Length
;
1359 assert(DeviceExtension
->BytesPerSector
== 512);
1360 SectorLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1361 DeviceExtension
->StartingSector
= SectorLI
.u
.LowPart
;
1362 if (DeviceExtension
->BytesRequested
> DeviceExtension
->BytesPerSector
*
1363 IDE_MAX_SECTORS_PER_XFER
)
1365 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesPerSector
*
1366 IDE_MAX_SECTORS_PER_XFER
;
1370 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1372 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1373 DeviceExtension
->SectorsTransferred
= 0;
1374 DeviceExtension
->TargetAddress
= (BYTE
*)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1375 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1376 IoAllocateController(DeviceExtension
->ControllerObject
,
1378 IDEAllocateController
,
1380 KeLowerIrql(OldIrql
);
1384 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1385 Irp
->IoStatus
.Information
= 0;
1386 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1387 IoStartNextPacket(DeviceObject
, FALSE
);
1392 // IDEAllocateController
1394 static IO_ALLOCATION_ACTION
1395 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
1397 IN PVOID MapRegisterBase
,
1400 PIDE_DEVICE_EXTENSION DeviceExtension
;
1401 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1403 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1404 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1405 DeviceExtension
->ControllerObject
->ControllerExtension
;
1406 ControllerExtension
->CurrentIrp
= Irp
;
1407 ControllerExtension
->Retries
= 0;
1408 return KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1410 DeviceExtension
) ? KeepObject
:
1414 // IDEStartController
1417 IDEStartController(IN OUT PVOID Context
)
1419 BYTE SectorCnt
, SectorNum
, CylinderLow
, CylinderHigh
;
1420 BYTE DrvHead
, Command
;
1422 ULONG StartingSector
;
1423 PIDE_DEVICE_EXTENSION DeviceExtension
;
1424 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1427 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) Context
;
1428 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1429 DeviceExtension
->ControllerObject
->ControllerExtension
;
1430 ControllerExtension
->OperationInProgress
= TRUE
;
1431 ControllerExtension
->DeviceForOperation
= DeviceExtension
;
1433 // Write controller registers to start opteration
1434 StartingSector
= DeviceExtension
->StartingSector
;
1435 SectorCnt
= DeviceExtension
->BytesToTransfer
/
1436 DeviceExtension
->BytesPerSector
;
1437 if (DeviceExtension
->LBASupported
)
1439 SectorNum
= StartingSector
& 0xff;
1440 CylinderLow
= (StartingSector
>> 8) & 0xff;
1441 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1442 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1443 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0) |
1448 SectorNum
= (StartingSector
% DeviceExtension
->SectorsPerLogTrk
) + 1;
1449 StartingSector
/= DeviceExtension
->SectorsPerLogTrk
;
1450 DrvHead
= (StartingSector
% DeviceExtension
->LogicalHeads
) |
1451 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0);
1452 StartingSector
/= DeviceExtension
->LogicalHeads
;
1453 CylinderLow
= StartingSector
& 0xff;
1454 CylinderHigh
= StartingSector
>> 8;
1456 Command
= DeviceExtension
->Operation
== IRP_MJ_READ
?
1457 IDE_CMD_READ_RETRY
: IDE_CMD_WRITE_RETRY
;
1458 if (DrvHead
& IDE_DH_LBA
)
1460 DPRINT("%s:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1461 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1462 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1463 ((DrvHead
& 0x0f) << 24) +
1464 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1470 DPRINT("%s:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1471 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1472 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1481 /* wait for BUSY to clear */
1482 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1484 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1485 if (!(Status
& IDE_SR_BUSY
))
1489 KeStallExecutionProcessor(10);
1491 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1493 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1495 Irp
= ControllerExtension
->CurrentIrp
;
1496 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1497 Irp
->IoStatus
.Information
= 0;
1503 IDEBeginControllerReset(ControllerExtension
);
1509 /* Select the desired drive */
1510 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1512 /* wait for BUSY to clear and DRDY to assert */
1513 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1515 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1516 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1520 KeStallExecutionProcessor(10);
1522 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1524 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1526 Irp
= ControllerExtension
->CurrentIrp
;
1527 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1528 Irp
->IoStatus
.Information
= 0;
1534 IDEBeginControllerReset(ControllerExtension
);
1540 /* Setup command parameters */
1541 IDEWritePrecomp(ControllerExtension
->CommandPortBase
, 0);
1542 IDEWriteSectorCount(ControllerExtension
->CommandPortBase
, SectorCnt
);
1543 IDEWriteSectorNum(ControllerExtension
->CommandPortBase
, SectorNum
);
1544 IDEWriteCylinderHigh(ControllerExtension
->CommandPortBase
, CylinderHigh
);
1545 IDEWriteCylinderLow(ControllerExtension
->CommandPortBase
, CylinderLow
);
1546 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1548 /* Issue command to drive */
1549 IDEWriteCommand(ControllerExtension
->CommandPortBase
, Command
);
1550 ControllerExtension
->TimerState
= IDETimerCmdWait
;
1551 ControllerExtension
->TimerCount
= IDE_CMD_TIMEOUT
;
1553 if (DeviceExtension
->Operation
== IRP_MJ_WRITE
)
1556 // Wait for controller ready
1557 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
1559 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1560 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
1564 KeStallExecutionProcessor(10);
1566 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1568 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1570 Irp
= ControllerExtension
->CurrentIrp
;
1571 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1572 Irp
->IoStatus
.Information
= 0;
1578 IDEBeginControllerReset(ControllerExtension
);
1584 // Load the first sector of data into the controller
1585 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1586 DeviceExtension
->TargetAddress
,
1588 DeviceExtension
->TargetAddress
+= IDE_SECTOR_BUF_SZ
;
1589 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1590 DeviceExtension
->SectorsTransferred
++;
1596 // IDEBeginControllerReset
1599 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1603 DPRINT("Controller Reset initiated on %04x\n",
1604 ControllerExtension
->ControlPortBase
);
1606 /* Assert drive reset line */
1607 DPRINT("Asserting reset line\n");
1608 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, IDE_DC_SRST
);
1610 /* Wait for BSY assertion */
1611 DPRINT("Waiting for BSY assertion\n");
1612 for (Retries
= 0; Retries
< IDE_MAX_RESET_RETRIES
; Retries
++)
1614 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1615 if ((Status
& IDE_SR_BUSY
))
1619 KeStallExecutionProcessor(10);
1621 if (Retries
== IDE_MAX_RESET_RETRIES
)
1623 DPRINT("Timeout on BSY assertion\n");
1626 /* Negate drive reset line */
1627 DPRINT("Negating reset line\n");
1628 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, 0);
1630 // FIXME: handle case of no device 0
1632 /* Set timer to check for end of reset */
1633 ControllerExtension
->TimerState
= IDETimerResetWaitForBusyNegate
;
1634 ControllerExtension
->TimerCount
= IDE_RESET_BUSY_TIMEOUT
;
1640 // Handle interrupts for IDE devices
1646 // IN PKINTERRUPT Interrupt The interrupt level in effect
1647 // IN PVOID ServiceContext The driver supplied context
1648 // (the controller extension)
1650 // TRUE This ISR handled the interrupt
1651 // FALSE Another ISR must handle this interrupt
1654 IDEIsr(IN PKINTERRUPT Interrupt
,
1655 IN PVOID ServiceContext
)
1657 BOOLEAN IsLastBlock
, AnErrorOccured
, RequestIsComplete
;
1658 BYTE
*TargetAddress
;
1660 NTSTATUS ErrorStatus
;
1661 ULONG ErrorInformation
;
1663 PIDE_DEVICE_EXTENSION DeviceExtension
;
1664 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1666 if (IDEInitialized
== FALSE
)
1671 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) ServiceContext
;
1673 // Read the status port to clear the interrtupt (even if it's not ours).
1674 ControllerExtension
->DeviceStatus
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1676 // If the interrupt is not ours, get the heck outta dodge.
1677 if (!ControllerExtension
->OperationInProgress
)
1682 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1683 IsLastBlock
= FALSE
;
1684 AnErrorOccured
= FALSE
;
1685 RequestIsComplete
= FALSE
;
1686 ErrorStatus
= STATUS_SUCCESS
;
1687 ErrorInformation
= 0;
1689 // Handle error condition if it exists
1690 if (ControllerExtension
->DeviceStatus
& IDE_SR_ERR
)
1692 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
1696 ErrorReg
= IDEReadError(ControllerExtension
->CommandPortBase
);
1697 CylinderLow
= IDEReadCylinderLow(ControllerExtension
->CommandPortBase
);
1698 CylinderHigh
= IDEReadCylinderHigh(ControllerExtension
->CommandPortBase
);
1699 DriveHead
= IDEReadDriveHead(ControllerExtension
->CommandPortBase
);
1700 SectorCount
= IDEReadSectorCount(ControllerExtension
->CommandPortBase
);
1701 SectorNum
= IDEReadSectorNum(ControllerExtension
->CommandPortBase
);
1702 // FIXME: should use the NT error logging facility
1703 DPRINT("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1704 DeviceExtension
->Operation
,
1705 ControllerExtension
->DeviceStatus
,
1712 // FIXME: should retry the command and perhaps recalibrate the drive
1714 // Set error status information
1715 AnErrorOccured
= TRUE
;
1716 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
1718 (((((((CylinderHigh
<< 8) + CylinderLow
) *
1719 DeviceExtension
->LogicalHeads
) +
1720 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
1721 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
1722 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
1727 // Check controller and setup for next transfer
1728 switch (DeviceExtension
->Operation
)
1732 // Update controller/device state variables
1733 TargetAddress
= DeviceExtension
->TargetAddress
;
1734 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1735 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1736 DeviceExtension
->SectorsTransferred
++;
1738 // Remember whether DRQ should be low at end (last block read)
1739 IsLastBlock
= DeviceExtension
->BytesToTransfer
== 0;
1741 // Wait for DRQ assertion
1742 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
1743 !(IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
);
1746 KeStallExecutionProcessor(10);
1749 // Copy the block of data
1750 IDEReadBlock(ControllerExtension
->CommandPortBase
,
1757 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1758 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1761 KeStallExecutionProcessor(10);
1764 // Check for data overrun
1765 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1767 AnErrorOccured
= TRUE
;
1768 ErrorStatus
= STATUS_DATA_OVERRUN
;
1769 ErrorInformation
= 0;
1774 // Setup next transfer or set RequestIsComplete
1775 if (DeviceExtension
->BytesRequested
>
1776 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1778 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1779 DeviceExtension
->SectorsTransferred
= 0;
1780 DeviceExtension
->BytesToTransfer
=
1781 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1782 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1784 else if (DeviceExtension
->BytesRequested
> 0)
1786 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1787 DeviceExtension
->SectorsTransferred
= 0;
1788 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1789 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1793 RequestIsComplete
= TRUE
;
1802 if (DeviceExtension
->BytesToTransfer
== 0)
1804 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1805 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1808 KeStallExecutionProcessor(10);
1811 // Check for data overrun
1812 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1814 AnErrorOccured
= TRUE
;
1815 ErrorStatus
= STATUS_DATA_OVERRUN
;
1816 ErrorInformation
= 0;
1821 // Setup next transfer or set RequestIsComplete
1823 if (DeviceExtension
->BytesRequested
>
1824 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1826 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1827 DeviceExtension
->SectorsTransferred
= 0;
1828 DeviceExtension
->BytesToTransfer
=
1829 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1830 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1832 else if (DeviceExtension
->BytesRequested
> 0)
1834 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1835 DeviceExtension
->SectorsTransferred
= 0;
1836 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1837 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1841 RequestIsComplete
= TRUE
;
1848 // Update controller/device state variables
1849 TargetAddress
= DeviceExtension
->TargetAddress
;
1850 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1851 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1852 DeviceExtension
->SectorsTransferred
++;
1854 // Write block to controller
1855 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1863 // If there was an error or the request is done, complete the packet
1864 if (AnErrorOccured
|| RequestIsComplete
)
1866 // Set the return status and info values
1867 Irp
= ControllerExtension
->CurrentIrp
;
1868 Irp
->IoStatus
.Status
= ErrorStatus
;
1869 Irp
->IoStatus
.Information
= ErrorInformation
;
1871 // Clear out controller fields
1872 ControllerExtension
->OperationInProgress
= FALSE
;
1873 ControllerExtension
->DeviceStatus
= 0;
1875 // Queue the Dpc to finish up
1876 IoRequestDpc(DeviceExtension
->DeviceObject
,
1878 ControllerExtension
);
1880 else if (IsLastBlock
)
1882 // Else more data is needed, setup next device I/O
1883 IDEStartController((PVOID
)DeviceExtension
);
1896 // IN PDEVICE_OBJECT DpcDeviceObject
1898 // IN PVOID DpcContext
1901 IDEDpcForIsr(IN PKDPC Dpc
,
1902 IN PDEVICE_OBJECT DpcDeviceObject
,
1904 IN PVOID DpcContext
)
1906 DPRINT("IDEDpcForIsr()\n");
1907 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION
) DpcContext
);
1910 // IDEFinishOperation
1913 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1915 PIDE_DEVICE_EXTENSION DeviceExtension
;
1919 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1920 Irp
= ControllerExtension
->CurrentIrp
;
1921 Operation
= DeviceExtension
->Operation
;
1922 ControllerExtension
->OperationInProgress
= FALSE
;
1923 ControllerExtension
->DeviceForOperation
= 0;
1924 ControllerExtension
->CurrentIrp
= 0;
1926 // Deallocate the controller
1927 IoFreeController(DeviceExtension
->ControllerObject
);
1929 // Start the next packet
1930 IoStartNextPacketByKey(DeviceExtension
->DeviceObject
,
1932 DeviceExtension
->StartingSector
);
1934 // Issue completion of the current packet
1935 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1937 // Flush cache if necessary
1938 if (Operation
== IRP_MJ_READ
)
1940 KeFlushIoBuffers(Irp
->MdlAddress
, TRUE
, FALSE
);
1946 // This function handles timeouts and other time delayed processing
1951 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1952 // IN PVOID Context the Controller extension for the
1953 // controller the device is on
1956 IDEIoTimer(PDEVICE_OBJECT DeviceObject
,
1959 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1961 // Setup Extension pointer
1962 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) Context
;
1963 DPRINT("Timer activated for %04lx\n", ControllerExtension
->CommandPortBase
);
1965 // Handle state change if necessary
1966 switch (ControllerExtension
->TimerState
)
1968 case IDETimerResetWaitForBusyNegate
:
1969 if (!(IDEReadStatus(ControllerExtension
->CommandPortBase
) &
1972 DPRINT("Busy line has negated, waiting for DRDY assert\n");
1973 ControllerExtension
->TimerState
= IDETimerResetWaitForDrdyAssert
;
1974 ControllerExtension
->TimerCount
= IDE_RESET_DRDY_TIMEOUT
;
1979 case IDETimerResetWaitForDrdyAssert
:
1980 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) &
1983 DPRINT("DRDY has asserted, reset complete\n");
1984 ControllerExtension
->TimerState
= IDETimerIdle
;
1985 ControllerExtension
->TimerCount
= 0;
1987 // FIXME: get diagnostic code from drive 0
1989 /* Start current packet command again */
1990 if (!KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1992 ControllerExtension
->DeviceForOperation
))
1994 IDEFinishOperation(ControllerExtension
);
2004 // If we're counting down, then count.
2005 if (ControllerExtension
->TimerCount
> 0)
2007 ControllerExtension
->TimerCount
--;
2009 // Else we'll check the state and process if necessary
2013 switch (ControllerExtension
->TimerState
)
2018 case IDETimerCmdWait
:
2019 /* Command timed out, reset drive and try again or fail */
2020 DPRINT("Timeout waiting for command completion\n");
2021 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
2023 DPRINT("Max retries has been reached, IRP finished with error\n");
2024 ControllerExtension
->CurrentIrp
->IoStatus
.Status
= STATUS_IO_TIMEOUT
;
2025 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2026 IDEFinishOperation(ControllerExtension
);
2027 ControllerExtension
->TimerState
= IDETimerIdle
;
2028 ControllerExtension
->TimerCount
= 0;
2032 IDEBeginControllerReset(ControllerExtension
);
2036 case IDETimerResetWaitForBusyNegate
:
2037 case IDETimerResetWaitForDrdyAssert
:
2038 DPRINT("Timeout waiting for drive reset, giving up on IRP\n");
2039 if (ControllerExtension
->CurrentIrp
!= NULL
)
2041 ControllerExtension
->CurrentIrp
->IoStatus
.Status
=
2043 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
2044 IDEFinishOperation(ControllerExtension
);
2046 ControllerExtension
->TimerState
= IDETimerIdle
;
2047 ControllerExtension
->TimerCount
= 0;