ONU SW upgrade API change - step 2: added Abort and Get_onu_image_status functionality

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I577442affd3f63f429367e012a67184429359f94
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index df3c477..3dd76ff 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -224,6 +224,7 @@
 	readyForOmciConfig          bool
 	deletionInProgress          bool
 	mutexDeletionInProgressFlag sync.RWMutex
+	upgradeSuccess              bool
 }
 
 //newDeviceHandler creates a new device handler
@@ -766,7 +767,7 @@
 func (dh *deviceHandler) reEnableDevice(ctx context.Context, device *voltha.Device) {
 	logger.Debugw(ctx, "reenable-device", log.Fields{"device-id": device.Id, "SerialNumber": device.SerialNumber})
 
-	//setting ReadyForSpecificOmciConfig here is just a workaround for BBSIM testing in the sequence
+	//setting readyForOmciConfig here is just a workaround for BBSIM testing in the sequence
 	//  OnuSoftReboot-disable-enable, because BBSIM does not generate a new OnuIndication-Up event after SoftReboot
 	//  which is the assumption for real ONU's, where the ready-state is then set according to the following MibUpload/Download
 	//  for real ONU's that should have nearly no influence
@@ -1285,6 +1286,57 @@
 		"device-id": dh.deviceID, "error": err})
 }
 
+func (dh *deviceHandler) requestOnuSwUpgradeState(ctx context.Context, aImageIdentifier string,
+	aVersion string, pDeviceImageState *voltha.DeviceImageState) {
+	pDeviceImageState.DeviceId = dh.deviceID
+	pDeviceImageState.ImageState.Version = aImageIdentifier
+	dh.lockUpgradeFsm.RLock()
+	if dh.pOnuUpradeFsm != nil {
+		dh.lockUpgradeFsm.RUnlock()
+		if pImageStates, err := dh.pOnuUpradeFsm.GetImageStates(ctx, aImageIdentifier, aVersion); err != nil {
+			pDeviceImageState.ImageState.DownloadState = pImageStates.DownloadState
+			pDeviceImageState.ImageState.Reason = pImageStates.Reason
+			pDeviceImageState.ImageState.ImageState = pImageStates.ImageState
+		} else {
+			pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
+			pDeviceImageState.ImageState.Reason = voltha.ImageState_NO_ERROR
+			pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
+		}
+	} else {
+		dh.lockUpgradeFsm.RUnlock()
+		pDeviceImageState.ImageState.Reason = voltha.ImageState_NO_ERROR
+		if dh.upgradeSuccess {
+			pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
+			pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_COMMITTED
+		} else {
+			pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
+			pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
+		}
+	}
+}
+
+func (dh *deviceHandler) cancelOnuSwUpgrade(ctx context.Context, aImageIdentifier string,
+	aVersion string, pDeviceImageState *voltha.DeviceImageState) {
+	pDeviceImageState.DeviceId = dh.deviceID
+	pDeviceImageState.ImageState.Version = aImageIdentifier
+	pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
+	dh.lockUpgradeFsm.RLock()
+	if dh.pOnuUpradeFsm != nil {
+		dh.lockUpgradeFsm.RUnlock()
+		//option: it could be also checked if the upgrade FSM is running on the given imageIdentifier or version
+		//  by now just straightforward assume this to be true
+		dh.pOnuUpradeFsm.CancelProcessing(ctx)
+		//nolint:misspell
+		pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
+		//nolint:misspell
+		pDeviceImageState.ImageState.Reason = voltha.ImageState_CANCELLED_ON_REQUEST
+	} else {
+		dh.lockUpgradeFsm.RUnlock()
+		pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
+		pDeviceImageState.ImageState.Reason = voltha.ImageState_NO_ERROR
+	}
+}
+
 //  deviceHandler methods that implement the adapters interface requests## end #########
 // #####################################################################################
 
@@ -1867,6 +1919,7 @@
 	if pDevEntry.PDevOmciCC != nil {
 		pDevEntry.PDevOmciCC.CancelRequestMonitoring()
 	}
+
 	if includingMibSyncFsm {
 		pDevEntry.CancelProcessing(ctx)
 	}
@@ -2239,6 +2292,10 @@
 		{
 			dh.processOmciVlanFilterDoneEvent(ctx, devEvent)
 		}
+	case OmciOnuSwUpgradeDone:
+		{
+			dh.upgradeSuccess = true
+		}
 	default:
 		{
 			logger.Debugw(ctx, "unhandled-device-event", log.Fields{"device-id": dh.deviceID, "event": devEvent})
@@ -2484,6 +2541,7 @@
 		pUpgradeStatemachine := dh.pOnuUpradeFsm.pAdaptFsm.pFsm
 		if pUpgradeStatemachine != nil {
 			if pUpgradeStatemachine.Is(upgradeStDisabled) {
+				dh.upgradeSuccess = false //for start of upgrade processing reset the last indication
 				if err := pUpgradeStatemachine.Event(upgradeEvStart); err != nil {
 					logger.Errorw(ctx, "OnuSwUpgradeFSM: can't start", log.Fields{"err": err})
 					// maybe try a FSM reset and then again ... - TODO!!!
@@ -3502,7 +3560,6 @@
 	dh.readyForOmciConfig = flagValue
 	dh.mutexReadyForOmciConfig.Unlock()
 }
-
 func (dh *deviceHandler) isReadyForOmciConfig() bool {
 	dh.mutexReadyForOmciConfig.RLock()
 	flagValue := dh.readyForOmciConfig
diff --git a/internal/pkg/onuadaptercore/file_download_manager.go b/internal/pkg/onuadaptercore/file_download_manager.go
index 0658c6f..1dfd50a 100644
--- a/internal/pkg/onuadaptercore/file_download_manager.go
+++ b/internal/pkg/onuadaptercore/file_download_manager.go
@@ -29,6 +29,7 @@
 	"time"
 
 	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+	"github.com/opencord/voltha-protos/v4/go/voltha"
 )
 
 const cDefaultLocalDir = "/tmp" //this is the default local dir to download to
@@ -348,3 +349,48 @@
 	}()
 	return nil
 }
+
+func (dm *fileDownloadManager) RequestDownloadState(ctx context.Context, aImageName string,
+	apDlToAdapterImageState *voltha.ImageState) {
+	logger.Debugw(ctx, "request download state for image to Adapter", log.Fields{"image-name": aImageName})
+	dm.mutexDownloadImageDsc.RLock()
+	defer dm.mutexDownloadImageDsc.RUnlock()
+
+	for _, dnldImgDsc := range dm.downloadImageDscSlice {
+		if dnldImgDsc.downloadImageName == aImageName {
+			//image found (by name)
+			apDlToAdapterImageState.DownloadState = voltha.ImageState_DOWNLOAD_REQUESTED
+			apDlToAdapterImageState.Reason = voltha.ImageState_NO_ERROR
+			return
+		}
+	}
+	//image not found (by name)
+	apDlToAdapterImageState.DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
+	apDlToAdapterImageState.Reason = voltha.ImageState_NO_ERROR
+}
+
+func (dm *fileDownloadManager) CancelDownload(ctx context.Context, aImageName string) {
+	logger.Debugw(ctx, "Cancel the download to Adapter", log.Fields{"image-name": aImageName})
+	// for the moment that would only support to wait for the download end and remove the image then
+	//   further reactions while still downloading can be considered with some effort, but does it make sense (synchronous load here!)
+	dm.mutexDownloadImageDsc.RLock()
+	defer dm.mutexDownloadImageDsc.RUnlock()
+
+	tmpSlice := dm.downloadImageDscSlice[:0]
+	for _, dnldImgDsc := range dm.downloadImageDscSlice {
+		if dnldImgDsc.downloadImageName == aImageName {
+			//image found (by name) - remove the image from filesystem
+			logger.Debugw(ctx, "removing image", log.Fields{"image-name": aImageName})
+			aLocalPathName := cDefaultLocalDir + "/" + aImageName
+			if err := os.Remove(aLocalPathName); err != nil {
+				logger.Debugw(ctx, "image not removed from filesystem", log.Fields{
+					"image-name": aImageName, "error": err})
+			}
+			// and in the imageDsc slice by just not appending
+		} else {
+			tmpSlice = append(tmpSlice, dnldImgDsc)
+		}
+	}
+	dm.downloadImageDscSlice = tmpSlice
+	//image not found (by name)
+}
diff --git a/internal/pkg/onuadaptercore/omci_onu_upgrade.go b/internal/pkg/onuadaptercore/omci_onu_upgrade.go
index 1e542ce..3da030d 100644
--- a/internal/pkg/onuadaptercore/omci_onu_upgrade.go
+++ b/internal/pkg/onuadaptercore/omci_onu_upgrade.go
@@ -124,10 +124,10 @@
 	waitCountEndSwDl                 uint8         //number, how often is waited for EndSwDl at maximum
 	waitDelayEndSwDl                 time.Duration //duration, how long is waited before next request on EndSwDl
 	chReceiveExpectedResponse        chan bool
-	useAPIVersion43                  bool //flag for indication on which API version is used (and accordingly which specific methods)
-	mutexUpgradeParams               sync.RWMutex
-	imageVersion                     string //name of the image as used within OMCI (and on extrenal API interface)
-	imageIdentifier                  string //name of the image as used in the adapter
+	useAPIVersion43                  bool         //flag for indication on which API version is used (and accordingly which specific methods)
+	mutexUpgradeParams               sync.RWMutex //mutex to protect members for parallel function requests and omci response processing
+	imageVersion                     string       //name of the image as used within OMCI (and on extrenal API interface)
+	imageIdentifier                  string       //name of the image as used in the adapter
 	mutexIsAwaitingAdapterDlResponse sync.RWMutex
 	chAdapterDlReady                 chan bool
 	isWaitingForAdapterDlResponse    bool
@@ -136,6 +136,9 @@
 	isWaitingForOnuDlResponse        bool
 	activateImage                    bool
 	commitImage                      bool
+	volthaDownloadState              voltha.ImageState_ImageDownloadState
+	volthaDownloadReason             voltha.ImageState_ImageFailureReason
+	volthaImageState                 voltha.ImageState_ImageActivationState
 }
 
 //NewOnuUpgradeFsm is the 'constructor' for the state machine to config the PON ANI ports
@@ -154,6 +157,9 @@
 		omciSectionInterleaveDelay:  cOmciSectionInterleaveMilliseconds,
 		waitCountEndSwDl:            cWaitCountEndSwDl,
 		waitDelayEndSwDl:            cWaitDelayEndSwDlSeconds,
+		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,
 	}
 	instFsm.chReceiveExpectedResponse = make(chan bool)
 	instFsm.chAdapterDlReady = make(chan bool)
@@ -234,11 +240,13 @@
 	apImageDsc *voltha.ImageDownload, apDownloadManager *adapterDownloadManager) error {
 	pBaseFsm := oFsm.pAdaptFsm.pFsm
 	if pBaseFsm != nil && pBaseFsm.Is(upgradeStStarting) {
+		oFsm.mutexUpgradeParams.Lock()
 		logger.Debugw(ctx, "OnuUpgradeFsm Parameter setting", log.Fields{
 			"device-id": oFsm.deviceID, "image-description": apImageDsc})
 		oFsm.inactiveImageMeID = aInactiveImageID //upgrade state machines run on configured inactive ImageId
 		oFsm.pImageDsc = apImageDsc
 		oFsm.pDownloadManager = apDownloadManager
+		oFsm.mutexUpgradeParams.Unlock()
 
 		go func(aPBaseFsm *fsm.FSM) {
 			// let the upgrade FSM proceed to PreparingDL
@@ -406,6 +414,25 @@
 	return fmt.Errorf(fmt.Sprintf("OnuUpgradeFsm abort: invalid FSM base pointer or state for device-id: %s", oFsm.deviceID))
 }
 
+//GetImageStates delivers the download states as per device proto buf or error indication
+func (oFsm *OnuUpgradeFsm) GetImageStates(ctx context.Context,
+	aImageIdentifier string, aVersion string) (*voltha.ImageState, error) {
+	pImageState := &voltha.ImageState{}
+	// check if the request refers to some active image/version of the processing
+	oFsm.mutexUpgradeParams.RLock()
+	if (aImageIdentifier == oFsm.imageIdentifier) || (aVersion == oFsm.imageVersion) {
+		pImageState.DownloadState = oFsm.volthaDownloadState
+		pImageState.Reason = oFsm.volthaDownloadReason
+		pImageState.ImageState = oFsm.volthaImageState
+	} else {
+		pImageState.DownloadState = voltha.ImageState_DOWNLOAD_UNKNOWN
+		pImageState.Reason = voltha.ImageState_NO_ERROR
+		pImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
+	}
+	oFsm.mutexUpgradeParams.RUnlock()
+	return pImageState, nil
+}
+
 //CancelProcessing ensures that suspended processing at waiting on some response is aborted and reset of FSM
 func (oFsm *OnuUpgradeFsm) CancelProcessing(ctx context.Context) {
 	//mutex protection is required for possible concurrent access to FSM members
@@ -460,6 +487,7 @@
 
 	var fileLen int64
 	var err error
+	oFsm.mutexUpgradeParams.Lock()
 	if oFsm.useAPIVersion43 {
 		//with the new API structure download to adapter is implicit and we have to wait until the image is available
 		fileLen, err = oFsm.pFileManager.GetImageBufferLen(ctx, oFsm.imageIdentifier)
@@ -467,6 +495,7 @@
 		fileLen, err = oFsm.pDownloadManager.getImageBufferLen(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
 	}
 	if err != nil || fileLen > int64(cMaxUint32) {
+		oFsm.mutexUpgradeParams.Unlock()
 		logger.Errorw(ctx, "OnuUpgradeFsm abort: problems getting image buffer length", log.Fields{
 			"device-id": oFsm.deviceID, "error": err, "length": fileLen})
 		pBaseFsm := oFsm.pAdaptFsm
@@ -485,6 +514,7 @@
 		oFsm.imageBuffer, err = oFsm.pDownloadManager.getDownloadImageBuffer(ctx, oFsm.pImageDsc.Name, oFsm.pImageDsc.LocalDir)
 	}
 	if err != nil {
+		oFsm.mutexUpgradeParams.Unlock()
 		logger.Errorw(ctx, "OnuUpgradeFsm abort: can't get image buffer", log.Fields{
 			"device-id": oFsm.deviceID, "error": err})
 		pBaseFsm := oFsm.pAdaptFsm
@@ -504,13 +534,14 @@
 	}
 	oFsm.origImageLength = uint32(fileLen)
 	oFsm.imageLength = uint32(len(oFsm.imageBuffer))
-
-	go oFsm.waitOnDownloadToOnuReady(ctx, oFsm.chOnuDlReady) // start supervision of the complete download-to-ONU procedure
-
 	logger.Infow(ctx, "OnuUpgradeFsm starts with StartSwDl values", log.Fields{
 		"MeId": oFsm.inactiveImageMeID, "windowSizeLimit": oFsm.omciDownloadWindowSizeLimit,
 		"ImageSize": oFsm.imageLength, "original file size": fileLen})
 	//"NumberOfCircuitPacks": oFsm.numberCircuitPacks, "CircuitPacks MeId": 0}) //parallel circuit packs download not supported
+
+	oFsm.mutexUpgradeParams.Unlock()
+	go oFsm.waitOnDownloadToOnuReady(ctx, oFsm.chOnuDlReady) // start supervision of the complete download-to-ONU procedure
+
 	err = oFsm.pOmciCC.sendStartSoftwareDownload(log.WithSpanFromContext(context.TODO(), ctx), oFsm.pDeviceHandler.pOpenOnuAc.omciTimeout, false,
 		oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID, oFsm.omciDownloadWindowSizeLimit, oFsm.origImageLength)
 	if err != nil {
@@ -535,9 +566,11 @@
 	var bufferEndOffset uint32
 	var downloadSection []byte
 	framePrint := false //default no printing of downloadSection frames
+	oFsm.mutexUpgradeParams.Lock()
 	if oFsm.nextDownloadSectionsAbsolute == 0 {
 		//debug print of first section frame
 		framePrint = true
+		oFsm.volthaImageState = voltha.ImageState_IMAGE_DOWNLOADING
 	}
 
 	for {
@@ -551,6 +584,7 @@
 			logger.Errorw(ctx, "OnuUpgradeFsm buffer error: exceeded length", log.Fields{
 				"device-id": oFsm.deviceID, "bufferStartOffset": bufferStartOffset,
 				"bufferEndOffset": bufferEndOffset, "imageLength": oFsm.imageLength})
+			oFsm.mutexUpgradeParams.Unlock()
 			//logical error -- reset the FSM
 			pBaseFsm := oFsm.pAdaptFsm
 			// Can't call FSM Event directly, decoupling it
@@ -572,6 +606,7 @@
 			logger.Infow(ctx, "DlSection expect Response for last window (section)", log.Fields{
 				"device-id": oFsm.deviceID, "DlSectionNoAbsolute": oFsm.nextDownloadSectionsAbsolute})
 		}
+		oFsm.mutexUpgradeParams.Unlock() //unlock here to give other functions some chance to process during/after the send request
 		err := oFsm.pOmciCC.sendDownloadSection(log.WithSpanFromContext(context.TODO(), ctx), oFsm.pDeviceHandler.pOpenOnuAc.omciTimeout, false,
 			oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID, windowAckRequest, oFsm.nextDownloadSectionsWindow, downloadSection, framePrint)
 		if err != nil {
@@ -585,10 +620,12 @@
 			}(pBaseFsm)
 			return
 		}
+		oFsm.mutexUpgradeParams.Lock()
 		oFsm.nextDownloadSectionsAbsolute++ //always increase the absolute section counter after having sent one
 		if windowAckRequest == 1 {
 			pBaseFsm := oFsm.pAdaptFsm
 			// Can't call FSM Event directly, decoupling it
+			oFsm.mutexUpgradeParams.Unlock()
 			go func(a_pAFsm *AdapterFsm) {
 				_ = a_pAFsm.pFsm.Event(upgradeEvWaitWindowAck) //state transition to upgradeStVerifyWindow
 			}(pBaseFsm)
@@ -598,7 +635,9 @@
 		oFsm.nextDownloadSectionsWindow++ //increase the window related section counter only if not in the last section
 		if oFsm.omciSectionInterleaveDelay > 0 {
 			//ensure a defined intersection-time-gap to leave space for further processing, other ONU's ...
+			oFsm.mutexUpgradeParams.Unlock() //unlock here to give other functions some chance to process during/after the send request
 			time.Sleep(oFsm.omciSectionInterleaveDelay * time.Millisecond)
+			oFsm.mutexUpgradeParams.Lock()
 		}
 	}
 }
@@ -612,10 +651,14 @@
 	logger.Infow(ctx, "OnuUpgradeFsm finalize DL", log.Fields{
 		"device-id": oFsm.deviceID, "crc": strconv.FormatInt(int64(oFsm.imageCRC), 16), "delay": oFsm.delayEndSwDl})
 
+	oFsm.mutexUpgradeParams.RLock()
 	if oFsm.delayEndSwDl {
+		oFsm.mutexUpgradeParams.RUnlock()
 		//give the ONU some time for image evaluation (hoping it does not base that on first EndSwDl itself)
 		// should not be set in case this state is used for real download abort (not yet implemented)
 		time.Sleep(cOmciEndSwDlDelaySeconds * time.Second)
+	} else {
+		oFsm.mutexUpgradeParams.RUnlock()
 	}
 
 	pBaseFsm := oFsm.pAdaptFsm
@@ -677,7 +720,9 @@
 			return
 		}
 		//retry End SW DL
+		oFsm.mutexUpgradeParams.Lock()
 		oFsm.delayEndSwDl = false //no more extra delay for the request
+		oFsm.mutexUpgradeParams.Unlock()
 		go func(a_pAFsm *AdapterFsm) {
 			_ = a_pAFsm.pFsm.Event(upgradeEvContinueFinalize)
 		}(pBaseFsm)
@@ -718,6 +763,10 @@
 	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 {
@@ -737,11 +786,15 @@
 	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
+		oFsm.mutexUpgradeParams.Lock()
 		if imageFit || activeImageID == oFsm.inactiveImageMeID {
+			inactiveImageID := oFsm.inactiveImageMeID
 			logger.Infow(ctx, "OnuUpgradeFsm commit SW", log.Fields{
-				"device-id": oFsm.deviceID, "me-id": oFsm.inactiveImageMeID}) //more efficient activeImageID with above check
+				"device-id": oFsm.deviceID, "me-id": inactiveImageID}) //more efficient activeImageID with above check
+			oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTING
+			oFsm.mutexUpgradeParams.Unlock()
 			err := oFsm.pOmciCC.sendCommitSoftware(log.WithSpanFromContext(context.TODO(), ctx), oFsm.pDeviceHandler.pOpenOnuAc.omciTimeout, false,
-				oFsm.pAdaptFsm.commChan, oFsm.inactiveImageMeID) //more efficient activeImageID with above check
+				oFsm.pAdaptFsm.commChan, inactiveImageID) //more efficient activeImageID with above check
 			if err != nil {
 				logger.Errorw(ctx, "CommitSw abort: can't send commit sw frame", log.Fields{
 					"device-id": oFsm.deviceID, "error": err})
@@ -758,6 +811,8 @@
 		}
 		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
@@ -910,6 +965,8 @@
 				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
+
+			oFsm.mutexUpgradeParams.Lock()
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
 				logger.Debugw(ctx, "Expected StartSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
 				if msgObj.WindowSize != oFsm.omciDownloadWindowSizeLimit {
@@ -929,9 +986,11 @@
 				oFsm.nextDownloadSectionsWindow = 0
 				oFsm.nextDownloadWindow = 0
 
+				oFsm.mutexUpgradeParams.Unlock()
 				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvRxStartSwDownload)
 				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 start request (once)?
@@ -966,6 +1025,7 @@
 				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
+			oFsm.mutexUpgradeParams.Lock()
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
 				sectionNumber := msgObj.SectionNumber
 				logger.Infow(ctx, "DlSectionResponse received", log.Fields{
@@ -978,6 +1038,7 @@
 							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)
 						return
 					}
@@ -988,6 +1049,7 @@
 					var byteSlice []byte = make([]byte, 4)
 					binary.LittleEndian.PutUint32(byteSlice, uint32(imageCRC))
 					oFsm.imageCRC = binary.BigEndian.Uint32(byteSlice)
+					oFsm.mutexUpgradeParams.Unlock()
 					_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvEndSwDownload)
 					return
 				}
@@ -995,14 +1057,17 @@
 					logger.Errorw(ctx, "OnuUpgradeFsm DlSectionResponse section error - later: repeat window once?", //TODO!!!
 						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)
 					return
 				}
 				oFsm.nextDownloadSectionsWindow = 0
+				oFsm.mutexUpgradeParams.Unlock()
 				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvContinueNextWindow)
 				return
 			}
+			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)?
@@ -1044,7 +1109,9 @@
 				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
+			oFsm.mutexUpgradeParams.RLock()
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
+				oFsm.mutexUpgradeParams.RUnlock()
 				logger.Debugw(ctx, "Expected EndSwDlResponse received", log.Fields{"device-id": oFsm.deviceID})
 				oFsm.mutexIsAwaitingOnuDlResponse.RLock()
 				if oFsm.isWaitingForOnuDlResponse {
@@ -1057,6 +1124,7 @@
 				oFsm.chReceiveExpectedResponse <- true //let the FSM proceed from the waitState
 				return
 			}
+			oFsm.mutexUpgradeParams.RUnlock()
 			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?
@@ -1092,11 +1160,14 @@
 				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
 				return
 			}
+			oFsm.mutexUpgradeParams.RLock()
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
+				oFsm.mutexUpgradeParams.RUnlock()
 				logger.Infow(ctx, "Expected ActivateSwResponse received", log.Fields{"device-id": oFsm.deviceID})
 				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvWaitForCommit)
 				return
 			}
+			oFsm.mutexUpgradeParams.RUnlock()
 			logger.Errorw(ctx, "OnuUpgradeFsm ActivateSwResponse wrong ME instance: abort",
 				log.Fields{"device-id": oFsm.deviceID, "ResponseMeId": msgObj.EntityInstance})
 			// TODO!!!: error treatment?
@@ -1128,12 +1199,15 @@
 				// TODO!!!: error treatment?, perhaps in the end reset the FSM
 				return
 			}
+			oFsm.mutexUpgradeParams.RLock()
 			if msgObj.EntityInstance == oFsm.inactiveImageMeID {
+				oFsm.mutexUpgradeParams.RUnlock()
 				logger.Debugw(ctx, "OnuUpgradeFsm Expected SwImage CommitResponse received", log.Fields{"device-id": oFsm.deviceID})
 				//verifying committed image
 				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvCheckCommitted)
 				return
 			}
+			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?
@@ -1184,8 +1258,9 @@
 			logger.Debugw(ctx, "OnuUpgradeFsm - GetResponse Data for SoftwareImage",
 				log.Fields{"device-id": oFsm.deviceID, "entityID": msgObj.EntityInstance,
 					"version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted})
-			if msgObj.EntityInstance == oFsm.inactiveImageMeID && imageIsActive == swIsActive &&
-				imageIsCommitted == swIsCommitted {
+
+			oFsm.mutexUpgradeParams.Lock()
+			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)
 				//  so checking that might be quite unreliable
@@ -1197,6 +1272,7 @@
 						logger.Errorw(ctx, "OnuUpgradeFsm SwImage GetResponse indications not matching 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)??
 						_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvAbort)
@@ -1205,11 +1281,21 @@
 					logger.Debugw(ctx, "OnuUpgradeFsm - expected ONU image version indicated by the ONU",
 						log.Fields{"device-id": oFsm.deviceID})
 				}
-				logger.Infow(ctx, "requested SW image committed, releasing OnuUpgrade", log.Fields{"device-id": oFsm.deviceID})
-				//releasing the upgrade FSM
-				_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvReset)
-				return
+				oFsm.volthaImageState = voltha.ImageState_IMAGE_ACTIVE
+				if imageIsCommitted == swIsCommitted {
+					oFsm.volthaDownloadState = voltha.ImageState_DOWNLOAD_SUCCEEDED
+					oFsm.volthaImageState = voltha.ImageState_IMAGE_COMMITTED
+					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
+					oFsm.mutexUpgradeParams.Unlock()
+					//releasing the upgrade FSM
+					_ = oFsm.pAdaptFsm.pFsm.Event(upgradeEvReset)
+					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
 			}
+			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?
diff --git a/internal/pkg/onuadaptercore/openonu.go b/internal/pkg/onuadaptercore/openonu.go
index c7f3e85..805944c 100644
--- a/internal/pkg/onuadaptercore/openonu.go
+++ b/internal/pkg/onuadaptercore/openonu.go
@@ -700,12 +700,127 @@
 // Get_onu_image_status delivers the adapter-related information about the download/activation/commitment
 //   status for the requested image
 func (oo *OpenONUAC) Get_onu_image_status(ctx context.Context, in *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
-	return nil, errors.New("unImplemented")
+	if in != nil && len((*in).DeviceId) > 0 && (*in).Version != "" {
+		loResponse := voltha.DeviceImageResponse{}
+		pDlToAdapterImageState := &voltha.ImageState{}
+		imageIdentifier := (*in).Version
+		firstDevice := true
+		var vendorID string
+		for _, pCommonID := range (*in).DeviceId {
+			loDeviceID := (*pCommonID).Id
+			onuVolthaDevice, err := oo.coreProxy.GetDevice(log.WithSpanFromContext(context.TODO(), ctx),
+				loDeviceID, loDeviceID)
+			if err != nil || onuVolthaDevice == nil {
+				logger.Warnw(ctx, "Failed to fetch Onu device to get image status",
+					log.Fields{"device-id": loDeviceID, "err": err})
+				continue //try the work with next deviceId
+			}
+			if firstDevice {
+				//start/verify download of the image to the adapter based on first found device only
+				//  use the OnuVendor identification from first given device
+				firstDevice = false
+				vendorID = onuVolthaDevice.VendorId
+				imageIdentifier = vendorID + imageIdentifier //head on vendor ID of the ONU
+				logger.Debugw(ctx, "status request for image", log.Fields{"image-id": imageIdentifier})
+				oo.pFileManager.RequestDownloadState(ctx, imageIdentifier, pDlToAdapterImageState)
+			} else {
+				//for all following devices verify the matching vendorID
+				if onuVolthaDevice.VendorId != vendorID {
+					logger.Warnw(ctx, "onu vendor id does not match image vendor id, device ignored",
+						log.Fields{"onu-vendor-id": onuVolthaDevice.VendorId, "image-vendor-id": vendorID})
+					continue //try the work with next deviceId
+				}
+			}
+			pDeviceImageState := &voltha.DeviceImageState{
+				ImageState: &voltha.ImageState{
+					DownloadState: (*pDlToAdapterImageState).DownloadState,
+					Reason:        (*pDlToAdapterImageState).Reason,
+				},
+			}
+			// get the handler for the device
+			if handler := oo.getDeviceHandler(ctx, loDeviceID, false); handler != nil {
+				logger.Debugw(ctx, "image status request for", log.Fields{
+					"image-id": imageIdentifier, "device-id": loDeviceID})
+				//status request is called synchronously to collect the indications for all concerned devices
+				handler.requestOnuSwUpgradeState(ctx, imageIdentifier, (*in).Version, pDeviceImageState)
+			} else {
+				//cannot get the handler
+				logger.Warnw(ctx, "no handler found for image status request ", log.Fields{"device-id": loDeviceID})
+				pDeviceImageState.DeviceId = loDeviceID
+				pDeviceImageState.ImageState.Version = (*in).Version
+				pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_FAILED
+				pDeviceImageState.ImageState.Reason = voltha.ImageState_UNKNOWN_ERROR
+				pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
+			}
+			loResponse.DeviceImageStates = append(loResponse.DeviceImageStates, pDeviceImageState)
+		}
+		pImageResp := &loResponse
+		return pImageResp, nil
+	}
+	return nil, errors.New("invalid image status request parameters")
 }
 
 // Abort_onu_image_upgrade stops the actual download/activation/commitment process (on next possibly step)
 func (oo *OpenONUAC) Abort_onu_image_upgrade(ctx context.Context, in *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
-	return nil, errors.New("unImplemented")
+	if in != nil && len((*in).DeviceId) > 0 && (*in).Version != "" {
+		loResponse := voltha.DeviceImageResponse{}
+		imageIdentifier := (*in).Version
+		firstDevice := true
+		var vendorID string
+		for _, pCommonID := range (*in).DeviceId {
+			loDeviceID := (*pCommonID).Id
+			onuVolthaDevice, err := oo.coreProxy.GetDevice(log.WithSpanFromContext(context.TODO(), ctx),
+				loDeviceID, loDeviceID)
+			if err != nil || onuVolthaDevice == nil {
+				logger.Warnw(ctx, "Failed to fetch Onu device to abort its download",
+					log.Fields{"device-id": loDeviceID, "err": err})
+				continue //try the work with next deviceId
+			}
+			pDeviceImageState := &voltha.DeviceImageState{}
+			if firstDevice {
+				//start/verify download of the image to the adapter based on first found device only
+				//  use the OnuVendor identification from first given device
+				firstDevice = false
+				vendorID = onuVolthaDevice.VendorId
+				imageIdentifier = vendorID + imageIdentifier //head on vendor ID of the ONU
+				logger.Debugw(ctx, "abort request for file", log.Fields{"image-id": imageIdentifier})
+			} else {
+				//for all following devices verify the matching vendorID
+				if onuVolthaDevice.VendorId != vendorID {
+					logger.Warnw(ctx, "onu vendor id does not match image vendor id, device ignored",
+						log.Fields{"onu-vendor-id": onuVolthaDevice.VendorId, "image-vendor-id": vendorID})
+					continue //try the work with next deviceId
+				}
+			}
+
+			// cancel the ONU upgrade activity for each possible device
+			if handler := oo.getDeviceHandler(ctx, loDeviceID, false); handler != nil {
+				logger.Debugw(ctx, "image upgrade abort requested", log.Fields{
+					"image-id": imageIdentifier, "device-id": loDeviceID})
+				//upgrade cancel is called synchronously to collect the imageResponse indications for all concerned devices
+				handler.cancelOnuSwUpgrade(ctx, imageIdentifier, (*in).Version, pDeviceImageState)
+			} else {
+				//cannot start ONU download for requested device
+				logger.Warnw(ctx, "no handler found for aborting upgrade ", log.Fields{"device-id": loDeviceID})
+				pDeviceImageState.DeviceId = loDeviceID
+				pDeviceImageState.ImageState.Version = (*in).Version
+				//nolint:misspell
+				pDeviceImageState.ImageState.DownloadState = voltha.ImageState_DOWNLOAD_CANCELLED
+				//nolint:misspell
+				pDeviceImageState.ImageState.Reason = voltha.ImageState_CANCELLED_ON_REQUEST
+				pDeviceImageState.ImageState.ImageState = voltha.ImageState_IMAGE_UNKNOWN
+			}
+			loResponse.DeviceImageStates = append(loResponse.DeviceImageStates, pDeviceImageState)
+		}
+		if !firstDevice {
+			//if at least one valid device was found cancel also a possibly running download to adapter and remove the image
+			//  this is to be done after the upgradeOnu cancel activities in order to not subduct the file for still running processes
+			oo.pFileManager.CancelDownload(ctx, imageIdentifier)
+		}
+		pImageResp := &loResponse
+		return pImageResp, nil
+	}
+	return nil, errors.New("invalid image upgrade abort parameters")
 }
 
 // Get_onu_images retrieves the ONU SW image status information via OMCI