text: /*
   * Copyright (C) 2007-2008, Hewlett-Packard Development Company, LLP
   * (C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP
   *                     All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or
   * without modification, are permitted provided that the following
   * conditions are met:
   *
   * Redistributions of source code must retain the above copyright
   * notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright
   * notice, this list of conditions and the following disclaimer in
   * the documentation and/or other materials provided with the distribution.
   *
   * Neither the name of the Hewlett Packard Enterprise, nor the names
   * of its contributors may be used to endorse or promote products
   * derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * Author(s)
   *      Raghavendra P.G. <raghavendra.pg@hp.com>
   *      Raghavendra M.S. <raghavendra.ms@hp.com>
   *      Shuah Khan <shuah.khan@hp.com>
   *
   * This file handles all the power related queries
   *
   *      oa_soap_get_power_state()       - gets the power state
   *
   *      oa_soap_set_power_state()       - sets the power state of the resource
   *
   *      get_server_power_state()        - gets the server blade resource power
   *                                        state
   *
   *      get_interconnect_power_state()  - gets the inter connect resource power
   *                                        state
   *
   *      set_server_power_state()        - sets the server blade resource power
   *                                        state
   *
   **/
  
  #include "oa_soap_power.h"
  
  /**
   * oa_soap_get_power_state
   *      @oh_handler:  Pointer to openhpi handler
   *      @resource_id: Resource id
   *      @state:       Pointer to power state
   *
   * Purpose:
   *      Gets the power state of the resource.
   *
   * Detailed Description: NA
   *
   * Return values:
   *      SA_OK                       - on success.
   *      SA_ERR_HPI_INVALID_PARAMS   - on wrong parameters
   *      SA_ERR_HPI_CAPABILITY       - on power capability is not set for
   *                                    the given resource
   *      SA_ERR_HPI_INVALID_RESOURCE - on not able to find the resource
   *      SA_ERR_HPI_INTERNAL_ERROR   - on failure.
   **/
  SaErrorT oa_soap_get_power_state(void *oh_handler,
                                   SaHpiResourceIdT resource_id,
                                   SaHpiPowerStateT *state)
  {
          SaErrorT rv = SA_OK;
          SaHpiRptEntryT *rpt;
          struct oa_soap_handler *oa_handler = NULL;
          SaHpiInt32T bay_number;
          struct oh_handler_state *handler;
  
          if (oh_handler == NULL || state == NULL) {
                  err("Invalid parameters");
                  return SA_ERR_HPI_INVALID_PARAMS;
          }
  
          handler = (struct oh_handler_state *) oh_handler;
          oa_handler = (struct oa_soap_handler *) handler->data;
  
          /* Check whether the oa_handler mutex has been locked or not */
          rv = lock_oa_soap_handler(oa_handler);
          if (rv != SA_OK) {
                  err("OA SOAP handler is locked");
                  return rv;
          }
  
          rpt = oh_get_resource_by_id(handler->rptcache, resource_id);
          if (rpt == NULL) {
                  err("INVALID RESOURCE");
                  return SA_ERR_HPI_INVALID_RESOURCE;
          }
  
          /* Check the resource has power capability */
          if (! (rpt->ResourceCapabilities & SAHPI_CAPABILITY_POWER)) {
                  err("INVALID RESOURCE CAPABILITY");
                  return SA_ERR_HPI_CAPABILITY;
          }
  
          bay_number = rpt->ResourceEntity.Entry[0].EntityLocation;
  
          /* Check resource type and query server or interconnect power state*/
          switch (rpt->ResourceEntity.Entry[0].EntityType) {
                  case (SAHPI_ENT_SYSTEM_BLADE):
                  case (SAHPI_ENT_IO_BLADE):
                  case (SAHPI_ENT_DISK_BLADE):
                          rv = get_server_power_state(oa_handler->active_con,
                                                      bay_number, state);
                          break;
  
                  case (SAHPI_ENT_SWITCH_BLADE):
                          rv = get_interconnect_power_state(
                                  oa_handler->active_con, bay_number, state);
                          break;
  
                  default:
                          err("Invalid Resource Type");
                          rv = SA_ERR_HPI_INTERNAL_ERROR;
          }
          return rv;
  }
  
  /**
   * oa_soap_set_power_state
   *      @oh_handler:  Pointer to openhpi handler structure
   *      @resource_id: Resource id
   *      @state:       Power state
   *
   * Purpose:
   *      Sets the power state of the resource
   *
   * Detailed Description: NA
   *
   * Return values:
   *      SA_OK                     - on success.
   *      SA_ERR_HPI_INVALID_PARAMS - on wrong parameters
   *      SA_ERR_HPI_INTERNAL_ERROR - on failure.
   **/
  SaErrorT oa_soap_set_power_state(void *oh_handler,
                                   SaHpiResourceIdT resource_id,
                                   SaHpiPowerStateT state)
  {
          SaErrorT rv = SA_OK;
          SaHpiRptEntryT *rpt = NULL;
          struct oa_soap_handler *oa_handler = NULL;
          SaHpiInt32T bay_number;
          struct oh_handler_state *handler = NULL;
  
          if (oh_handler == NULL) {
                  err("Invalid parameters");
                  return SA_ERR_HPI_INVALID_PARAMS;
          }
  
          handler = (struct oh_handler_state *) oh_handler;
          oa_handler = (struct oa_soap_handler *) handler->data;
  
          /* Check whether the oa_handler mutex has been locked or not */
          rv = lock_oa_soap_handler(oa_handler);
          if (rv != SA_OK) {
                  err("OA SOAP handler is locked");
                  return rv;
          }
  
          rpt = oh_get_resource_by_id(handler->rptcache, resource_id);
          if (rpt == NULL) {
                  err(" INVALID RESOURCE");
                  return SA_ERR_HPI_INVALID_RESOURCE;
          }
  
          /* Check the resource has power capability */
          if (! (rpt->ResourceCapabilities & SAHPI_CAPABILITY_POWER)) {
                  err(" INVALID RESOURCE CAPABILITY");
                  return SA_ERR_HPI_CAPABILITY;
          }
  
          bay_number = rpt->ResourceEntity.Entry[0].EntityLocation;
          /* Check resource type and set the server or interconnect power state*/
          switch (rpt->ResourceEntity.Entry[0].EntityType) {
                   case (SAHPI_ENT_SYSTEM_BLADE):
                          rv = set_server_power_state(oa_handler->active_con,
                                                      bay_number, state);
                          break;
  
                   case (SAHPI_ENT_IO_BLADE):
                   case (SAHPI_ENT_DISK_BLADE):
                          return(SA_ERR_HPI_UNSUPPORTED_API);
  
                   case (SAHPI_ENT_SWITCH_BLADE):
                          rv = set_interconnect_power_state(
                                  oa_handler->active_con, bay_number, state);
                          break;
  
                   default:
                          err("Invalid Resource Type");
                          return SA_ERR_HPI_UNKNOWN;
          }
  
          return rv;
  }
  
  /**
   * get_server_power_state
   *      @con:        Pointer to the soap client handler
   *      @bay_number: Bay number of the server balde
   *      @state:      Pointer to power state of the server blade
   *
   * Purpose:
   *      Gets the server blade power state.
   *
   * Detailed Description: NA
   *
   * Return values:
   *      SA_OK                     - on success.
   *      SA_ERR_HPI_INVALID_PARAMS - on wrong parameters
   *      SA_ERR_HPI_INTERNAL_ERROR - on failure.
   **/
  SaErrorT get_server_power_state(SOAP_CON *con,
                                  SaHpiInt32T bay_number,
                                  SaHpiPowerStateT *state)
  {
          SaErrorT rv = SA_OK;
          struct getBladeStatus request;
          struct bladeStatus response;
  
          if (con == NULL || state == NULL) {
                  err("Invalid parameters");
                  return SA_ERR_HPI_INVALID_PARAMS;
          }
  
          request.bayNumber = bay_number;
          rv = soap_getBladeStatus(con, &request, &response);
          if (rv != SOAP_OK) {
                  err("Get blade status failed");
                  return SA_ERR_HPI_INTERNAL_ERROR;
          }
  
          switch (response.powered) {
                  case (POWER_ON):
                          *state = SAHPI_POWER_ON;
                          break;
                  case (POWER_OFF):
                          *state = SAHPI_POWER_OFF;
                          break;
                  case (POWER_REBOOT):
                          err("Wrong Power State (REBOOT) detected");
                          return SA_ERR_HPI_INTERNAL_ERROR;
                          break;
                  default:
                          err("Unknown Power State %d detected for Blade in "
  				" bay %d", response.powered, bay_number);
                          return SA_ERR_HPI_INTERNAL_ERROR;
          }
          return SA_OK;
  }
  
  /**
   * get_interconnect_power_state
   *      @con:        Pointer to the soap client handler
   *      @bay_number: Bay number of the interconnect balde
   *      @state:      Pointer to power state of the interconnect blade
   *
   * Purpose:
   *      Gets the interconnect power state.
   *
   * Detailed Description: NA
   *
   * Return values:
   *      SA_OK                     - on success.
   *      SA_ERR_HPI_INVALID_PARAMS - on wrong parameters
   *      SA_ERR_HPI_INTERNAL_ERROR - on failure.
   **/
  SaErrorT get_interconnect_power_state(SOAP_CON *con,
                                        SaHpiInt32T bay_number,
                                        SaHpiPowerStateT *state)
  {
          SaErrorT rv = SA_OK;
          struct getInterconnectTrayStatus request;
          struct interconnectTrayStatus response;
  
          if (con == NULL || state == NULL) {
                  err("Invalid parameters");
                  return SA_ERR_HPI_INVALID_PARAMS;
          }
  
          request.bayNumber = bay_number;
          rv = soap_getInterconnectTrayStatus(con, &request, &response);
          if (rv != SOAP_OK) {
                  err("Get interconnect tray status failed");
                  return SA_ERR_HPI_INTERNAL_ERROR;
          }
  
          switch (response.powered) {
                  case (POWER_ON):
                          *state = SAHPI_POWER_ON;
                          break;
                  case (POWER_OFF):
                          *state = SAHPI_POWER_OFF;
                          break;
                  case (POWER_REBOOT):
                          err("Wrong (REBOOT) Power State detected");
                          return SA_ERR_HPI_INTERNAL_ERROR;
                          break;
                  case (POWER_UNKNOWN):
                          *state = SAHPI_POWER_OFF;
                          break;
                  default:
                          err("Unknown Power State %d detected for interconnect"
  				" at bay %d", response.powered, bay_number);
                          return SA_ERR_HPI_INTERNAL_ERROR;
          }
          return SA_OK;
  }
  
  
  
  /**
   * set_server_power_state
   *      @con:        Pointer to the soap client handler
   *      @bay_namber: Bay number of the server blade
   *      @state:      Power state of the server blade
   *
   * Purpose:
   *      Sets the power state of the server blade,
   *      if the current state is not same as requested state.
   *
   * Detailed Description: NA
   *
   * Return values:
   *      SA_OK                      - on success.
   *      SA_ERR_HPI_INVALID_PARAMS  - on wrong parameters
   *      SA_ERR_HPI_INTERNAL_ERROR  - on failure.
   **/
  SaErrorT set_server_power_state(SOAP_CON *con,
                                  SaHpiInt32T bay_number,
                                  SaHpiPowerStateT state)
  {
          SaErrorT rv = SA_OK;
          SaHpiPowerStateT tmp;
          struct setBladePower blade_power;
          SaHpiInt32T pwroff_poll = 0;
  
          if (con == NULL) {
                  err("Invalid parameters");
                  return SA_ERR_HPI_INVALID_PARAMS;
          }
  
          rv = get_server_power_state(con, bay_number, &tmp);
          if (rv != SA_OK) {
                  err("get server power state failed");
                  return rv;
          }
  
          /* Check whether the current server blade power state is same
           * as requested by user. If yes, ignore the user request
           */
          if (state == tmp) {
                  err("Nothing to be done. Blade is in the requested state");
                  return SA_OK;
          }
  
          blade_power.bayNumber = bay_number;
          switch (state) {
                  case (SAHPI_POWER_ON):
                          blade_power.power = MOMENTARY_PRESS;
                          rv = soap_setBladePower(con, &blade_power);
                          if (rv != SOAP_OK) {
                                  err("Set blade at %d to power on failed",
  							bay_number);
                                  return SA_ERR_HPI_INTERNAL_ERROR;
                          }
                          break;
  
                  case (SAHPI_POWER_OFF):
                          blade_power.power = PRESS_AND_HOLD;
                          rv = soap_setBladePower(con, &blade_power);
                          if (rv != SOAP_OK) {
                                  err("Set blade at %d to power off failed",
  							bay_number);
                                  return SA_ERR_HPI_INTERNAL_ERROR;
                          }
                          break;
  
                  case (SAHPI_POWER_CYCLE):
                          /* Power cycle requires the server to be
                           * power off and then power on
                           * Check whether the current server power state is off
                           * If yes, power on the server
                           * Else, power off and then power on
                           */
                          if (tmp != SAHPI_POWER_OFF) {
                                  blade_power.power = PRESS_AND_HOLD;
  
                                  rv = soap_setBladePower(con, &blade_power);
                                  if (rv != SOAP_OK) {
                                          err("Set blade power to power off "
                                              "failed");
                                          return SA_ERR_HPI_INTERNAL_ERROR;
                                  }
  
  				/* Check whether the power state is OFF for 
  				 * every OA_POWEROFF_POLL_INTERVAL seconds.
  			 	 * Server blades take a few seconds (around 4
  				 * secs) to power off if no operating system is
  				 * running there. Otherwise, an orderly shutdown
  				 * is performed, which could take a while.
  				 */
  
  				while (pwroff_poll < OA_MAX_POWEROFF_POLLS) {
  					rv = get_server_power_state(con,
  							      bay_number, &tmp);
  					if (rv != SA_OK) {
  						err("get_server_power_state failed");
  						return(SA_ERR_HPI_INTERNAL_ERROR);
  					}
  
  					if ( tmp == SAHPI_POWER_OFF)
  						break;
  
  					sleep(OA_POWEROFF_POLL_INTERVAL);
  					pwroff_poll++;
  				}
  
  				if( pwroff_poll >= OA_MAX_POWEROFF_POLLS){
  
  					err("Max poweroff polls exceeded (%d)",
  							 OA_MAX_POWEROFF_POLLS);
  					return( SA_ERR_HPI_INTERNAL_ERROR);
  				}
  
  				/* There is a race condition if a "power on"
  				 * command is sent immediately after a 
  				 * "power off" command, and we may hit this
  				 * even if we have polled for the current 
  				 * power state, unless we wait a bit first.
  				 */
  				sleep(OA_SERVER_POWER_OFF_WAIT_PERIOD);
  
  			} /* end if tmp != SAHPI_POWER_OFF */
  
  			/* Now, turn the blade back on */
  
                          blade_power.power = MOMENTARY_PRESS;
                          rv = soap_setBladePower(con, &blade_power);
                          if (rv != SOAP_OK) {
                                  err("Set blade at %d to power on failed",
  							bay_number);
                                  return SA_ERR_HPI_INTERNAL_ERROR;
                          }
                          break;
  
                  default:
                          err("Invalid power state %d detected in bay %d", 
  							state, bay_number);
                          return SA_ERR_HPI_INVALID_PARAMS;
          }
          return SA_OK;
  }
  
  /**
   * set_interconnect_power_state
   *      @con:        Pointer to the soap client handler
   *      @bay_namber: Bay number of the interconnect blade
   *      @state:      Power state of the interconnect blade
   *
   * Purpose:
   *      Sets the power state of the interconnect blade,
   *
   * Detailed Description: NA
   *
   * Return values:
   *      SA_OK                      - on success.
   *      SA_ERR_HPI_INVALID_PARAMS  - on wrong parameters
   *      SA_ERR_HPI_INTERNAL_ERROR  - on failure.
   **/
  SaErrorT set_interconnect_power_state(SOAP_CON *con,
                                        SaHpiInt32T bay_number,
                                        SaHpiPowerStateT state)
  {
          SaErrorT rv = SA_OK;
          SaHpiPowerStateT tmp;
          struct setInterconnectTrayPower interconnect_power;
  
          if (con == NULL) {
                  err("Invalid parameter");
                  return SA_ERR_HPI_INVALID_PARAMS;
          }
  
          interconnect_power.bayNumber = bay_number;
          switch (state) {
                  case (SAHPI_POWER_ON):
                          interconnect_power.on = HPOA_TRUE;
                          rv = soap_setInterconnectTrayPower(con,
                                                             &interconnect_power);
                          if (rv != SOAP_OK) {
                                  err("Set interconnect at bay %d to  "
                                      "power on failed", bay_number);
                                  return SA_ERR_HPI_INTERNAL_ERROR;
                          }
                          break;
  
                  case (SAHPI_POWER_OFF):
                          interconnect_power.on = HPOA_FALSE;
                          rv = soap_setInterconnectTrayPower(con,
                                                             &interconnect_power);
                          if (rv != SOAP_OK) {
                                  err("Set interconnect at bay %d to "
                                      "power off failed", bay_number);
                                  return SA_ERR_HPI_INTERNAL_ERROR;
                          }
                          break;
  
                  case (SAHPI_POWER_CYCLE):
                          /* Get the current power state of the interconnect */
                          rv = get_interconnect_power_state(con, bay_number,
                                                            &tmp);
                          if (rv != SA_OK ) {
                                  err("get interconnect power state failed");
                                  return rv;
                          }
  
                          /* Power cycle requires the server to be
                           * power off and then power on
                           * Check whether the current server power state is off
                           * If yes, power on the server
                           * Else, power off and then power on
                           */
                          if (tmp != SAHPI_POWER_OFF) {
                                  interconnect_power.on = HPOA_FALSE;
                                  rv = soap_setInterconnectTrayPower(
                                          con, &interconnect_power);
                                  if (rv != SOAP_OK) {
                                          err("Set interconnect at bay %d to "
  					    "power on failed", bay_number);
                                          return SA_ERR_HPI_INTERNAL_ERROR;
                                  }
                          }
                          interconnect_power.on = HPOA_TRUE;
  
                          rv = soap_setInterconnectTrayPower(con,
                                                             &interconnect_power);
                          if (rv != SOAP_OK) {
                                  err("Set interconnect at %d to power on "
                                      "failed", bay_number);
                                  return SA_ERR_HPI_INTERNAL_ERROR;
                          }
                          break;
                  default:
                          err("Invalid power state %d detected for interconnect "
  					"at bay %d", state, bay_number);
                          return SA_ERR_HPI_INVALID_PARAMS;
          }
          return SA_OK;
  }
  
  void * oh_get_power_state (void *, SaHpiResourceIdT, SaHpiPowerStateT *)
                  __attribute__ ((weak, alias("oa_soap_get_power_state")));
  
  void * oh_set_power_state (void *, SaHpiResourceIdT, SaHpiPowerStateT)
                  __attribute__ ((weak, alias("oa_soap_set_power_state")));
  
  