/*++ Copyright (c) 1992 Microsoft Corporation Module Name: ultra14f.c Abstract: This is the port driver for the ULTRASTOR 14F ISA SCSI adapter. Author: Stephen Fong Environment: kernel mode only Notes: Revision History: --*/ #include "miniport.h" #include "ultra14f.h" // includes scsi.h CONST ULONG AdapterAddresses[] = {0X330, 0X340, /* 0X310, */ 0X240, 0X230, 0X210, 0X140, 0X130, 0}; // // Logical Unit extension // typedef struct _SPECIFIC_LU_EXTENSION { UCHAR DisconnectErrorCount; // keep track of # of disconnect error } SPECIFIC_LU_EXTENSION, *PSPECIFIC_LU_EXTENSION; // // Device extension // typedef struct _HW_DEVICE_EXTENSION { PU14_BASEIO_ADDRESS U14_BaseIO_Address; UCHAR HostTargetId; } HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION; // // Function declarations // // Functions that start with 'Ultra14f' are entry points // for the OS port driver. // ULONG DriverEntry( IN PVOID DriverObject, IN PVOID Argument2 ); ULONG Ultra14fFindAdapter( IN PVOID DeviceExtension, IN PVOID Context, IN PVOID BusInformation, IN PCHAR ArgumentString, IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, OUT PBOOLEAN Again ); BOOLEAN Ultra14fInitialize( IN PVOID DeviceExtension ); BOOLEAN Ultra14fStartIo( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ); BOOLEAN Ultra14fInterrupt( IN PVOID DeviceExtension ); BOOLEAN Ultra14fResetBus( IN PVOID HwDeviceExtension, IN ULONG PathId ); // // This function is called from Ultra14fStartIo. // VOID BuildMscp( IN PHW_DEVICE_EXTENSION DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb, IN PSPECIFIC_LU_EXTENSION luExtension ); // // This function is called from BuildMscp. // VOID BuildSgl( IN PHW_DEVICE_EXTENSION DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ); // // This function is called from Ultra14fInterrupt. // VOID MapErrorToSrbStatus( IN PHW_DEVICE_EXTENSION DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ); ULONG DriverEntry ( IN PVOID DriverObject, IN PVOID Argument2 ) /*++ Routine Description: Installable driver initialization entry point for system. Arguments: Driver Object Return Value: Status from ScsiPortInitialize() --*/ { HW_INITIALIZATION_DATA hwInitializationData; ULONG i; ULONG AdapterCount = 0; DebugPrint((1,"\n\nSCSI UltraStor 14f MiniPort Driver\n")); // // Zero out structure. // for (i=0; iAdapterInterfaceType, // AdapterInterfaceType ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]), 0x10, // NumberOfBytes TRUE // InIoSpace ); // // Update the adapter count to indicate this IO addr has been checked. // (*adapterCount)++; productId1 = ScsiPortReadPortUchar(&baseIoAddress->ProductId1); productId2 = ScsiPortReadPortUchar(&baseIoAddress->ProductId2); if ((productId1 == ULTRASTOR_14F_ID1) && ((productId2 & (0xF0)) == ULTRASTOR_14F_ID2)) { DebugPrint((1, "Ultra14f: Adapter found at io address %x\n", baseIoAddress)); break; } // // If an adapter was not found unmap it. // ScsiPortFreeDeviceBase(deviceExtension, baseIoAddress); } // end while (AdapterAddress ... if (!AdapterAddresses[*adapterCount]) { // // No adapter was found. Indicate that we are done and there are no // more adapters here. Clear the adapter count for the next bus. // *Again = FALSE; *adapterCount = 0; return SP_RETURN_NOT_FOUND; } // // There is still more to look at. // *Again = TRUE; // // Store IO base address of Ultra 14F in device extension. // deviceExtension->U14_BaseIO_Address = baseIoAddress; deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0] = ScsiPortReadPortUchar(&baseIoAddress->Config2) & 0x07; // // Indicate maximum transfer length in bytes. // ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH; // // The supported maximum number of physical segments is 17, // but 16 is used to circumvent a firmware bug. // ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS; ConfigInfo->ScatterGather = TRUE; ConfigInfo->Master = TRUE; ConfigInfo->NumberOfBuses = 1; // // Get the system interrupt vector and IRQL. // interruptLevel = ScsiPortReadPortUchar(&baseIoAddress->Config1) & 0x30; switch (interruptLevel) { case US_INTERRUPT_LEVEL_15: ConfigInfo->BusInterruptLevel = 15; break; case US_INTERRUPT_LEVEL_14: ConfigInfo->BusInterruptLevel = 14; break; case US_INTERRUPT_LEVEL_11: ConfigInfo->BusInterruptLevel = 11; break; case US_INTERRUPT_LEVEL_10: ConfigInfo->BusInterruptLevel = 10; break; default: DebugPrint((1,"Ultra24fConfiguration: No interrupt level\n")); return SP_RETURN_ERROR; } DebugPrint((2,"Ultra14f: IRQ Configurated at %x\n", ConfigInfo->BusInterruptLevel)); // // If product sub-model is 1 (indicate 34L), don't setup DMA // if (!(productId2 & 0x01)) { // // Get the dma Channel // dmaChannel = ScsiPortReadPortUchar(&baseIoAddress->Config1) & 0xC0; switch (dmaChannel) { case US_DMA_CHANNEL_5: ConfigInfo->DmaChannel = 5; break; case US_DMA_CHANNEL_6: ConfigInfo->DmaChannel = 6; break; case US_DMA_CHANNEL_7: ConfigInfo->DmaChannel = 7; break; case US_DMA_CHANNEL_5_RESERVED: ConfigInfo->DmaChannel = 5; break; default: DebugPrint((1,"Ultra14fFindAdapter: Invalid DMA channel\n")); return SP_RETURN_ERROR; } //end switch DebugPrint((2,"Ultra14f: DMA Configurated at %x\n", ConfigInfo->DmaChannel)); } //end if // // Check if ISA TSR port is enabled. // if ((ScsiPortReadPortUchar(&baseIoAddress->Config2) & 0xC0) == US_ISA_SECONDARY_ADDRESS) { DebugPrint((1, "Ultra14fFindAdapter: ATDISK emulation at secondary address\n")); ConfigInfo->AtdiskSecondaryClaimed = TRUE; } else if ((ScsiPortReadPortUchar(&baseIoAddress->Config2) & 0xC0) == US_ISA_PRIMARY_ADDRESS) { DebugPrint((1, "Ultra24fConfiguration: ATDISK emulation at primary address\n")); ConfigInfo->AtdiskPrimaryClaimed = TRUE; } // // Fill in the access array information. // (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]); (*ConfigInfo->AccessRanges)[0].RangeLength = 16; (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; return SP_RETURN_FOUND; } // end Ultra14fFindAdapter() BOOLEAN Ultra14fInitialize( IN PVOID HwDeviceExtension ) /*++ Routine Description: Inititialize adapter. Arguments: HwDeviceExtension - HBA miniport driver's adapter data storage Return Value: TRUE - if initialization successful. FALSE - if initialization unsuccessful. --*/ { PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; PU14_BASEIO_ADDRESS u14_baseio_address = deviceExtension->U14_BaseIO_Address; UCHAR status; ULONG i; // // issue a Soft reset and a SCSI bus reset to Ultra14F // ScsiPortWritePortUchar(&u14_baseio_address->LocalDoorBellInterrupt, US_HA_SOFT_RESET); ScsiPortStallExecution(500*1000); //stall about 0.5 seconds // // Wait up to 1500,000 microseconds (1.5 sec) for adapter to initialize // Keep polling for Soft Reset bit to be clear. // for (i = 0; i < 150000; i++) { ScsiPortStallExecution(10); status = ScsiPortReadPortUchar( &u14_baseio_address->LocalDoorBellInterrupt); if (!(status & US_HA_SOFT_RESET)) { break; } } // // Check if reset failed or succeeded. // if (status & US_HA_SOFT_RESET) { DebugPrint((1, "Ultra14F, HwInitialize: Soft reset failed.\n")); } // // Enable ICMINT and SINTEN // ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellMask, US_ENABLE_ICMINT+US_ENABLE_SYSTEM_DOORBELL); // // reset the ICMINT // ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellInterrupt, US_RESET_ICMINT); return(TRUE); // // Enable system doorbell interrupt and Incoming mail interrupt. // ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellMask, (US_ENABLE_ICMINT + US_ENABLE_SYSTEM_DOORBELL)); } // end Ultra14fInitialize() BOOLEAN Ultra14fStartIo( IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) /*++ Routine Description: This routine is called from the SCSI port driver synchronized with the kernel to send an MSCP. Arguments: HwDeviceExtension - HBA miniport driver's adapter data storage Srb - IO request packet Return Value: TRUE --*/ { PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; PU14_BASEIO_ADDRESS u14_baseio_address = deviceExtension->U14_BaseIO_Address; PSPECIFIC_LU_EXTENSION luExtension; PMSCP mscp; PSCSI_REQUEST_BLOCK abortedSrb; ULONG physicalMscp; ULONG length; ULONG i = 0; // // Check for ABORT command. // if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) { DebugPrint((1, "Ultra14fStartIo: Received Abort command\n")); // // Verify that SRB to abort is still outstanding. // abortedSrb = ScsiPortGetSrb(deviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun, Srb->QueueTag); if (abortedSrb != Srb->NextSrb || abortedSrb->SrbStatus != SRB_STATUS_PENDING) { DebugPrint((1, "Ultra14fStartIo: SRB to abort already completed\n")); // // Complete abort SRB. // Srb->SrbStatus = SRB_STATUS_ABORT_FAILED; ScsiPortNotification(RequestComplete, deviceExtension, Srb); // // Adapter ready for next request. // ScsiPortNotification(NextRequest, deviceExtension, NULL); } else { // // Check if interrupt pending. // if (ScsiPortReadPortUchar(&u14_baseio_address->SystemDoorBellInterrupt) & US_ICMINT) { DebugPrint((1,"Ultra14fStartIo: Interrupt pending\n")); // // Reset the ICMINT system doorbell interrupt. // ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellInterrupt, US_RESET_ICMINT); // // Abort the outstanding SRB. // abortedSrb->SrbStatus = SRB_STATUS_ABORTED; ScsiPortNotification(RequestComplete, deviceExtension, abortedSrb); // // Complete abort SRB. // Srb->SrbStatus = SRB_STATUS_SUCCESS; ScsiPortNotification(RequestComplete, deviceExtension, Srb); // // Adapter ready for next request. // ScsiPortNotification(NextRequest, deviceExtension, NULL); } else { // // Ultra14f adapter does not support the abort command. // Reset the bus. The reset routine will complete all // outstanding requests and indicate ready for next request. // if (!Ultra14fResetBus(deviceExtension, Srb->PathId)) { DebugPrint((1, "Ultra14fStartIo: Reset scsi bus failed\n")); } // // Adapter ready for next request. // ScsiPortNotification(NextRequest, deviceExtension, NULL); } } return TRUE; } else { // // This is a request to a device. // mscp = Srb->SrbExtension; // // Save SRB back pointer in MSCP. // mscp->SrbAddress = Srb; mscp->AbortSrb = NULL; } // // Get MSCP physical address. // physicalMscp = ScsiPortConvertPhysicalAddressToUlong( ScsiPortGetPhysicalAddress(deviceExtension, NULL, mscp, &length)); // // Assume physical address is contiguous for size of ECB. // ASSERT(length >= sizeof(MSCP)); switch (Srb->Function) { case SRB_FUNCTION_EXECUTE_SCSI: // // Determine the logical unit that this request is for. // luExtension = ScsiPortGetLogicalUnit(deviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun); // // Build MSCP for this request. // BuildMscp(deviceExtension, Srb, luExtension); break; default: // // Set error, complete request // and signal ready for next request. // Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; ScsiPortNotification(RequestComplete, deviceExtension, Srb); ScsiPortNotification(NextRequest, deviceExtension, NULL); return TRUE; } // end switch // // wait for a free OGM Slot (OGMINT to be clear) // for (i=0; i<50000; i++) { if (!(ScsiPortReadPortUchar( &u14_baseio_address->LocalDoorBellInterrupt) & US_OGMINT)) { break; } else { // // Stall 1 microsecond before trying again. // ScsiPortStallExecution(1); } } if (i == 50000) { // // Let operating system time out SRB. // DebugPrint((1,"Ultra14fStartIo: Timed out waiting for mailbox\n")); } else { // // Write MSCP pointer to mailbox. // ScsiPortWritePortUlong(&u14_baseio_address->OutGoingMailPointer, physicalMscp); // // Issue a OGMINT to send to the host adapter // ScsiPortWritePortUchar(&u14_baseio_address->LocalDoorBellInterrupt, US_OGMINT); if (!mscp->DisableDisconnect) { // // Adapter ready for next request. // ScsiPortNotification(NextRequest, deviceExtension); } } return TRUE; } // end Ultra14fStartIo() BOOLEAN Ultra14fInterrupt( IN PVOID HwDeviceExtension ) /*++ Routine Description: This is the interrupt service routine for the Ultra14f SCSI adapter. It reads the system Doorbell interrupt register to determine if the adapter is indeed the source of the interrupt and clears the interrupt at the device. If the adapter is interrupting because a mailbox is full, the MSCP is retrieved to complete the request. Arguments: HwDeviceExtension - HBA miniport driver's adapter data storage Return Value: TRUE if MailboxIn full --*/ { PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; PMSCP mscp; PSCSI_REQUEST_BLOCK srb; PU14_BASEIO_ADDRESS u14_baseio_address = deviceExtension->U14_BaseIO_Address; ULONG physicalMscp; // // Check interrupt pending. // if (!(ScsiPortReadPortUchar(&u14_baseio_address->SystemDoorBellInterrupt) & US_ICMINT)) { // // Handle spurious interrupt. // DebugPrint((2,"Ultra14fInterrupt: Spurious interrupt\n")); return FALSE; } // // Get physical address of MSCP // physicalMscp = ScsiPortReadPortUlong( &u14_baseio_address->InComingMailPointer); // // Get virtual MSCP address. // mscp = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalMscp)); // // Make sure the physical address was valid. // if (mscp == NULL) { ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellInterrupt, US_RESET_ICMINT); DebugPrint((1,"\n\nUltra14f Interrupt: recieve NULL MSCP\n")); return FALSE; } else { // // Get SRB from MSCP. // srb = mscp->SrbAddress; // // Check status of completing MSCP in mailbox. and update SRB statuses // if (!((mscp->AdapterStatus) | (mscp->TargetStatus))) { srb->SrbStatus = SRB_STATUS_SUCCESS; srb->ScsiStatus = SCSISTAT_GOOD; } else { // // Translate adapter status to SRB status // and log error if necessary. // MapErrorToSrbStatus(deviceExtension, srb); } } if (mscp->DisableDisconnect) { // // Adapter ready for next request. // ScsiPortNotification(NextRequest, deviceExtension); } // // Call notification routine for the SRB. // ScsiPortNotification(RequestComplete, (PVOID)deviceExtension, srb); // // Reset the ICMINT system doorbell interrupt. // ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellInterrupt, US_RESET_ICMINT); return TRUE; } // end Ultra14fInterrupt() VOID BuildMscp( IN PHW_DEVICE_EXTENSION DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb, IN PSPECIFIC_LU_EXTENSION luExtension ) /*++ Routine Description: Build MSCP for Ultra14f from SRB. Arguments: DeviceExtenson SRB Return Value: Nothing. --*/ { PMSCP mscp = Srb->SrbExtension; ULONG length; // // Set MSCP command. // mscp->OperationCode = MSCP_OPERATION_SCSI_COMMAND; // // Check SRB for disabled disconnect. // // NOTE: UltraStor 14f SCSI adapter does not // support disabling synchronous transfer // per request. // if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) { mscp->DisableDisconnect = TRUE; } else { // // Earlier ultra14f firmware has a bug with disconnect. // A counter is used here to check whether or not to disable // disconnect due to disconnect related problem that already happened // for the requested device, // if (luExtension->DisconnectErrorCount >= 5) { if (luExtension->DisconnectErrorCount == 5) { ScsiPortLogError(DeviceExtension, NULL, 0, DeviceExtension->HostTargetId, 0, SP_BAD_FW_WARNING, 1 << 16); } mscp->DisableDisconnect = TRUE; } else { mscp->DisableDisconnect = FALSE; } } // // Set channel, target id and lun. // mscp->Channel = Srb->PathId; mscp->TargetId = Srb->TargetId; mscp->Lun = Srb->Lun; // // Set CDB length and copy to MSCP. // mscp->CdbLength = Srb->CdbLength; ScsiPortMoveMemory(mscp->Cdb, Srb->Cdb, Srb->CdbLength); // // Build SGL in MSCP if data transfer. // if (Srb->DataTransferLength > 0) { // // Build scattergather descriptor list. // BuildSgl(DeviceExtension, Srb); // // Set transfer direction. // if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { // // Write request. // mscp->TransferDirection = MSCP_TRANSFER_OUT; } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) { // // Read request. // mscp->TransferDirection = MSCP_TRANSFER_IN; } } else { // // Set up MSCP for no data transfer. // mscp->TransferDirection = MSCP_NO_TRANSFER; mscp->DataLength = 0; mscp->ScatterGather = FALSE; mscp->SgDescriptorCount = 0; } // // Setup auto sense if necessary. // if (Srb->SenseInfoBufferLength != 0 && !(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)) { // // Set the flag to enable auto sense and fill in the address and // length of the sense buffer. // mscp->RequestSenseLength = Srb->SenseInfoBufferLength; mscp->RequestSensePointer = ScsiPortConvertPhysicalAddressToUlong( ScsiPortGetPhysicalAddress(DeviceExtension, Srb, Srb->SenseInfoBuffer, &length)); ASSERT(length >= Srb->SenseInfoBufferLength); } else { // // Ultra14F uses nonzero request sense pointer // as an indication of autorequestsense. // mscp->RequestSenseLength = 0; mscp->RequestSensePointer = 0; } // // Zero out command link, status and abort fields. // mscp->CommandLink = 0; mscp->CommandLinkId = 0; mscp->AdapterStatus = 0; mscp->TargetStatus = 0; mscp->AbortSrb = 0; // // Bypass cache. // mscp->UseCache = FALSE; return; } // end BuildMscp() VOID BuildSgl( IN PHW_DEVICE_EXTENSION DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) /*++ Routine Description: This routine builds a scatter/gather descriptor list in the MSCP. Arguments: DeviceExtension Srb Return Value: None --*/ { PVOID dataPointer = Srb->DataBuffer; ULONG bytesLeft = Srb->DataTransferLength; PMSCP mscp = Srb->SrbExtension; PSDL sdl = &mscp->Sdl; ULONG physicalSdl; ULONG physicalAddress; ULONG length; ULONG descriptorCount = 0; // // Get physical SDL address. // physicalSdl = ScsiPortConvertPhysicalAddressToUlong( ScsiPortGetPhysicalAddress(DeviceExtension, NULL, sdl, &length)); // // Assume physical memory contiguous for sizeof(SGL) bytes. // ASSERT(length >= sizeof(SDL)); // // Create SDL segment descriptors. // do { // // Get physical address and length of contiguous // physical buffer. // physicalAddress = ScsiPortConvertPhysicalAddressToUlong( ScsiPortGetPhysicalAddress(DeviceExtension, Srb, dataPointer, &length)); // // If length of physical memory is more // than bytes left in transfer, use bytes // left as final length. // if (length > bytesLeft) { length = bytesLeft; } sdl->Descriptor[descriptorCount].Address = physicalAddress; sdl->Descriptor[descriptorCount].Length = length; // // Adjust counts. // dataPointer = (PUCHAR)dataPointer + length; bytesLeft -= length; descriptorCount++; } while (bytesLeft); // // Check for only one descriptor. As an optimization, in these // cases, use nonscattergather requests. // if (descriptorCount == 1) { // // Set descriptor count to 0. // mscp->SgDescriptorCount = 0; // // Set data pointer to data buffer. // mscp->DataPointer = physicalAddress; // // Set data transfer length. // mscp->DataLength = Srb->DataTransferLength; // // Clear scattergather bit. // mscp->ScatterGather = FALSE; } else { // // Write SDL count to MSCP. // mscp->SgDescriptorCount = (UCHAR)descriptorCount; // // Write SGL address to ECB. // mscp->DataPointer = physicalSdl; mscp->DataLength = Srb->DataTransferLength; // // Indicate scattergather operation. // mscp->ScatterGather = TRUE; } return; } // end BuildSgl() BOOLEAN Ultra14fResetBus( IN PVOID HwDeviceExtension, IN ULONG PathId ) /*++ Routine Description: Reset Ultra14f SCSI adapter and SCSI bus. Arguments: HwDeviceExtension - HBA miniport driver's adapter data storage Return Value: Nothing. --*/ { PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; PU14_BASEIO_ADDRESS u14_baseio_address = deviceExtension->U14_BaseIO_Address; ULONG j; // // The Ultra14f only supports a single SCSI channel. // UNREFERENCED_PARAMETER(PathId); // // Reset SCSI bus. // ScsiPortWritePortUchar(&u14_baseio_address->LocalDoorBellInterrupt, (US_HA_SOFT_RESET | US_ENABLE_SCSI_BUS_RESET)); // // Wait for local processor to clear both reset bits. // for (j=0; j<200000; j++) { if (!(ScsiPortReadPortUchar(&u14_baseio_address->LocalDoorBellInterrupt) & (US_HA_SOFT_RESET | US_ENABLE_SCSI_BUS_RESET))) { break; } ScsiPortStallExecution(10); } // end for (j=0 ... if (j == 200000) { DebugPrint((1,"Ultra14fResetBus: Reset timed out\n")); // // Busy has not gone low. Assume the card is gone. // Log the error and fail the request. // ScsiPortLogError(deviceExtension, NULL, 0, deviceExtension->HostTargetId, 0, SP_INTERNAL_ADAPTER_ERROR, 3 << 16); return FALSE; } // ScsiPortStallExecution(200*1000); // has to wait about 2 seconds // for F/W to be actually ready // don't do this for now until // Ha_Inquiry is implemented later // // Complete all outstanding requests. // ScsiPortCompleteRequest(deviceExtension, (UCHAR)0, (UCHAR)-1, (UCHAR)-1, SRB_STATUS_BUS_RESET); // // Adapter ready for next request. // ScsiPortNotification(NextRequest, deviceExtension, NULL); return TRUE; } // end Ultra14fResetBus() VOID MapErrorToSrbStatus( IN PHW_DEVICE_EXTENSION DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) /*++ Routine Description: Translate Ultra14f error to SRB error. Arguments: Device Extension for logging error SRB Return Value: Updated SRB --*/ { ULONG logError = 0; UCHAR srbStatus; PMSCP mscp = Srb->SrbExtension; PSPECIFIC_LU_EXTENSION luExtension; switch (mscp->AdapterStatus) { case MSCP_NO_ERROR: srbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID; break; case MSCP_SELECTION_TIMEOUT: srbStatus = SRB_STATUS_SELECTION_TIMEOUT; DebugPrint((1,"MapErrorToSrbStatus: Target SCSI device not found\n")); break; case MSCP_BUS_UNDER_OVERRUN: DebugPrint((1,"MapErrorToSrbStatus: Data over/underrun\n")); srbStatus = SRB_STATUS_DATA_OVERRUN; break; case MSCP_UNEXPECTED_BUS_FREE: // // Ultra14F older firmware has a bug that causes unexpected bus free // error and invalid SCSI command errors during disconnect. A counter // is used here to keep track of the number of such error for each // device. When the number of maximum disconnected error count is // reached, the driver will disable disconnect for the device with the // disconnected problem. // DebugPrint((1,"MapErrorToSrbStatus: Unexpected bus free\n")); // // Determine the logical unit that this request is for. // luExtension = ScsiPortGetLogicalUnit(DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun); logError = SP_PROTOCOL_ERROR; luExtension->DisconnectErrorCount += 1; srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE; break; case MSCP_ILLEGAL_SCSI_COMMAND: // // Ultra14F older firmware has a bug that causes unexpected bus free // error and invalid SCSI command errors during disconnect. A counter // is used here to keep track of the number of such error for each // device. When the number of maximum disconnected error count is // reached, the driver will disable disconnect for the device with the // disconnected problem. // DebugPrint((1,"MapErrorToSrbStatus: Illegal SCSI Command\n")); // // Determine the logical unit that this request is for. // luExtension = ScsiPortGetLogicalUnit(DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun); luExtension->DisconnectErrorCount += 1; srbStatus = SRB_STATUS_INVALID_REQUEST; break; case MSCP_INVALID_PHASE_CHANGE: DebugPrint((1,"MapErrorToSrbStatus: Invalid bus phase\n")); logError = SP_PROTOCOL_ERROR; srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE; break; case MSCP_INVALID_COMMAND: case MSCP_INVALID_PARAMETER: case MSCP_INVALID_DATA_LIST: case MSCP_INVALID_SG_LIST: // case MSCP_ILLEGAL_SCSI_COMMAND: DebugPrint((1,"MapErrorToSrbStatus: Invalid command %x\n", mscp->AdapterStatus)); srbStatus = SRB_STATUS_INVALID_REQUEST; break; case MSCP_BUS_RESET_ERROR: DebugPrint((1,"MapErrorToSrbStatus: Bus reset\n")); srbStatus = SRB_STATUS_BUS_RESET; break; case MSCP_ABORT_NOT_FOUND: case MSCP_SCSI_BUS_ABORT_ERROR: DebugPrint((1,"MapErrorToSrbStatus: Abort not found\n")); srbStatus = SRB_STATUS_ABORT_FAILED; break; default: logError = SP_PROTOCOL_ERROR; srbStatus = SRB_STATUS_ERROR; break; } // end switch ... // // Log error if indicated. // if (logError) { ScsiPortLogError( DeviceExtension, Srb, Srb->PathId, Srb->TargetId, Srb->Lun, logError, 2 << 16 | mscp->AdapterStatus ); } // // Set SRB status. // Srb->SrbStatus = srbStatus; // // Set target SCSI status in SRB. // Srb->ScsiStatus = mscp->TargetStatus; return; } // end MapErrorToSrbStatus()