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
65 #include <ddk/ntddk.h>
67 // -------------------------------- This stuff should be defined in NTDDK.H
69 typedef DISK_GEOMETRY
*PDISK_GEOMETRY
;
71 // -------------------------------------------------------------------------
73 #include <internal/kernel.h>
74 #include <internal/i386/io.h>
75 #include <internal/string.h>
78 #include <internal/debug.h>
84 #define VERSION "V0.1.3"
86 // ------------------------------------------------------- File Static Data
88 typedef struct _IDE_CONTROLLER_PARAMETERS
97 KINTERRUPT_MODE InterruptMode
;
99 } IDE_CONTROLLER_PARAMETERS
, *PIDE_CONTROLLER_PARAMETERS
;
101 // NOTE: Do not increase max drives above 2
103 #define IDE_MAX_DRIVES 2
105 #define IDE_MAX_CONTROLLERS 4
106 IDE_CONTROLLER_PARAMETERS Controllers
[IDE_MAX_CONTROLLERS
] =
108 {0x01f0, 8, 0x03f6, 1, 14, 14, 15, LevelSensitive
, 0xffff},
109 {0x0170, 8, 0x0376, 1, 15, 15, 15, LevelSensitive
, 0xffff},
110 {0x01E8, 8, 0x03ee, 1, 11, 11, 15, LevelSensitive
, 0xffff},
111 {0x0168, 8, 0x036e, 1, 10, 10, 15, LevelSensitive
, 0xffff}
114 static BOOLEAN IDEInitialized
= FALSE
;
115 static int TotalPartitions
= 0;
117 // ----------------------------------------------- Discardable Declarations
121 // make the initialization routines discardable, so that they
124 #pragma alloc_text(init, DriverEntry)
125 #pragma alloc_text(init, IDECreateController)
126 #pragma alloc_text(init, IDECreateDevices)
127 #pragma alloc_text(init, IDECreateDevice)
128 #pragma alloc_text(init, IDEPolledRead)
130 // make the PASSIVE_LEVEL routines pageable, so that they don't
131 // waste nonpaged memory
133 #pragma alloc_text(page, IDEShutdown)
134 #pragma alloc_text(page, IDEDispatchOpenClose)
135 #pragma alloc_text(page, IDEDispatchRead)
136 #pragma alloc_text(page, IDEDispatchWrite)
138 #endif /* ALLOC_PRAGMA */
140 // ---------------------------------------------------- Forward Declarations
142 static BOOLEAN
IDECreateController(IN PDRIVER_OBJECT DriverObject
,
143 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
144 IN
int ControllerIdx
);
145 static BOOLEAN
IDEResetController(IN WORD CommandPort
, IN WORD ControlPort
);
146 static BOOLEAN
IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
147 IN PCONTROLLER_OBJECT ControllerObject
,
148 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
151 static BOOLEAN
IDEGetDriveIdentification(IN
int CommandPort
,
153 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
154 static BOOLEAN
IDEGetPartitionTable(IN
int CommandPort
,
157 IN PIDE_DRIVE_IDENTIFY DrvParms
,
158 PARTITION
*PartitionTable
);
159 static NTSTATUS
IDECreateDevice(IN PDRIVER_OBJECT DriverObject
,
161 OUT PDEVICE_OBJECT
*DeviceObject
,
162 IN PCONTROLLER_OBJECT ControllerObject
,
165 IN PIDE_DRIVE_IDENTIFY DrvParms
,
168 static int IDEPolledRead(IN WORD Address
,
173 IN BYTE CylinderHigh
,
177 static NTSTATUS
IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
178 static NTSTATUS
IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
179 static NTSTATUS
IDEDispatchDeviceControl(IN PDEVICE_OBJECT pDO
, IN PIRP Irp
);
180 static VOID
IDEStartIo(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
);
181 static IO_ALLOCATION_ACTION
IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
183 IN PVOID MapRegisterBase
,
185 static BOOLEAN
IDEStartController(IN OUT PVOID Context
);
186 VOID
IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
187 static BOOLEAN
IDEIsr(IN PKINTERRUPT Interrupt
, IN PVOID ServiceContext
);
188 static VOID
IDEDpcForIsr(IN PKDPC Dpc
,
189 IN PDEVICE_OBJECT DpcDeviceObject
,
191 IN PVOID DpcContext
);
192 static VOID
IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
);
193 static VOID
IDEIoTimer(PDEVICE_OBJECT DeviceObject
, PVOID Context
);
195 // ---------------------------------------------------------------- Inlines
198 IDESwapBytePairs(char *Buf
,
204 for (i
= 0; i
< Cnt
; i
+= 2)
212 // ------------------------------------------------------- Public Interface
217 // This function initializes the driver, locates and claims
218 // hardware resources, and creates various NT objects needed
219 // to process I/O requests.
225 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
227 // IN PUNICODE_STRING RegistryPath Name of registry driver service
234 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
235 IN PUNICODE_STRING RegistryPath
)
237 BOOLEAN WeGotSomeDisks
;
240 DbgPrint("IDE Driver %s\n", VERSION
);
242 // Export other driver entry points...
243 DriverObject
->DriverStartIo
= IDEStartIo
;
244 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = IDEDispatchOpenClose
;
245 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = IDEDispatchOpenClose
;
246 DriverObject
->MajorFunction
[IRP_MJ_READ
] = IDEDispatchReadWrite
;
247 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = IDEDispatchReadWrite
;
248 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
249 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
250 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = IDEDispatchDeviceControl
;
252 WeGotSomeDisks
= FALSE
;
253 for (ControllerIdx
= 0; ControllerIdx
< IDE_MAX_CONTROLLERS
; ControllerIdx
++)
255 WeGotSomeDisks
|= IDECreateController(DriverObject
,
256 &Controllers
[ControllerIdx
], ControllerIdx
);
261 IDEInitialized
= TRUE
;
264 return WeGotSomeDisks
? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
;
267 // ---------------------------------------------------- Discardable statics
269 // IDECreateController
272 // Creates a controller object and a device object for each valid
273 // device on the controller
279 // IN PDRIVER_OBJECT DriverObject The system created driver object
280 // IN PIDE_CONTROLLER_PARAMETERS The parameter block for this
281 // ControllerParams controller
282 // IN int ControllerIdx The index of this controller
285 // TRUE Devices where found on this controller
286 // FALSE The controller does not respond or there are no devices on it
290 IDECreateController(IN PDRIVER_OBJECT DriverObject
,
291 IN PIDE_CONTROLLER_PARAMETERS ControllerParams
,
292 IN
int ControllerIdx
)
294 BOOLEAN CreatedDevices
, ThisDriveExists
;
297 PCONTROLLER_OBJECT ControllerObject
;
298 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
300 // Try to reset the controller and return FALSE if it fails
301 if (!IDEResetController(ControllerParams
->CommandPortBase
,
302 ControllerParams
->ControlPortBase
))
304 DPRINT("Could not find controller %d at %04lx\n",
305 ControllerIdx
, ControllerParams
->CommandPortBase
);
309 ControllerObject
= IoCreateController(sizeof(IDE_CONTROLLER_EXTENSION
));
310 if (ControllerObject
== NULL
)
312 DPRINT("Could not create controller object for controller %d\n",
317 // Fill out Controller extension data
318 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
319 ControllerObject
->ControllerExtension
;
320 ControllerExtension
->Number
= ControllerIdx
;
321 ControllerExtension
->CommandPortBase
= ControllerParams
->CommandPortBase
;
322 ControllerExtension
->ControlPortBase
= ControllerParams
->ControlPortBase
;
323 ControllerExtension
->Vector
= ControllerParams
->Vector
;
324 ControllerExtension
->DMASupported
= FALSE
;
325 ControllerExtension
->ControllerInterruptBug
= FALSE
;
326 ControllerExtension
->OperationInProgress
= FALSE
;
328 // Initialize the spin lock in the controller extension
329 KeInitializeSpinLock(&ControllerExtension
->SpinLock
);
331 // Register an interrupt handler for this controller
332 RC
= IoConnectInterrupt(&ControllerExtension
->Interrupt
,
335 &ControllerExtension
->SpinLock
,
336 ControllerExtension
->Vector
,
337 ControllerParams
->IrqL
,
338 ControllerParams
->SynchronizeIrqL
,
339 ControllerParams
->InterruptMode
,
341 ControllerParams
->Affinity
,
345 DPRINT("Could not Connect Interrupt %d\n", ControllerExtension
->Vector
);
346 IoDeleteController(ControllerObject
);
350 // Create device objects for each raw device (and for partitions)
351 CreatedDevices
= FALSE
;
352 for (DriveIdx
= 0; DriveIdx
< IDE_MAX_DRIVES
; DriveIdx
++)
354 ThisDriveExists
= IDECreateDevices(DriverObject
,
358 ControllerIdx
* 2 + DriveIdx
);
361 CreatedDevices
= TRUE
;
367 DPRINT("Did not find any devices for controller %d\n", ControllerIdx
);
368 IoDisconnectInterrupt(ControllerExtension
->Interrupt
);
369 IoDeleteController(ControllerObject
);
373 IoStartTimer(ControllerExtension
->TimerDevice
);
376 return CreatedDevices
;
379 // IDEResetController
382 // Reset the controller and report completion status
388 // IN WORD CommandPort The address of the command port
389 // IN WORD ControlPort The address of the control port
395 IDEResetController(IN WORD CommandPort
,
400 // Assert drive reset line
401 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
403 // Wait for BUSY assertion
404 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
406 if (IDEReadStatus(CommandPort
) & IDE_SR_BUSY
)
410 KeStallExecutionProcessor(10);
412 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
417 // Negate drive reset line
418 IDEWriteDriveControl(ControlPort
, 0);
420 // Wait for BUSY negation
421 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
423 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
427 KeStallExecutionProcessor(10);
429 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
434 // return TRUE if controller came back to life. and
435 // the registers are initialized correctly
436 return IDEReadError(CommandPort
) == 1 &&
437 IDEReadSectorCount(CommandPort
) == 1 &&
438 IDEReadSectorNum(CommandPort
) == 1 &&
439 IDEReadCylinderLow(CommandPort
) == 0 &&
440 IDEReadCylinderHigh(CommandPort
) == 0 &&
441 IDEReadDriveHead(CommandPort
) == 0;
447 // Create the raw device and any partition devices on this drive
453 // IN PDRIVER_OBJECT DriverObject The system created driver object
454 // IN PCONTROLLER_OBJECT ControllerObject
455 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
456 // The IDE controller extension for
458 // IN int DriveIdx The index of the drive on this
460 // IN int HarddiskIdx The NT device number for this
464 // TRUE Drive exists and devices were created
465 // FALSE no devices were created for this device
469 IDECreateDevices(IN PDRIVER_OBJECT DriverObject
,
470 IN PCONTROLLER_OBJECT ControllerObject
,
471 IN PIDE_CONTROLLER_EXTENSION ControllerExtension
,
475 BOOLEAN CreatedDevices
;
476 char RawDeviceName
[IDE_MAX_NAME_LENGTH
];
477 char PrimaryDeviceName
[IDE_MAX_NAME_LENGTH
];
478 char LogicalDeviceName
[IDE_MAX_NAME_LENGTH
];
479 char Win32AliasName
[IDE_MAX_NAME_LENGTH
];
480 int CommandPort
, PartitionIdx
, PartitionNum
;
481 int ExtPartitionIdx
, ExtOffset
;
483 IDE_DRIVE_IDENTIFY DrvParms
;
484 PDEVICE_OBJECT RawDeviceObject
;
485 PDEVICE_OBJECT PrimaryDeviceObject
;
486 PDEVICE_OBJECT LogicalDeviceObject
;
487 PIDE_DEVICE_EXTENSION RawDeviceExtension
;
488 PARTITION PrimaryPartitionTable
[4], *p
;
489 PARTITION ExtendedPartitionTable
[4], *ep
;
490 char DeviceDirName
[IDE_MAX_NAME_LENGTH
+ 1];
491 ANSI_STRING AnsiDeviceDirName
;
492 UNICODE_STRING UnicodeDeviceDirName
;
493 OBJECT_ATTRIBUTES DeviceDirAttributes
;
496 // Copy I/O port offsets for convenience
497 CommandPort
= ControllerExtension
->CommandPortBase
;
498 // ControlPort = ControllerExtension->ControlPortBase;
499 DPRINT("probing IDE controller %d Addr %04lx Drive %d\n",
500 ControllerExtension
->Number
,
504 // Get the Drive Identification Data
505 if (!IDEGetDriveIdentification(CommandPort
, DriveIdx
, &DrvParms
))
507 DPRINT("Giving up on drive %d on controller %d...\n",
509 ControllerExtension
->Number
);
513 CreatedDevices
= FALSE
;
515 // Create the harddisk device directory
516 strcpy(DeviceDirName
, IDE_NT_ROOTDIR_NAME
);
517 strcat(DeviceDirName
, IDE_NT_DEVICE_NAME
);
518 DeviceDirName
[strlen(DeviceDirName
) + 1] = '\0';
519 DeviceDirName
[strlen(DeviceDirName
)] = '0' + HarddiskIdx
;
520 RtlInitAnsiString(&AnsiDeviceDirName
, DeviceDirName
);
521 RC
= RtlAnsiStringToUnicodeString(&UnicodeDeviceDirName
,
526 DPRINT("Could not convert ansi to unicode for device dir\n", 0);
529 InitializeObjectAttributes(&DeviceDirAttributes
,
530 &UnicodeDeviceDirName
,
534 RC
= ZwCreateDirectoryObject(&Handle
, 0, &DeviceDirAttributes
);
537 DPRINT("Could not create device dir object\n", 0);
540 RtlFreeUnicodeString(&UnicodeDeviceDirName
);
542 // Create the raw device
543 strcpy(RawDeviceName
, IDE_NT_ROOTDIR_NAME
);
544 strcat(RawDeviceName
, IDE_NT_DEVICE_NAME
);
545 RawDeviceName
[strlen(RawDeviceName
) + 1] = '\0';
546 RawDeviceName
[strlen(RawDeviceName
)] = '0' + HarddiskIdx
;
547 strcat(RawDeviceName
, IDE_NT_PARTITION_NAME
);
548 RawDeviceName
[strlen(RawDeviceName
) + 1] = '\0';
549 RawDeviceName
[strlen(RawDeviceName
)] = '0';
550 RC
= IDECreateDevice(DriverObject
,
558 DrvParms
.LogicalCyls
* DrvParms
.LogicalHeads
* DrvParms
.SectorsPerTrack
);
561 DPRINT("IDECreateDevice call failed for raw device\n",0);
565 CreatedDevices
= TRUE
;
566 RawDeviceExtension
= (PIDE_DEVICE_EXTENSION
)
567 RawDeviceObject
->DeviceExtension
;
569 // Initialze the controller timer here (since it has to be
570 // tied to a device)...
573 ControllerExtension
->TimerState
= IDETimerIdle
;
574 ControllerExtension
->TimerCount
= 0;
575 ControllerExtension
->TimerDevice
= RawDeviceObject
;
576 IoInitializeTimer(RawDeviceObject
, IDEIoTimer
, ControllerExtension
);
580 // Get Main partition table for device
582 if (!IDEGetPartitionTable(CommandPort
, DriveIdx
, 0, &DrvParms
, PrimaryPartitionTable
))
584 DPRINT("drive %d controller %d: Could not get primary partition table\n",
586 ControllerExtension
->Number
);
591 // build devices for all partitions in table
592 DPRINT("partitions on %s:\n", DeviceDirName
);
593 for (PartitionIdx
= 0; PartitionIdx
< 4; PartitionIdx
++)
596 // copy partition pointer for convenience
597 p
= &PrimaryPartitionTable
[PartitionIdx
];
599 // if the partition entry is in use, create a device for it
600 if (PartitionIsSupported(p
))
602 DPRINT("%s ptbl entry:%d type:%02x Offset:%d Size:%d\n",
609 // Create Device for partition
610 strcpy(PrimaryDeviceName
, IDE_NT_ROOTDIR_NAME
);
611 strcat(PrimaryDeviceName
, IDE_NT_DEVICE_NAME
);
612 PrimaryDeviceName
[strlen(PrimaryDeviceName
) + 1] = '\0';
613 PrimaryDeviceName
[strlen(PrimaryDeviceName
)] = '0' + HarddiskIdx
;
614 strcat(PrimaryDeviceName
, IDE_NT_PARTITION_NAME
);
615 PrimaryDeviceName
[strlen(PrimaryDeviceName
) + 1] = '\0';
616 PrimaryDeviceName
[strlen(PrimaryDeviceName
)] = '0' + PartitionNum
++;
617 strcpy(Win32AliasName
, "\\??\\ :");
618 Win32AliasName
[4] = 'C' + TotalPartitions
;
620 RC
= IDECreateDevice(DriverObject
,
622 &PrimaryDeviceObject
,
631 DPRINT("IDECreateDevice call failed\n",0);
635 // Create devices for logical partitions within an extended partition
637 else if (PartitionIsExtended(p
))
639 ExtOffset
= p
->StartingBlock
;
641 // Get the Extended partition table
642 if (!IDEGetPartitionTable(CommandPort
,
646 ExtendedPartitionTable
))
648 DPRINT("Harddisk%d: could not get extended partition table at offset %d",
649 HarddiskIdx
, ExtOffset
);
653 for (ExtPartitionIdx
= 0; ExtPartitionIdx
< 4; ExtPartitionIdx
++)
655 ep
= &ExtendedPartitionTable
[ExtPartitionIdx
];
656 if (PartitionIsSupported(ep
))
658 DPRINT("Harddisk%d: Type:%02x Offset:%d Size:%d\n",
661 ep
->StartingBlock
+ ExtOffset
,
664 // Create device for logical partition
665 strcpy(LogicalDeviceName
, IDE_NT_ROOTDIR_NAME
);
666 strcat(LogicalDeviceName
, IDE_NT_DEVICE_NAME
);
667 LogicalDeviceName
[strlen(LogicalDeviceName
) + 1] = '\0';
668 LogicalDeviceName
[strlen(LogicalDeviceName
)] = '0' + HarddiskIdx
;
669 strcat(LogicalDeviceName
, IDE_NT_PARTITION_NAME
);
670 LogicalDeviceName
[strlen(LogicalDeviceName
) + 1] = '\0';
671 LogicalDeviceName
[strlen(LogicalDeviceName
)] = '0' + PartitionNum
++;
672 strcpy(Win32AliasName
, "\\??\\ :");
673 Win32AliasName
[4] = 'C' + TotalPartitions
;
675 RC
= IDECreateDevice(DriverObject
,
677 &LogicalDeviceObject
,
682 ep
->StartingBlock
+ ExtOffset
,
686 DPRINT("IDECreateDevice call failed\n",0);
699 // IDEGetDriveIdentification
702 // Get the identification block from the drive
708 // IN int CommandPort Address of the command port
709 // IN int DriveNum The drive index (0,1)
710 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
713 // TRUE The drive identification block was retrieved successfully
717 IDEGetDriveIdentification(IN
int CommandPort
,
719 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
722 // Get the Drive Identify block from drive or die
723 if (IDEPolledRead(CommandPort
, 0, 0, 0, 0, 0, (DriveNum
? IDE_DH_DRV1
: 0),
724 IDE_CMD_IDENT_DRV
, (BYTE
*)DrvParms
) != 0)
729 // Report on drive parameters if debug mode
730 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
731 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
732 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
733 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
734 DrvParms
->ConfigBits
,
735 DrvParms
->LogicalCyls
,
736 DrvParms
->LogicalHeads
,
737 DrvParms
->SectorsPerTrack
,
738 DrvParms
->InterSectorGap
,
739 DrvParms
->InterSectorGapSize
);
740 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
741 DrvParms
->BytesInPLO
,
742 DrvParms
->VendorUniqueCnt
,
743 DrvParms
->SerialNumber
);
744 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
745 DrvParms
->ControllerType
,
746 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
747 DrvParms
->ECCByteCnt
,
748 DrvParms
->FirmwareRev
);
749 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
750 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
751 (DrvParms
->RWMultImplemented
) & 0xff,
752 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
753 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
754 DrvParms
->MinPIOTransTime
,
755 DrvParms
->MinDMATransTime
);
756 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%d\n",
757 DrvParms
->TMCylinders
,
759 DrvParms
->TMSectorsPerTrk
,
760 DrvParms
->TMCapacity
);
765 // IDEGetPartitionTable
768 // Gets the partition table from the device at the given offset if one exists
774 // IN int CommandPort Address of command port for controller
775 // IN int DriveNum index of drive (0,1)
776 // IN int Offset Block offset (LBA addressing)
777 // OUT PARTITION *PartitionTable address to write partition table
780 // TRUE partition table was retrieved successfully
784 IDEGetPartitionTable(IN
int CommandPort
,
787 IN PIDE_DRIVE_IDENTIFY DrvParms
,
788 OUT PARTITION
*PartitionTable
)
790 BYTE SectorBuf
[512], SectorNum
, DrvHead
, CylinderLow
, CylinderHigh
;
797 // Get sector at offset
799 if (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
801 SectorNum
= Offset
& 0xff;
802 CylinderLow
= (Offset
>> 8) & 0xff;
803 CylinderHigh
= (Offset
>> 16) & 0xff;
804 DrvHead
= ((Offset
>> 24) & 0x0f) |
805 (DriveNum
? IDE_DH_DRV1
: 0) |
810 SectorNum
= (Offset
% DrvParms
->SectorsPerTrack
) + 1;
811 Offset
/= DrvParms
->SectorsPerTrack
;
812 DrvHead
= (Offset
% DrvParms
->LogicalHeads
) |
813 (DriveNum
? IDE_DH_DRV1
: 0);
814 Offset
/= DrvParms
->LogicalHeads
;
815 CylinderLow
= Offset
& 0xff;
816 CylinderHigh
= Offset
>> 8;
820 RC
= IDEPolledRead(CommandPort
,
831 DPRINT("read failed: port %04x drive %d sector %d rc %d\n",
838 else if (*((WORD
*)(SectorBuf
+ PART_MAGIC_OFFSET
)) != PARTITION_MAGIC
)
840 DPRINT("Bad partition magic: port %04x drive %d offset %d magic %d\n",
844 *((short *)(SectorBuf
+ PART_MAGIC_OFFSET
)));
847 RtlCopyMemory(PartitionTable
, SectorBuf
+ PARTITION_OFFSET
, sizeof(PARTITION
) * 4);
850 DPRINT("Partition Table for device %d at offset %d on port %x\n",
854 for (i
= 0; i
< PARTITION_TBL_SIZE
; i
++)
856 DPRINT(" %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
858 PartitionTable
[i
].BootFlags
,
859 PartitionTable
[i
].PartitionType
,
860 PartitionTable
[i
].StartingHead
,
861 PartitionTable
[i
].StartingSector
,
862 PartitionTable
[i
].StartingCylinder
,
863 PartitionTable
[i
].EndingHead
,
864 PartitionTable
[i
].EndingSector
,
865 PartitionTable
[i
].EndingCylinder
,
866 PartitionTable
[i
].StartingBlock
,
867 PartitionTable
[i
].SectorCount
);
877 // Creates a device by calling IoCreateDevice and a sylbolic link for Win32
883 // IN PDRIVER_OBJECT DriverObject The system supplied driver object
884 // IN PCHAR DeviceName The name of the device
885 // OUT PDEVICE_OBJECT *DeviceObject The created device object
886 // IN PCONTROLLER_OBJECT ControllerObject The Controller for the device
887 // IN BOOLEAN LBASupported Does the drive support LBA addressing?
888 // IN BOOLEAN DMASupported Does the drive support DMA?
889 // IN int SectorsPerLogCyl Sectors per cylinder
890 // IN int SectorsPerLogTrk Sectors per track
891 // IN DWORD Offset First valid sector for this device
892 // IN DWORD Size Count of valid sectors for this device
899 IDECreateDevice(IN PDRIVER_OBJECT DriverObject
,
901 OUT PDEVICE_OBJECT
*DeviceObject
,
902 IN PCONTROLLER_OBJECT ControllerObject
,
905 IN PIDE_DRIVE_IDENTIFY DrvParms
,
909 WORD UnicodeBuffer
[IDE_MAX_NAME_LENGTH
];
911 ANSI_STRING AnsiName
, AnsiSymLink
;
912 UNICODE_STRING UnicodeName
, SymLink
;
913 PIDE_DEVICE_EXTENSION DeviceExtension
;
915 // Create a unicode device name
916 RtlInitAnsiString(&AnsiName
, DeviceName
);
917 UnicodeName
.MaximumLength
= IDE_MAX_NAME_LENGTH
;
918 UnicodeName
.Buffer
= UnicodeBuffer
;
919 RtlAnsiStringToUnicodeString(&UnicodeName
, &AnsiName
, FALSE
);
922 RC
= IoCreateDevice(DriverObject
, sizeof(IDE_DEVICE_EXTENSION
),
923 &UnicodeName
, FILE_DEVICE_DISK
, 0, TRUE
, DeviceObject
);
926 DPRINT("IoCreateDevice call failed\n",0);
930 // Set the buffering strategy here...
931 (*DeviceObject
)->Flags
|= DO_DIRECT_IO
;
932 (*DeviceObject
)->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
934 // Fill out Device extension data
935 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) (*DeviceObject
)->DeviceExtension
;
936 DeviceExtension
->DeviceObject
= (*DeviceObject
);
937 DeviceExtension
->ControllerObject
= ControllerObject
;
938 DeviceExtension
->UnitNumber
= UnitNumber
;
939 DeviceExtension
->LBASupported
=
940 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0;
941 DeviceExtension
->DMASupported
=
942 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0;
943 // FIXME: deal with bizarre sector sizes
944 DeviceExtension
->BytesPerSector
= 512 /* DrvParms->BytesPerSector */;
945 DeviceExtension
->SectorsPerLogCyl
= DrvParms
->LogicalHeads
*
946 DrvParms
->SectorsPerTrack
;
947 DeviceExtension
->SectorsPerLogTrk
= DrvParms
->SectorsPerTrack
;
948 DeviceExtension
->LogicalHeads
= DrvParms
->LogicalHeads
;
949 DeviceExtension
->Offset
= Offset
;
950 DeviceExtension
->Size
= Size
;
951 DPRINT("%s: offset %d size %d \n",
953 DeviceExtension
->Offset
,
954 DeviceExtension
->Size
);
956 // FIXME: Create Win32 symbolic link (destroy device if it fails)
958 if (Win32Alias
!= NULL
)
960 DPRINT("Creating SymLink %s --> %s\n", DeviceName
, Win32Alias
);
961 RtlInitAnsiString(&AnsiSymLink
, Win32Alias
);
962 RtlAnsiStringToUnicodeString(&SymLink
, &AnsiSymLink
, TRUE
);
963 IoCreateSymbolicLink(&SymLink
, &UnicodeName
);
964 RtlFreeUnicodeString(&SymLink
);
967 // Initialize the DPC object here
968 IoInitializeDpcRequest(*DeviceObject
, IDEDpcForIsr
);
970 if (Win32Alias
!= NULL
)
972 DbgPrint("%s is %s %dMB\n", DeviceName
, Win32Alias
, Size
/ 2048);
982 // Read a sector of data from the drive in a polled fashion.
988 // IN WORD Address Address of command port for drive
989 // IN BYTE PreComp Value to write to precomp register
990 // IN BYTE SectorCnt Value to write to sectorCnt register
991 // IN BYTE SectorNum Value to write to sectorNum register
992 // IN BYTE CylinderLow Value to write to CylinderLow register
993 // IN BYTE CylinderHigh Value to write to CylinderHigh register
994 // IN BYTE DrvHead Value to write to Drive/Head register
995 // IN BYTE Command Value to write to Command register
996 // OUT BYTE *Buffer Buffer for output data
999 // int 0 is success, non 0 is an error code
1003 IDEPolledRead(IN WORD Address
,
1007 IN BYTE CylinderLow
,
1008 IN BYTE CylinderHigh
,
1016 /* Wait for STATUS.BUSY to clear */
1017 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1019 Status
= IDEReadStatus(Address
);
1020 if (!(Status
& IDE_SR_BUSY
))
1024 KeStallExecutionProcessor(10);
1026 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1031 /* Write Drive/Head to select drive */
1032 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1034 /* Wait for STATUS.BUSY to clear and STATUS.DRDY to assert */
1035 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1037 Status
= IDEReadStatus(Address
);
1038 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1042 KeStallExecutionProcessor(10);
1044 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1049 /* Issue command to drive */
1050 if (DrvHead
& IDE_DH_LBA
)
1052 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1053 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1054 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1060 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1061 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1070 /* Setup command parameters */
1071 IDEWritePrecomp(Address
, PreComp
);
1072 IDEWriteSectorCount(Address
, SectorCnt
);
1073 IDEWriteSectorNum(Address
, SectorNum
);
1074 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1075 IDEWriteCylinderLow(Address
, CylinderLow
);
1076 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1078 /* Issue the command */
1079 IDEWriteCommand(Address
, Command
);
1080 KeStallExecutionProcessor(50);
1085 // wait for DRQ or error
1086 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1088 Status
= IDEReadStatus(Address
);
1089 if (!(Status
& IDE_SR_BUSY
))
1091 if (Status
& IDE_SR_ERR
)
1093 BYTE Err
= IDEReadError(Address
);
1096 else if (Status
& IDE_SR_DRQ
)
1101 KeStallExecutionProcessor(10);
1103 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1108 // Read data into buffer
1109 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1110 Buffer
+= IDE_SECTOR_BUF_SZ
;
1112 // Check for more sectors to read
1113 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
&&
1114 (IDEReadStatus(Address
) & IDE_SR_DRQ
); RetryCount
++)
1116 if (!(IDEReadStatus(Address
) & IDE_SR_BUSY
))
1123 // ------------------------------------------- Nondiscardable statics
1125 // IDEDispatchOpenClose
1128 // Answer requests for Open/Close calls: a null operation
1134 // Standard dispatch arguments
1141 IDEDispatchOpenClose(IN PDEVICE_OBJECT pDO
,
1144 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1145 Irp
->IoStatus
.Information
= FILE_OPENED
;
1146 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1148 return STATUS_SUCCESS
;
1151 // IDEDispatchReadWrite
1154 // Answer requests for reads and writes
1160 // Standard dispatch arguments
1167 IDEDispatchReadWrite(IN PDEVICE_OBJECT pDO
,
1171 LARGE_INTEGER AdjustedOffset
, AdjustedExtent
, PartitionExtent
, InsertKeyLI
;
1172 PIO_STACK_LOCATION IrpStack
;
1173 PIDE_DEVICE_EXTENSION DeviceExtension
;
1175 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1176 DeviceExtension
= (PIDE_DEVICE_EXTENSION
)pDO
->DeviceExtension
;
1178 // Validate operation parameters
1179 AdjustedOffset
= RtlEnlargedIntegerMultiply(DeviceExtension
->Offset
,
1180 DeviceExtension
->BytesPerSector
);
1181 AdjustedOffset
= RtlLargeIntegerAdd(AdjustedOffset
,
1182 IrpStack
->Parameters
.Read
.ByteOffset
);
1183 AdjustedExtent
= RtlLargeIntegerAdd(AdjustedOffset
,
1184 RtlConvertLongToLargeInteger(IrpStack
->Parameters
.Read
.Length
));
1185 // FIXME: this assumption will fail on drives bigger than 1TB
1186 PartitionExtent
.HighPart
= 0;
1187 PartitionExtent
.LowPart
= DeviceExtension
->Offset
+ DeviceExtension
->Size
;
1188 PartitionExtent
= RtlExtendedIntegerMultiply(PartitionExtent
,
1189 DeviceExtension
->BytesPerSector
);
1190 if (RtlLargeIntegerGreaterThan(AdjustedExtent
, PartitionExtent
) ||
1191 (IrpStack
->Parameters
.Read
.Length
& (DeviceExtension
->BytesPerSector
- 1)))
1193 DPRINT("Request failed on bad parameters\n",0);
1194 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1195 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1196 return STATUS_INVALID_PARAMETER
;
1199 // Adjust operation to absolute sector offset
1200 IrpStack
->Parameters
.Read
.ByteOffset
= AdjustedOffset
;
1202 // Start the packet and insert the request in order of sector offset
1203 assert(DeviceExtension
->BytesPerSector
== 512);
1204 InsertKeyLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1205 IrpInsertKey
= InsertKeyLI
.LowPart
;
1206 IoStartPacket(DeviceExtension
->DeviceObject
, Irp
, &IrpInsertKey
, NULL
);
1208 return STATUS_PENDING
;
1211 // IDEDispatchDeviceControl
1214 // Answer requests for device control calls
1220 // Standard dispatch arguments
1227 IDEDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1231 ULONG ControlCode
, InputLength
, OutputLength
;
1232 PIO_STACK_LOCATION IrpStack
;
1233 PIDE_DEVICE_EXTENSION DeviceExtension
;
1235 RC
= STATUS_SUCCESS
;
1236 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1237 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1238 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1239 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1240 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1242 // A huge switch statement in a Windows program?! who would have thought?
1243 switch (ControlCode
)
1245 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1246 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1248 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1252 PDISK_GEOMETRY Geometry
;
1254 Geometry
= (PDISK_GEOMETRY
) Irp
->AssociatedIrp
.SystemBuffer
;
1255 Geometry
->MediaType
= FixedMedia
;
1256 // FIXME: should report for RawDevice even on partition
1257 QUAD_PART(Geometry
->Cylinders
) = DeviceExtension
->Size
/
1258 DeviceExtension
->SectorsPerLogCyl
;
1259 Geometry
->TracksPerCylinder
= DeviceExtension
->SectorsPerLogTrk
/
1260 DeviceExtension
->SectorsPerLogCyl
;
1261 Geometry
->SectorsPerTrack
= DeviceExtension
->SectorsPerLogTrk
;
1262 Geometry
->BytesPerSector
= DeviceExtension
->BytesPerSector
;
1264 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1265 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1269 case IOCTL_DISK_GET_PARTITION_INFO
:
1270 case IOCTL_DISK_SET_PARTITION_INFO
:
1271 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
1272 case IOCTL_DISK_SET_DRIVE_LAYOUT
:
1273 case IOCTL_DISK_VERIFY
:
1274 case IOCTL_DISK_FORMAT_TRACKS
:
1275 case IOCTL_DISK_PERFORMANCE
:
1276 case IOCTL_DISK_IS_WRITABLE
:
1277 case IOCTL_DISK_LOGGING
:
1278 case IOCTL_DISK_FORMAT_TRACKS_EX
:
1279 case IOCTL_DISK_HISTOGRAM_STRUCTURE
:
1280 case IOCTL_DISK_HISTOGRAM_DATA
:
1281 case IOCTL_DISK_HISTOGRAM_RESET
:
1282 case IOCTL_DISK_REQUEST_STRUCTURE
:
1283 case IOCTL_DISK_REQUEST_DATA
:
1285 // If we get here, something went wrong. inform the requestor
1287 RC
= STATUS_INVALID_DEVICE_REQUEST
;
1288 Irp
->IoStatus
.Status
= RC
;
1289 Irp
->IoStatus
.Information
= 0;
1293 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1301 // Get the next requested I/O packet started
1307 // Dispatch routine standard arguments
1314 IDEStartIo(IN PDEVICE_OBJECT DeviceObject
,
1317 LARGE_INTEGER SectorLI
;
1318 PIO_STACK_LOCATION IrpStack
;
1319 PIDE_DEVICE_EXTENSION DeviceExtension
;
1322 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1323 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1325 // FIXME: implement the supported functions
1327 switch (IrpStack
->MajorFunction
)
1331 DeviceExtension
->Operation
= IrpStack
->MajorFunction
;
1332 DeviceExtension
->BytesRequested
= IrpStack
->Parameters
.Read
.Length
;
1333 assert(DeviceExtension
->BytesPerSector
== 512);
1334 SectorLI
= RtlLargeIntegerShiftRight(IrpStack
->Parameters
.Read
.ByteOffset
, 9);
1335 DeviceExtension
->StartingSector
= SectorLI
.LowPart
;
1336 if (DeviceExtension
->BytesRequested
> DeviceExtension
->BytesPerSector
*
1337 IDE_MAX_SECTORS_PER_XFER
)
1339 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesPerSector
*
1340 IDE_MAX_SECTORS_PER_XFER
;
1344 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1346 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1347 DeviceExtension
->SectorsTransferred
= 0;
1348 DeviceExtension
->TargetAddress
= (BYTE
*)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1349 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1350 IoAllocateController(DeviceExtension
->ControllerObject
,
1352 IDEAllocateController
,
1354 KeLowerIrql(OldIrql
);
1358 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1359 Irp
->IoStatus
.Information
= 0;
1360 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1361 IoStartNextPacket(DeviceObject
, FALSE
);
1366 // IDEAllocateController
1368 static IO_ALLOCATION_ACTION
1369 IDEAllocateController(IN PDEVICE_OBJECT DeviceObject
,
1371 IN PVOID MapRegisterBase
,
1374 PIDE_DEVICE_EXTENSION DeviceExtension
;
1375 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1377 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
1378 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1379 DeviceExtension
->ControllerObject
->ControllerExtension
;
1380 ControllerExtension
->CurrentIrp
= Irp
;
1381 ControllerExtension
->Retries
= 0;
1382 return KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1384 DeviceExtension
) ? KeepObject
:
1388 // IDEStartController
1391 IDEStartController(IN OUT PVOID Context
)
1393 BYTE SectorCnt
, SectorNum
, CylinderLow
, CylinderHigh
;
1394 BYTE DrvHead
, Command
;
1396 ULONG StartingSector
;
1397 PIDE_DEVICE_EXTENSION DeviceExtension
;
1398 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1401 DeviceExtension
= (PIDE_DEVICE_EXTENSION
) Context
;
1402 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
)
1403 DeviceExtension
->ControllerObject
->ControllerExtension
;
1404 ControllerExtension
->OperationInProgress
= TRUE
;
1405 ControllerExtension
->DeviceForOperation
= DeviceExtension
;
1407 // Write controller registers to start opteration
1408 StartingSector
= DeviceExtension
->StartingSector
;
1409 SectorCnt
= DeviceExtension
->BytesToTransfer
/
1410 DeviceExtension
->BytesPerSector
;
1411 if (DeviceExtension
->LBASupported
)
1413 SectorNum
= StartingSector
& 0xff;
1414 CylinderLow
= (StartingSector
>> 8) & 0xff;
1415 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1416 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1417 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0) |
1422 SectorNum
= (StartingSector
% DeviceExtension
->SectorsPerLogTrk
) + 1;
1423 StartingSector
/= DeviceExtension
->SectorsPerLogTrk
;
1424 DrvHead
= (StartingSector
% DeviceExtension
->LogicalHeads
) |
1425 (DeviceExtension
->UnitNumber
? IDE_DH_DRV1
: 0);
1426 StartingSector
/= DeviceExtension
->LogicalHeads
;
1427 CylinderLow
= StartingSector
& 0xff;
1428 CylinderHigh
= StartingSector
>> 8;
1430 Command
= DeviceExtension
->Operation
== IRP_MJ_READ
?
1431 IDE_CMD_READ_RETRY
: IDE_CMD_WRITE_RETRY
;
1432 if (DrvHead
& IDE_DH_LBA
)
1434 DPRINT("%s:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1435 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1436 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1437 ((DrvHead
& 0x0f) << 24) +
1438 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1444 DPRINT("%s:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1445 DeviceExtension
->Operation
== IRP_MJ_READ
? "READ" : "WRITE",
1446 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1455 /* wait for BUSY to clear */
1456 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1458 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1459 if (!(Status
& IDE_SR_BUSY
))
1463 KeStallExecutionProcessor(10);
1465 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1467 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1469 Irp
= ControllerExtension
->CurrentIrp
;
1470 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1471 Irp
->IoStatus
.Information
= 0;
1477 IDEBeginControllerReset(ControllerExtension
);
1483 /* Select the desired drive */
1484 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1486 /* wait for BUSY to clear and DRDY to assert */
1487 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1489 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1490 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1494 KeStallExecutionProcessor(10);
1496 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1498 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1500 Irp
= ControllerExtension
->CurrentIrp
;
1501 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1502 Irp
->IoStatus
.Information
= 0;
1508 IDEBeginControllerReset(ControllerExtension
);
1514 /* Setup command parameters */
1515 IDEWritePrecomp(ControllerExtension
->CommandPortBase
, 0);
1516 IDEWriteSectorCount(ControllerExtension
->CommandPortBase
, SectorCnt
);
1517 IDEWriteSectorNum(ControllerExtension
->CommandPortBase
, SectorNum
);
1518 IDEWriteCylinderHigh(ControllerExtension
->CommandPortBase
, CylinderHigh
);
1519 IDEWriteCylinderLow(ControllerExtension
->CommandPortBase
, CylinderLow
);
1520 IDEWriteDriveHead(ControllerExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1522 /* Issue command to drive */
1523 IDEWriteCommand(ControllerExtension
->CommandPortBase
, Command
);
1524 ControllerExtension
->TimerState
= IDETimerCmdWait
;
1525 ControllerExtension
->TimerCount
= IDE_CMD_TIMEOUT
;
1527 if (DeviceExtension
->Operation
== IRP_MJ_WRITE
)
1530 // Wait for controller ready
1531 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
1533 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1534 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
1538 KeStallExecutionProcessor(10);
1540 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1542 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1544 Irp
= ControllerExtension
->CurrentIrp
;
1545 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1546 Irp
->IoStatus
.Information
= 0;
1552 IDEBeginControllerReset(ControllerExtension
);
1558 // Load the first sector of data into the controller
1559 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1560 DeviceExtension
->TargetAddress
,
1562 DeviceExtension
->TargetAddress
+= IDE_SECTOR_BUF_SZ
;
1563 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1564 DeviceExtension
->SectorsTransferred
++;
1570 // IDEBeginControllerReset
1573 IDEBeginControllerReset(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1577 // Assert drive reset line
1578 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, IDE_DC_SRST
);
1580 // FIXME: wait for BSY assertion
1581 for (Retries
= 0; Retries
< IDE_MAX_RESET_RETRIES
; Retries
++)
1583 BYTE Status
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1584 if ((Status
& IDE_SR_BUSY
))
1588 KeStallExecutionProcessor(10);
1591 // Negate drive reset line
1592 IDEWriteDriveControl(ControllerExtension
->ControlPortBase
, 0);
1594 // FIXME: handle case of no device 0
1596 // FIXME: set timer to check for end of reset
1597 ControllerExtension
->TimerState
= IDETimerResetWaitForBusyNegate
;
1598 ControllerExtension
->TimerCount
= IDE_RESET_BUSY_TIMEOUT
;
1604 // Handle interrupts for IDE devices
1610 // IN PKINTERRUPT Interrupt The interrupt level in effect
1611 // IN PVOID ServiceContext The driver supplied context
1612 // (the controller extension)
1614 // TRUE This ISR handled the interrupt
1615 // FALSE Another ISR must handle this interrupt
1618 IDEIsr(IN PKINTERRUPT Interrupt
,
1619 IN PVOID ServiceContext
)
1621 BOOLEAN IsLastBlock
, AnErrorOccured
, RequestIsComplete
;
1622 BYTE
*TargetAddress
;
1624 NTSTATUS ErrorStatus
;
1625 ULONG ErrorInformation
;
1627 PIDE_DEVICE_EXTENSION DeviceExtension
;
1628 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1630 if (IDEInitialized
== FALSE
)
1635 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) ServiceContext
;
1637 // Read the status port to clear the interrtupt (even if it's not ours).
1638 ControllerExtension
->DeviceStatus
= IDEReadStatus(ControllerExtension
->CommandPortBase
);
1640 // If the interrupt is not ours, get the heck outta dodge.
1641 if (!ControllerExtension
->OperationInProgress
)
1646 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1647 IsLastBlock
= FALSE
;
1648 AnErrorOccured
= FALSE
;
1649 RequestIsComplete
= FALSE
;
1650 ErrorStatus
= STATUS_SUCCESS
;
1651 ErrorInformation
= 0;
1653 // Handle error condition if it exists
1654 if (ControllerExtension
->DeviceStatus
& IDE_SR_ERR
)
1656 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
1660 ErrorReg
= IDEReadError(ControllerExtension
->CommandPortBase
);
1661 CylinderLow
= IDEReadCylinderLow(ControllerExtension
->CommandPortBase
);
1662 CylinderHigh
= IDEReadCylinderHigh(ControllerExtension
->CommandPortBase
);
1663 DriveHead
= IDEReadDriveHead(ControllerExtension
->CommandPortBase
);
1664 SectorCount
= IDEReadSectorCount(ControllerExtension
->CommandPortBase
);
1665 SectorNum
= IDEReadSectorNum(ControllerExtension
->CommandPortBase
);
1666 // FIXME: should use the NT error logging facility
1667 DPRINT("IDE Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
1668 DeviceExtension
->Operation
,
1669 ControllerExtension
->DeviceStatus
,
1676 // FIXME: should retry the command and perhaps recalibrate the drive
1678 // Set error status information
1679 AnErrorOccured
= TRUE
;
1680 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
1682 (((((((CylinderHigh
<< 8) + CylinderLow
) *
1683 DeviceExtension
->LogicalHeads
) +
1684 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
1685 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
1686 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
1691 // Check controller and setup for next transfer
1692 switch (DeviceExtension
->Operation
)
1696 // Update controller/device state variables
1697 TargetAddress
= DeviceExtension
->TargetAddress
;
1698 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1699 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1700 DeviceExtension
->SectorsTransferred
++;
1702 // Remember whether DRQ should be low at end (last block read)
1703 IsLastBlock
= DeviceExtension
->BytesToTransfer
== 0;
1705 // Wait for DRQ assertion
1706 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
1707 !(IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
);
1710 KeStallExecutionProcessor(10);
1713 // Copy the block of data
1714 IDEReadBlock(ControllerExtension
->CommandPortBase
,
1721 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1722 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1725 KeStallExecutionProcessor(10);
1728 // Check for data overrun
1729 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1731 AnErrorOccured
= TRUE
;
1732 ErrorStatus
= STATUS_DATA_OVERRUN
;
1733 ErrorInformation
= 0;
1738 // Setup next transfer or set RequestIsComplete
1739 if (DeviceExtension
->BytesRequested
>
1740 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1742 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1743 DeviceExtension
->SectorsTransferred
= 0;
1744 DeviceExtension
->BytesToTransfer
=
1745 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1746 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1748 else if (DeviceExtension
->BytesRequested
> 0)
1750 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1751 DeviceExtension
->SectorsTransferred
= 0;
1752 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1753 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1757 RequestIsComplete
= TRUE
;
1766 if (DeviceExtension
->BytesToTransfer
== 0)
1768 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1769 (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_BUSY
);
1772 KeStallExecutionProcessor(10);
1775 // Check for data overrun
1776 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) & IDE_SR_DRQ
)
1778 AnErrorOccured
= TRUE
;
1779 ErrorStatus
= STATUS_DATA_OVERRUN
;
1780 ErrorInformation
= 0;
1785 // Setup next transfer or set RequestIsComplete
1787 if (DeviceExtension
->BytesRequested
>
1788 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
1790 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1791 DeviceExtension
->SectorsTransferred
= 0;
1792 DeviceExtension
->BytesToTransfer
=
1793 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
1794 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1796 else if (DeviceExtension
->BytesRequested
> 0)
1798 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
1799 DeviceExtension
->SectorsTransferred
= 0;
1800 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
1801 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
1805 RequestIsComplete
= TRUE
;
1812 // Update controller/device state variables
1813 TargetAddress
= DeviceExtension
->TargetAddress
;
1814 DeviceExtension
->TargetAddress
+= DeviceExtension
->BytesPerSector
;
1815 DeviceExtension
->BytesToTransfer
-= DeviceExtension
->BytesPerSector
;
1816 DeviceExtension
->SectorsTransferred
++;
1818 // Write block to controller
1819 IDEWriteBlock(ControllerExtension
->CommandPortBase
,
1827 // If there was an error or the request is done, complete the packet
1828 if (AnErrorOccured
|| RequestIsComplete
)
1830 // Set the return status and info values
1831 Irp
= ControllerExtension
->CurrentIrp
;
1832 Irp
->IoStatus
.Status
= ErrorStatus
;
1833 Irp
->IoStatus
.Information
= ErrorInformation
;
1835 // Clear out controller fields
1836 ControllerExtension
->OperationInProgress
= FALSE
;
1837 ControllerExtension
->DeviceStatus
= 0;
1839 // Queue the Dpc to finish up
1840 IoRequestDpc(DeviceExtension
->DeviceObject
,
1842 ControllerExtension
);
1844 else if (IsLastBlock
)
1846 // Else more data is needed, setup next device I/O
1847 IDEStartController((PVOID
)DeviceExtension
);
1860 // IN PDEVICE_OBJECT DpcDeviceObject
1862 // IN PVOID DpcContext
1865 IDEDpcForIsr(IN PKDPC Dpc
,
1866 IN PDEVICE_OBJECT DpcDeviceObject
,
1868 IN PVOID DpcContext
)
1870 IDEFinishOperation((PIDE_CONTROLLER_EXTENSION
) DpcContext
);
1873 // IDEFinishOperation
1876 IDEFinishOperation(PIDE_CONTROLLER_EXTENSION ControllerExtension
)
1878 PIDE_DEVICE_EXTENSION DeviceExtension
;
1882 DeviceExtension
= ControllerExtension
->DeviceForOperation
;
1883 Irp
= ControllerExtension
->CurrentIrp
;
1884 Operation
= DeviceExtension
->Operation
;
1885 ControllerExtension
->OperationInProgress
= FALSE
;
1886 ControllerExtension
->DeviceForOperation
= 0;
1887 ControllerExtension
->CurrentIrp
= 0;
1889 // Deallocate the controller
1890 IoFreeController(DeviceExtension
->ControllerObject
);
1892 // Start the next packet
1893 IoStartNextPacketByKey(DeviceExtension
->DeviceObject
,
1895 DeviceExtension
->StartingSector
);
1897 // Issue completion of the current packet
1898 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1900 // Flush cache if necessary
1901 if (Operation
== IRP_MJ_READ
)
1903 KeFlushIoBuffers(Irp
->MdlAddress
, TRUE
, FALSE
);
1909 // This function handles timeouts and other time delayed processing
1914 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1915 // IN PVOID Context the Controller extension for the
1916 // controller the device is on
1919 IDEIoTimer(PDEVICE_OBJECT DeviceObject
,
1922 PIDE_CONTROLLER_EXTENSION ControllerExtension
;
1924 // Setup Extension pointer
1925 ControllerExtension
= (PIDE_CONTROLLER_EXTENSION
) Context
;
1927 // Handle state change if necessary
1928 switch (ControllerExtension
->TimerState
)
1930 case IDETimerResetWaitForBusyNegate
:
1931 if (!(IDEReadStatus(ControllerExtension
->CommandPortBase
) &
1934 ControllerExtension
->TimerState
= IDETimerResetWaitForDrdyAssert
;
1935 ControllerExtension
->TimerCount
= IDE_RESET_DRDY_TIMEOUT
;
1940 case IDETimerResetWaitForDrdyAssert
:
1941 if (IDEReadStatus(ControllerExtension
->CommandPortBase
) &
1944 ControllerExtension
->TimerState
= IDETimerIdle
;
1945 ControllerExtension
->TimerCount
= 0;
1947 // FIXME: get diagnostic code from drive 0
1949 // Start current packet command again
1950 if (!KeSynchronizeExecution(ControllerExtension
->Interrupt
,
1952 ControllerExtension
->DeviceForOperation
))
1954 IDEFinishOperation(ControllerExtension
);
1964 // If we're counting down, then count.
1965 if (ControllerExtension
->TimerCount
> 0)
1967 ControllerExtension
->TimerCount
--;
1969 // Else we'll check the state and process if necessary
1973 switch (ControllerExtension
->TimerState
)
1978 case IDETimerCmdWait
:
1979 // Command timed out, reset drive and try again or fail
1980 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1982 ControllerExtension
->CurrentIrp
->IoStatus
.Status
= STATUS_IO_TIMEOUT
;
1983 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
1984 IDEFinishOperation(ControllerExtension
);
1988 IDEBeginControllerReset(ControllerExtension
);
1992 case IDETimerResetWaitForBusyNegate
:
1993 case IDETimerResetWaitForDrdyAssert
:
1994 ControllerExtension
->CurrentIrp
->IoStatus
.Status
= STATUS_IO_TIMEOUT
;
1995 ControllerExtension
->CurrentIrp
->IoStatus
.Information
= 0;
1996 IDEFinishOperation(ControllerExtension
);