text: /*      -*- linux-c -*-
   *
   * Copyright (c) 2003 by Intel Corp.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  This
   * file and program are licensed under a BSD style license.  See
   * the Copying file included with the OpenHPI distribution for
   * full licensing terms.
   *
   * Authors:
   *     Louis Zhuang <louis.zhuang@linux.intel.com>
   *     Racing Guo <racing.guo@intel.com>
   */
  
  #include "ipmi.h"
  #include <oh_utils.h>
  #include <string.h>
  
  
  static
  SaHpiHsStateT _ipmi_to_hpi_state_conv(enum ipmi_hot_swap_states ipmi_state)
  {
          SaHpiHsStateT state = 0;
          switch (ipmi_state) {
                  case IPMI_HOT_SWAP_NOT_PRESENT:
                  case IPMI_HOT_SWAP_OUT_OF_CON:
                          state = SAHPI_HS_STATE_NOT_PRESENT;
                          break;
                  case IPMI_HOT_SWAP_INACTIVE:
                          state = SAHPI_HS_STATE_INACTIVE;
                          break;
                  case IPMI_HOT_SWAP_ACTIVATION_REQUESTED:
                  case IPMI_HOT_SWAP_ACTIVATION_IN_PROGRESS:
                          state = SAHPI_HS_STATE_INSERTION_PENDING;
                          break;
                  case IPMI_HOT_SWAP_ACTIVE:
                          state = SAHPI_HS_STATE_ACTIVE;
                          break;
                  case IPMI_HOT_SWAP_DEACTIVATION_REQUESTED:
                  case IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS:
                          state = SAHPI_HS_STATE_EXTRACTION_PENDING;
                          break;
  #if 0
                  case IPMI_HOT_SWAP_OUT_OF_CON:
                          state = SAHPI_HS_STATE_ACTIVE_UNHEALTHY;
                          break;
  #endif
                  default:
                          err("Unknown state: %d", ipmi_state);
          }
          return state;
  }
  
  static
  enum ipmi_hot_swap_states _hpi_to_ipmi_state_conv(SaHpiHsStateT hpi_state)
  {
          enum ipmi_hot_swap_states state = 0;
          switch (hpi_state) {
                  case SAHPI_HS_STATE_NOT_PRESENT:
                          state = IPMI_HOT_SWAP_NOT_PRESENT;
                          break;
                  case SAHPI_HS_STATE_INACTIVE:
                          state = IPMI_HOT_SWAP_INACTIVE;
                          break;
                  case SAHPI_HS_STATE_INSERTION_PENDING:
                          state = IPMI_HOT_SWAP_ACTIVATION_IN_PROGRESS;
                          break;
                  case SAHPI_HS_STATE_ACTIVE:
                          state = IPMI_HOT_SWAP_ACTIVE;
                          break;
                  case SAHPI_HS_STATE_EXTRACTION_PENDING:
                          state = IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS;
                          break;
                  default:
                          err("Unknown state: %d", hpi_state);
          }
          return state;
  }
  
  
  
  static SaHpiSeverityT get_severity(enum ipmi_hot_swap_states prev,
                                     enum ipmi_hot_swap_states curr,
                                     SaHpiRptEntryT  *rpt,
  				   struct ohoi_resource_info   *res_info)
  {
  	unsigned char hs_mark = 0;
  
  	if (res_info) {
  		hs_mark = res_info->hs_mark;
  		res_info->hs_mark = 0;
  	}
  	if ((prev == IPMI_HOT_SWAP_ACTIVATION_IN_PROGRESS) &&
  			(curr == IPMI_HOT_SWAP_INACTIVE)) {
  		return rpt->ResourceSeverity;
  	}
  	if ((prev != IPMI_HOT_SWAP_INACTIVE) &&
  			(curr == IPMI_HOT_SWAP_NOT_PRESENT)) {
  		return rpt->ResourceSeverity;
  	}
  	if (hs_mark && (prev == IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS) &&
  			(curr == IPMI_HOT_SWAP_INACTIVE)) {
  		return rpt->ResourceSeverity;
  	}
  	return SAHPI_INFORMATIONAL;
  }
  
  
  static unsigned char _ipmi_to_hpi_cause_of_change_conv(unsigned char cause)
  {
  	switch (cause) {
  		case 0x00: return 0;
  		case 0x03: return 1;
  		case 0x02: return 2;
  		case 0x07: return 3;
  		case 0x09: return 4;
  		case 0x06: return 5;
  		case 0x08: return 6;
  		case 0x0f:
  		default:   return 7;
  	}
  }
  
  
  
  
  
  
  
  
  int ohoi_hot_swap_cb(ipmi_entity_t  *ent,
  		     enum ipmi_hot_swap_states last_state,
                       enum ipmi_hot_swap_states curr_state,
  		     void                      *cb_data,
  		     ipmi_event_t              *event)
  {
  	struct oh_handler_state *handler =  (struct oh_handler_state*)cb_data;
  	struct ohoi_handler *ipmi_handler =
  					(struct ohoi_handler *)handler->data;
  	ipmi_entity_id_t entity_id;
  	SaHpiRptEntryT  *rpt_entry;
          struct ohoi_resource_info   *res_info;
  	struct oh_event  *e;
  
  #if 0
  if (event) {
  unsigned char	data[IPMI_EVENT_DATA_MAX_LEN];
  unsigned int	dt_len, i;
  printf("event body : ");
  dt_len = ipmi_event_get_data(event, data, 0, IPMI_EVENT_DATA_MAX_LEN);
  for (i =0; i < dt_len; i++) printf(" 0x%02x", data[i]);
  printf("\n");
  }
  #endif
  
  
  
  	if (getenv("OHOI_TRACE_HOTSWAP") || IHOI_TRACE_ALL) {
  		printf(" *** Hotswap HANDLER for entity %d,%d,%d,%d "
  			"(%s). states 0x%x -> 0x%x.    entity = %p\n",
  			ipmi_entity_get_entity_id(ent),
  			ipmi_entity_get_entity_instance(ent),
  			ipmi_entity_get_device_channel(ent),
  			ipmi_entity_get_device_address(ent),
  			ipmi_entity_get_entity_id_string(ent),
  			last_state, curr_state, ent);
  	}
  	trace_ipmi("HotSwap Handler called");
  
  	entity_id = ipmi_entity_convert_to_id(ent);
  
  	rpt_entry = ohoi_get_resource_by_entityid(handler->rptcache, &entity_id);
  
  	if (!rpt_entry) {
  		err(" No rpt\n");
  		return IPMI_EVENT_HANDLED;
  	}
          res_info = oh_get_resource_data(handler->rptcache, rpt_entry->ResourceId);
  	if ((last_state == IPMI_HOT_SWAP_ACTIVATION_IN_PROGRESS) &&
  			(curr_state == IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS)) {
  		if (res_info) {
  			res_info->hs_mark = 1;
  		}
  		return IPMI_EVENT_HANDLED;
  	}
  	e = malloc(sizeof(*e));
  	if (!e) {
  		err("Out of space");
  		return IPMI_EVENT_HANDLED;
  	}
  
  	memset(e, 0, sizeof(*e));
  	e->event.Source = rpt_entry->ResourceId;
  	if ((curr_state == IPMI_HOT_SWAP_OUT_OF_CON) &&
  			(last_state != IPMI_HOT_SWAP_NOT_PRESENT)) {
  		// special case. connection to entity lost
  		rpt_entry->ResourceFailed = SAHPI_TRUE;
  		e->event.EventType = SAHPI_ET_RESOURCE;
  		e->event.Severity = rpt_entry->ResourceSeverity;
  		oh_gettimeofday(&e->event.Timestamp);
  		e->event.Source = rpt_entry->ResourceId;
  		e->event.EventDataUnion.ResourceEvent.
  			ResourceEventType = SAHPI_RESE_RESOURCE_FAILURE;
  		e->resource = *rpt_entry;
                  e->hid = handler->hid;
                  oh_evt_queue_push(handler->eventq, e);
  		if (!IS_ATCA(ipmi_handler->d_type)) {
  			return IPMI_EVENT_HANDLED;
  		}
  		if (ipmi_entity_get_entity_id(ent) == 0xf0) {
  			// Shelf Manager. Handle ShM Redundancy Sensor
  			if (ipmi_handler->fully_up) {
  				ipmi_handler->shmc_present_num--;
  				ohoi_send_vshmgr_redundancy_sensor_event(
  						handler, 0);
  			}
  		}
  		return IPMI_EVENT_HANDLED;
  	}
  
  	if ((curr_state != IPMI_HOT_SWAP_OUT_OF_CON) &&
  			rpt_entry->ResourceFailed) {
  		// special case
  		rpt_entry->ResourceFailed = SAHPI_FALSE;
  		if (curr_state != IPMI_HOT_SWAP_NOT_PRESENT) {
  			// connection to entity restored
  			e->event.EventType = SAHPI_ET_RESOURCE;
  			e->event.Severity = rpt_entry->ResourceSeverity;
  			oh_gettimeofday(&e->event.Timestamp);
  			e->event.Source = rpt_entry->ResourceId;
  			e->event.EventDataUnion.ResourceEvent.
  				ResourceEventType = SAHPI_RESE_RESOURCE_RESTORED;
  			e->resource = *rpt_entry;
  			e->hid = handler->hid;
                          oh_evt_queue_push(handler->eventq, e);
  			if (!IS_ATCA(ipmi_handler->d_type)) {
  				return IPMI_EVENT_HANDLED;
  			}
  			if (ipmi_entity_get_entity_id(ent) == 0xf0) {
  				// Shelf Manager. Handle ShM Redundancy Sensor
  				if (ipmi_handler->fully_up) {
  					ipmi_handler->shmc_present_num++;
  					ohoi_send_vshmgr_redundancy_sensor_event(
  						handler, 1);
  				}
  			}
  			return IPMI_EVENT_HANDLED;
  		}
  		// XXX here must be handled M7->M0 transition
  	}
  
  	e->event.Source = rpt_entry->ResourceId;
  	e->event.EventType = SAHPI_ET_HOTSWAP;
  	e->event.Severity = get_severity(last_state, curr_state,
  					rpt_entry, res_info);
  
  
  	if (event != NULL) {
  	      	e->event.Timestamp =
  		    (SaHpiTimeT)ipmi_event_get_timestamp(event);
  	} else {
  	      	e->event.Timestamp = SAHPI_TIME_UNSPECIFIED;
  	}
  	if (e->event.Timestamp == SAHPI_TIME_UNSPECIFIED) {
  		oh_gettimeofday(&e->event.Timestamp);
  	}
  
  
  	e->event.EventDataUnion.HotSwapEvent.HotSwapState
  			= _ipmi_to_hpi_state_conv(curr_state);
  	e->event.EventDataUnion.HotSwapEvent.PreviousHotSwapState
  			= _ipmi_to_hpi_state_conv(last_state);
  
  	e->resource = *rpt_entry;
  
  	if (e->event.EventDataUnion.HotSwapEvent.PreviousHotSwapState ==
  		e->event.EventDataUnion.HotSwapEvent.HotSwapState) {
  		free(e);
  		return IPMI_EVENT_HANDLED;
  	}
  	if (e->event.EventDataUnion.HotSwapEvent.HotSwapState ==
  					SAHPI_HS_STATE_INSERTION_PENDING) {
  		res_info->hs_inspen_time = e->event.Timestamp;
  	} else {
  		res_info->hs_inspen_time = SAHPI_TIME_UNSPECIFIED;
  	}
  	if (e->event.EventDataUnion.HotSwapEvent.HotSwapState ==
  	    					SAHPI_HS_STATE_NOT_PRESENT) {
  		trace_ipmi("HS_STATE NOT PRESENT, removing RPT");
  	  	e->hid = handler->hid;
                  oh_evt_queue_push(handler->eventq, e);
  	}else if (e->event.EventDataUnion.HotSwapEvent.HotSwapState ==
  			SAHPI_HS_STATE_ACTIVE) {
  		trace_ipmi("HS_STATE ACTIVE");
  		e->hid = handler->hid;
                  oh_evt_queue_push(handler->eventq, e);
  	}else {
  	  	e->hid = handler->hid;
                  oh_evt_queue_push(handler->eventq, e);
  	}
  //	oh_wake_event_thread(0);
  	if (!IS_ATCA(ipmi_handler->d_type) || !event) {
  		return IPMI_EVENT_HANDLED;
  	}
  
  	unsigned char	data[IPMI_EVENT_DATA_MAX_LEN];
  	unsigned int	dt_len;
  
  	dt_len = ipmi_event_get_data(event, data, 0, IPMI_EVENT_DATA_MAX_LEN);
  	if (dt_len < 12) {
  		err("event data len (%d) too short", dt_len);
  		return IPMI_EVENT_HANDLED;
  	}
  
  	e = malloc(sizeof(*e));
  	if (!e) {
  		err("Out of space");
  		return IPMI_EVENT_HANDLED;
  	}
  	memset(e, 0, sizeof(*e));
  
  	e->resource = *rpt_entry;
  	e->event.Source = rpt_entry->ResourceId;
  	e->event.Timestamp =
  		    (SaHpiTimeT)ipmi_event_get_timestamp(event);
  	e->event.Severity = SAHPI_INFORMATIONAL;
  	e->event.EventType = SAHPI_ET_OEM;
  	e->event.EventDataUnion.OemEvent.MId = ATCAHPI_PICMG_MID;
  	e->event.EventDataUnion.OemEvent.OemEventData.DataType =
  					SAHPI_TL_TYPE_TEXT;
  	e->event.EventDataUnion.OemEvent.OemEventData.Language =
  					SAHPI_LANG_UNDEF;
  	e->event.EventDataUnion.OemEvent.OemEventData.DataLength =
  					 3;
  	e->event.EventDataUnion.OemEvent.OemEventData.Data[0] =
  					_ipmi_to_hpi_state_conv(curr_state);
  	e->event.EventDataUnion.OemEvent.OemEventData.Data[1] =
  					_ipmi_to_hpi_state_conv(last_state);
  	e->event.EventDataUnion.OemEvent.OemEventData.Data[2] =
  			_ipmi_to_hpi_cause_of_change_conv(data[11] >> 4);
  
  	e->hid = handler->hid;
          oh_evt_queue_push(handler->eventq, e);
  
  	return IPMI_EVENT_HANDLED;
  
  }
  
  
  
  		/*    GET HOTSWAP STATE */
  
  
  typedef struct {
  	int done;
  	SaErrorT err;
  	enum ipmi_hot_swap_states ipmi_state;
  } get_hs_state_t;
  
  
  static
  void _get_hotswap_state(ipmi_entity_t             *ent,
                         int                       err,
                         enum ipmi_hot_swap_states state,
                         void                      *cb_data)
  {
  	get_hs_state_t *info = cb_data;
  	if (err) {
  		err("_get_hotswap_state. err = 0x%x", err);
  		err = SA_ERR_HPI_INVALID_CMD;
  	} else {
          	info->ipmi_state = state;
  	}
  	info->done = 1;
  }
  
  SaErrorT ohoi_get_hotswap_state(void *hnd, SaHpiResourceIdT id,
                                  SaHpiHsStateT *state)
  {
          struct oh_handler_state         *handler;
          const struct ohoi_resource_info   *ohoi_res_info;
  	get_hs_state_t info;
  
          int rv;
  
          handler = (struct oh_handler_state *)hnd;
          ohoi_res_info = oh_get_resource_data(handler->rptcache, id);
          if (!(ohoi_res_info->type & OHOI_RESOURCE_ENTITY)) {
                  err("BUG: try to get sel in unsupported resource");
                  return SA_ERR_HPI_INVALID_CMD;
          }
  
  	info.done = 0;
  	info.err = SA_OK;
          rv = ipmi_entity_id_get_hot_swap_state(ohoi_res_info->u.entity.entity_id,
                                                 _get_hotswap_state,
                                                 &info);
          if (rv) {
                  err("Unable to get hotswap state: %d", rv);
                  return SA_ERR_HPI_INVALID_CMD;
          }
  
          rv = ohoi_loop(&info.done, handler->data);
  	if (rv) {
  		err("ohoi_loop returned %d", rv);
  		return rv;
  	}
  	if (info.err != SA_OK) {
  		err("info.err = %d", info.err);
  		return info.err;
  	}
          *state = _ipmi_to_hpi_state_conv(info.ipmi_state);
          return SA_OK;
  }
  
  
  
  		/*   SET HOTSWAP STATE  */
  
  struct hs_done_s {
  	int done;
  	int err;
  };
  
  
  static void _hotswap_done(ipmi_entity_t *ent,
                            int           err,
                            void          *cb_data)
  {
  	struct hs_done_s *info = cb_data;
  
  	if (err) {
  		err("err = 0x%x", err);
  	}
  	info->err = err;
  	info->done = 1;
  }
  
  SaErrorT ohoi_set_hotswap_state(void *hnd, SaHpiResourceIdT id,
                                  SaHpiHsStateT state)
  {
          struct oh_handler_state *handler = (struct oh_handler_state *)hnd;
  	struct ohoi_handler *ipmi_handler = handler->data;
          const struct ohoi_resource_info   *ohoi_res_info;
  	struct hs_done_s info;
  	SaErrorT rv;
  
  
          ohoi_res_info = oh_get_resource_data(handler->rptcache, id);
  
          if (!(ohoi_res_info->type & OHOI_RESOURCE_ENTITY)) {
                  err("BUG: try to get sel in unsupported resource");
                  return SA_ERR_HPI_INVALID_CMD;
          }
  
  	info.done = 0;
  	info.err = 0;
          switch (_hpi_to_ipmi_state_conv(state)) {
                  case IPMI_HOT_SWAP_ACTIVE:
                           ipmi_entity_id_activate(ohoi_res_info->u.entity.entity_id,
                                                   _hotswap_done,
                                                   &info);
                           break;
                  case IPMI_HOT_SWAP_INACTIVE:
                           ipmi_entity_id_deactivate(ohoi_res_info->u.entity.entity_id,
                                                     _hotswap_done,
                                                     &info);
                           break;
                  default:
                           err("Unable set hotswap state: %d", state);
                           return SA_ERR_HPI_INVALID_CMD;
          }
  
          rv = ohoi_loop(&info.done, ipmi_handler);
  	if (rv != SA_OK) {
  		return rv;
  	}
  	if (info.err) {
  		return SA_ERR_HPI_INVALID_CMD;
  	}
  	return SA_OK;
  }
  
  
  
  		/*    REQUEST HOTSWAP ACTION */
  
  
  
  static void activation_request(ipmi_entity_t *ent, void *cb_data)
  {
  	int rv;
  	struct hs_done_s *info = cb_data;
  
  	rv = ipmi_entity_set_activation_requested(ent, _hotswap_done,
  					cb_data);
  
  	if (rv == ENOSYS) {
  		err("ipmi_entity_set_activation_requested = ENOSYS. "
  		    "Use ipmi_entity_activate");
  		rv = ipmi_entity_activate(ent, _hotswap_done, cb_data);
  	}
  	if (rv) {
  		err("ipmi_entity_set_activation_requested = 0x%x", rv);
  		info->done = 1;
  		info->err = -1;
  	}
  }
  
  static void deactivation_request(ipmi_entity_t *ent, void *cb_data)
  {
  	int rv;
  	struct hs_done_s *info = cb_data;
  
  	rv = ipmi_entity_deactivate(ent, _hotswap_done,
  					cb_data);
  	if (rv) {
  		err("ipmi_entity_set_activation_requested = 0x%x", rv);
  		info->done = 1;
  		info->err = -1;
  	}
  }
  
  SaErrorT ohoi_request_hotswap_action(void *hnd, SaHpiResourceIdT id,
                                       SaHpiHsActionT act)
  {
         struct oh_handler_state         *handler;
          const struct ohoi_resource_info   *ohoi_res_info;
  	struct hs_done_s info;
  	SaErrorT rv;
  
          handler = (struct oh_handler_state *)hnd;
  	struct ohoi_handler *ipmi_handler = handler->data;
  
          ohoi_res_info = oh_get_resource_data(handler->rptcache, id);
  
          if (!(ohoi_res_info->type & OHOI_RESOURCE_ENTITY)) {
                  err("BUG: try to get sel in unsupported resource");
                  return SA_ERR_HPI_INVALID_CMD;
          }
  
  	info.done = 0;
  	info.err = 0;
  
  	switch (act) {
  	case SAHPI_HS_ACTION_INSERTION:
  		rv = ipmi_entity_pointer_cb(ohoi_res_info->u.entity.entity_id,
  						activation_request, &info);
  		if (rv) {
  			err("ipmi_entity_pointer_cb = 0x%x", rv);
  			return SA_ERR_HPI_INVALID_PARAMS;
  		}
  		break;
  	case SAHPI_HS_ACTION_EXTRACTION:
  		rv = ipmi_entity_pointer_cb(ohoi_res_info->u.entity.entity_id,
  						deactivation_request, &info);
  		if (rv) {
  			err("ipmi_entity_pointer_cb = 0x%x", rv);
  			return SA_ERR_HPI_INVALID_PARAMS;
  		}
  		break;
          	//return SA_ERR_HPI_UNSUPPORTED_API;
  	default :
  		return SA_ERR_HPI_INVALID_PARAMS;
  	}
  
  	rv = ohoi_loop(&info.done, ipmi_handler);
  	if (rv != SA_OK) {
  		return rv;
  	}
  	if (info.err) {
  		return SA_ERR_HPI_INVALID_REQUEST;
  	}
  	return SA_OK;
  }
  
  
  
  #if 0
  SaErrorT ohoi_get_indicator_state(void *hnd, SaHpiResourceIdT id,
                                    SaHpiHsIndicatorStateT *state)
  {
          struct oh_handler_state         *handler;
          const struct ohoi_resource_info   *ohoi_res_info;
  	SaHpiCtrlStateT c_state;
          SaErrorT rv;
  
          handler = (struct oh_handler_state *)hnd;
          ohoi_res_info = oh_get_resource_data(handler->rptcache, id);
          if (!(ohoi_res_info->type & OHOI_RESOURCE_ENTITY)) {
                  err("BUG: try to get HS in unsupported resource");
                  return SA_ERR_HPI_INVALID_CMD;
          }
  
  	rv = ohoi_get_control_state(hnd, id, ohoi_res_info->hotswapind,
  			NULL, &c_state);
  	if (rv != SA_OK) {
  		return rv;
  	}
  
  	if (c_state.StateUnion.Oem.Body[1] == 0) {
  		*state = SAHPI_HS_INDICATOR_OFF;
  	} else {
  		*state = SAHPI_HS_INDICATOR_ON;
  	}
  	return SA_OK;
  }
  
  
  SaErrorT ohoi_set_indicator_state(void *hnd, SaHpiResourceIdT id,
  				  SaHpiHsIndicatorStateT state)
  {
          struct oh_handler_state         *handler;
          const struct ohoi_resource_info   *ohoi_res_info;
  	SaErrorT rv;
  	SaHpiCtrlStateT c_state;
  	SaHpiCtrlModeT mode;
  
          handler = (struct oh_handler_state *)hnd;
          ohoi_res_info = oh_get_resource_data(handler->rptcache, id);
          if (!(ohoi_res_info->type & OHOI_RESOURCE_ENTITY)) {
                  err("BUG: try to set HS in unsupported resource");
                  return SA_ERR_HPI_INVALID_CMD;
          }
  	rv = ohoi_get_control_state(hnd, id, ohoi_res_info->hotswapind,
  			&mode, &c_state);
  	if (rv != SA_OK) {
  		return rv;
  	}
  	if (state == SAHPI_HS_INDICATOR_OFF) {
  		c_state.StateUnion.Oem.Body[0] = 1;
  		c_state.StateUnion.Oem.Body[1] = 0;
  	} else if (state == SAHPI_HS_INDICATOR_ON) {
  		c_state.StateUnion.Oem.Body[0] = 0;
  		c_state.StateUnion.Oem.Body[1] = 1;
  	} else {
  		return SA_ERR_HPI_INVALID_PARAMS;
  	}
  
  	rv = ohoi_set_control_state(hnd, id, ohoi_res_info->hotswapind,
  			SAHPI_CTRL_MODE_MANUAL, &c_state);
  	if ((rv == SA_OK) && (mode == SAHPI_CTRL_MODE_AUTO)) {
  		ohoi_set_control_state(hnd, id, ohoi_res_info->hotswapind,
  			SAHPI_CTRL_MODE_AUTO, NULL);
  	}
  
  	return rv;
  }
  
  #endif
  
  
  
  
  struct ohoi_indicator_state {
          int done;
          int val;
  	int err;
  };
  
  static
  void _get_indicator_state(ipmi_entity_t *ent,
                            int           err,
                            int           val,
                            void          *cb_data)
  {
          struct ohoi_indicator_state *state;
          state = cb_data;
  
          if (state->err) {
  		err("err = 0x%x", err);
  	}
  	state->err = err;
  	state->done = 1;
          state->val  = val;
  }
  
  SaErrorT ohoi_set_indicator_state(void *hnd, SaHpiResourceIdT id,
  				  SaHpiHsIndicatorStateT state)
  {
          struct oh_handler_state         *handler;
          const struct ohoi_resource_info   *ohoi_res_info;
  	struct hs_done_s info;
  	SaErrorT rv;
  
          handler = (struct oh_handler_state *)hnd;
  		struct ohoi_handler *ipmi_handler = handler->data;
  
          ohoi_res_info = oh_get_resource_data(handler->rptcache, id);
  	        if (!(ohoi_res_info->type & OHOI_RESOURCE_ENTITY)) {
                  err("BUG: try to get sel in unsupported resource");
                  return SA_ERR_HPI_INVALID_CMD;
          }
  
          info.done = 0;
  	info.err = 0;
          ipmi_entity_id_set_hot_swap_indicator(ohoi_res_info->u.entity.entity_id,
                                       state, _hotswap_done, &info);
          rv = ohoi_loop(&info.done,ipmi_handler);
  	if (rv != SA_OK) {
  		return rv;
  	}
  	if (info.err) {
  		return SA_ERR_HPI_INVALID_CMD;
  	}
  	return SA_OK;
  }
  
  
  SaErrorT ohoi_get_indicator_state(void *hnd, SaHpiResourceIdT id,
                                    SaHpiHsIndicatorStateT *state)
  {
          struct oh_handler_state         *handler;
          const struct ohoi_resource_info   *ohoi_res_info;
          struct ohoi_indicator_state     ipmi_state;
  	SaErrorT rv;
  
          handler = (struct oh_handler_state *)hnd;
  		struct ohoi_handler *ipmi_handler = handler->data;
  
          ohoi_res_info = oh_get_resource_data(handler->rptcache, id);
          if (!(ohoi_res_info->type & OHOI_RESOURCE_ENTITY)) {
                  err("BUG: try to get HS in unsupported resource");
                  return SA_ERR_HPI_INVALID_CMD;
          }
  
          ipmi_state.done = 0;
          rv = ipmi_entity_id_get_hot_swap_indicator(
  				ohoi_res_info->u.entity.entity_id,
  				_get_indicator_state, &ipmi_state);
  	if(rv) {
  		return SA_ERR_HPI_INTERNAL_ERROR;
  	}
  
          rv = ohoi_loop(&ipmi_state.done, ipmi_handler);
          if (rv != SA_OK) {
                  return rv;
  	}
  
          *state = ipmi_state.val;
          return SA_OK;;
  }
  
  
  SaErrorT ohoi_hotswap_policy_cancel(void *hnd, SaHpiResourceIdT rid,
                                      SaHpiTimeoutT  ins_timeout)
  {
  	struct oh_handler_state         *handler = hnd;
  	struct ohoi_handler *ipmi_handler = handler->data;
          struct ohoi_resource_info   *res_info;
  	struct ohoi_control_info	*ctrl_info;
          SaHpiRptEntryT *rpt;
  	SaHpiResourceIdT prid;
  	SaHpiTimeoutT curtime;
  	SaErrorT rv;
  
  	if (!IS_ATCA(ipmi_handler->d_type)) {
  		return SA_OK;
  	}
          rpt = oh_get_resource_by_id(handler->rptcache, rid);
          if (rpt == NULL) {
          	err("No rpt for id = %d", rid);
  		return SA_ERR_HPI_INTERNAL_ERROR;
  	}
  
  	// get parent (slot) rpt
  
  	prid = ohoi_get_parent_id(rpt);
          rv = ohoi_get_rdr_data(hnd, prid, SAHPI_CTRL_RDR,
  		ATCAHPI_CTRL_NUM_FRU_ACTIVATION, (void *)&ctrl_info);
  
  	if (rv != SA_OK) {
  		err("NO FRU Activation Control");
  		return SA_ERR_HPI_INVALID_REQUEST;
  	}
  
  	if (ctrl_info->mode == SAHPI_CTRL_MODE_AUTO) {
  		err("mode == AUTO");
  		return SA_ERR_HPI_INVALID_REQUEST;
  	}
  
  	res_info = oh_get_resource_data(handler->rptcache, rid);
  	if (res_info == NULL) {
  		err("no res_info");
  		return SA_ERR_HPI_INTERNAL_ERROR;
  	}
  	if (ins_timeout == SAHPI_TIMEOUT_BLOCK) {
  		return SA_OK;
  	}
  	if (res_info->hs_inspen_time == SAHPI_TIME_UNSPECIFIED) {
  		// time of last insertion pending state unknown
  		err("time of last insertion pending state unknown");
  		return SA_ERR_HPI_INVALID_REQUEST;
  	}
  	if (ins_timeout == SAHPI_TIMEOUT_IMMEDIATE) {
  		err("ins_timeout == SAHPI_TIMEOUT_IMMEDIATE");
  		return SA_ERR_HPI_INVALID_REQUEST;
  	}
  	oh_gettimeofday(&curtime);
  	if (res_info->hs_inspen_time + ins_timeout > curtime) {
  		err("time expired");
  		return SA_ERR_HPI_INVALID_REQUEST;
  	}
  	return SA_OK;
  }
  
  
  
  void * oh_get_hotswap_state (void *, SaHpiResourceIdT, SaHpiHsStateT *)
                  __attribute__ ((weak, alias("ohoi_get_hotswap_state")));
  
  void * oh_set_hotswap_state (void *, SaHpiResourceIdT, SaHpiHsStateT)
                  __attribute__ ((weak, alias("ohoi_set_hotswap_state")));
  
  void * oh_request_hotswap_action (void *, SaHpiResourceIdT, SaHpiHsActionT)
                  __attribute__ ((weak, alias("ohoi_request_hotswap_action")));
  
  void * oh_get_indicator_state (void *, SaHpiResourceIdT,
                                 SaHpiHsIndicatorStateT *)
                  __attribute__ ((weak, alias("ohoi_get_indicator_state")));
  
  void * oh_set_indicator_state (void *, SaHpiResourceIdT,
                                 SaHpiHsIndicatorStateT)
                  __attribute__ ((weak, alias("ohoi_set_indicator_state")));
  void * oh_hotswap_policy_cancel (void *, SaHpiResourceIdT, SaHpiTimeoutT)
                  __attribute__ ((weak, alias("ohoi_hotswap_policy_cancel")));
  
  
  
  