docs: def softDeactivate(rh):
      """
      Deactivate a virtual machine by first shutting down Linux and
      then log it off.
  
      Input:
         Request Handle with the following properties:
            function    - 'POWERVM'
            subfunction - 'SOFTOFF'
            userid      - userid of the virtual machine
            parms['maxQueries']     - Maximum number of queries to issue.
                                      Optional.
            parms['maxWait']        - Maximum time to wait in seconds.
                                      Optional,
                                      unless 'maxQueries' is specified.
            parms['poll']           - Polling interval in seconds. Optional,
                                      unless 'maxQueries' is specified.
  
      Output:
         Request Handle updated with the results.
         Return code - 0: ok, non-zero: error
      """
  
      rh.printSysLog("Enter powerVM.softDeactivate, userid: " +
          rh.userid)
  
      strCmd = "echo 'ping'"
      iucvResults = execCmdThruIUCV(rh, rh.userid, strCmd)
  
      if iucvResults['overallRC'] == 0:
          # We could talk to the machine, tell it to shutdown nicely.
          strCmd = "shutdown -h now"
          iucvResults = execCmdThruIUCV(rh, rh.userid, strCmd)
          if iucvResults['overallRC'] == 0:
              time.sleep(15)
          else:
              # Shutdown failed.  Let CP take down the system
              # after we log the results.
              rh.printSysLog("powerVM.softDeactivate " + rh.userid +
                  " is unreachable. Treating it as already shutdown.")
      else:
          # Could not ping the machine.  Treat it as a success
          # after we log the results.
          rh.printSysLog("powerVM.softDeactivate " + rh.userid +
              " is unreachable. Treating it as already shutdown.")
  
      # Tell z/VM to log off the system.
      parms = ["-T", rh.userid]
      smcliResults = invokeSMCLI(rh, "Image_Deactivate", parms)
      if smcliResults['overallRC'] == 0:
          pass
      elif (smcliResults['overallRC'] == 8 and smcliResults['rc'] == 200 and
          (smcliResults['rs'] == 12 or + smcliResults['rs'] == 16)):
          # Tolerable error.
          # Machine is already logged off or is logging off.
          rh.printLn("N", rh.userid + " is already logged off.")
      else:
          # SMAPI API failed.
          rh.printLn("ES", smcliResults['response'])
          rh.updateResults(smcliResults)    # Use results from invokeSMCLI
  
      if rh.results['overallRC'] == 0 and 'maxQueries' in rh.parms:
          # Wait for the system to log off.
          waitResults = waitForVMState(
              rh,
              rh.userid,
              'off',
              maxQueries=rh.parms['maxQueries'],
              sleepSecs=rh.parms['poll'])
          if waitResults['overallRC'] == 0:
              rh.printLn("N", "Userid '" + rh.userid +
                  " is in the desired state: off")
          else:
              rh.updateResults(waitResults)
  
      rh.printSysLog("Exit powerVM.softDeactivate, rc: " +
          str(rh.results['overallRC']))
      return rh.results['overallRC']