Leaked source code of windows server 2003
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

/*++
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;
}