Пример #1
0
//
//	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);
	}
}
Пример #2
0
//
//	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);
}
Пример #3
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;
}
Пример #4
0
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;
}