firmware_Cr50Update: handle ignored posted resets

For cr50 images 0.0.19 and beyond cr50 rebooting relies on the firmware
to enable the invalid RW header. On each boot the firmware will try to
enable any invalidated RW headers and if there is an invalid one Cr50
will enable it, wait 1000ms and then reboot. Cr50 will no longer reboot
on its own after usb_update is run.

The support for enabling the invalid cr50 RW header is not in firmware
yet. This changes firmware_Cr50Update so the test not care if cr50 does
not reboot immediately after usb_update is run for rollback updates. We
force the rollback ourselves and reboot, so it is ok if cr50 does not
reboot immediately on its own.

BUG=none
BRANCH=none
TEST=build a cr50 dbg image from TOT and then use it as a 'dev_image'
while running the test.

Change-Id: Ie2acafb4e163ba2697cd4e1421f0f37daf9f2758
Signed-off-by: Mary Ruthven <mruthven@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/469075
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Reviewed-by: Tyler Reid <twreid@google.com>
diff --git a/server/cros/servo/chrome_ec.py b/server/cros/servo/chrome_ec.py
index b96b804..829420f 100644
--- a/server/cros/servo/chrome_ec.py
+++ b/server/cros/servo/chrome_ec.py
@@ -423,11 +423,12 @@
 
 
     @ccd_command
-    def wait_for_ccd_state(self, state, timeout):
+    def wait_for_ccd_state(self, state, timeout, raise_error=True):
         """Wait up to timeout seconds for CCD to be 'on' or 'off'
         Args:
             state: a string either 'on' or 'off'.
             timeout: time in seconds to wait
+            raise_error: Raise TestFail if the value is state is not reached.
 
         Raises
             TestFail if ccd never reaches the specified state
@@ -436,14 +437,17 @@
         value = utils.wait_for_value(self.get_ccd_state, state,
                                      timeout_sec=timeout)
         if value != state:
-            raise error.TestFail("timed out before detecting ccd '%s'" % state)
-        logging.info("ccd is '%s'", state)
+            error_msg = "timed out before detecting ccd '%s'" % state
+            if raise_error:
+                raise error.TestFail(error_msg)
+            logging.warning(error_msg)
+        logging.info("ccd is '%s'", value)
 
 
     @ccd_command
-    def wait_for_ccd_disable(self, timeout=60):
+    def wait_for_ccd_disable(self, timeout=60, raise_error=True):
         """Wait for the cr50 console to stop working"""
-        self.wait_for_ccd_state('off', timeout)
+        self.wait_for_ccd_state('off', timeout, raise_error)
 
 
     @ccd_command
diff --git a/server/site_tests/firmware_Cr50Update/firmware_Cr50Update.py b/server/site_tests/firmware_Cr50Update/firmware_Cr50Update.py
index 510344b..6b6f492 100644
--- a/server/site_tests/firmware_Cr50Update/firmware_Cr50Update.py
+++ b/server/site_tests/firmware_Cr50Update/firmware_Cr50Update.py
@@ -35,7 +35,7 @@
     ORIGINAL_NAME = "original_image"
     RESTORE_ORIGINAL_TRIES = 3
     SUCCESS = 0
-    UPSTART_SUCCESS = 1
+    UPDATE_OK = 1
 
 
     def initialize(self, host, cmdline_args, release_image, dev_image,
@@ -175,26 +175,30 @@
             # immediately.
             result = self.host.run("usb_updater -s -u %s" % dest,
                                    ignore_status=True)
-            # After a posted reboot, the usb_update exit code should equal 1.
-            if result.exit_status != self.UPSTART_SUCCESS:
-                logging.debug(result)
-                raise error.TestError("Got unexpected usb_update exit code")
-            # Reset the AP to finish the Cr50 update.
-            self.cr50.send_command("sysrst pulse")
         else:
             logging.info("Flashing image into inactive partition")
             # The image at 'dest' is older than the one Cr50 is running, so
             # upstart cannot be used. Without -u Cr50 will flash the image into
             # the inactive partition and reboot immediately.
             result = self.host.run("usb_updater -s %s" % dest,
+                                   ignore_status=True,
                                    ignore_timeout=True,
                                    timeout=self.UPDATE_TIMEOUT)
-            logging.info(result)
+
+        # After a posted reboot, the usb_update exit code should equal 1.
+        if result.exit_status and result.exit_status != self.UPDATE_OK:
+            logging.debug(result)
+            raise error.TestError("Got unexpected usb_update exit code %d" %
+                                  result.exit_status)
+
+        # Reset the AP to finish the Cr50 update.
+        if is_newer:
+            self.cr50.send_command("sysrst pulse")
 
         # After usb_updater finishes running, Cr50 will reboot. Wait until Cr50
         # reboots before continuing. Cr50 reboot can be detected by detecting
         # when CCD stops working.
-        self.cr50.wait_for_ccd_disable()
+        self.cr50.wait_for_ccd_disable(raise_error=is_newer)
 
 
     def finish_rollback(self, image_rw, erase_nvmem):
@@ -224,10 +228,7 @@
 
         # CCD may disapppear after resetting the EC. If it does, re-enable it.
         # TODO: remove this when CCD is no longer disabled after ec reset.
-        try:
-            self.cr50.wait_for_ccd_disable(timeout=15)
-        except error.TestFail, e:
-            pass
+        self.cr50.wait_for_ccd_disable(timeout=15, raise_error=False)
         self.cr50.ccd_enable()
 
         if erase_nvmem: