VOL-692: ADTRAN OLT: Fixes for disable, enable, and delete for latest OLT drivers

Change-Id: I73a85247fa294750bee0bd8c179213a740e88c64
diff --git a/voltha/adapters/adtran_olt/adtran_device_handler.py b/voltha/adapters/adtran_olt/adtran_device_handler.py
index 6f28504..7437611 100644
--- a/voltha/adapters/adtran_olt/adtran_device_handler.py
+++ b/voltha/adapters/adtran_olt/adtran_device_handler.py
@@ -169,13 +169,32 @@
 
         # Installed flows
         self._evcs = {}  # Flow ID/name -> FlowEntry
+ 
+
+    def _delete_logical_device(self):
+        ldi, self.logical_device_id = self.logical_device_id, None
+
+        if ldi is None:
+            return
+
+        self.log.debug('delete-logical-device', ldi=ldi)
+
+        logical_device = self.adapter_agent.get_logical_device(ldi)
+        self.adapter_agent.delete_logical_device(logical_device)
+
+        device = self.adapter_agent.get_device(self.device_id)
+        device.parent_id = ''
+
+        #  Update the logical device mapping
+        if ldi in self.adapter.logical_device_id_to_root_device_id:
+            del self.adapter.logical_device_id_to_root_device_id[ldi]
+
 
     def __del__(self):
         # Kill any startup or heartbeat defers
 
         d, self.startup = self.startup, None
         h, self.heartbeat = self.heartbeat, None
-        ldi, self.logical_device_id = self.logical_device_id, None
 
         if d is not None and not d.called:
             d.cancel()
@@ -186,10 +205,7 @@
         self._deactivate_io_port()
 
         # Remove the logical device
-
-        if ldi is not None:
-            logical_device = self.adapter_agent.get_logical_device(ldi)
-            self.adapter_agent.delete_logical_device(logical_device)
+        self._delete_logical_device()
 
         self.northbound_ports.clear()
         self.southbound_ports.clear()
@@ -478,6 +494,20 @@
                 self.alarms = AdapterAlarms(self.adapter, device.id)
 
                 ############################################################################
+                # Set the ports in a known good initial state
+                if not reconciling:
+                    try:
+                        for port in self.northbound_ports.itervalues():
+                            self.startup = yield port.reset()
+
+                        for port in self.southbound_ports.itervalues():
+                            self.startup = yield port.reset()
+
+                    except Exception as e:
+                        self.log.exception('port-reset', e=e)
+                        self.activate_failed(device, e.message)
+
+                ############################################################################
                 # Create logical ports for all southbound and northbound interfaces
                 try:
                     device.reason = 'Creating logical ports'
@@ -668,22 +698,14 @@
                 if lp is not None:
                     self.adapter_agent.add_logical_port(ld_initialized.id, lp)
 
-            # Set the ports in a known good initial state
-            try:
-                for port in self.northbound_ports.itervalues():
-                    self.startup = yield port.reset()
-
-                for port in self.southbound_ports.itervalues():
-                    self.startup = yield port.reset()
-
-            except Exception as e:
-                self.log.exception('port-reset', e=e)
-                self.activate_failed(device, e.message)
-
             # Clean up all EVCs, EVC maps and ACLs (exceptions are ok)
             try:
                 from flow.evc import EVC
                 self.startup = yield EVC.remove_all(self.netconf_client)
+                from flow.utility_evc import UtilityEVC
+                self.startup = yield UtilityEVC.remove_all(self.netconf_client)
+                from flow.untagged_evc import UntaggedEVC
+                self.startup = yield UntaggedEVC.remove_all(self.netconf_client)
 
             except Exception as e:
                 self.log.exception('evc-cleanup', e=e)
@@ -695,13 +717,17 @@
             except Exception as e:
                 self.log.exception('evc-map-cleanup', e=e)
 
+            from flow.acl import ACL
+            ACL.clear_all(device.id)
             try:
-                from flow.acl import ACL
                 self.startup = yield ACL.remove_all(self.netconf_client)
 
             except Exception as e:
                 self.log.exception('acl-cleanup', e=e)
 
+            from flow.flow_entry import FlowEntry
+            FlowEntry.clear_all(device.id)
+
         # Start/stop the interfaces as needed. These are deferred calls
 
         dl = []
@@ -856,13 +882,6 @@
         device.connect_status = ConnectStatus.UNREACHABLE
         self.adapter_agent.update_device(device)
 
-        # Remove the logical device
-        ldi, self.logical_device_id = self.logical_device_id, None
-
-        if ldi is not None:
-            logical_device = self.adapter_agent.get_logical_device(ldi)
-            self.adapter_agent.delete_logical_device(logical_device)
-
         # Disable all child devices first
         self.adapter_agent.update_child_devices_state(self.device_id,
                                                       admin_state=AdminState.DISABLED)
@@ -870,6 +889,9 @@
         # Remove the peer references from this device
         self.adapter_agent.delete_all_peer_references(self.device_id)
 
+        # Remove the logical device
+        self._delete_logical_device()
+
         # Set all ports to disabled
         self.adapter_agent.disable_all_ports(self.device_id)
 
@@ -898,10 +920,6 @@
         self.startup.addCallbacks(_drop_netconf, _null_clients)
         self.startup.addCallbacks(_null_clients, _null_clients)
 
-        #  Update the logical device mapping
-        if ldi in self.adapter.logical_device_id_to_root_device_id:
-            del self.adapter.logical_device_id_to_root_device_id[ldi]
-
         self.log.info('disabled', device_id=device.id)
         return self.startup
 
@@ -925,14 +943,27 @@
 
         # Update the connect status to REACHABLE
         device.connect_status = ConnectStatus.REACHABLE
+        device.oper_status = OperStatus.ACTIVATING
         self.adapter_agent.update_device(device)
 
-        # Set all ports to enabled
-        self.adapter_agent.enable_all_ports(self.device_id)
+        # Reenable any previously configured southbound ports
+        for port in self.southbound_ports.itervalues():
+            self.log.debug('reenable-checking-pon-port', pon_id=port.pon_id)
 
-        # Recreate the logical device
+            gpon_info = self.get_xpon_info(port.pon_id)
+            if gpon_info is not None and \
+                gpon_info['channel-terminations'] is not None and \
+                len(gpon_info['channel-terminations']) > 0:
 
-        ld_initialized = self.create_logical_device(device)
+                cterms = gpon_info['channel-terminations']
+                if any(term.get('enabled') for term in cterms.itervalues()):
+                    self.log.info('reenable', pon_id=port.pon_id)
+                    port.enabled = True
+
+        # Flows should not exist on re-enable. They are re-pushed
+        if len(self._evcs):
+            self.log.warn('evcs-found', evcs=self._evcs)
+        self._evcs.clear()
 
         try:
             yield self.make_restconf_connection()
@@ -946,8 +977,11 @@
         except Exception as e:
             self.log.exception('NETCONF-re-connection', e=e)
 
-        # Create logical ports for all southbound and northbound interfaces
+        # Recreate the logical device
+        # NOTE: This causes a flow update event
+        ld_initialized = self.create_logical_device(device)
 
+        # Create logical ports for all southbound and northbound interfaces
         try:
             self.startup = self.create_logical_ports(device, ld_initialized, False)
             yield self.startup
@@ -959,29 +993,14 @@
         device.parent_id = ld_initialized.id
         device.oper_status = OperStatus.ACTIVE
         device.reason = ''
-        self.adapter_agent.update_device(device)
         self.logical_device_id = ld_initialized.id
 
+        # update device active status now
+        self.adapter_agent.update_device(device)
+
         # Reenable all child devices
         self.adapter_agent.update_child_devices_state(device.id,
                                                       admin_state=AdminState.ENABLED)
-        dl = []
-
-        for port in self.northbound_ports.itervalues():
-            dl.append(port.start())
-
-        for port in self.southbound_ports.itervalues():
-            dl.append(port.start())
-
-        # Flows should not exist on re-enable. They are re-pushed
-        if len(self._evcs):
-            self.log.error('evcs-found', evcs=self._evcs)
-        self._evcs.clear()
-
-        # Wait for completion
-
-        self.startup = defer.gatherResults(dl, consumeErrors=True)
-        results = yield self.startup
 
         # Re-subscribe for ONU detection
         # self.adapter_agent.register_for_onu_detect_state(self.device.id)
@@ -997,7 +1016,7 @@
         if done_deferred is not None:
             done_deferred.callback('Done')
 
-        returnValue(results)
+        returnValue('reenabled')
 
     @inlineCallbacks
     def reboot(self):
@@ -1183,7 +1202,7 @@
         # Remove all flows from the device
         # TODO: Create a bulk remove-all by device-id
 
-        evcs = self._evcs()
+        evcs = self._evcs
         self._evcs.clear()
 
         for evc in evcs:
@@ -1192,10 +1211,8 @@
         # Remove all child devices
         self.adapter_agent.delete_all_child_devices(self.device_id)
 
-        # Remove the logical device
-        logical_device = self.adapter_agent.get_logical_device(self.logical_device_id)
-        self.adapter_agent.delete_logical_device(logical_device)
-        # TODO: For some reason, the logical device does not seem to get deleted
+        # Remove the logical device (should already be gone if disable came first)
+        self._delete_logical_device()
 
         # Remove the peer references from this device
         self.adapter_agent.delete_all_peer_references(self.device_id)
diff --git a/voltha/adapters/adtran_olt/adtran_olt_handler.py b/voltha/adapters/adtran_olt/adtran_olt_handler.py
index 96acf0f..1f21602 100644
--- a/voltha/adapters/adtran_olt/adtran_olt_handler.py
+++ b/voltha/adapters/adtran_olt/adtran_olt_handler.py
@@ -522,12 +522,19 @@
                 except:
                     pass
 
+    def _unregister_for_inter_adapter_messages(self):
+        try:
+            self.adapter_agent.unregister_for_inter_adapter_messages()
+        except:
+            pass
+
     def disable(self):
         self._cancel_deferred()
 
         # Drop registration for adapter messages
-        self.adapter_agent.unregister_for_inter_adapter_messages()
+        self._unregister_for_inter_adapter_messages()
         self._zmq_shutdown()
+        self._pio_exception_map = []
 
         super(AdtranOltHandler, self).disable()
 
@@ -546,7 +553,7 @@
         self._cancel_deferred()
 
         # Drop registration for adapter messages
-        self.adapter_agent.unregister_for_inter_adapter_messages()
+        self._unregister_for_inter_adapter_messages()
         self._zmq_shutdown()
 
         # Download supported protocols may change (if new image gets activated)
@@ -572,7 +579,7 @@
         self._cancel_deferred()
 
         # Drop registration for adapter messages
-        self.adapter_agent.unregister_for_inter_adapter_messages()
+        self._unregister_for_inter_adapter_messages()
         self._zmq_shutdown()
 
         super(AdtranOltHandler, self).delete()
@@ -850,22 +857,23 @@
 
         valid_flows = []
 
-        # Special helper egress Packet In/Out flows
-        for special_flow in (self._create_untagged_flow(),
-                             self._create_utility_flow()):
-            valid_flow, evc = FlowEntry.create(special_flow, self)
+        if flows:
+            # Special helper egress Packet In/Out flows
+            for special_flow in (self._create_untagged_flow(),
+                                 self._create_utility_flow()):
+                valid_flow, evc = FlowEntry.create(special_flow, self)
 
-            if valid_flow is not None:
-                valid_flows.append(valid_flow.flow_id)
+                if valid_flow is not None:
+                    valid_flows.append(valid_flow.flow_id)
 
-            if evc is not None:
-                try:
-                    evc.schedule_install()
-                    self.add_evc(evc)
+                if evc is not None:
+                    try:
+                        evc.schedule_install()
+                        self.add_evc(evc)
 
-                except Exception as e:
-                    evc.status = 'EVC Install Exception: {}'.format(e.message)
-                    self.log.exception('EVC-install', e=e)
+                    except Exception as e:
+                        evc.status = 'EVC Install Exception: {}'.format(e.message)
+                        self.log.exception('EVC-install', e=e)
 
         # verify exception flows were installed by OLT PET process
         reactor.callLater(5, self.send_packet_exceptions_request)
diff --git a/voltha/adapters/adtran_olt/flow/acl.py b/voltha/adapters/adtran_olt/flow/acl.py
index 170d997..b2dc21f 100644
--- a/voltha/adapters/adtran_olt/flow/acl.py
+++ b/voltha/adapters/adtran_olt/flow/acl.py
@@ -290,6 +290,15 @@
         raise NotImplemented("TODO: Implement this")
 
     @staticmethod
+    def clear_all(device_id):
+        """
+        Clear all acls for this device id from the list
+        :param device_id: id of the device
+        """
+        if device_id in _acl_list:
+            del _acl_list[device_id]
+
+    @staticmethod
     def remove_all(client, regex_=ACL_NAME_REGEX_ALL):
         """
         Remove all matching ACLs from hardware
diff --git a/voltha/adapters/adtran_olt/flow/evc_map.py b/voltha/adapters/adtran_olt/flow/evc_map.py
index 17228d1..f873271 100644
--- a/voltha/adapters/adtran_olt/flow/evc_map.py
+++ b/voltha/adapters/adtran_olt/flow/evc_map.py
@@ -551,7 +551,7 @@
 
                         # Scan EVC to see if it needs to move back to the Utility
                         # or Untagged EVC from a user data EVC
-                        if not self._evc.service_evc and\
+                        if self._evc and not self._evc.service_evc and\
                             len(self._flows) > 0 and\
                             all(f.is_acl_flow for f in self._flows.itervalues()):
 
@@ -796,4 +796,4 @@
             if d is not None and not d.called:
                 d.cancel()
         except:
-            pass
\ No newline at end of file
+            pass
diff --git a/voltha/adapters/adtran_olt/flow/flow_entry.py b/voltha/adapters/adtran_olt/flow/flow_entry.py
index 993eb38..7575be8 100644
--- a/voltha/adapters/adtran_olt/flow/flow_entry.py
+++ b/voltha/adapters/adtran_olt/flow/flow_entry.py
@@ -595,20 +595,8 @@
                 del _existing_upstream_flow_entries[device_id]
 
         elif self.flow_direction == FlowEntry.FlowDirection.DOWNSTREAM:
-            flow_evc = flow_table['evc']
-
-            # If this flow owns the EVC, assign it to a remaining flow
-            if flow_evc is not None and flow_id == flow_evc.flow_entry.flow_id:
-                flow_table['evc'].flow_entry = next((_flow for _flow in flow_table.itervalues()
-                                                     if isinstance(_flow, FlowEntry)
-                                                     and _flow.flow_id != flow_id), None)
-
             if len(flow_table) == 1:   # Only 'evc' entry present
-                evc = flow_evc
-                del flow_table['evc']
-                del sig_table[self.signature]
-                if len(sig_table) == 0:
-                    del _existing_downstream_flow_entries[device_id]
+                evc = flow_table['evc']
             else:
                 assert flow_table['evc'] is not None, 'EVC flow re-assignment error'
 
@@ -626,6 +614,24 @@
         except Exception as e:
             log.exception('removal', e=e)
 
+        if self.flow_direction == FlowEntry.FlowDirection.DOWNSTREAM:
+
+            # If this flow owns the EVC, assign it to a remaining flow
+            flow_evc = flow_table['evc']
+
+            if flow_evc is not None and flow_evc.flow_entry is not None and \
+                flow_id == flow_evc.flow_entry.flow_id:
+                flow_table['evc'].flow_entry = next((_flow for _flow in flow_table.itervalues()
+                                                     if isinstance(_flow, FlowEntry)
+                                                     and _flow.flow_id != flow_id), None)
+
+        # If evc was deleted, remove the flow table reference
+        if evc is not None:
+            del flow_table['evc']
+            del sig_table[self.signature]
+            if len(sig_table) == 0:
+                del _existing_downstream_flow_entries[device_id]
+
         self.evc = None
         returnValue('Done')
 
@@ -680,13 +686,19 @@
     # Bulk operations
 
     @staticmethod
-    def remove_all():
+    def clear_all(device_id):
         """
-        Remove all matching EVCs and associated EVC MAPs from hardware
+        Remove all flows for the device.
 
-        :param regex_: (String) Regular expression for name matching
+        :param device_id: voltha adapter device id
         """
-        raise NotImplemented("TODO: Implement this")
+
+        if device_id in _existing_downstream_flow_entries:
+            del _existing_downstream_flow_entries[device_id]
+
+        if device_id in _existing_upstream_flow_entries:
+            del _existing_upstream_flow_entries[device_id]
+
 
     @staticmethod
     def get_packetout_info(device_id, logical_port):
diff --git a/voltha/adapters/adtran_olt/flow/untagged_evc.py b/voltha/adapters/adtran_olt/flow/untagged_evc.py
index 3a4a3dc..98f267a 100644
--- a/voltha/adapters/adtran_olt/flow/untagged_evc.py
+++ b/voltha/adapters/adtran_olt/flow/untagged_evc.py
@@ -98,7 +98,6 @@
     def remove_downstream_flows(self, flow_id):
         self._downstream_flows.discard(flow_id)
 
-    @inlineCallbacks
     def remove(self, remove_maps=True):
         """
         Remove EVC (and optional associated EVC-MAPs) from hardware
@@ -108,21 +107,22 @@
         log.info('removing', evc=self, remove_maps=remove_maps)
 
         device_id = self._flow.handler.device_id
-        flow_id = self._flow.id
+        flow_id = self._flow.flow_id
         evc_table = _untagged_evcs.get(device_id)
 
-        if evc_table is None or flow_id not in evc_table:
-            returnValue('NOP')
+        if evc_table is None:
+            return defer.succeed('NOP')
+
 
         # Remove flow reference
         if self._flow.flow_id in self._downstream_flows:
-            del self._downstream_flows[self._flow.flow_id]
+            self._downstream_flows.discard(self._flow.flow_id)
 
         if len(self._downstream_flows) == 0:
             # Use base class to clean up
-            returnValue(super(UntaggedEVC, self).remove(remove_maps=True))
+            return super(UntaggedEVC, self).remove(remove_maps=True)
 
-        returnValue('More references')
+        return defer.succeed('More references')
 
     @inlineCallbacks
     def delete(self, delete_maps=True):
@@ -140,13 +140,14 @@
 
             yield defer.gatherResults(dl, consumeErrors=True)
 
+            self._evc_maps = None
+            f, self._flow = self._flow, None
+            if f is not None and f.handler is not None:
+                f.handler.remove_evc(self)
+
         except Exception as e:
             log.exception('removal', e=e)
 
-        self._evc_maps = None
-        f, self._flow = self._flow, None
-        if f is not None and f.handler is not None:
-            f.handler.remove_evc(self)
 
     def reflow(self, reflow_maps=True):
         pass    # TODO: Implement or use base class?
@@ -159,4 +160,5 @@
         :param regex_: (String) Regular expression for name matching
         :return: (deferred)
         """
-        pass    # TODO: ???
+        _untagged_evcs.clear()
+        EVC.remove_all(client, regex_)
diff --git a/voltha/adapters/adtran_olt/flow/utility_evc.py b/voltha/adapters/adtran_olt/flow/utility_evc.py
index 60a463a..2317b2a 100644
--- a/voltha/adapters/adtran_olt/flow/utility_evc.py
+++ b/voltha/adapters/adtran_olt/flow/utility_evc.py
@@ -95,7 +95,6 @@
     def remove_downstream_flows(self, flow_id):
         self._downstream_flows.discard(flow_id)
 
-    @inlineCallbacks
     def remove(self, remove_maps=True):
         """
         Remove EVC (and optional associated EVC-MAPs) from hardware
@@ -105,26 +104,27 @@
         log.info('removing', evc=self, remove_maps=remove_maps)
 
         device_id = self._flow.handler.device_id
-        flow_id = self._flow.id
+        flow_id = self._flow.flow_id
         evc_table = _utility_evcs.get(device_id)
 
-        if evc_table is None or flow_id not in evc_table:
-            returnValue('NOP')
+        if evc_table is None:
+            return defer.succeed('NOP')
 
         # Remove flow reference
         if self._flow.flow_id in self._downstream_flows:
-            del self._downstream_flows[self._flow.flow_id]
+            self._downstream_flows.discard(self._flow.flow_id)
 
         if len(self._downstream_flows) == 0:
             # Use base class to clean up
-            returnValue(super(UtilityEVC, self).remove(remove_maps=True))
+            return super(UtilityEVC, self).remove(remove_maps=True)
 
-        returnValue('More references')
+        return defer.succeed('More references')
 
     @inlineCallbacks
     def delete(self, delete_maps=True):
         """
         Remove from hardware and delete/clean-up EVC Object
+        :return: (deferred)
         """
         log.info('deleting', evc=self, delete_maps=delete_maps)
 
@@ -137,13 +137,15 @@
 
             yield defer.gatherResults(dl, consumeErrors=True)
 
+            self._evc_maps = None
+            f, self._flow = self._flow, None
+            if f is not None and f.handler is not None:
+                f.handler.remove_evc(self)
+
         except Exception as e:
             log.exception('removal', e=e)
 
-        self._evc_maps = None
-        f, self._flow = self._flow, None
-        if f is not None and f.handler is not None:
-            f.handler.remove_evc(self)
+        returnValue('Done')
 
     def reflow(self, reflow_maps=True):
         pass    # TODO: Implement or use base class?
@@ -156,4 +158,5 @@
         :param regex_: (String) Regular expression for name matching
         :return: (deferred)
         """
-        pass    # TODO: ???
+        _utility_evcs.clear()
+        EVC.remove_all(client, regex_)
\ No newline at end of file
diff --git a/voltha/adapters/adtran_olt/nni_port.py b/voltha/adapters/adtran_olt/nni_port.py
index e836004..fac91de 100644
--- a/voltha/adapters/adtran_olt/nni_port.py
+++ b/voltha/adapters/adtran_olt/nni_port.py
@@ -93,12 +93,23 @@
         Get the VOLTHA PORT object for this port
         :return: VOLTHA Port object
         """
+        self.log.debug('get-port-status-update', port=self._port_no,
+            label=self._label)
         if self._port is None:
             self._port = Port(port_no=self._port_no,
                               label=self._label,
                               type=Port.ETHERNET_NNI,
                               admin_state=self._admin_state,
                               oper_status=self._oper_status)
+
+        if self._port.admin_state != self._admin_state or\
+           self._port.oper_status != self._oper_status:
+
+            self.log.debug('get-port-status-update', admin_state=self._admin_state,
+                oper_status = self._oper_status)
+            self._port.admin_state = self._admin_state
+            self._port.oper_status = self._oper_status
+
         return self._port
 
     @property
@@ -116,9 +127,10 @@
             pass
 
     def _update_adapter_agent(self):
-        # TODO: Currently the adapter_agent does not allow 'update' of port status
-        # self.adapter_agent.update_port(self.olt.device_id, self.get_port())
-        pass
+        # adapter_agent add_port also does an update of port status
+        self.log.debug('update-adapter-agent', admin_state=self._admin_state,
+            oper_status=self._oper_status)
+        self.adapter_agent.add_port(self.olt.device_id, self.get_port())
 
     def get_logical_port(self):
         """
@@ -150,9 +162,9 @@
         if self.state != AdtnPort.State.INITIAL:
             returnValue('Done')
 
+        self.log.debug('final-startup')
         # TODO: Start status polling of NNI interfaces
         self.deferred = None  # = reactor.callLater(3, self.do_stuff)
-        self.state = AdtnPort.State.RUNNING
 
         # Begin statistics sync
         self._stats_deferred = reactor.callLater(self._stats_tick * 2, self._update_statistics)
@@ -182,9 +194,9 @@
         Set the NNI Port to a known good state on initial port startup.  Actual
         NNI 'Start' is done elsewhere
         """
-        if self.state != AdtnPort.State.INITIAL:
-            self.log.error('reset-ignored', state=self.state)
-            returnValue('Ignored')
+        #if self.state != AdtnPort.State.INITIAL:
+        #    self.log.error('reset-ignored', state=self.state)
+        #    returnValue('Ignored')
 
         self.log.info('resetting', label=self._label)
 
@@ -251,7 +263,11 @@
                 self.log.debug('read-config', results=results)
                 try:
                     result_dict = xmltodict.parse(results.data_xml)
-                    entries = result_dict['data']['interfaces']['interface']
+                    interfaces = result_dict['data']['interfaces']
+                    if 'if:interface' in interfaces:
+                        entries = interfaces['if:interface']
+                    else:
+                        entries = interfaces['interface']
 
                     enabled = entries.get('enabled',
                                           str(not self.enabled).lower()) == 'true'
diff --git a/voltha/adapters/adtran_olt/pon_port.py b/voltha/adapters/adtran_olt/pon_port.py
index bb02379..e3d0e48 100644
--- a/voltha/adapters/adtran_olt/pon_port.py
+++ b/voltha/adapters/adtran_olt/pon_port.py
@@ -101,11 +101,9 @@
             self._port = Port(port_no=self._port_no,
                               label=self._label,
                               type=Port.PON_OLT,
-                              admin_state=AdminState.ENABLED,
-                              oper_status=OperStatus.ACTIVE)
-            # TODO: For now, no way to report the proper ADMIN or OPER status
-            # admin_state=self._admin_state,
-            # oper_status=self._oper_status)
+                              admin_state=self._admin_state,
+                              oper_status=self._oper_status)
+
         return self._port
 
     @property
@@ -286,9 +284,30 @@
             pass
 
     def _update_adapter_agent(self):
-        # TODO: Currently the adapter_agent does not allow 'update' of port status
-        # self.adapter_agent.update_port(self.olt.device_id, self.get_port())
-        pass
+        """
+        Update the port status and state in the core
+        """
+        self.log.debug('update-adapter-agent', admin_state=self._admin_state,
+            oper_status=self._oper_status)
+
+        # because the core does not provide methods for updating admin
+        # and oper status per port, we need to copy any existing port
+        # info so that we don't wipe out the peers
+        if self._port is not None:
+            agent_ports = self.adapter_agent.get_ports(self.olt.device_id, Port.PON_OLT)
+
+            agent_port = next((ap for ap in agent_ports if ap.port_no == self._port_no), None)
+
+            # copy current Port info
+            if agent_port is not None:
+                self._port = agent_port;
+
+        # set new states
+        self._port.admin_state = self._admin_state
+        self._port.oper_status = self._oper_status
+
+        # adapter_agent add_port also does an update of existing port
+        self.adapter_agent.add_port(self.olt.device_id, self.get_port())
 
     @inlineCallbacks
     def finish_startup(self):
@@ -399,9 +418,9 @@
         Set the PON Port to a known good state on initial port startup.  Actual
         PON 'Start' is done elsewhere
         """
-        if self.state != AdtnPort.State.INITIAL:
-            self.log.error('reset-ignored', state=self.state)
-            returnValue('Ignored')
+        #if self.state != AdtnPort.State.INITIAL:
+        #    self.log.error('reset-ignored', state=self.state)
+        #    returnValue('Ignored')
 
         initial_port_state = AdminState.DISABLED
         self.log.info('reset', initial_state=initial_port_state)
diff --git a/voltha/adapters/adtran_olt/port.py b/voltha/adapters/adtran_olt/port.py
index f0b8b36..5a0a025 100644
--- a/voltha/adapters/adtran_olt/port.py
+++ b/voltha/adapters/adtran_olt/port.py
@@ -174,7 +174,7 @@
         if self.state == AdtnPort.State.RUNNING:
             return succeed('Running')
 
-        self.log.info('start')
+        self.log.info('start-port')
 
         self.cancel_deferred()
         self.state = AdtnPort.State.INITIAL