You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
419 lines
10 KiB
419 lines
10 KiB
/*++
|
|
|
|
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;
|
|
}
|