[VOL-4239] openonu-go-adapter: wrong indication of download failure,
[VOL-4258] openonu-go-adapter: wrong indication of download from wrong url

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I5f03085e4c7268c2370c92c081f31b9e7fb178c1
diff --git a/internal/pkg/onuadaptercore/omci_onu_upgrade.go b/internal/pkg/onuadaptercore/omci_onu_upgrade.go
index 88101b3..b4c4d35 100644
--- a/internal/pkg/onuadaptercore/omci_onu_upgrade.go
+++ b/internal/pkg/onuadaptercore/omci_onu_upgrade.go
@@ -58,6 +58,7 @@
 	upgradeEvEndSwDownload      = "upgradeEvEndSwDownload"
 	upgradeEvWaitEndDownload    = "upgradeEvWaitEndDownload"
 	upgradeEvContinueFinalize   = "upgradeEvContinueFinalize"
+	upgradeEvCheckImageName     = "upgradeEvCheckImageName"
 	upgradeEvWaitForActivate    = "upgradeEvWaitForActivate"
 	upgradeEvRequestActivate    = "upgradeEvRequestActivate"
 	upgradeEvActivationDone     = "upgradeEvActivationDone"
@@ -82,6 +83,7 @@
 	upgradeStVerifyWindow       = "upgradeStVerifyWindow"
 	upgradeStFinalizeDL         = "upgradeStFinalizeDL"
 	upgradeStWaitEndDL          = "upgradeStWaitEndDL"
+	upgradeStCheckImageName     = "upgradeStCheckImageName"
 	upgradeStWaitForActivate    = "upgradeStWaitForActivate"
 	upgradeStRequestingActivate = "upgradeStRequestingActivate"
 	upgradeStActivated          = "upgradeStActivated"
@@ -100,7 +102,7 @@
 	pDownloadManager *adapterDownloadManager
 	pFileManager     *fileDownloadManager //used from R2.8 with new API version
 	deviceID         string
-	pOnuOmciDevice   *OnuDeviceEntry
+	pDevEntry        *OnuDeviceEntry
 	pOmciCC          *omciCC
 	pOnuDB           *onuDeviceDB
 	requestEvent     OnuDeviceEvent
@@ -138,6 +140,9 @@
 	isWaitingForOnuDlResponse        bool
 	activateImage                    bool
 	commitImage                      bool
+	mutexAbortRequest                sync.RWMutex
+	abortRequested                   voltha.ImageState_ImageFailureReason
+	conditionalCancelRequested       bool
 	volthaDownloadState              voltha.ImageState_ImageDownloadState
 	volthaDownloadReason             voltha.ImageState_ImageFailureReason
 	volthaImageState                 voltha.ImageState_ImageActivationState
@@ -151,7 +156,7 @@
 	instFsm := &OnuUpgradeFsm{
 		pDeviceHandler:              apDeviceHandler,
 		deviceID:                    apDeviceHandler.deviceID,
-		pOnuOmciDevice:              apDevEntry,
+		pDevEntry:                   apDevEntry,
 		pOmciCC:                     apDevEntry.PDevOmciCC,
 		pOnuDB:                      apOnuDB,
 		requestEvent:                aRequestEvent,
@@ -163,6 +168,7 @@
 		volthaDownloadState:         voltha.ImageState_DOWNLOAD_STARTED, //if FSM created we can assume that the download (to adapter) really started
 		volthaDownloadReason:        voltha.ImageState_NO_ERROR,
 		volthaImageState:            voltha.ImageState_IMAGE_UNKNOWN,
+		abortRequested:              voltha.ImageState_NO_ERROR,
 	}
 	instFsm.chReceiveExpectedResponse = make(chan bool)
 	instFsm.chAdapterDlReady = make(chan bool)
@@ -186,9 +192,13 @@
 			{Name: upgradeEvEndSwDownload, Src: []string{upgradeStVerifyWindow}, Dst: upgradeStFinalizeDL},
 			{Name: upgradeEvWaitEndDownload, Src: []string{upgradeStFinalizeDL}, Dst: upgradeStWaitEndDL},
 			{Name: upgradeEvContinueFinalize, Src: []string{upgradeStWaitEndDL}, Dst: upgradeStFinalizeDL},
-			{Name: upgradeEvWaitForActivate, Src: []string{upgradeStWaitEndDL}, Dst: upgradeStWaitForActivate},
-			{Name: upgradeEvRequestActivate, Src: []string{upgradeStStarting, upgradeStWaitEndDL, upgradeStWaitForActivate},
-				Dst: upgradeStRequestingActivate}, //allows also for direct activation (without download) [TODO!!!]
+			//upgradeStCheckImageName only used with useAPIVersion43
+			{Name: upgradeEvCheckImageName, Src: []string{upgradeStWaitEndDL}, Dst: upgradeStCheckImageName},
+			//upgradeEvWaitForActivate state transitions depend on useAPIVersion43
+			{Name: upgradeEvWaitForActivate, Src: []string{upgradeStWaitEndDL, upgradeStCheckImageName}, Dst: upgradeStWaitForActivate},
+			//upgradeEvRequestActivate state transitions depend on useAPIVersion43
+			{Name: upgradeEvRequestActivate, Src: []string{upgradeStStarting, upgradeStWaitEndDL, upgradeStCheckImageName,
+				upgradeStWaitForActivate}, Dst: upgradeStRequestingActivate}, //allows also for direct activation (without download) [TODO!!!]
 			{Name: upgradeEvActivationDone, Src: []string{upgradeStRequestingActivate}, Dst: upgradeStActivated},
 			{Name: upgradeEvWaitForCommit, Src: []string{upgradeStRequestingActivate}, Dst: upgradeStWaitForCommit},
 			{Name: upgradeEvCommitSw, Src: []string{upgradeStStarting, upgradeStRequestingActivate, upgradeStWaitForCommit,
@@ -205,12 +215,15 @@
 			//on upgradeEvReset: upgradeStRequestingActivate, upgradeStWaitForCommit and upgradeStActivated are not reset
 			// (to let the FSM survive the expected OnuDown indication)
 			{Name: upgradeEvReset, Src: []string{upgradeStStarting, upgradeStWaitingAdapterDL, upgradeStPreparingDL, upgradeStDLSection,
-				upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStWaitEndDL, upgradeStWaitForActivate,
+				upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStWaitEndDL, upgradeStCheckImageName,
+				upgradeStWaitForActivate,
 				upgradeStCommitSw, upgradeStCheckCommitted},
 				Dst: upgradeStResetting},
 			{Name: upgradeEvAbort, Src: []string{upgradeStStarting, upgradeStWaitingAdapterDL, upgradeStPreparingDL, upgradeStDLSection,
-				upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStWaitEndDL, upgradeStWaitForActivate,
-				upgradeStRequestingActivate, upgradeStActivated, upgradeStWaitForCommit, upgradeStCommitSw, upgradeStCheckCommitted},
+				upgradeStVerifyWindow, upgradeStDLSection, upgradeStFinalizeDL, upgradeStWaitEndDL, upgradeStCheckImageName,
+				upgradeStWaitForActivate,
+				upgradeStRequestingActivate, upgradeStActivated, upgradeStWaitForCommit,
+				upgradeStCommitSw, upgradeStCheckCommitted},
 				Dst: upgradeStResetting},
 			{Name: upgradeEvRestart, Src: []string{upgradeStResetting}, Dst: upgradeStDisabled},
 		},
@@ -223,6 +236,7 @@
 			"enter_" + upgradeStVerifyWindow:       func(e *fsm.Event) { instFsm.enterVerifyWindow(ctx, e) },
 			"enter_" + upgradeStFinalizeDL:         func(e *fsm.Event) { instFsm.enterFinalizeDL(ctx, e) },
 			"enter_" + upgradeStWaitEndDL:          func(e *fsm.Event) { instFsm.enterWaitEndDL(ctx, e) },
+			"enter_" + upgradeStCheckImageName:     func(e *fsm.Event) { instFsm.enterCheckImageName(ctx, e) },
 			"enter_" + upgradeStRequestingActivate: func(e *fsm.Event) { instFsm.enterActivateSw(ctx, e) },
 			"enter_" + upgradeStCommitSw:           func(e *fsm.Event) { instFsm.enterCommitSw(ctx, e) },
 			"enter_" + upgradeStCheckCommitted:     func(e *fsm.Event) { instFsm.enterCheckCommitted(ctx, e) },
@@ -318,15 +332,20 @@
 	}
 	oFsm.activateImage = true
 	oFsm.commitImage = aCommit
-	oFsm.mutexUpgradeParams.Unlock()
 	var pBaseFsm *fsm.FSM = nil
 	if oFsm.pAdaptFsm != nil {
 		pBaseFsm = oFsm.pAdaptFsm.pFsm
 	}
 	if pBaseFsm != nil {
 		if pBaseFsm.Is(upgradeStWaitForActivate) {
+			oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
+			oFsm.mutexUpgradeParams.Unlock()
 			logger.Debugw(ctx, "OnuUpgradeFsm finish waiting for activate", log.Fields{"device-id": oFsm.deviceID})
 			_ = pBaseFsm.Event(upgradeEvRequestActivate) //no need to call the FSM event in background here
+		} else {
+			oFsm.mutexUpgradeParams.Unlock()
+			logger.Debugw(ctx, "OnuUpgradeFsm not (yet?) waiting for activate", log.Fields{
+				"device-id": oFsm.deviceID, "current FsmState": pBaseFsm.Current()})
 		}
 		return nil
 	}
@@ -351,7 +370,9 @@
 		oFsm.imageVersion = aImageVersion
 		oFsm.activateImage = true
 		oFsm.commitImage = aCommit
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN // this is just an activate request without prior download
+		// indicate start of the upgrade activity
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
+		oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE      //as simply applied for inactive image
 		oFsm.mutexUpgradeParams.Unlock()
 		//directly request the FSM to activate the image
 		_ = pBaseFsm.Event(upgradeEvRequestActivate) //no need to call the FSM event in background here
@@ -365,20 +386,23 @@
 
 //SetCommitmentParamsRunning sets the commit flag for a running download to the ONU according to adapters rpc call
 //  called from 'new' API Commit_onu_image
-func (oFsm *OnuUpgradeFsm) SetCommitmentParamsRunning(ctx context.Context, aImageIdentifier string) error {
+func (oFsm *OnuUpgradeFsm) SetCommitmentParamsRunning(ctx context.Context,
+	aImageIdentifier string, aImageVersion string) error {
 	oFsm.mutexUpgradeParams.Lock()
 	//set commit independent from state, if FSM is already beyond commit state (just ready), then it does not matter anyway
 	//  (as long as the Imageidentifier is correct)
 	logger.Debugw(ctx, "OnuUpgradeFsm commit parameter setting", log.Fields{
 		"device-id": oFsm.deviceID, "image-id": aImageIdentifier})
-	if aImageIdentifier != oFsm.imageIdentifier {
+	if (aImageIdentifier != oFsm.imageIdentifier) && (aImageVersion != oFsm.imageVersion) {
 		logger.Errorw(ctx, "OnuUpgradeFsm abort: mismatching upgrade image", log.Fields{
-			"device-id": oFsm.deviceID, "request-image": aImageIdentifier, "fsm-image": oFsm.imageIdentifier})
+			"device-id": oFsm.deviceID, "request-identifier": aImageIdentifier, "fsm-identifier": oFsm.imageIdentifier,
+			"request-version": aImageVersion, "fsm-version": oFsm.imageVersion})
 		oFsm.mutexUpgradeParams.Unlock()
 		return fmt.Errorf(fmt.Sprintf("OnuUpgradeFsm params ignored: requested image-name not used in current upgrade for device-id: %s",
 			oFsm.deviceID))
 	}
 	oFsm.commitImage = true
+	oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
 	oFsm.mutexUpgradeParams.Unlock()
 	var pBaseFsm *fsm.FSM = nil
 	if oFsm.pAdaptFsm != nil {
@@ -391,6 +415,7 @@
 		_ = pBaseFsm.Event(upgradeEvCommitSw) //no need to call the FSM event in background here
 		return nil
 	}
+	//should never occur
 	logger.Errorw(ctx, "OnuUpgradeFsm abort: invalid FSM base pointer", log.Fields{
 		"device-id": oFsm.deviceID})
 	return fmt.Errorf(fmt.Sprintf("OnuUpgradeFsm abort: invalid FSM base pointer for device-id: %s", oFsm.deviceID))
@@ -411,9 +436,10 @@
 		oFsm.inactiveImageMeID = aActiveImageID //upgrade state machines inactive ImageId is the new active ImageId
 		oFsm.imageVersion = aImageVersion
 		oFsm.commitImage = true
-		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN // this is just a commit request without prior download
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_STARTED //better choice would be 'UpgradeState=Started'
+		oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVE        //as simply applied for active image
 		oFsm.mutexUpgradeParams.Unlock()
-		//directly request the FSM to activate the image
+		//directly request the FSM to commit the image
 		_ = pBaseFsm.Event(upgradeEvCommitSw) //no need to call the FSM event in background here
 		return nil
 	}
@@ -430,10 +456,11 @@
 	return oFsm.commitImage
 }
 
-//GetImageStates delivers the download states as per device proto buf or error indication
+//GetImageStates delivers the download/image states as per device proto buf definition
 func (oFsm *OnuUpgradeFsm) GetImageStates(ctx context.Context,
-	aImageIdentifier string, aVersion string) (*voltha.ImageState, error) {
+	aImageIdentifier string, aVersion string) *voltha.ImageState {
 	pImageState := &voltha.ImageState{}
+	pImageState.Version = aVersion //version as requested
 	// check if the request refers to some active image/version of the processing
 	oFsm.mutexUpgradeParams.RLock()
 	if (aImageIdentifier == oFsm.imageIdentifier) || (aVersion == oFsm.imageVersion) {
@@ -446,18 +473,42 @@
 		pImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
 	}
 	oFsm.mutexUpgradeParams.RUnlock()
-	return pImageState, nil
+	return pImageState
 }
 
-//SetImageState sets the FSM internal volthaImageState
-func (oFsm *OnuUpgradeFsm) SetImageState(ctx context.Context, aImageState voltha.ImageState_ImageActivationState) {
+//GetSpecificImageState delivers ImageState of the download/image states as per device proto buf definition
+func (oFsm *OnuUpgradeFsm) GetSpecificImageState(ctx context.Context) voltha.ImageState_ImageActivationState {
+	oFsm.mutexUpgradeParams.RLock()
+	imageState := oFsm.volthaImageState
+	oFsm.mutexUpgradeParams.RUnlock()
+	return imageState
+}
+
+//SetImageStateActive sets the FSM internal volthaImageState to ImageState_IMAGE_ACTIVE
+func (oFsm *OnuUpgradeFsm) SetImageStateActive(ctx context.Context) {
 	oFsm.mutexUpgradeParams.Lock()
 	defer oFsm.mutexUpgradeParams.Unlock()
-	oFsm.volthaImageState = aImageState
+	oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVE
+	if !oFsm.commitImage {
+		//if commit is not additionally set, regard the upgrade activity as successful
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED //better choice would be 'UpgradeState=Succeeded'
+	}
+}
+
+//GetImageVersion delivers image-version of the running upgrade
+func (oFsm *OnuUpgradeFsm) GetImageVersion(ctx context.Context) string {
+	oFsm.mutexUpgradeParams.RLock()
+	imageVersion := oFsm.imageVersion
+	oFsm.mutexUpgradeParams.RUnlock()
+	return imageVersion
 }
 
 //CancelProcessing ensures that suspended processing at waiting on some response is aborted and reset of FSM
-func (oFsm *OnuUpgradeFsm) CancelProcessing(ctx context.Context) {
+func (oFsm *OnuUpgradeFsm) CancelProcessing(ctx context.Context, abCompleteAbort bool,
+	aReason voltha.ImageState_ImageFailureReason) {
+	oFsm.mutexAbortRequest.Lock()
+	oFsm.abortRequested = aReason //possibly abort the sectionDownload loop
+	oFsm.mutexAbortRequest.Unlock()
 	//mutex protection is required for possible concurrent access to FSM members
 	//attention: for an unbuffered channel the sender is blocked until the value is received (processed)!
 	// accordingly the mutex must be released before sending to channel here (mutex acquired in receiver)
@@ -479,9 +530,33 @@
 		go func(aPAFsm *AdapterFsm) {
 			if aPAFsm.pFsm != nil {
 				if aPAFsm.pFsm.Is(upgradeStWaitEndDL) {
-					oFsm.chReceiveExpectedResponse <- false //which aborts the FSM (activate was not yet sent)
+					oFsm.chReceiveExpectedResponse <- false //which aborts the FSM in WaitEndDL state
 				}
-				_ = aPAFsm.pFsm.Event(upgradeEvReset) //anyway and for all other states
+				// in case of state-conditional request the
+
+				var err error
+				if abCompleteAbort {
+					oFsm.mutexUpgradeParams.Lock()
+					//any previous lingering conditional cancelRequest is superseded by this abortion
+					oFsm.conditionalCancelRequested = false
+					if aReason == voltha.ImageState_CANCELLED_ON_REQUEST {
+						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
+					} else {
+						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+					}
+					oFsm.volthaDownloadReason = aReason
+					oFsm.mutexUpgradeParams.Unlock()
+					err = aPAFsm.pFsm.Event(upgradeEvAbort) //as unconditional default FSM cancellation
+				} else {
+					//at conditional request the image states are set when reaching the reset state
+					oFsm.conditionalCancelRequested = true
+					err = aPAFsm.pFsm.Event(upgradeEvReset) //as state-conditional default FSM cleanup
+				}
+				if err != nil {
+					//error return is expected in case of conditional request and no state transition
+					logger.Debugw(ctx, "onu upgrade fsm could not cancel with abort/reset event", log.Fields{
+						"device-id": oFsm.deviceID, "error": err})
+				}
 			} //else the FSM seems already to be in some released state
 		}(pAdaptFsm)
 	}
@@ -499,7 +574,10 @@
 func (oFsm *OnuUpgradeFsm) enterWaitingAdapterDL(ctx context.Context, e *fsm.Event) {
 	logger.Debugw(ctx, "OnuUpgradeFsm waiting for adapter download", log.Fields{"in state": e.FSM.Current(),
 		"device-id": oFsm.deviceID})
-	go oFsm.waitOnDownloadToAdapterReady(ctx, oFsm.chAdapterDlReady)
+	syncChannel := make(chan struct{})
+	go oFsm.waitOnDownloadToAdapterReady(ctx, syncChannel, oFsm.chAdapterDlReady)
+	//block until the wait routine is really blocked on chAdapterDlReady
+	<-syncChannel
 	go oFsm.pFileManager.RequestDownloadReady(ctx, oFsm.imageIdentifier, oFsm.chAdapterDlReady)
 }
 
@@ -517,6 +595,9 @@
 		fileLen, err = oFsm.pDownloadManager.getImageBufferLen(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
 	}
 	if err != nil || fileLen > int64(cMaxUint32) {
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+		oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //Something like 'LOCAL_FILE_ERROR' would be better (proto)
+		oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN
 		oFsm.mutexUpgradeParams.Unlock()
 		logger.Errorw(ctx, "OnuUpgradeFsm abort: problems getting image buffer length", log.Fields{
 			"device-id": oFsm.deviceID, "error": err, "length": fileLen})
@@ -536,6 +617,9 @@
 		oFsm.imageBuffer, err = oFsm.pDownloadManager.getDownloadImageBuffer(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
 	}
 	if err != nil {
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+		oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //Something like 'LOCAL_FILE_ERROR' would be better (proto)
+		oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN
 		oFsm.mutexUpgradeParams.Unlock()
 		logger.Errorw(ctx, "OnuUpgradeFsm abort: can't get image buffer", log.Fields{
 			"device-id": oFsm.deviceID, "error": err})
@@ -569,12 +653,7 @@
 	if err != nil {
 		logger.Errorw(ctx, "StartSwDl abort: can't send section", log.Fields{
 			"device-id": oFsm.deviceID, "error": err})
-		//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
-		pBaseFsm := oFsm.pAdaptFsm
-		// Can't call FSM Event directly, decoupling it
-		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
-		}(pBaseFsm)
+		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
 		return
 	}
 }
@@ -596,6 +675,26 @@
 	}
 
 	for {
+		oFsm.mutexAbortRequest.RLock()
+		// this way out of the section download loop on abort request
+		if oFsm.abortRequested != voltha.ImageState_NO_ERROR {
+			if oFsm.abortRequested == voltha.ImageState_CANCELLED_ON_REQUEST {
+				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
+			} else {
+				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+			}
+			oFsm.volthaDownloadReason = oFsm.abortRequested
+			oFsm.mutexAbortRequest.RUnlock()
+			oFsm.mutexUpgradeParams.Unlock()
+			pBaseFsm := oFsm.pAdaptFsm
+			// Can't call FSM Event directly, decoupling it
+			go func(a_pAFsm *AdapterFsm) {
+				_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
+			}(pBaseFsm)
+			return
+		}
+		oFsm.mutexAbortRequest.RUnlock()
+
 		bufferStartOffset = oFsm.nextDownloadSectionsAbsolute * cOmciDownloadSectionSize
 		bufferEndOffset = bufferStartOffset + cOmciDownloadSectionSize - 1 //for representing cOmciDownloadSectionSizeLimit values
 		logger.Debugw(ctx, "DlSection values are", log.Fields{
@@ -606,6 +705,8 @@
 			logger.Errorw(ctx, "OnuUpgradeFsm buffer error: exceeded length", log.Fields{
 				"device-id": oFsm.deviceID, "bufferStartOffset": bufferStartOffset,
 				"bufferEndOffset": bufferEndOffset, "imageLength": oFsm.imageLength})
+			oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+			oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR //Something like 'LOCAL_FILE_ERROR' would be better (proto)
 			oFsm.mutexUpgradeParams.Unlock()
 			//logical error -- reset the FSM
 			pBaseFsm := oFsm.pAdaptFsm
@@ -634,12 +735,7 @@
 		if err != nil {
 			logger.Errorw(ctx, "DlSection abort: can't send section", log.Fields{
 				"device-id": oFsm.deviceID, "section absolute": oFsm.nextDownloadSectionsAbsolute, "error": err})
-			//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
-			pBaseFsm := oFsm.pAdaptFsm
-			// Can't call FSM Event directly, decoupling it
-			go func(a_pAFsm *AdapterFsm) {
-				_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
-			}(pBaseFsm)
+			oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
 			return
 		}
 		oFsm.mutexUpgradeParams.Lock()
@@ -685,9 +781,11 @@
 
 	pBaseFsm := oFsm.pAdaptFsm
 	if pBaseFsm == nil {
-		logger.Errorw(ctx, "EndSwDl abort: BaseFsm invalid", log.Fields{
-			"device-id": oFsm.deviceID})
-		//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
+		logger.Errorw(ctx, "EndSwDl abort: BaseFsm invalid", log.Fields{"device-id": oFsm.deviceID})
+		oFsm.mutexUpgradeParams.Lock()
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+		oFsm.volthaDownloadReason = voltha.ImageState_UNKNOWN_ERROR
+		oFsm.mutexUpgradeParams.Unlock()
 		// Can't call FSM Event directly, decoupling it
 		go func(a_pAFsm *AdapterFsm) {
 			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
@@ -699,11 +797,7 @@
 	if err != nil {
 		logger.Errorw(ctx, "EndSwDl abort: can't send section", log.Fields{
 			"device-id": oFsm.deviceID, "error": err})
-		//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
-		// Can't call FSM Event directly, decoupling it
-		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
-		}(pBaseFsm)
+		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
 		return
 	}
 	// go waiting for the EndSwDLResponse and check, if the ONU is ready for activation
@@ -725,6 +819,10 @@
 				"device-id": oFsm.deviceID})
 			return
 		}
+		oFsm.mutexUpgradeParams.Lock()
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+		oFsm.volthaDownloadReason = voltha.ImageState_IMAGE_REFUSED_BY_ONU //Something like 'END_DOWNLOAD_TIMEOUT' would be better (proto)
+		oFsm.mutexUpgradeParams.Unlock()
 		go func(a_pAFsm *AdapterFsm) {
 			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
 		}(pBaseFsm)
@@ -760,56 +858,74 @@
 		}
 		if success {
 			//answer received with ready indication
-			if oFsm.activateImage {
-				//immediate activation requested
+			//useAPIVersion43 may not conflict in concurrency in this state function
+			if oFsm.useAPIVersion43 { // newer API usage requires verification of downloaded image version
 				go func(a_pAFsm *AdapterFsm) {
-					_ = a_pAFsm.pFsm.Event(upgradeEvRequestActivate)
+					_ = a_pAFsm.pFsm.Event(upgradeEvCheckImageName)
 				}(pBaseFsm)
-			} else {
-				//have to wait on explicit activation request
-				go func(a_pAFsm *AdapterFsm) {
-					_ = a_pAFsm.pFsm.Event(upgradeEvWaitForActivate)
-				}(pBaseFsm)
+			} else { // elder API usage does not support image version check -immediately consider download as successful
+				if oFsm.activateImage {
+					//immediate activation requested
+					go func(a_pAFsm *AdapterFsm) {
+						_ = a_pAFsm.pFsm.Event(upgradeEvRequestActivate)
+					}(pBaseFsm)
+				} else {
+					//have to wait on explicit activation request
+					go func(a_pAFsm *AdapterFsm) {
+						_ = a_pAFsm.pFsm.Event(upgradeEvWaitForActivate)
+					}(pBaseFsm)
+				}
 			}
 			return
 		}
 		//timer was aborted
-		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
-		}(pBaseFsm)
+		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
 		return
 	}
 }
 
+func (oFsm *OnuUpgradeFsm) enterCheckImageName(ctx context.Context, e *fsm.Event) {
+	logger.Debugw(ctx, "OnuUpgradeFsm checking downloaded image name", log.Fields{
+		"device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID})
+	requestedAttributes := me.AttributeValueMap{"IsCommitted": 0, "IsActive": 0, "Version": ""}
+	meInstance, err := oFsm.pOmciCC.sendGetMe(log.WithSpanFromContext(context.TODO(), ctx),
+		me.SoftwareImageClassID, oFsm.inactiveImageMeID, requestedAttributes, oFsm.pDeviceHandler.pOpenOnuAc.omciTimeout,
+		false, oFsm.pAdaptFsm.commChan)
+	if err != nil {
+		logger.Errorw(ctx, "OnuUpgradeFsm get Software Image ME result error",
+			log.Fields{"device-id": oFsm.deviceID, "Error": err})
+		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
+		return
+	}
+	oFsm.pLastTxMeInstance = meInstance
+}
+
 func (oFsm *OnuUpgradeFsm) enterActivateSw(ctx context.Context, e *fsm.Event) {
 	logger.Infow(ctx, "OnuUpgradeFsm activate SW", log.Fields{
 		"device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID})
 
-	oFsm.mutexUpgradeParams.Lock()
-	oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVATING
-	oFsm.mutexUpgradeParams.Unlock()
-
 	err := oFsm.pOmciCC.sendActivateSoftware(log.WithSpanFromContext(context.TODO(), ctx), oFsm.pDeviceHandler.pOpenOnuAc.omciTimeout, false,
 		oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID)
 	if err != nil {
 		logger.Errorw(ctx, "ActivateSw abort: can't send activate frame", log.Fields{
 			"device-id": oFsm.deviceID, "error": err})
-		//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
-		pBaseFsm := oFsm.pAdaptFsm
-		// Can't call FSM Event directly, decoupling it
-		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
-		}(pBaseFsm)
+		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
 		return
 	}
+	oFsm.mutexUpgradeParams.Lock()
+	oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVATING
+	oFsm.mutexUpgradeParams.Unlock()
 }
 
 func (oFsm *OnuUpgradeFsm) enterCommitSw(ctx context.Context, e *fsm.Event) {
-	if activeImageID, err := oFsm.pOnuOmciDevice.GetActiveImageMeID(ctx); err == nil {
-		//TODO!!: as long as testing with BBSIM and BBSIM not support upgrade tests following check needs to be deactivated
-		imageFit := true //TODO!!: test workaround as long as BBSIM does not fully support upgrade
+	logger.Debugw(ctx, "OnuUpgradeFsm start commit SW", log.Fields{
+		"device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID})
+	//any abort request (also conditional) is still regarded as valid as the commit indication might not be possible to verify
+	// (which is a bit problematic as the ONU might already be in committed state,
+	// in this case (committing failed) always 'onuimage list' should be used to verify the real state (if ONU is reachable))
+	if activeImageID, err := oFsm.pDevEntry.GetActiveImageMeID(ctx); err == nil {
 		oFsm.mutexUpgradeParams.Lock()
-		if imageFit || activeImageID == oFsm.inactiveImageMeID {
+		if activeImageID == oFsm.inactiveImageMeID {
 			inactiveImageID := oFsm.inactiveImageMeID
 			logger.Infow(ctx, "OnuUpgradeFsm commit SW", log.Fields{
 				"device-id": oFsm.deviceID, "me-id": inactiveImageID}) //more efficient activeImageID with above check
@@ -820,31 +936,24 @@
 			if err != nil {
 				logger.Errorw(ctx, "CommitSw abort: can't send commit sw frame", log.Fields{
 					"device-id": oFsm.deviceID, "error": err})
-				//TODO!!!: define some more sophisticated error treatment with some repetition, for now just reset the FSM
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				pBaseFsm := oFsm.pAdaptFsm
-				// Can't call FSM Event directly, decoupling it
-				go func(a_pAFsm *AdapterFsm) {
-					_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
-				}(pBaseFsm)
+				oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_COMMIT_ABORTED)
 				return
 			}
 			return
 		}
+		oFsm.mutexUpgradeParams.Unlock()
 		logger.Errorw(ctx, "OnuUpgradeFsm active ImageId <> IdToCommit", log.Fields{
 			"device-id": oFsm.deviceID, "active ID": activeImageID, "to commit ID": oFsm.inactiveImageMeID})
-		oFsm.mutexUpgradeParams.Unlock()
-
-		//TODO!!!: possibly send event information for aborted upgrade (not activated)??
-		pBaseFsm := oFsm.pAdaptFsm
-		// Can't call FSM Event directly, decoupling it
-		go func(a_pAFsm *AdapterFsm) {
-			_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
-		}(pBaseFsm)
-		return
+	} else {
+		logger.Errorw(ctx, "OnuUpgradeFsm can't commit, no valid active image", log.Fields{
+			"device-id": oFsm.deviceID})
 	}
-	logger.Errorw(ctx, "OnuUpgradeFsm can't commit, no valid active image", log.Fields{
-		"device-id": oFsm.deviceID})
+	oFsm.mutexUpgradeParams.Lock()
+	oFsm.conditionalCancelRequested = false //any lingering conditional cancelRequest is superseded by this error
+	oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+	oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+	oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMIT_ABORTED
+	oFsm.mutexUpgradeParams.Unlock()
 	//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
 	pBaseFsm := oFsm.pAdaptFsm
 	// Can't call FSM Event directly, decoupling it
@@ -854,22 +963,15 @@
 }
 
 func (oFsm *OnuUpgradeFsm) enterCheckCommitted(ctx context.Context, e *fsm.Event) {
-	logger.Infow(ctx, "OnuUpgradeFsm checking committed SW", log.Fields{
+	logger.Debugw(ctx, "OnuUpgradeFsm checking committed SW", log.Fields{
 		"device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID})
 	requestedAttributes := me.AttributeValueMap{"IsCommitted": 0, "IsActive": 0, "Version": ""}
 	meInstance, err := oFsm.pOmciCC.sendGetMe(log.WithSpanFromContext(context.TODO(), ctx),
 		me.SoftwareImageClassID, oFsm.inactiveImageMeID, requestedAttributes, oFsm.pDeviceHandler.pOpenOnuAc.omciTimeout, false, oFsm.pAdaptFsm.commChan)
-	//accept also nil as (error) return value for writing to LastTx
-	//  - this avoids misinterpretation of new received OMCI messages
 	if err != nil {
 		logger.Errorw(ctx, "OnuUpgradeFsm get Software Image ME result error",
 			log.Fields{"device-id": oFsm.deviceID, "Error": err})
-		pOnuUpgradeFsm := oFsm.pAdaptFsm
-		if pOnuUpgradeFsm != nil {
-			go func(a_pAFsm *AdapterFsm) {
-				_ = a_pAFsm.pFsm.Event(upgradeEvAbort)
-			}(pOnuUpgradeFsm)
-		}
+		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_COMMIT_ABORTED)
 		return
 	}
 	oFsm.pLastTxMeInstance = meInstance
@@ -878,6 +980,14 @@
 func (oFsm *OnuUpgradeFsm) enterResetting(ctx context.Context, e *fsm.Event) {
 	logger.Debugw(ctx, "OnuUpgradeFsm resetting", log.Fields{"device-id": oFsm.deviceID})
 
+	// if the reset was conditionally requested
+	if oFsm.conditionalCancelRequested {
+		oFsm.mutexUpgradeParams.Lock()
+		oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+		oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+		oFsm.mutexUpgradeParams.Unlock()
+	}
+
 	// in case the download-to-ONU timer is still running - cancel it
 	oFsm.mutexIsAwaitingOnuDlResponse.RLock()
 	if oFsm.isWaitingForOnuDlResponse {
@@ -914,7 +1024,13 @@
 	// no need to flush possible channels here, Upgrade FSM will be completely removed, garbage collector should find its way
 	if oFsm.pDeviceHandler != nil {
 		//request removal of 'reference' in the Handler (completely clear the FSM and its data)
-		go oFsm.pDeviceHandler.removeOnuUpgradeFsm(ctx)
+		pLastUpgradeImageState := &voltha.ImageState{
+			Version:       oFsm.imageVersion,
+			DownloadState: oFsm.volthaDownloadState,
+			Reason:        oFsm.volthaDownloadReason,
+			ImageState:    oFsm.volthaImageState,
+		}
+		go oFsm.pDeviceHandler.removeOnuUpgradeFsm(ctx, pLastUpgradeImageState)
 	}
 }
 
@@ -929,7 +1045,7 @@
 		if !ok {
 			logger.Info(ctx, "OnuUpgradeFsm Rx Msg - could not read from channel", log.Fields{"device-id": oFsm.deviceID})
 			// but then we have to ensure a restart of the FSM as well - as exceptional procedure
-			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+			oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
 			break loop
 		}
 		logger.Debugw(ctx, "OnuUpgradeFsm Rx Msg", log.Fields{"device-id": oFsm.deviceID})
@@ -965,16 +1081,14 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for StartSwDlResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.StartSoftwareDownloadResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for StartSwDlResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm StartSwDlResponse data", log.Fields{
@@ -982,9 +1096,7 @@
 			if msgObj.Result != me.Success {
 				logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse result error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 				return
 			}
 
@@ -1015,9 +1127,7 @@
 			oFsm.mutexUpgradeParams.Unlock()
 			logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			// TODO!!!: possibly repeat the start request (once)?
-			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 			return
 		} //StartSoftwareDownloadResponseType
 	case omci.DownloadSectionResponseType:
@@ -1026,16 +1136,14 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for DlSectionResponse",
 					log.Fields{"device-id": oFsm.deviceID, "omci-message": msg.OmciMsg})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.DownloadSectionResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for DlSectionResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm DlSectionResponse Data", log.Fields{
@@ -1043,8 +1151,7 @@
 			if msgObj.Result != me.Success {
 				logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse result error - later: repeat window once?", //TODO!!!
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 				return
 			}
 			oFsm.mutexUpgradeParams.Lock()
@@ -1059,9 +1166,8 @@
 						logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error last window - later: repeat window once?", //TODO!!!
 							log.Fields{"device-id": oFsm.deviceID, "actual section": sectionNumber,
 								"expected section": oFsm.omciDownloadWindowSizeLast})
-						//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
 						oFsm.mutexUpgradeParams.Unlock()
-						_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+						oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 						return
 					}
 					oFsm.delayEndSwDl = true //ensure a delay for the EndSwDl message
@@ -1080,8 +1186,7 @@
 						log.Fields{"device-id": oFsm.deviceID, "actual-section": sectionNumber,
 							"expected section": oFsm.omciDownloadWindowSizeLimit})
 					oFsm.mutexUpgradeParams.Unlock()
-					//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-					_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+					oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 					return
 				}
 				oFsm.nextDownloadSectionsWindow = 0
@@ -1092,9 +1197,7 @@
 			oFsm.mutexUpgradeParams.Unlock()
 			logger.Errorw(ctx, "OnuUpgradeFsm Omci StartSwDlResponse wrong ME instance: try again (later)?",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			// TODO!!!: possibly repeat the download (section) (once)?
-			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 			return
 		} //DownloadSectionResponseType
 	case omci.EndSoftwareDownloadResponseType:
@@ -1103,16 +1206,14 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for EndSwDlResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.EndSoftwareDownloadResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for EndSwDlResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm EndSwDlResponse data", log.Fields{
@@ -1126,34 +1227,44 @@
 				}
 				logger.Errorw(ctx, "OnuUpgradeFsm EndSwDlResponse result error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				// possibly force FSM into abort or ignore some errors for some messages? store error for mgmt display?
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 				return
 			}
 			oFsm.mutexUpgradeParams.Lock()
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
+				//EndSwDownloadSuccess is used to indicate 'DOWNLOAD_SUCCEEDED'
 				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
-				oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
-				oFsm.mutexUpgradeParams.Unlock()
-				logger.Debugw(ctx, "Expected EndSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
-				oFsm.mutexIsAwaitingOnuDlResponse.RLock()
-				if oFsm.isWaitingForOnuDlResponse {
-					oFsm.mutexIsAwaitingOnuDlResponse.RUnlock()
-					//use channel to indicate that the download to ONU was successful
-					oFsm.chOnuDlReady <- true
+				if !oFsm.useAPIVersion43 {
+					//in the older API version the image version check was not possible
+					//  - assume new loaded image as valid-inactive immediately
+					oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
+					oFsm.mutexUpgradeParams.Unlock()
+					oFsm.mutexIsAwaitingOnuDlResponse.RLock()
+					if oFsm.isWaitingForOnuDlResponse {
+						oFsm.mutexIsAwaitingOnuDlResponse.RUnlock()
+						//use non-blocking channel to indicate that the download to ONU was successful
+						select {
+						case oFsm.chOnuDlReady <- true:
+						default:
+						}
+					} else {
+						oFsm.mutexIsAwaitingOnuDlResponse.RUnlock()
+					}
 				} else {
-					oFsm.mutexIsAwaitingOnuDlResponse.RUnlock()
+					oFsm.mutexUpgradeParams.Unlock()
 				}
-				oFsm.chReceiveExpectedResponse <- true //let the FSM proceed from the waitState
+				logger.Debugw(ctx, "Expected EndSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
+				//use non-blocking channel to let the FSM proceed from the waitState
+				select {
+				case oFsm.chReceiveExpectedResponse <- true:
+				default:
+				}
 				return
 			}
 			oFsm.mutexUpgradeParams.Unlock()
 			logger.Errorw(ctx, "OnuUpgradeFsm StartSwDlResponse wrong ME instance: try again (later)?",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			// TODO!!!: possibly repeat the end request (once)? or verify ONU upgrade state?
-			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_DOWNLOADING)
 			return
 		} //EndSoftwareDownloadResponseType
 	case omci.ActivateSoftwareResponseType:
@@ -1162,16 +1273,14 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for ActivateSw",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.ActivateSoftwareResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for ActivateSw",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm ActivateSwResponse data", log.Fields{
@@ -1179,13 +1288,12 @@
 			if msgObj.Result != me.Success {
 				logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse result error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				// TODO!!!: error treatment?, perhaps in the end reset the FSM
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
 				return
 			}
 			oFsm.mutexUpgradeParams.Lock()
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
+				// the image is regarded as active really only after ONU reboot and according indication (ONU down/up procedure)
 				oFsm.mutexUpgradeParams.Unlock()
 				logger.Infow(ctx, "Expected ActivateSwResponse received",
 					log.Fields{"device-id": oFsm.deviceID, "commit": oFsm.commitImage})
@@ -1199,9 +1307,7 @@
 			oFsm.mutexUpgradeParams.Unlock()
 			logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse wrong ME instance: abort",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			// TODO!!!: error treatment?
-			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_ACTIVATION_ABORTED)
 			return
 		} //ActivateSoftwareResponseType
 	case omci.CommitSoftwareResponseType:
@@ -1210,22 +1316,20 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for CommitResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.CommitSoftwareResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for CommitResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
 				return
 			}
 			if msgObj.Result != me.Success {
 				logger.Errorw(ctx, "OnuUpgradeFsm SwImage CommitResponse result error - later: drive FSM to abort state ?",
 					log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-				// TODO!!!: error treatment?, perhaps in the end reset the FSM
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
 				return
 			}
 			oFsm.mutexUpgradeParams.RLock()
@@ -1239,9 +1343,7 @@
 			oFsm.mutexUpgradeParams.RUnlock()
 			logger.Errorw(ctx, "OnuUpgradeFsm SwImage CommitResponse  wrong ME instance: abort",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
-			// TODO!!!: error treatment?
-			//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-			_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+			oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
 			return
 		} //CommitSoftwareResponseType
 	case omci.GetResponseType:
@@ -1250,16 +1352,14 @@
 			if msgLayer == nil {
 				logger.Errorw(ctx, "Omci Msg layer could not be detected for SwImage GetResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
 				return
 			}
 			msgObj, msgOk := msgLayer.(*omci.GetResponse)
 			if !msgOk {
 				logger.Errorw(ctx, "Omci Msg layer could not be assigned for SwImage GetResponse",
 					log.Fields{"device-id": oFsm.deviceID})
-				//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
 				return
 			}
 			logger.Debugw(ctx, "OnuUpgradeFsm SwImage GetResponse data", log.Fields{
@@ -1269,9 +1369,7 @@
 				if msgObj.Result != me.Success {
 					logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse result error - later: drive FSM to abort state ?",
 						log.Fields{"device-id": oFsm.deviceID, "Error": msgObj.Result})
-					// TODO!!!: error treatment?, perhaps in the end reset the FSM
-					//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
-					_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+					oFsm.abortOnOmciError(ctx, false, voltha.ImageState_IMAGE_COMMIT_ABORTED)
 					return
 				}
 			} else {
@@ -1288,7 +1386,80 @@
 				log.Fields{"device-id": oFsm.deviceID, "entityID": msgObj.EntityInstance,
 					"version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted})
 
+			if oFsm.pAdaptFsm.pFsm.Current() == upgradeStCheckImageName {
+				//image name check after EndSwDownload, this state (and block) can only be taken if APIVersion43 is used
+				oFsm.mutexUpgradeParams.Lock()
+				if msgObj.EntityInstance == oFsm.inactiveImageMeID && imageIsActive == swIsInactive &&
+					imageIsCommitted == swIsUncommitted {
+					if imageVersion != oFsm.imageVersion {
+						//new stored inactive version indicated on OMCI from ONU is not the expected version
+						logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse version indication not matching requested upgrade",
+							log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance,
+								"onu-version": imageVersion, "expected-version": oFsm.imageVersion})
+						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED         //not the expected image was downloaded
+						oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
+						oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN              //something like 'DOWNLOADED' would be better - proto def
+						oFsm.mutexUpgradeParams.Unlock()
+						//stop the running ONU download timer
+						oFsm.mutexIsAwaitingOnuDlResponse.RLock()
+						if oFsm.isWaitingForOnuDlResponse {
+							oFsm.mutexIsAwaitingOnuDlResponse.RUnlock()
+							//use channel to indicate that the download to ONU was not successful
+							oFsm.chOnuDlReady <- false
+						} else {
+							oFsm.mutexIsAwaitingOnuDlResponse.RUnlock()
+						}
+						// TODO!!!: error treatment?
+						//TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
+						_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+						return
+					}
+					//with APIVersion43 this is the point to consider the newly loaded image as valid (and inactive)
+					oFsm.volthaImageState = voltha.ImageState_IMAGE_INACTIVE
+					//store the new inactive version to onuSwImageIndications (to keep them in sync)
+					oFsm.pDevEntry.modifySwImageInactiveVersion(ctx, oFsm.imageVersion)
+					//proceed within upgrade FSM
+					if oFsm.activateImage {
+						//immediate activation requested
+						oFsm.mutexUpgradeParams.Unlock()
+						logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, continue with activation",
+							log.Fields{"device-id": oFsm.deviceID})
+						_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvRequestActivate)
+					} else {
+						//have to wait on explicit activation request
+						// but a previously requested download activity (without activation) was successful here
+						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
+						oFsm.mutexUpgradeParams.Unlock()
+						logger.Infow(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU, wait for activate request",
+							log.Fields{"device-id": oFsm.deviceID})
+						_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvWaitForActivate)
+					}
+					oFsm.mutexIsAwaitingOnuDlResponse.RLock()
+					if oFsm.isWaitingForOnuDlResponse {
+						oFsm.mutexIsAwaitingOnuDlResponse.RUnlock()
+						//use channel to indicate that the download to ONU was successful
+						oFsm.chOnuDlReady <- true
+					} else {
+						oFsm.mutexIsAwaitingOnuDlResponse.RUnlock()
+					}
+					return
+				}
+				//not the expected image/image state
+				oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+				oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+				oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN //real image state not known
+				oFsm.mutexUpgradeParams.Unlock()
+				logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
+					log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
+				// TODO!!!: error treatment?
+				//TODO!!!: possibly send event information for aborted upgrade (aborted by ONU state indication)?
+				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				return
+			}
+
+			//assumed only relevant state here is upgradeStCheckCommitted
 			oFsm.mutexUpgradeParams.Lock()
+			oFsm.conditionalCancelRequested = false //getting here any set (conditional) cancelRequest is not relevant anymore
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID && imageIsActive == swIsActive {
 				//a check on the delivered image version is not done, the ONU delivered version might be different from what might have been
 				//  indicated in the download image version string (version must be part of the image content itself)
@@ -1298,12 +1469,15 @@
 				if oFsm.useAPIVersion43 {
 					if imageVersion != oFsm.imageVersion {
 						//new active version indicated on OMCI from ONU is not the expected version
-						logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
+						logger.Errorw(ctx, "OnuUpgradeFsm image-version not matching the requested upgrade",
 							log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance,
 								"onu-version": imageVersion, "expected-version": oFsm.imageVersion})
-						oFsm.mutexUpgradeParams.Unlock()
 						// TODO!!!: error treatment?
-						//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+						//TODO!!!: possibly send event information for aborted upgrade (aborted by wrong version)?
+						oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED         //not the expected image was committed
+						oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE //something like 'UNEXPECTED_VERSION' would be better - proto def
+						oFsm.volthaImageState = voltha.ImageState_IMAGE_UNKNOWN              //expected image not known
+						oFsm.mutexUpgradeParams.Unlock()
 						_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 						return
 					}
@@ -1311,17 +1485,23 @@
 						log.Fields{"device-id": oFsm.deviceID})
 				}
 				if imageIsCommitted == swIsCommitted {
+					oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
 					oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTED
+					//store the new commit flag to onuSwImageIndications (to keep them in sync)
+					oFsm.pDevEntry.modifySwImageActiveCommit(ctx, imageIsCommitted)
 					logger.Infow(ctx, "requested SW image committed, releasing OnuUpgrade", log.Fields{"device-id": oFsm.deviceID})
-					oFsm.pDeviceHandler.deviceProcStatusUpdate(ctx, OnuDeviceEvent(oFsm.requestEvent)) //to let the handler now about success
+					//deviceProcStatusUpdate not used anymore,
+					// replaced by transferring the last (more) upgrade state information within removeOnuUpgradeFsm
 					oFsm.mutexUpgradeParams.Unlock()
-					//releasing the upgrade FSM
+					//releasing the upgrade FSM on success
 					_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 					return
 				}
-				oFsm.mutexUpgradeParams.Unlock()
-				return //if the imageId is active but not committed let upgrade persist, maybe ONU reboot or manual commit may resolve the situation
+				//if not committed, abort upgrade as failed. There is no implementation here that would trigger this test again
 			}
+			oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+			oFsm.volthaDownloadReason = voltha.ImageState_CANCELLED_ON_ONU_STATE
+			oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMIT_ABORTED
 			oFsm.mutexUpgradeParams.Unlock()
 			logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching requested upgrade",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
@@ -1339,12 +1519,48 @@
 	}
 }
 
+//abortOnOmciError aborts the upgrade processing with OMCI_TRANSFER_ERROR indication
+func (oFsm *OnuUpgradeFsm) abortOnOmciError(ctx context.Context, aAsync bool,
+	aImageState voltha.ImageState_ImageActivationState) {
+	oFsm.mutexUpgradeParams.Lock()
+	oFsm.conditionalCancelRequested = false //any conditional cancelRequest is superseded by this abortion
+	oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_FAILED
+	oFsm.volthaDownloadReason = voltha.ImageState_OMCI_TRANSFER_ERROR
+	if aImageState != voltha.ImageState_IMAGE_UNKNOWN {
+		// update image state only in case some explicite state is given (otherwise the existing state is used)
+		oFsm.volthaImageState = aImageState
+	}
+	oFsm.mutexUpgradeParams.Unlock()
+	//TODO!!!: possibly send event information for aborted upgrade (aborted by omci processing)??
+	if oFsm.pAdaptFsm != nil {
+		var err error
+		if aAsync { //asynchronous call requested to ensure state transition
+			go func(a_pAFsm *AdapterFsm) {
+				if a_pAFsm.pFsm != nil {
+					err = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+				}
+			}(oFsm.pAdaptFsm)
+		} else {
+			if oFsm.pAdaptFsm.pFsm != nil {
+				err = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
+			}
+		}
+		if err != nil {
+			logger.Warnw(ctx, "onu upgrade fsm could not abort on omci error", log.Fields{
+				"device-id": oFsm.deviceID, "error": err})
+		}
+	}
+}
+
 //waitOnDownloadToAdapterReady state can only be reached with useAPIVersion43 (usage of pFileManager)
-func (oFsm *OnuUpgradeFsm) waitOnDownloadToAdapterReady(ctx context.Context, aWaitChannel chan bool) {
-	downloadToAdapterTimeout := oFsm.pFileManager.GetDownloadTimeout(ctx)
+//  precondition: mutexIsAwaitingAdapterDlResponse is lockek on call
+func (oFsm *OnuUpgradeFsm) waitOnDownloadToAdapterReady(ctx context.Context, aSyncChannel chan<- struct{},
+	aWaitChannel chan bool) {
 	oFsm.mutexIsAwaitingAdapterDlResponse.Lock()
+	downloadToAdapterTimeout := oFsm.pFileManager.GetDownloadTimeout(ctx)
 	oFsm.isWaitingForAdapterDlResponse = true
 	oFsm.mutexIsAwaitingAdapterDlResponse.Unlock()
+	aSyncChannel <- struct{}{}
 	select {
 	// maybe be also some outside cancel (but no context modeled for the moment ...)
 	// case <-ctx.Done():
@@ -1356,13 +1572,7 @@
 		oFsm.mutexIsAwaitingAdapterDlResponse.Lock()
 		oFsm.isWaitingForAdapterDlResponse = false
 		oFsm.mutexIsAwaitingAdapterDlResponse.Unlock()
-		//the upgrade process has to be aborted
-		pUpgradeFsm := oFsm.pAdaptFsm
-		if pUpgradeFsm != nil {
-			_ = pUpgradeFsm.pFsm.Event(upgradeEvAbort)
-		} else {
-			logger.Errorw(ctx, "pUpgradeFsm is nil", log.Fields{"device-id": oFsm.deviceID})
-		}
+		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
 		return
 
 	case success := <-aWaitChannel:
@@ -1387,12 +1597,7 @@
 		oFsm.isWaitingForAdapterDlResponse = false
 		oFsm.mutexIsAwaitingAdapterDlResponse.Unlock()
 		//the upgrade process has to be aborted
-		pUpgradeFsm := oFsm.pAdaptFsm
-		if pUpgradeFsm != nil {
-			_ = pUpgradeFsm.pFsm.Event(upgradeEvAbort)
-		} else {
-			logger.Errorw(ctx, "pUpgradeFsm is nil", log.Fields{"device-id": oFsm.deviceID})
-		}
+		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
 		return
 	}
 }
@@ -1416,12 +1621,7 @@
 		oFsm.isWaitingForOnuDlResponse = false
 		oFsm.mutexIsAwaitingOnuDlResponse.Unlock()
 		//the upgrade process has to be aborted
-		pUpgradeFsm := oFsm.pAdaptFsm
-		if pUpgradeFsm != nil {
-			_ = pUpgradeFsm.pFsm.Event(upgradeEvAbort)
-		} else {
-			logger.Errorw(ctx, "pUpgradeFsm is nil", log.Fields{"device-id": oFsm.deviceID})
-		}
+		oFsm.abortOnOmciError(ctx, true, voltha.ImageState_IMAGE_UNKNOWN) //no ImageState update
 		return
 
 	case success := <-aWaitChannel: