Exemple #1
0
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;
}
Exemple #2
0
NTSTATUS
NdscAdapterCompletion(
		  IN PCCB							Ccb,
		  IN PMINIPORT_DEVICE_EXTENSION		HwDeviceExtension
	  )
{
	KIRQL						oldIrql;
	static	LONG				SrbSeq;
	LONG						srbSeqIncremented;
	PSCSI_REQUEST_BLOCK			srb;
	PCCB						abortCcb;
	NTSTATUS					return_status;
	UINT32						AdapterStatus, AdapterStatusBefore;
	UINT32						NeedToUpdatePdoInfoInLSBus;
	BOOLEAN						busResetOccured;

	KDPrint(4,("RequestExecuting = %d\n", HwDeviceExtension->RequestExecuting));

	srb = Ccb->Srb;
	if(!srb) {
		KDPrint(2,("Ccb:%p CcbStatus %d. No srb assigned.\n", Ccb, Ccb->CcbStatus));
		ASSERT(srb);
		return STATUS_SUCCESS;
	}
 
	//
	//	NDASSCSI completion routine will do post operation to complete CCBs.
	//
	return_status = STATUS_MORE_PROCESSING_REQUIRED;

	//
	// Set SRB completion sequence for debugging
	//

	srbSeqIncremented = InterlockedIncrement(&SrbSeq);

#if 0
	if(KeGetCurrentIrql() == PASSIVE_LEVEL) {
		if((srbSeqIncremented%100) == 0) {
			LARGE_INTEGER	interval;

			KDPrint(2,("Interval for debugging.\n"));

			interval.QuadPart = - 11 * 10000000; // 10 seconds
			KeDelayExecutionThread(KernelMode, FALSE, &interval);
		}
	}
#endif

	//
	// Update Adapter status flag
	//

	NeedToUpdatePdoInfoInLSBus = FALSE;

	ACQUIRE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, &oldIrql);

	// Save the bus-reset flag
	if(ADAPTER_ISSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_BUSRESET_PENDING)) {
		busResetOccured = TRUE;
	} else {
		busResetOccured = FALSE;
	}

	// Save the current flag
	AdapterStatusBefore = HwDeviceExtension->AdapterStatus;


	//	Check reconnecting process.
	
	if (LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_RECONNECTING)) {

		ADAPTER_SETSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RECONNECT_PENDING);

	} else {
		
		ADAPTER_RESETSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RECONNECT_PENDING);
	}

	if (!LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_RAID_FLAG_VALID)) {

		NDASMINI_ASSERT( Ccb->NdasrStatusFlag8 == 0 );
	
	} else {

		NDASMINI_ASSERT( Ccb->NdasrStatusFlag8 == CCBSTATUS_FLAG_RAID_DEGRADED	 >> 8	||
						 Ccb->NdasrStatusFlag8 == CCBSTATUS_FLAG_RAID_RECOVERING >> 8	||
						 Ccb->NdasrStatusFlag8 == CCBSTATUS_FLAG_RAID_FAILURE    >> 8	||
						 Ccb->NdasrStatusFlag8 == CCBSTATUS_FLAG_RAID_NORMAL     >> 8 );
	}


	// Update adapter status only when CCBSTATUS_FLAG_RAID_FLAG_VALID is on.
	// In other case, Ccb has no chance to get flag information from RAID.

	if (LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_RAID_FLAG_VALID)) {

		//	Check to see if the associate member is in error.

		if (LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_RAID_DEGRADED)) {

			if (!ADAPTER_ISSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT)) {

				KDPrint(2, ("NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT is Set\n") );
			}

			ADAPTER_SETSTATUSFLAG( HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT );
		
		} else {
		
			ADAPTER_RESETSTATUSFLAG( HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT );
		}

		//	Check recovering process.

		if (LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_RAID_RECOVERING)) {

			if (!ADAPTER_ISSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING)) {

				KDPrint(2, ("NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING is Set\n") );
			}

			ADAPTER_SETSTATUSFLAG( HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING );
		
		} else {

			ADAPTER_RESETSTATUSFLAG( HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING );
		}

		// Check RAID failure

		if (LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_RAID_FAILURE)) {

			if (!ADAPTER_ISSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RAID_FAILURE)) {

				KDPrint(2, ("NDASSCSI_ADAPTER_STATUSFLAG_RAID_FAILURE is Set\n") );
			}

			ADAPTER_SETSTATUSFLAG( HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RAID_FAILURE );
	
		} else {

			ADAPTER_RESETSTATUSFLAG( HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RAID_FAILURE );
		}

		// Set RAID normal status

		if (LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_RAID_NORMAL)) {
		
			if (!ADAPTER_ISSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RAID_NORMAL)) {

				KDPrint(2, ("NDASSCSI_ADAPTER_STATUSFLAG_RAID_NORMAL is Set\n") );
			}

			ADAPTER_SETSTATUSFLAG( HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RAID_NORMAL );

		} else {

			ADAPTER_RESETSTATUSFLAG( HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_RAID_NORMAL );
		}
	}

	// power-recycle occurred.
	if(LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_POWERRECYLE_OCCUR)) {

		ADAPTER_SETSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_POWERRECYCLED);
	} else {
		ADAPTER_RESETSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_POWERRECYCLED);
	}

	if (ADAPTER_ISSTATUSFLAG(HwDeviceExtension, NDASSCSI_ADAPTER_STATUSFLAG_POWERRECYCLED)) {

		//NDASMINI_ASSERT( FALSE );
	}

	AdapterStatus = HwDeviceExtension->AdapterStatus;
	RELEASE_SPIN_LOCK(&HwDeviceExtension->LanscsiAdapterSpinLock, oldIrql);

	if(AdapterStatus != AdapterStatusBefore)
	{
		if(
			!(AdapterStatusBefore & NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT) &&
			(AdapterStatus & NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT)
			)
		{
			// NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT on
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_MEMBER_FAULT, EVTLOG_MEMBER_IN_ERROR);
			KDPrint(2,("Ccb:%p CcbStatus %d. Set member fault.\n", Ccb, Ccb->CcbStatus));
		}
		if(
			(AdapterStatusBefore & NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT) &&
			!(AdapterStatus & NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT)
			)
		{
			// NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT off
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_MEMBER_FAULT_RECOVERED, EVTLOG_MEMBER_RECOVERED);
			KDPrint(2,("Ccb:%p CcbStatus %d. Reset member fault.\n", Ccb, Ccb->CcbStatus));
		}
		if(
			!(AdapterStatusBefore & NDASSCSI_ADAPTER_STATUSFLAG_RECONNECT_PENDING) &&
			(AdapterStatus & NDASSCSI_ADAPTER_STATUSFLAG_RECONNECT_PENDING)
			)
		{
			// NDASSCSI_ADAPTER_STATUSFLAG_RECONNECT_PENDING on
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_RECONNECT_START, EVTLOG_START_RECONNECTION);
			KDPrint(2,("Ccb:%p CcbStatus %d. Start reconnecting\n", Ccb, Ccb->CcbStatus));
		}
		if(
			(AdapterStatusBefore & NDASSCSI_ADAPTER_STATUSFLAG_RECONNECT_PENDING) &&
			!(AdapterStatus & NDASSCSI_ADAPTER_STATUSFLAG_RECONNECT_PENDING)
			)
		{
			// NDASSCSI_ADAPTER_STATUSFLAG_RECONNECT_PENDING off
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_RECONNECTED, EVTLOG_END_RECONNECTION);
			KDPrint(2,("Ccb:%p CcbStatus %d. Finish reconnecting\n", Ccb, Ccb->CcbStatus));
		}
		if(
			!(AdapterStatusBefore & NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING) &&
			(AdapterStatus & NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING)
			)
		{
			// NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING on
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_RECOVERY_START, EVTLOG_START_RECOVERING);
			KDPrint(2,("Ccb:%p CcbStatus %d. Started recovering\n", Ccb, Ccb->CcbStatus));
		}
		if(
			(AdapterStatusBefore & NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING) &&
			!(AdapterStatus & NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING) &&
			!(AdapterStatus & (NDASSCSI_ADAPTER_STATUSFLAG_RAID_FAILURE|NDASSCSI_ADAPTER_STATUSFLAG_MEMBER_FAULT)) &&
			(AdapterStatus & NDASSCSI_ADAPTER_STATUSFLAG_RAID_NORMAL))
		{
			// NDASSCSI_ADAPTER_STATUSFLAG_RECOVERING off
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_RECOVERED, EVTLOG_END_RECOVERING);
			KDPrint(2,("Ccb:%p CcbStatus %d. Ended recovering\n", Ccb, Ccb->CcbStatus));
		}
		if (
			(AdapterStatus & NDASSCSI_ADAPTER_STATUSFLAG_RAID_FAILURE)	 &&
			!(AdapterStatusBefore & NDASSCSI_ADAPTER_STATUSFLAG_RAID_FAILURE))
		{
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_RAID_FAILURE, EVTLOG_RAID_FAILURE);
			KDPrint(2,("Ccb:%p CcbStatus %d. RAID failure\n", Ccb, Ccb->CcbStatus));
		}
		
		if(
			!(AdapterStatusBefore & NDASSCSI_ADAPTER_STATUSFLAG_POWERRECYCLED) &&
			(AdapterStatus & NDASSCSI_ADAPTER_STATUSFLAG_POWERRECYCLED)
			)
		{
			// NDASSCSI_ADAPTER_STATUSFLAG_POWERRECYCLED on
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_DISK_POWERRECYCLE, EVTLOG_DISK_POWERRECYCLED);
			KDPrint(2,("Ccb:%p CcbStatus %d. Started recovering\n", Ccb, Ccb->CcbStatus));
		}


		NeedToUpdatePdoInfoInLSBus = TRUE;
	}

	//
	//	If CCB_OPCODE_UPDATE is successful, update adapter status in LanscsiBus
	//
	if(Ccb->OperationCode == CCB_OPCODE_UPDATE) {
		if(Ccb->CcbStatus == CCB_STATUS_SUCCESS) {
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_UPGRADE_SUCC, EVTLOG_SUCCEED_UPGRADE);
		} else {
			SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_UPGRADE_FAIL, EVTLOG_FAIL_UPGRADE);
		}
		NeedToUpdatePdoInfoInLSBus = TRUE;
	}

	//
	// Copy IO control results to the SRB buffer.
	//
	// If device lock CCB is successful, copy the result to the SRB.
	//

	if(Ccb->OperationCode == CCB_OPCODE_DEVLOCK) {
		if(Ccb->CcbStatus == CCB_STATUS_SUCCESS) {
			PSRB_IO_CONTROL			srbIoctlHeader;
			PUCHAR					lockIoctlBuffer;
			PNDSCIOCTL_DEVICELOCK	ioCtlAcReDeviceLock;
			PLURN_DEVLOCK_CONTROL	lurnAcReDeviceLock;

			//
			// Get the Ioctl buffer.
			//
			srbIoctlHeader = (PSRB_IO_CONTROL)srb->DataBuffer;
			srbIoctlHeader->ReturnCode = SRB_STATUS_SUCCESS;
			lockIoctlBuffer = (PUCHAR)(srbIoctlHeader + 1);
			ioCtlAcReDeviceLock = (PNDSCIOCTL_DEVICELOCK)lockIoctlBuffer;
			lurnAcReDeviceLock = (PLURN_DEVLOCK_CONTROL)Ccb->DataBuffer;

			// Copy the result
			RtlCopyMemory(	ioCtlAcReDeviceLock->LockData,
							lurnAcReDeviceLock->LockData,
							NDSCLOCK_LOCKDATA_LENGTH);
		}
	} else if(Ccb->OperationCode == CCB_OPCODE_QUERY) {

		if(Ccb->CcbStatus == CCB_STATUS_SUCCESS) {
			PSRB_IO_CONTROL		srbIoctlHeader;
			NTSTATUS			copyStatus;

			srbIoctlHeader = (PSRB_IO_CONTROL)srb->DataBuffer;

			copyStatus = NdscCopyQueryOutputToSrb(
				HwDeviceExtension,
				Ccb->DataBufferLength,
				Ccb->DataBuffer,
				srbIoctlHeader->Length,
				(PUCHAR)(srbIoctlHeader + 1)
			);
			if(copyStatus == STATUS_BUFFER_TOO_SMALL) {
				srbIoctlHeader->ReturnCode = SRB_STATUS_DATA_OVERRUN;
			}else if(NT_SUCCESS(copyStatus)) {
				srbIoctlHeader->ReturnCode = SRB_STATUS_SUCCESS;
			} else {
				srbIoctlHeader->ReturnCode = SRB_STATUS_ERROR;
			}
		}
	}

	KDPrint(4,("CcbStatus %d\n", Ccb->CcbStatus));

	//
	//	Translate CcbStatus to SrbStatus
	//

	CcbStatusToSrbStatus(Ccb, srb);

	//
	// Perform stop process when we get stop status.
	//

	if(Ccb->CcbStatus == CCB_STATUS_STOP) {
		//
		// Stop in the timer routine.
		//
		KDPrint(2, ("Stop status. Stop in the timer routine.\n"));
	} else {
		//
		// Update PDO information on the NDAS bus.
		//

		if(NeedToUpdatePdoInfoInLSBus)
		{
			KDPrint(2, ("<<<<<<<<<<<<<<<< %08lx -> %08lx ADAPTER STATUS CHANGED"
				" >>>>>>>>>>>>>>>>\n", AdapterStatusBefore, AdapterStatus));
			UpdatePdoInfoInLSBus(HwDeviceExtension, HwDeviceExtension->AdapterStatus);
		}
	}

	//
	// Process Abort CCB.
	//
	abortCcb = Ccb->AbortCcb;

	if(abortCcb != NULL) {

		KDPrint(2,("abortSrb\n"));
		ASSERT(FALSE);

		srb->SrbStatus = SRB_STATUS_SUCCESS;
		LsCcbSetStatusFlag(Ccb, CCBSTATUS_FLAG_TIMER_COMPLETE);
		InitializeListHead(&Ccb->ListEntry);
		ExInterlockedInsertTailList(
				&HwDeviceExtension->CcbTimerCompletionList,
				&Ccb->ListEntry,
				&HwDeviceExtension->CcbTimerCompletionListSpinLock
			);

		((PSCSI_REQUEST_BLOCK)abortCcb->Srb)->SrbStatus = SRB_STATUS_ABORTED;
		LsCcbSetStatusFlag(abortCcb, CCBSTATUS_FLAG_TIMER_COMPLETE);
		InitializeListHead(&abortCcb->ListEntry);
		ExInterlockedInsertTailList(
				&HwDeviceExtension->CcbTimerCompletionList,
				&abortCcb->ListEntry,
				&HwDeviceExtension->CcbTimerCompletionListSpinLock
			);

	} else {
		BOOLEAN	criticalSrb;

		//
		// We should not use completion IRP method with disable-disconnect flag.
		// A SRB with DISABLE_DISCONNECT flag causes the SCSI port queue locked.
		//

		criticalSrb =	(srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) != 0 ||
						(srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) != 0 ||
						(srb->SrbFlags & SRB_FLAGS_BYPASS_LOCKED_QUEUE) != 0;
#if DBG
		if(criticalSrb) {
			KDPrint(2, ("Critical Srb:%p\n", srb));
		}
#endif
		//
		// 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_DATA_OVERRUN) &&
				!LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_TIMER_COMPLETE) &&
				!LsCcbIsStatusFlagOn(Ccb, CCBSTATUS_FLAG_BUSCHANGE) &&
				!busResetOccured &&
				!criticalSrb
			)
		{
			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), NDSC_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, NDSC_PTAG_SRB);
				goto Out;
			}

			completionData = ExAllocatePoolWithTag(NonPagedPool, sizeof(COMPLETION_DATA), NDSC_PTAG_CMPDATA);
			if(completionData == NULL) {
				ExFreePoolWithTag(completionSrb, NDSC_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 = Ccb;

			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 completion data for the completion IRP.
			//
			completionData->HwDeviceExtension = HwDeviceExtension;
			completionData->CompletionSrb = completionSrb;
			completionData->ShippedCcb = Ccb;
			completionData->ShippedCcbAllocatedFromPool = LsCcbIsFlagOn(Ccb, CCB_FLAG_ALLOCATED);

Out:
			KDPrint(5,("Before Completion\n"));
			IoSetCompletionRoutine(	pCompletionIrp,
									CompletionIrpCompletionRoutine,
									completionData,
									TRUE, TRUE, TRUE);
			ASSERT(HwDeviceExtension->RequestExecuting != 0);

#if 0
			{
				LARGE_INTEGER	interval;
				ULONG			SrbTimeout;
				static			DebugCount = 0;

				DebugCount ++;
				SrbTimeout = ((PSCSI_REQUEST_BLOCK)(Ccb->Srb))->TimeOutValue;
				if(	SrbTimeout>9 &&
					(DebugCount%1000) == 0
					) {
					KDPrint(2,("Experiment!!!!!!! Delay completion. SrbTimeout:%d\n", SrbTimeout));
					interval.QuadPart = - (INT64)SrbTimeout * 11 * 1000000;
					KeDelayExecutionThread(KernelMode, FALSE, &interval);
				}
			}
#endif
			//
			//	call Scsiport FDO.
			//
			ntStatus = IoCallDriver(pDeviceObject, pCompletionIrp);
			ASSERT(NT_SUCCESS(ntStatus));
			if(ntStatus!= STATUS_SUCCESS && ntStatus!= STATUS_PENDING) {
				KDPrint(2,("ntStatus = 0x%x\n", ntStatus));

				SCSI_PORT_LOG_ERROR_MODULE_COMPLETION(NDASSCSI_IO_COMPIRP_FAIL, EVTLOG_FAIL_COMPLIRP);

				KDPrint(2,("IoCallDriver() error. 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->CcbTimerCompletionList,
							&Ccb->ListEntry,
							&HwDeviceExtension->CcbTimerCompletionListSpinLock
						);
			}
		} else {
			KDPrint(2,("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->CcbTimerCompletionList,
					&Ccb->ListEntry,
					&HwDeviceExtension->CcbTimerCompletionListSpinLock
				);
		}
	}

	return return_status;
}