// // Complete a Ccb // VOID LSCcbPostCompleteCcb( IN PCCB Ccb ) { PKEVENT event; ASSERT(Ccb->Type == LSSTRUC_TYPE_CCB); ASSERT(Ccb->Length == sizeof(CCB)); ASSERT(LSCcbIsStatusFlagOn(Ccb,CCBSTATUS_FLAG_COMPLETED)); ASSERT(Ccb->AssociateCount == 0); ASSERT(Ccb->CcbCurrentStackLocationIndex <= NR_MAX_CCB_STACKLOCATION); ASSERT(Ccb->CcbCurrentStackLocation == &Ccb->CcbStackLocation[Ccb->CcbCurrentStackLocationIndex]); if(LSCcbIsStatusFlagOn(Ccb,CCBSTATUS_FLAG_POST_COMPLETED)) { ASSERT(FALSE); return; } LSCcbSetStatusFlag(Ccb, CCBSTATUS_FLAG_POST_COMPLETED); event = Ccb->CompletionEvent; if(LSCcbIsFlagOn(Ccb, CCB_FLAG_DATABUF_ALLOCATED) && Ccb->DataBuffer && Ccb->DataBufferLength) { ASSERT(LSCcbIsFlagOn(Ccb, CCB_FLAG_ALLOCATED)); KDPrintM(DBG_CCB_INFO, ("Freeing Ccb->DataBuffer=%p.\n", Ccb->DataBuffer)); ExFreePool(Ccb->DataBuffer); } if(LSCcbIsFlagOn(Ccb, CCB_FLAG_ALLOCATED)) { KDPrintM(DBG_CCB_TRACE, ("Freeing Ccb=%p.\n", Ccb)); LSCcbFree(Ccb); } // You must not use any data in Ccb after KeSetEvent // because caller will free Ccb after event received if(event) { KeSetEvent(event, IO_DISK_INCREMENT, FALSE); } }
// // Complete a Ccb // // We can set the CCBSTATUS_FLAG_COMPLETED flag only in this function // VOID LSCcbCompleteCcb( IN PCCB Ccb ) { LONG idx_sl; NTSTATUS status; ASSERT(Ccb->Type == LSSTRUC_TYPE_CCB); ASSERT(Ccb->Length == sizeof(CCB)); ASSERT(!LSCcbIsStatusFlagOn(Ccb,CCBSTATUS_FLAG_COMPLETED)); ASSERT(Ccb->AssociateCount == 0); ASSERT(Ccb->CcbCurrentStackLocationIndex < NR_MAX_CCB_STACKLOCATION); ASSERT(Ccb->CcbCurrentStackLocation == &Ccb->CcbStackLocation[Ccb->CcbCurrentStackLocationIndex]); KDPrintM(DBG_CCB_TRACE, ("entered with Ccb:%p\n", Ccb)); LSCcbSetStatusFlag(Ccb, CCBSTATUS_FLAG_COMPLETED); LSCcbResetStatusFlag(Ccb, CCBSTATUS_FLAG_PENDING); Ccb->CcbCurrentStackLocationIndex++; Ccb->CcbCurrentStackLocation++; // // Call completion routines in order. // for( idx_sl = Ccb->CcbCurrentStackLocationIndex; idx_sl < NR_MAX_CCB_STACKLOCATION; idx_sl++, Ccb->CcbCurrentStackLocation++, Ccb->CcbCurrentStackLocationIndex++ ) { ASSERT(Ccb->CcbCurrentStackLocation <= &Ccb->CcbStackLocation[NR_MAX_CCB_STACKLOCATION - 1]); if(Ccb->CcbCurrentStackLocation->CcbCompletionRoutine) { status = Ccb->CcbCurrentStackLocation->CcbCompletionRoutine(Ccb, Ccb->CcbCurrentStackLocation->CcbCompletionContext); if(status == STATUS_MORE_PROCESSING_REQUIRED) { KDPrintM(DBG_CCB_TRACE, ("Ccb=%p, more processing required.\n", Ccb)); return; } KDPrintM(DBG_CCB_TRACE, ("Ccb=%p, completion complete.\n", Ccb)); } } // // Do post operation // LSCcbPostCompleteCcb(Ccb); }
NTSTATUS LanscsiMiniportCompletion( IN PCCB Ccb, IN PMINIPORT_DEVICE_EXTENSION HwDeviceExtension ) { KIRQL oldIrql; static LONG SrbSeq; LONG srbSeqIncremented; PSCSI_REQUEST_BLOCK srb; PCCB abortCcb; NTSTATUS return_status; KDPrint(3,("RequestExecuting = %d\n", HwDeviceExtension->RequestExecuting)); srb = Ccb->Srb; if(!srb) { KDPrint(1,("Ccb:%p CcbStatus %d. No srb assigned.\n", Ccb, Ccb->CcbStatus)); ASSERT(srb); return STATUS_SUCCESS; } // // LanscsiMiniport completion routine will do post operation to complete CCBs. // return_status = STATUS_MORE_PROCESSING_REQUIRED; srbSeqIncremented = InterlockedIncrement(&SrbSeq); // // check to see if this CCB was sent before BusReset occurs. // TODO: we need to calculate the accurate BUSRESET_EFFECT_TICKCOUNT. // ASSERT(Ccb->CreateTime.QuadPart); KDPrint(3,("!!!!! SRB:%p CCB:%p CCB->CreateTime: %I64u!!!!!!\n", srb, Ccb, Ccb->CreateTime.QuadPart)); ACQUIRE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, &oldIrql); if( Ccb->CreateTime.QuadPart <= HwDeviceExtension->LastBusResetTime.QuadPart + BUSRESET_EFFECT_TICKCOUNT || ADAPTER_ISSTATUSFLAG(HwDeviceExtension, ADAPTER_STATUSFLAG_BUSRESET_PENDING) ) { ADAPTER_RESETSTATUSFLAG(HwDeviceExtension, ADAPTER_STATUSFLAG_BUSRESET_PENDING); RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql); KDPrint(1,("!!!!!! BusReset occured after this CCB has entered." " Make it completed with Timer. CCB->CreateTime: %I64u!!!!!!\n", Ccb->CreateTime.QuadPart)); LSCcbSetStatusFlag(Ccb, CCBSTATUS_FLAG_TIMER_COMPLETE); } else { RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql); } // // Check reconnecting process. // Translate CCB to SRB. // if(LSCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_RECONNECTING)) { ACQUIRE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, &oldIrql); if(!ADAPTER_ISSTATUSFLAG(HwDeviceExtension, ADAPTER_STATUSFLAG_RECONNECTPENDING)) { UINT32 AdapterStatus; AdapterStatus = ADAPTER_SETSTATUSFLAG(HwDeviceExtension, ADAPTER_STATUSFLAG_RECONNECTPENDING); RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql); UpdatePdoInfoInLSBus(HwDeviceExtension, AdapterStatus); KDPrint(1,("Ccb:%p CcbStatus %d. Start reconnecting\n", Ccb, Ccb->CcbStatus)); } else { RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql); } } else { // // If CCbStatus != CCB_STATUS_STOP, reconnecting is successful. // if(Ccb->CcbStatus != CCB_STATUS_STOP) { ACQUIRE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, &oldIrql); if(ADAPTER_ISSTATUSFLAG(HwDeviceExtension, ADAPTER_STATUSFLAG_RECONNECTPENDING)) { UINT32 AdapterStatus; AdapterStatus = ADAPTER_RESETSTATUSFLAG(HwDeviceExtension, ADAPTER_STATUSFLAG_RECONNECTPENDING); RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql); UpdatePdoInfoInLSBus(HwDeviceExtension, AdapterStatus); KDPrint(1,("Ccb:%p CcbStatus %d. Finish reconnecting\n", Ccb, Ccb->CcbStatus)); } else { RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql); } } } // // If CCB_OPCODE_UPDATE is successful, update adapter status in LanscsiBus // if(Ccb->OperationCode == CCB_OPCODE_UPDATE && Ccb->CcbStatus == CCB_STATUS_SUCCESS) { UINT32 AdapterStatus; ACQUIRE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, &oldIrql); AdapterStatus = HwDeviceExtension->AdapterStatus; RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql); UpdatePdoInfoInLSBus(HwDeviceExtension, AdapterStatus); } KDPrint(3,("CcbStatus %d\n", Ccb->CcbStatus)); // // Translate CcbStatus to SrbStatus // switch(Ccb->CcbStatus) { case CCB_STATUS_SUCCESS: srb->SrbStatus = SRB_STATUS_SUCCESS; srb->ScsiStatus = SCSISTAT_GOOD; // // Check to see if the associate member is in error. // if(LSCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_LURN_STOP)) { ACQUIRE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, &oldIrql); if(!ADAPTER_ISSTATUSFLAG(HwDeviceExtension, ADAPTER_STATUSFLAG_MEMBER_FAULT)) { UINT32 AdapterStatus; AdapterStatus = ADAPTER_SETSTATUSFLAG(HwDeviceExtension, ADAPTER_STATUSFLAG_MEMBER_FAULT); RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql); UpdatePdoInfoInLSBus(HwDeviceExtension, AdapterStatus); KDPrint(1,("Ccb:%p CcbStatus %d. Associate member is in error.\n", Ccb, Ccb->CcbStatus)); // // Send DisconEvent to the service. // TODO: alternate to AlarmEvent. // KeSetEvent(HwDeviceExtension->DisconEventToService, IO_NO_INCREMENT, FALSE); } else { RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql); } } break; case CCB_STATUS_NOT_EXIST: srb->SrbStatus = SRB_STATUS_NO_DEVICE; srb->ScsiStatus = SCSISTAT_GOOD; break; case CCB_STATUS_INVALID_COMMAND: srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; srb->ScsiStatus = SCSISTAT_GOOD; break; case CCB_STATUS_COMMAND_FAILED: srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID; srb->ScsiStatus = SCSISTAT_CHECK_CONDITION; srb->DataTransferLength -= Ccb->ResidualDataLength; break; // Added by ILGU HONG 2004_07_05 case CCB_STATUS_COMMMAND_DONE_SENSE: srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID ; srb->DataTransferLength = 0; srb->ScsiStatus = SCSISTAT_GOOD; break; // Added by ILGU HONG 2004_07_05 end case CCB_STATUS_RESET: srb->SrbStatus = SRB_STATUS_BUS_RESET; srb->ScsiStatus = SCSISTAT_GOOD; break; case CCB_STATUS_COMMUNICATION_ERROR: { PSENSE_DATA senseData; srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID; srb->ScsiStatus = SCSISTAT_CHECK_CONDITION; srb->DataTransferLength = 0; senseData = srb->SenseInfoBuffer; senseData->ErrorCode = 0x70; senseData->Valid = 1; //senseData->SegmentNumber = 0; senseData->SenseKey = SCSI_SENSE_HARDWARE_ERROR; //SCSI_SENSE_MISCOMPARE; //senseData->IncorrectLength = 0; //senseData->EndOfMedia = 0; //senseData->FileMark = 0; senseData->AdditionalSenseLength = 0xb; senseData->AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE; senseData->AdditionalSenseCodeQualifier = 0; } break; case CCB_STATUS_BUSY: srb->SrbStatus = SRB_STATUS_BUSY; srb->ScsiStatus = SCSISTAT_GOOD; KDPrint(1,("CCB_STATUS_BUSY\n")); break; // // Stop one LUR // case CCB_STATUS_STOP: { KDPrint(1,("CCB_STATUS_STOP. Stopping!\n")); srb->SrbStatus = SRB_STATUS_NO_DEVICE; srb->ScsiStatus = SCSISTAT_GOOD; MiniStopAdapter(HwDeviceExtension, TRUE); break; } default: // Error in Connection... // CCB_STATUS_UNKNOWN_STATUS, CCB_STATUS_RESET, and so on. srb->SrbStatus = SRB_STATUS_ERROR; srb->ScsiStatus = SCSISTAT_GOOD; } // // Process Abort CCB. // abortCcb = Ccb->AbortCcb; if(abortCcb != NULL) { KDPrint(1,("abortSrb\n")); ASSERT(FALSE); srb->SrbStatus = SRB_STATUS_SUCCESS; LSCcbSetStatusFlag(Ccb, CCBSTATUS_FLAG_TIMER_COMPLETE); InitializeListHead(&Ccb->ListEntry); ExInterlockedInsertTailList( &HwDeviceExtension->CcbCompletionList, &Ccb->ListEntry, &HwDeviceExtension->CcbCompletionListSpinLock ); ((PSCSI_REQUEST_BLOCK)abortCcb->Srb)->SrbStatus = SRB_STATUS_ABORTED; LSCcbSetStatusFlag(abortCcb, CCBSTATUS_FLAG_TIMER_COMPLETE); InitializeListHead(&abortCcb->ListEntry); ExInterlockedInsertTailList( &HwDeviceExtension->CcbCompletionList, &abortCcb->ListEntry, &HwDeviceExtension->CcbCompletionListSpinLock ); } else { // // Make Complete IRP and Send it. // // // In case of HostStatus == CCB_STATUS_SUCCESS_TIMER, CCB will go to the timer to complete. // if( (Ccb->CcbStatus == CCB_STATUS_SUCCESS || Ccb->CcbStatus == CCB_STATUS_INVALID_COMMAND) && !LSCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_TIMER_COMPLETE) && !LSCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_BUSRESET_REQUIRED) ) { PDEVICE_OBJECT pDeviceObject = HwDeviceExtension->ScsiportFdoObject; PIRP pCompletionIrp = NULL; PIO_STACK_LOCATION pIoStack; NTSTATUS ntStatus; PSCSI_REQUEST_BLOCK completionSrb = NULL; PCOMPLETION_DATA completionData = NULL; completionSrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK), LSMP_PTAG_SRB); if(completionSrb == NULL) goto Out; RtlZeroMemory( completionSrb, sizeof(SCSI_REQUEST_BLOCK) ); // Build New IRP. pCompletionIrp = IoAllocateIrp((CCHAR)(pDeviceObject->StackSize + 1), FALSE); if(pCompletionIrp == NULL) { ExFreePoolWithTag(completionSrb, LSMP_PTAG_SRB); goto Out; } completionData = ExAllocatePoolWithTag(NonPagedPool, sizeof(COMPLETION_DATA), LSMP_PTAG_CMPDATA); if(completionData == NULL) { ExFreePoolWithTag(completionSrb, LSMP_PTAG_SRB); IoFreeIrp(pCompletionIrp); pCompletionIrp = NULL; goto Out; } pCompletionIrp->MdlAddress = NULL; // Set IRP stack location. pIoStack = IoGetNextIrpStackLocation(pCompletionIrp); pIoStack->DeviceObject = pDeviceObject; pIoStack->MajorFunction = IRP_MJ_SCSI; pIoStack->Parameters.DeviceIoControl.InputBufferLength = 0; pIoStack->Parameters.DeviceIoControl.OutputBufferLength = 0; pIoStack->Parameters.Scsi.Srb = completionSrb; // Set SRB. completionSrb->Length = sizeof(SCSI_REQUEST_BLOCK); completionSrb->Function = SRB_FUNCTION_EXECUTE_SCSI; completionSrb->PathId = srb->PathId; completionSrb->TargetId = srb->TargetId; completionSrb->Lun = srb->Lun; completionSrb->QueueAction = SRB_SIMPLE_TAG_REQUEST; completionSrb->DataBuffer = srb; completionSrb->SrbFlags |= SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE; completionSrb->OriginalRequest = pCompletionIrp; completionSrb->CdbLength = MAXIMUM_CDB_SIZE; completionSrb->Cdb[0] = SCSIOP_COMPLETE; completionSrb->Cdb[1] = (UCHAR)srbSeqIncremented; completionSrb->TimeOutValue = 20; completionSrb->SrbStatus = SRB_STATUS_SUCCESS; // // Set compeltion data for the completion IRP. // completionData->HwDeviceExtension = HwDeviceExtension; completionData->CompletionSrb = completionSrb; completionData->ShippedCcb = Ccb; completionData->ShippedCcbAllocatedFromPool = LSCcbIsFlagOn(Ccb, CCB_FLAG_ALLOCATED); Out: KDPrint(4,("Before Completion\n")); if(pCompletionIrp) { IoSetCompletionRoutine(pCompletionIrp, CompletionIrpCompletionRoutine, completionData, TRUE, TRUE, TRUE); ASSERT(HwDeviceExtension->RequestExecuting != 0); // // call Scsiport FDO. // ntStatus = IoCallDriver(pDeviceObject, pCompletionIrp); ASSERT(NT_SUCCESS(ntStatus)); #if DBG if(ntStatus!= STATUS_SUCCESS && ntStatus!= STATUS_PENDING) { KDPrint(1,("ntStatus = 0x%x\n", ntStatus)); } #endif }else { KDPrint(1,("CompletionIRP NULL. CCB(%p) and SRB(%p) is going to the timer. CcbStatus:%x CcbFlag:%x\n", Ccb, Ccb->Srb, Ccb->CcbStatus, Ccb->Flags)); InitializeListHead(&Ccb->ListEntry); LSCcbSetStatusFlag(Ccb, CCBSTATUS_FLAG_TIMER_COMPLETE); ExInterlockedInsertTailList( &HwDeviceExtension->CcbCompletionList, &Ccb->ListEntry, &HwDeviceExtension->CcbCompletionListSpinLock ); } } else { KDPrint(1,("CCB(%p) and SRB(%p) is going to the timer. CcbStatus:%x CcbFlag:%x\n", Ccb, Ccb->Srb, Ccb->CcbStatus, Ccb->Flags)); InitializeListHead(&Ccb->ListEntry); LSCcbSetStatusFlag(Ccb, CCBSTATUS_FLAG_TIMER_COMPLETE); ExInterlockedInsertTailList( &HwDeviceExtension->CcbCompletionList, &Ccb->ListEntry, &HwDeviceExtension->CcbCompletionListSpinLock ); } } return return_status; }
VOID MiniTimer( IN PMINIPORT_DEVICE_EXTENSION HwDeviceExtension ) { BOOLEAN BusChanged; MiniCounter ++; BusChanged = FALSE; do { PLIST_ENTRY listEntry; PCCB ccb; PSCSI_REQUEST_BLOCK srb; // Get Completed CCB listEntry = ExInterlockedRemoveHeadList( &HwDeviceExtension->CcbCompletionList, &HwDeviceExtension->CcbCompletionListSpinLock ); if(listEntry == NULL) break; ccb = CONTAINING_RECORD(listEntry, CCB, ListEntry); srb = ccb->Srb; ASSERT(srb); ASSERT(LSCcbIsStatusFlagOn(ccb, CCBSTATUS_FLAG_TIMER_COMPLETE)); KDPrint(1,("completed SRB:%p SCSIOP:%x\n", srb, srb->Cdb[0])); if(LSCcbIsStatusFlagOn(ccb, CCBSTATUS_FLAG_BUSRESET_REQUIRED)) { BusChanged = TRUE; } // // Free a CCB // LSCcbPostCompleteCcb(ccb); ScsiPortNotification( RequestComplete, HwDeviceExtension, srb ); InterlockedDecrement(&HwDeviceExtension->RequestExecuting); } while(1); if(BusChanged) { KDPrint(1,("Bus change detected. RequestExecuting = %d\n", HwDeviceExtension->RequestExecuting)); ScsiPortNotification( BusChangeDetected, HwDeviceExtension, NULL ); } if((MiniCounter % 1000) == 0) KDPrint(4,("RequestExecuting = %d\n", HwDeviceExtension->RequestExecuting)); if(HwDeviceExtension->RequestExecuting != 0) { ScsiPortNotification( RequestTimerCall, HwDeviceExtension, MiniTimer, 1 ); } else { HwDeviceExtension->TimerOn = FALSE; if(ADAPTER_ISSTATUS(HwDeviceExtension,ADAPTER_STATUS_RUNNING)) ScsiPortNotification( RequestTimerCall, HwDeviceExtension, MiniTimer, 1 //1000 ); } ScsiPortNotification( NextRequest, HwDeviceExtension, NULL ); return; }