[VOL-4900] openonuAdapterGo: Suppress OMCI timeout device event if OLT is not available

Change-Id: I05959e169abd7b022b8627a96a8ee509b9fdd5a8
diff --git a/VERSION b/VERSION
index e70b452..24ba9a3 100755
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.6.0
+2.7.0
diff --git a/internal/pkg/common/interfaces.go b/internal/pkg/common/interfaces.go
index 3268564..728d10e 100755
--- a/internal/pkg/common/interfaces.go
+++ b/internal/pkg/common/interfaces.go
@@ -88,6 +88,7 @@
 
 	SetReadyForOmciConfig(bool)
 	IsReadyForOmciConfig() bool
+	IsOltAvailable() bool
 
 	StorePersistentData(context.Context) error
 	StorePersUniFlowConfig(context.Context, uint8, *[]UniVlanFlowParams, bool) error
diff --git a/internal/pkg/common/omci_cc.go b/internal/pkg/common/omci_cc.go
index 8726eb3..6dbddbd 100755
--- a/internal/pkg/common/omci_cc.go
+++ b/internal/pkg/common/omci_cc.go
@@ -4463,9 +4463,14 @@
 			break loop
 		case <-time.After(time.Duration(aTimeout) * time.Second):
 			if retryCounter == retries {
-				logger.Errorw(ctx, "reqMon: timeout waiting for response - no of max retries reached - send ONU device event!",
-					log.Fields{"tid": tid, "retries": retryCounter, "device-id": oo.deviceID})
-				oo.pOnuDeviceEntry.SendOnuDeviceEvent(ctx, OnuOmciCommunicationFailureSwUpgrade, OnuOmciCommunicationFailureSwUpgradeDesc)
+				if oo.pBaseDeviceHandler.IsOltAvailable() {
+					logger.Errorw(ctx, "reqMon: timeout waiting for response - no of max retries reached - send ONU device event!",
+						log.Fields{"tid": tid, "retries": retryCounter, "device-id": oo.deviceID})
+					oo.pOnuDeviceEntry.SendOnuDeviceEvent(ctx, OnuOmciCommunicationFailureSwUpgrade, OnuOmciCommunicationFailureSwUpgradeDesc)
+				} else {
+					logger.Errorw(ctx, "reqMon: timeout waiting for response - no of max retries reached - skip ONU device event: OLT unavailable!",
+						log.Fields{"tid": tid, "retries": retryCounter, "device-id": oo.deviceID})
+				}
 				oo.incrementTxTimesouts()
 				break loop
 			} else {
@@ -4966,9 +4971,14 @@
 			break loop
 		case <-time.After(time.Duration(aTimeout) * time.Second):
 			if retryCounter == retries {
-				logger.Errorw(ctx, "reqMon: timeout waiting for response - no of max retries reached - send ONU device event!",
-					log.Fields{"tid": tid, "retries": retryCounter, "device-id": oo.deviceID})
-				oo.pOnuDeviceEntry.SendOnuDeviceEvent(ctx, OnuOmciCommunicationFailureConfig, OnuOmciCommunicationFailureConfigDesc)
+				if oo.pBaseDeviceHandler.IsOltAvailable() {
+					logger.Errorw(ctx, "reqMon: timeout waiting for response - no of max retries reached - send ONU device event!",
+						log.Fields{"tid": tid, "retries": retryCounter, "device-id": oo.deviceID})
+					oo.pOnuDeviceEntry.SendOnuDeviceEvent(ctx, OnuOmciCommunicationFailureConfig, OnuOmciCommunicationFailureConfigDesc)
+				} else {
+					logger.Errorw(ctx, "reqMon: timeout waiting for response - no of max retries reached - skip ONU device event: OLT unavailable!",
+						log.Fields{"tid": tid, "retries": retryCounter, "device-id": oo.deviceID})
+				}
 				oo.incrementTxTimesouts()
 				break loop
 			} else {
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index 744834a..5910f5f 100755
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -55,6 +55,8 @@
 	oop "github.com/opencord/voltha-protos/v5/go/openolt"
 	"github.com/opencord/voltha-protos/v5/go/tech_profile"
 	"github.com/opencord/voltha-protos/v5/go/voltha"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
 )
 
 const (
@@ -224,9 +226,11 @@
 	flowCbChan                     []chan FlowCb
 	mutexFlowMonitoringRoutineFlag sync.RWMutex
 	mutexForDisableDeviceRequested sync.RWMutex
+	mutexOltAvailable              sync.RWMutex
 	stopFlowMonitoringRoutine      []chan bool // length of slice equal to number of uni ports
 	isFlowMonitoringRoutineActive  []bool      // length of slice equal to number of uni ports
 	disableDeviceRequested         bool        // this flag identify ONU received disable request or not
+	oltAvailable                   bool
 }
 
 //newDeviceHandler creates a new device handler
@@ -261,6 +265,7 @@
 	dh.reconcilingReasonUpdate = false
 	dh.reconcilingFirstPass = true
 	dh.disableDeviceRequested = false
+	dh.oltAvailable = false
 	dh.chReconcilingFinished = make(chan bool)
 	dh.reconcileExpiryComplete = adapter.maxTimeoutReconciling //assumption is to have it as duration in s!
 	rECSeconds := int(dh.reconcileExpiryComplete / time.Second)
@@ -4422,12 +4427,16 @@
 	}
 	subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), dh.config.MaxTimeoutInterAdapterComm)
 	defer cancel()
+	dh.setOltAvailable(true)
 	logger.Debugw(subCtx, "send-omci-request", log.Fields{"device-id": dh.device.Id, "request": request, "parent-endpoint": parentEndpoint})
 	_, err = pgClient.ProxyOmciRequest(subCtx, request)
 	if err != nil {
+		if status.Code(err) == codes.Unavailable {
+			dh.setOltAvailable(false)
+		}
 		logger.Errorw(ctx, "omci-failure",
 			log.Fields{"device-id": dh.device.Id, "request": request, "error": err, "request-parent": request.ParentDeviceId,
-				"request-child": request.ChildDeviceId, "request-proxy": request.ProxyAddress})
+				"request-child": request.ChildDeviceId, "request-proxy": request.ProxyAddress, "oltAvailable": dh.IsOltAvailable})
 	}
 	return err
 }
@@ -4602,6 +4611,19 @@
 	return dh.device
 }
 
+func (dh *deviceHandler) setOltAvailable(value bool) {
+	dh.mutexOltAvailable.Lock()
+	dh.oltAvailable = value
+	dh.mutexOltAvailable.Unlock()
+}
+
+// IsOltAvailable - TODO: add comment
+func (dh *deviceHandler) IsOltAvailable() bool {
+	dh.mutexOltAvailable.RLock()
+	defer dh.mutexOltAvailable.RUnlock()
+	return dh.oltAvailable
+}
+
 // GetMetricsEnabled - TODO: add comment
 func (dh *deviceHandler) GetMetricsEnabled() bool {
 	return dh.pOpenOnuAc.MetricsEnabled