📄 ide.c
字号:
// check the controller status
//
if (controllerStatus & ERROR_STATUS) {
#if DBG
DbgPrint("IdeDPC: Error for RESET_DRIVER_RECALIBRATION - controllerStatus %x\n",controllerStatus);
#endif
goto RetryIrp;
}
//
// if we have an irp, then we need to restart the packet
//
#if DBG
DbgPrint("IdeDPC: Recalibrating drive : IRP %x\n",irp);
#endif
//
// If the disk operation was a verify then don't retry.
//
if ((devExt->IrpRetryCount < MAXIMUM_IRP_RETRY_COUNT) &&
(ioStack->MajorFunction != IRP_MJ_DEVICE_CONTROL)) {
devExt->PacketIsBeingRetried = TRUE;
//
// Let the disk catch its breath
//
KeStallExecutionProcessor(25);
//
// and let's try that again
//
IdeStartIo(deviceObject, irp);
} else {
//
// We've retried too many times. Finish the irp with
// failure and return.
//
#if DBG
DbgPrint( "IdeDPC: too many retries 1; will fail IRP\n");
#endif
FinishIrp(devExt, STATUS_DISK_RECALIBRATE_FAILED);
}
//
// clear the reset status and return
//
devExt->ControllerData->ResettingController = RESET_NOT_RESETTING;
return;
}
//
// We're not resetting
//
// Note that for READ and WRITE operations, if the operation did NOT
// not complete, that fact will be caught later in the code and some
// attempts at corrective action will take place.
//
if (devExt->OperationType == IRP_MJ_READ) {
PVOID BufferToReadTo;
BOOLEAN CheckDrq = FALSE;
#if DBG
DbgPrint("IdeDPC: IRP_MJ_READ - RemainingTransferLength %x\n",
devExt->RemainingTransferLength);
#endif
//
// Make sure that since the IO is complete, the DRQ is low
// So, first let's wait until the controller is ready.
//
ntStatus = STATUS_SUCCESS;
//
// If the controller is busy, wait for it to become ready...
//
if (READ_PORT_UCHAR(controllerData->ControllerAddress + STATUS_REGISTER) &
BUSY_STATUS) {
#if DBG
DbgPrint("Extra wait -- READ\n");
#endif
ntStatus = IdeWaitControllerReady(controllerData, 10, 5000);
}
//
// Did the controller become ready?
//
if (NT_SUCCESS(ntStatus)) {
//
// We're not in a data request phase, right?
//
if (READ_PORT_UCHAR(
controllerData->ControllerAddress + STATUS_REGISTER) &
DATA_REQUEST_STATUS) {
//
// Data request is ASSERTED? We must have a problem...
//
#if DBG
DbgPrint("IdeDPC: READ data overrun - controller status %x\n",
controllerStatus);
#endif
controllerStatus |= ERROR_STATUS;
goto RetryIrp;
}
} else {
//
// Error reading the controller. Bummer city.
//
#if DBG
DbgPrint("IdeDPC: IdeWaitControllerReady failure during READ\n");
#endif
controllerStatus |= ERROR_STATUS;
goto RetryIrp;
}
} else {
//
// The operation wasn't a READ, so it BETTER be a WRITE
//
ASSERT(devExt->OperationType == IRP_MJ_WRITE);
//
// Make sure the controller is happy
//
#if DBG
DbgPrint("IdeDPC: IRP_MJ_WRITE - RemainingTransferLength %x\n",
devExt->RemainingTransferLength);
#endif
#if DBG
DbgPrint("Extra wait -- WRITE\n");
#endif
//
// Make sure that since the IO is complete, the DRQ is low
// So, first let's wait until the controller is ready.
//
ntStatus = STATUS_SUCCESS;
//
// If the controller is busy, wait for it to become ready...
//
if (READ_PORT_UCHAR(controllerData->ControllerAddress + STATUS_REGISTER) &
BUSY_STATUS) {
#if DBG
DbgPrint("Extra wait -- WRITE\n");
#endif
ntStatus = IdeWaitControllerReady(controllerData, 10, 5000);
}
//
// Did the controller become ready?
//
if (NT_SUCCESS(ntStatus)) {
//
// Is DRQ low?
//
if (READ_PORT_UCHAR(controllerData->ControllerAddress + STATUS_REGISTER) &
DATA_REQUEST_STATUS) {
//
// not low => we must have a problem
//
#if DBG
DbgPrint("IdeDPC: WRITE data overrun - controller status %x\n",
controllerStatus);
#endif
controllerStatus |= ERROR_STATUS;
goto RetryIrp;
}
} else {
//
// error reading the controller. Bummer city.
//
#if DBG
DbgPrint("IdeDPC: IdeWaitControllerReady failure during WRITE\n");
#endif
controllerStatus |= ERROR_STATUS;
goto RetryIrp;
}
}
//
// If there was a correctable error, let us know, but we can continue.
//
if (controllerStatus & CORRECTED_ERROR_STATUS) {
#if DBG
DbgPrint("IdeDPC: CORRECTABLE ERROR - Continuing Operation\n");
#endif
}
RetryIrp:
//
// does the controller have a problem?
//
if (controllerStatus & ERROR_STATUS) {
//
// inform us that we're going to try and recover this irp
//
#if DBG
DbgPrint("IdeDPC: IRP recovery: Irp %x - retry %d more times\n",
irp,
MAXIMUM_IRP_RETRY_COUNT - devExt->IrpRetryCount);
#endif
//
// Check if we're exceeded the IRP retry count
//
if (devExt->IrpRetryCount < MAXIMUM_IRP_RETRY_COUNT) {
//
// We haven't exceeded our count, so let's reset the disk.
// Since this will cause an interrupt, we can't do
// anything more in the DPC, so we just return
//
KeSynchronizeExecution(controllerData->InterruptObject,
ResetDisk,
devExt);
return;
} else {
//
// Too many retries, so fail the IRP
//
#if DBG
DbgPrint("IdeDPC: Disk Controller still fails after %d retries - FAILING operation\n",MAXIMUM_IRP_RETRY_COUNT);
#endif
returnStatus = STATUS_DISK_OPERATION_FAILED;
}
}
//
// Now, test for the success/failure of the operation.
//
if (NT_SUCCESS(returnStatus) && devExt->RemainingTransferLength == 0) {
//
// Success (complete transfer of data). Let the requestor know.
//
returnStatus = STATUS_SUCCESS;
irp->IoStatus.Information = ioStack->Parameters.Read.Length;
} else {
//
// An error. Bummer. Oh well...
//
// I'm thinkin' we're not big on error recovery in this driver...
//
irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
irp->IoStatus.Information = 0;
#if DBG
DbgPrint("IdeDPC: Irp %x fails, status %x info %x\n",
irp->IoStatus.Information);
#endif
}
//
// Complete this IRP and call IoStartNextPacketByKey
//
FinishIrp(devExt, returnStatus);
}
///////////////////////////////////////////////////////////////////////////////
//
// FinishIrp
//
// This routine will request to start the next transaction and
// complete the current IRP.
//
// INPUTS:
//
// devExt - disk information
// completionStatus - status to complete the IRP with
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL_DISPATCH_LEVEL
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
static VOID
FinishIrp(IN PIDE_DEV_EXT devExt,
IN NTSTATUS NtStatus)
{
PIRP irp = devExt->DeviceObject->CurrentIrp;
//
// For completing read requests we need to flush the I/O buffers.
//
if (IoGetCurrentIrpStackLocation(irp)->MajorFunction == IRP_MJ_READ) {
KeFlushIoBuffers(irp->MdlAddress, TRUE, FALSE);
}
//
// Start the next packet by keep... Next sector first scan to try to keep
// the heads moving forward! Such an optimization...
//
IoStartNextPacketByKey(devExt->DeviceObject,
FALSE,
devExt->FirstSectorOfRequest);
irp->IoStatus.Status = NtStatus;
#if DBG
DbgPrint("FinishIrp: Finishing Request of Irp: %x\n", irp);
#endif
IoCompleteRequest(irp, IO_DISK_INCREMENT);
}
///////////////////////////////////////////////////////////////////////////////
//
// ResetDisk
//
// This routine will reset the disk
//
// INPUTS:
//
// Context - really, the devExt
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// FALSE, every time, all the time
//
// IRQL:
//
// DIRQL
//
// NOTES:
//
// Has to be called at DIRQL to access the registers and protect against
// other outstanding interrupts generated by outstanding requests
//
///////////////////////////////////////////////////////////////////////////////
static BOOLEAN
ResetDisk(PVOID Context)
{
PIDE_DEV_EXT devExt = Context;
PCONTROLLER_DATA controllerData = devExt->ControllerData;
//
// Let it Be Known that we are resetting the controller.
//
#if DBG
DbgPrint("ResetDisk: Starting reset with failing extension: %x\n",devExt);
#endif
controllerData->ResettingController = RESET_DRIVE_SET;
//
// Reset the controller, since its state isn't what we expect.
// Wait up to 2 seconds between writes to the control port.
// Normally we don't like to wait at DIRQL, but this won't generate
// an interrupt and 10us isn't so bad.
//
WRITE_PORT_UCHAR(controllerData->ControlPortAddress,
RESET_CONTROLLER);
IdeWaitControllerBusy(controllerData->ControllerAddress + STATUS_REGISTER,
20,
75000);
WRITE_PORT_UCHAR(controllerData->ControlPortAddress,
(UCHAR)(ENABLE_INTERRUPTS | controllerData->ControlFlags));
//
// Every controller reset must be followed by setting the drive
// parameters of all attached drives. This DOES cause an
// interrupt.
//
controllerData->InterruptRequiresDpc = TRUE;
//
// Before we write to the controller, wait until we're sure it's
// not still busy setting itself up. We don't like waiting here,
// but there's no interrupt to wait on, the wait should be very
// short, and this code is only executed if the hardware gets
// messed up. If it's not ready after 3 seconds, just blast ahead...
// the operation won't work, but it will time out and be handled
// later. Note that we ordinarily don't want to wait this long
// in a driver, but we don't wait longer than we have to and we
// may just have to. This isn't an ordinary event.
//
(VOID) IdeWaitControllerReady(controllerData, 20, 150000);
WRITE_PORT_UCHAR(controllerData->ControllerAddress + DRIVE_HEAD_REGISTER,
(UCHAR)(devExt->DeviceUnit | (devExt->TracksPerCylinder - 1)));
WRITE_PORT_UCHAR((controllerData->ControllerAddress + SECTOR_COUNT_REGISTER),
(UCHAR)(devExt->SectorsPerTrack));
WRITE_PORT_UCHAR(controllerData->ControllerAddress + COMMAND_REGISTER,
SET_DRIVE_PARAMETERS_COMMAND);
//
// When the interrupt comes, the DPC will see ResettingController
// and restarting any packets that were in progress.
//
return(FALSE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -