420 lines
10 KiB
C
420 lines
10 KiB
C
/*++
|
||
|
||
Copyright (C) 1990 - 99 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
port.c
|
||
|
||
Abstract:
|
||
|
||
This is the NT SCSI port driver.
|
||
|
||
Authors:
|
||
|
||
Mike Glass
|
||
Jeff Havens
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
This module is a dll for the kernel.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ideport.h"
|
||
//#include "port.h"
|
||
|
||
|
||
|
||
|
||
VOID
|
||
IdePortNotification(
|
||
IN IDE_NOTIFICATION_TYPE NotificationType,
|
||
IN PVOID HwDeviceExtension,
|
||
...
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION deviceExtension = (PFDO_EXTENSION) HwDeviceExtension - 1;
|
||
PLOGICAL_UNIT_EXTENSION logicalUnit;
|
||
PSRB_DATA srbData;
|
||
PSCSI_REQUEST_BLOCK srb;
|
||
UCHAR pathId;
|
||
UCHAR targetId;
|
||
UCHAR lun;
|
||
va_list ap;
|
||
|
||
va_start(ap, HwDeviceExtension);
|
||
|
||
switch (NotificationType) {
|
||
|
||
case IdeNextRequest:
|
||
|
||
//
|
||
// Start next packet on adapter's queue.
|
||
//
|
||
|
||
deviceExtension->InterruptData.InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;
|
||
break;
|
||
|
||
case IdeRequestComplete:
|
||
|
||
srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
|
||
|
||
ASSERT(srb->SrbStatus != SRB_STATUS_PENDING);
|
||
|
||
ASSERT(srb->SrbStatus != SRB_STATUS_SUCCESS || srb->ScsiStatus == SCSISTAT_GOOD || srb->Function != SRB_FUNCTION_EXECUTE_SCSI);
|
||
|
||
//
|
||
// If this srb has already been completed then return.
|
||
//
|
||
|
||
if (!(srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) {
|
||
|
||
va_end(ap);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Clear the active flag.
|
||
//
|
||
|
||
CLRMASK (srb->SrbFlags, SRB_FLAGS_IS_ACTIVE);
|
||
|
||
//
|
||
// Treat abort completions as a special case.
|
||
//
|
||
|
||
if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
|
||
|
||
PIRP irp;
|
||
PIO_STACK_LOCATION irpStack;
|
||
|
||
irp = srb->OriginalRequest;
|
||
irpStack = IoGetCurrentIrpStackLocation(irp);
|
||
logicalUnit = IDEPORT_GET_LUNEXT_IN_IRP(irpStack);
|
||
|
||
logicalUnit->CompletedAbort =
|
||
deviceExtension->InterruptData.CompletedAbort;
|
||
|
||
deviceExtension->InterruptData.CompletedAbort = logicalUnit;
|
||
|
||
} else {
|
||
|
||
PIDE_REGISTERS_1 baseIoAddress1 = &(deviceExtension->
|
||
HwDeviceExtension->BaseIoAddress1);
|
||
|
||
//
|
||
// Get the SRB data and link it into the completion list.
|
||
//
|
||
|
||
srbData = IdeGetSrbData(deviceExtension, srb);
|
||
|
||
ASSERT(srbData);
|
||
ASSERT(srbData->CurrentSrb != NULL && srbData->CompletedRequests == NULL);
|
||
|
||
if ((srb->SrbStatus == SRB_STATUS_SUCCESS) &&
|
||
((srb->Cdb[0] == SCSIOP_READ) ||
|
||
(srb->Cdb[0] == SCSIOP_WRITE))) {
|
||
ASSERT(srb->DataTransferLength);
|
||
}
|
||
|
||
ASSERT (deviceExtension->InterruptData.CompletedRequests == NULL);
|
||
|
||
srbData->CompletedRequests =
|
||
deviceExtension->InterruptData.CompletedRequests;
|
||
deviceExtension->InterruptData.CompletedRequests = srbData;
|
||
|
||
//
|
||
// Save the task file registers
|
||
//
|
||
IdeLogSaveTaskFile(srbData, baseIoAddress1);
|
||
}
|
||
|
||
break;
|
||
|
||
case IdeResetDetected:
|
||
|
||
{
|
||
PIRP irp;
|
||
PIO_STACK_LOCATION irpStack;
|
||
|
||
//
|
||
// Notifiy the port driver that a reset has been reported.
|
||
//
|
||
srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
|
||
|
||
if (srb) {
|
||
|
||
irp = srb->OriginalRequest;
|
||
irpStack = IoGetCurrentIrpStackLocation(irp);
|
||
logicalUnit = IDEPORT_GET_LUNEXT_IN_IRP(irpStack);
|
||
|
||
} else {
|
||
|
||
logicalUnit = NULL;
|
||
}
|
||
|
||
ASSERT(deviceExtension->InterruptData.PdoExtensionResetBus == NULL);
|
||
|
||
deviceExtension->InterruptData.InterruptFlags |= PD_RESET_REPORTED;
|
||
deviceExtension->InterruptData.PdoExtensionResetBus = logicalUnit;
|
||
break;
|
||
}
|
||
|
||
case IdeRequestTimerCall:
|
||
|
||
//
|
||
// The driver wants to set the miniport timer.
|
||
// Save the timer parameters.
|
||
//
|
||
|
||
deviceExtension->InterruptData.InterruptFlags |=
|
||
PD_TIMER_CALL_REQUEST;
|
||
deviceExtension->InterruptData.HwTimerRequest =
|
||
va_arg(ap, PHW_INTERRUPT);
|
||
deviceExtension->InterruptData.MiniportTimerValue =
|
||
va_arg(ap, ULONG);
|
||
break;
|
||
|
||
case IdeAllDeviceMissing:
|
||
deviceExtension->InterruptData.InterruptFlags |= PD_ALL_DEVICE_MISSING;
|
||
break;
|
||
|
||
case IdeResetRequest:
|
||
|
||
//
|
||
// A reset was requested
|
||
//
|
||
deviceExtension->InterruptData.InterruptFlags |= PD_RESET_REQUEST;
|
||
break;
|
||
|
||
default:
|
||
|
||
ASSERT(0);
|
||
}
|
||
|
||
va_end(ap);
|
||
|
||
//
|
||
// Request a DPC be queued after the interrupt completes.
|
||
//
|
||
|
||
deviceExtension->InterruptData.InterruptFlags |= PD_NOTIFICATION_REQUIRED;
|
||
|
||
} // end IdePortNotification()
|
||
|
||
|
||
VOID
|
||
IdePortLogError(
|
||
IN PVOID HwDeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
|
||
IN UCHAR PathId,
|
||
IN UCHAR TargetId,
|
||
IN UCHAR Lun,
|
||
IN ULONG ErrorCode,
|
||
IN ULONG UniqueId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine saves the error log information, and queues a DPC if necessary.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - Supplies the HBA miniport driver's adapter data storage.
|
||
|
||
Srb - Supplies an optional pointer to srb if there is one.
|
||
|
||
TargetId, Lun and PathId - specify device address on a SCSI bus.
|
||
|
||
ErrorCode - Supplies an error code indicating the type of error.
|
||
|
||
UniqueId - Supplies a unique identifier for the error.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION deviceExtension =
|
||
((PFDO_EXTENSION) HwDeviceExtension) - 1;
|
||
PDEVICE_OBJECT DeviceObject = deviceExtension->DeviceObject;
|
||
PSRB_DATA srbData;
|
||
PERROR_LOG_ENTRY errorLogEntry;
|
||
|
||
//
|
||
// If the error log entry is already full, then dump the error.
|
||
//
|
||
|
||
if (deviceExtension->InterruptData.InterruptFlags & PD_LOG_ERROR) {
|
||
|
||
#if DBG
|
||
DebugPrint((1,"IdePortLogError: Dumping scsi error log packet.\n"));
|
||
DebugPrint((1,
|
||
"PathId = %2x, TargetId = %2x, Lun = %2x, ErrorCode = %x, UniqueId = %x.",
|
||
PathId,
|
||
TargetId,
|
||
Lun,
|
||
ErrorCode,
|
||
UniqueId
|
||
));
|
||
#endif
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Save the error log data in the log entry.
|
||
//
|
||
|
||
errorLogEntry = &deviceExtension->InterruptData.LogEntry;
|
||
|
||
errorLogEntry->ErrorCode = ErrorCode;
|
||
errorLogEntry->TargetId = TargetId;
|
||
errorLogEntry->Lun = Lun;
|
||
errorLogEntry->PathId = PathId;
|
||
errorLogEntry->UniqueId = UniqueId;
|
||
|
||
//
|
||
// Get the sequence number from the SRB data.
|
||
//
|
||
|
||
if (Srb != NULL) {
|
||
|
||
srbData = IdeGetSrbData(deviceExtension, Srb);
|
||
|
||
if (srbData == NULL) {
|
||
return;
|
||
}
|
||
|
||
errorLogEntry->SequenceNumber = srbData->SequenceNumber;
|
||
errorLogEntry->ErrorLogRetryCount = srbData->ErrorLogRetryCount++;
|
||
} else {
|
||
errorLogEntry->SequenceNumber = 0;
|
||
errorLogEntry->ErrorLogRetryCount = 0;
|
||
}
|
||
|
||
//
|
||
// Indicate that the error log entry is in use.
|
||
//
|
||
|
||
deviceExtension->InterruptData.InterruptFlags |= PD_LOG_ERROR;
|
||
|
||
//
|
||
// Request a DPC be queued after the interrupt completes.
|
||
//
|
||
|
||
deviceExtension->InterruptData.InterruptFlags |= PD_NOTIFICATION_REQUIRED;
|
||
|
||
return;
|
||
|
||
} // end IdePortLogError()
|
||
|
||
|
||
VOID
|
||
IdePortCompleteRequest(
|
||
IN PVOID HwDeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb,
|
||
IN UCHAR SrbStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Complete all active requests for the specified logical unit.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtenson - Supplies the HBA miniport driver's adapter data storage.
|
||
|
||
TargetId, Lun and PathId - specify device address on a SCSI bus.
|
||
|
||
SrbStatus - Status to be returned in each completed SRB.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION fdoExtension = ((PFDO_EXTENSION) HwDeviceExtension) - 1;
|
||
PLOGICAL_UNIT_EXTENSION logUnitExtension;
|
||
PIO_STACK_LOCATION irpStack;
|
||
PIRP Irp;
|
||
PSRB_DATA srbData;
|
||
PLIST_ENTRY entry;
|
||
ULONG limit = 0;
|
||
|
||
Irp = (PIRP) Srb->OriginalRequest;
|
||
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
logUnitExtension = IDEPORT_GET_LUNEXT_IN_IRP(irpStack);
|
||
|
||
DebugPrint((2,
|
||
"IdePortCompleteRequest: Complete requests for targetid %d\n",
|
||
logUnitExtension->TargetId));
|
||
|
||
//
|
||
// Complete any pending abort reqeusts.
|
||
//
|
||
|
||
if (logUnitExtension->AbortSrb != NULL) {
|
||
logUnitExtension->AbortSrb->SrbStatus = SrbStatus;
|
||
|
||
IdePortNotification(
|
||
IdeRequestComplete,
|
||
HwDeviceExtension,
|
||
logUnitExtension->AbortSrb
|
||
);
|
||
}
|
||
|
||
IdeCompleteRequest(fdoExtension, &logUnitExtension->SrbData, SrbStatus);
|
||
|
||
return;
|
||
|
||
} // end IdePortCompleteRequest()
|
||
|
||
BOOLEAN
|
||
TestForEnumProbing (
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
)
|
||
{
|
||
BOOLEAN enumProbing = FALSE;
|
||
|
||
if (Srb) {
|
||
|
||
if ((Srb->Function == SRB_FUNCTION_ATA_POWER_PASS_THROUGH) ||
|
||
(Srb->Function == SRB_FUNCTION_ATA_PASS_THROUGH)) {
|
||
|
||
PATA_PASS_THROUGH ataPassThroughData;
|
||
|
||
ataPassThroughData = Srb->DataBuffer;
|
||
|
||
enumProbing = ataPassThroughData->IdeReg.bReserved & ATA_PTFLAGS_ENUM_PROBING ? TRUE: FALSE;
|
||
}
|
||
}
|
||
|
||
return enumProbing;
|
||
}
|