Adtran ONU: Allow 0xFF to also specify an unallocated alloc-id
and fix to SFU which needs older style vlan filter ME

Change-Id: I2caa11a3c8bdc4a09840afff55c5662a803d3000
diff --git a/voltha/adapters/adtran_onu/adtran_onu.py b/voltha/adapters/adtran_onu/adtran_onu.py
index b573137..c5288b0 100755
--- a/voltha/adapters/adtran_onu/adtran_onu.py
+++ b/voltha/adapters/adtran_onu/adtran_onu.py
@@ -41,8 +41,8 @@
                                                config=config,
                                                device_handler_class=AdtranOnuHandler,
                                                name='adtran_onu',
-                                               vendor='Adtran Inc.',
-                                               version='1.20',
+                                               vendor='ADTRAN, Inc.',
+                                               version='1.21',
                                                device_type='adtran_onu',
                                                vendor_id='ADTN',
                                                accepts_add_remove_flow_updates=False),  # TODO: Support flow-mods
diff --git a/voltha/adapters/adtran_onu/omci/adtn_mib_download_task.py b/voltha/adapters/adtran_onu/omci/adtn_mib_download_task.py
index 5b852a1..2b2853f 100644
--- a/voltha/adapters/adtran_onu/omci/adtn_mib_download_task.py
+++ b/voltha/adapters/adtran_onu/omci/adtn_mib_download_task.py
@@ -68,7 +68,7 @@
                                                   omci_agent,
                                                   handler.device_id,
                                                   priority=AdtnMibDownloadTask.task_priority,
-                                                  exclusive=True)
+                                                  exclusive=False)
         self._handler = handler
         self._onu_device = omci_agent.get_device(handler.device_id)
         self._local_deferred = None
@@ -270,13 +270,13 @@
             #
             # Set anything, this request will not be used when using Extended Vlan
 
-            # frame = VlanTaggingFilterDataFrame(
-            #     self._mac_bridge_port_ani_entity_id,  # Entity ID
-            #     vlan_tcis=[self._vlan_tcis_1],        # VLAN IDs
-            #     forward_operation=0x10
-            # ).create()
-            # results = yield omci_cc.send(frame)
-            # self.check_status_and_state(results, 'create-vlan-tagging-filter-data')
+            frame = VlanTaggingFilterDataFrame(
+                self._mac_bridge_port_ani_entity_id,  # Entity ID
+                vlan_tcis=[self._vlan_tcis_1],        # VLAN IDs
+                forward_operation=0x00
+            ).create()
+            results = yield omci_cc.send(frame)
+            self.check_status_and_state(results, 'create-vlan-tagging-filter-data')
 
             #############################################################
             # Create GalEthernetProfile - Once per ONU/PON interface
diff --git a/voltha/adapters/adtran_onu/omci/adtn_service_download_task.py b/voltha/adapters/adtran_onu/omci/adtn_service_download_task.py
index e2e6b54..209dcd8 100644
--- a/voltha/adapters/adtran_onu/omci/adtn_service_download_task.py
+++ b/voltha/adapters/adtran_onu/omci/adtn_service_download_task.py
@@ -56,6 +56,7 @@
     default_tpid = 0x8100                       # TODO: Move to a better location
     name = "ADTRAN Service Download Task"
     free_tcont_alloc_id = 0xFFFF
+    free_gpon_tcont_alloc_id = 0xFF
 
     def __init__(self, omci_agent, handler):
         """
@@ -68,7 +69,7 @@
                                                       omci_agent,
                                                       handler.device_id,
                                                       priority=AdtnServiceDownloadTask.task_priority,
-                                                      exclusive=True)
+                                                      exclusive=False)
         self._handler = handler
         self._onu_device = omci_agent.get_device(handler.device_id)
         self._local_deferred = None
@@ -213,17 +214,21 @@
 
             for tcont in self._pon.tconts.itervalues():
                 if tcont.entity_id is None:
+                    free_ids = {AdtnServiceDownloadTask.free_tcont_alloc_id,
+                                AdtnServiceDownloadTask.free_gpon_tcont_alloc_id}
+
                     free_entity_id = next((k for k, v in tcont_idents.items()
                                            if isinstance(k, int) and
-                                           v.get('attributes', {}).get('alloc_id', 0) ==
-                                           AdtnServiceDownloadTask.free_tcont_alloc_id), None)
+                                           v.get('attributes', {}).get('alloc_id', 0) in
+                                           free_ids), None)
 
                     if free_entity_id is None:
                         self.log.error('no-available-tconts')
                         raise ServiceResourcesFailure('No Available TConts')
 
                     try:
-                        yield tcont.add_to_hardware(omci_cc, free_entity_id)
+                        prev_alloc_id = tcont_idents[free_entity_id].get('attributes').get('alloc_id')
+                        yield tcont.add_to_hardware(omci_cc, free_entity_id, prev_alloc_id=prev_alloc_id)
 
                     except Exception as e:
                         self.log.exception('tcont-set', e=e, eid=free_entity_id)
diff --git a/voltha/adapters/adtran_onu/omci/omci.py b/voltha/adapters/adtran_onu/omci/omci.py
index a72a991..6690aba 100644
--- a/voltha/adapters/adtran_onu/omci/omci.py
+++ b/voltha/adapters/adtran_onu/omci/omci.py
@@ -86,6 +86,10 @@
         self._subscribe_to_events()
         self._onu_omci_device.start()
 
+        device = self._handler.adapter_agent.get_device(self._handler.device_id)
+        device.reason = 'Performing MIB Upload'
+        self._handler.adapter_agent.update_device(device)
+
         if self._onu_omci_device.mib_db_in_sync:
             self._deferred = reactor.callLater(0, self._mib_in_sync)
 
@@ -175,7 +179,7 @@
         device = self._handler.adapter_agent.get_device(self._handler.device_id)
         device.oper_status = OperStatus.ACTIVE
         device.connect_status = ConnectStatus.REACHABLE
-        device.reason = 'MIB Synchronization complete'
+        device.reason = ''
         self._handler.adapter_agent.update_device(device)
 
         omci_dev = self._onu_omci_device
@@ -325,6 +329,10 @@
             self._mib_download_task = None
 
             def success(_results):
+                device = self._handler.adapter_agent.get_device(self._handler.device_id)
+                device.reason = ''
+                self._handler.adapter_agent.update_device(device)
+
                 if self._mib_downloaded:
                     self._service_downloaded = True
                 else:
@@ -337,13 +345,21 @@
             def failure(reason):
                 self.log.error('mib-download-failure', reason=reason)
                 self._mib_download_task = None
+                device = self._handler.adapter_agent.get_device(self._handler.device_id)
+                self._handler.adapter_agent.update_device(device)
                 self._mib_download_deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
                                                                 self.capabilities_handler,
                                                                 None, None)
             if not self._mib_downloaded:
+                device = self._handler.adapter_agent.get_device(self._handler.device_id)
+                device.reason = 'Initial MIB Download'
+                self._handler.adapter_agent.update_device(device)
                 self._mib_download_task = AdtnMibDownloadTask(self.omci_agent,
                                                               self._handler)
             elif not self._service_downloaded:
+                device = self._handler.adapter_agent.get_device(self._handler.device_id)
+                device.reason = 'Initial Service Download'
+                self._handler.adapter_agent.update_device(device)
                 self._mib_download_task = AdtnServiceDownloadTask(self.omci_agent,
                                                                   self._handler)
             if self._mib_download_task is not None:
diff --git a/voltha/adapters/adtran_onu/onu_tcont.py b/voltha/adapters/adtran_onu/onu_tcont.py
index f89829f..1f24b76 100644
--- a/voltha/adapters/adtran_onu/onu_tcont.py
+++ b/voltha/adapters/adtran_onu/onu_tcont.py
@@ -26,12 +26,14 @@
     Adtran ONU specific implementation
     """
     free_tcont_alloc_id = 0xFFFF
+    free_gpon_tcont_alloc_id = 0xFF     # SFU may use this to indicate a free TCONT
 
     def __init__(self, handler, alloc_id, traffic_descriptor, name=None):
         super(OnuTCont, self).__init__(alloc_id, traffic_descriptor, name=name)
         self._handler = handler
         self._entity_id = None
         self.log = structlog.get_logger(device_id=handler.device_id, alloc_id=alloc_id)
+        self._free_alloc_id = OnuTCont.free_tcont_alloc_id
 
     @property
     def entity_id(self):
@@ -44,7 +46,7 @@
         return OnuTCont(handler, tcont['alloc-id'], td, name=tcont['name'])
 
     @inlineCallbacks
-    def add_to_hardware(self, omci, tcont_entity_id):
+    def add_to_hardware(self, omci, tcont_entity_id, prev_alloc_id=OnuTCont.free_tcont_alloc_id):
         self.log.debug('add-to-hardware', tcont_entity_id=tcont_entity_id)
 
         if self._entity_id == tcont_entity_id:
@@ -54,6 +56,7 @@
             raise KeyError('TCONT already assigned: {}'.format(self.entity_id))
 
         try:
+            self._free_alloc_id = prev_alloc_id
             frame = TcontFrame(tcont_entity_id, self.alloc_id).set()
             results = yield omci.send(frame)
 
@@ -78,7 +81,7 @@
     def remove_from_hardware(self, omci):
         self.log.debug('remove-from-hardware', tcont_entity_id=self.entity_id)
         try:
-            frame = TcontFrame(self.entity_id, OnuTCont.free_tcont_alloc_id).set()
+            frame = TcontFrame(self.entity_id, self._free_alloc_id).set()
             results = yield omci.send(frame)
 
             status = results.fields['omci_message'].fields['success_code']