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