/// /// @brief Enforce the plug-rules per MCA /// @param[in] i_target FAPI2 target (MCA) /// @return fapi2::FAPI2_RC_SUCCESS if okay, otherwise a MSS_PLUG_RULE error code /// fapi2::ReturnCode plug_rule::enforce_plug_rules(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target) { const auto l_dimms = mss::find_targets<TARGET_TYPE_DIMM>(i_target); // Check to see that we have DIMM on this MCA. If we don't, just carry on - this is valid. // Cronus does this often; they don't deconfigure empty ports or controllers. However, f/w // does. So if we're here we're running on Cronus or f/w has a bug <grin> if (l_dimms.size() == 0) { FAPI_INF("No DIMM configured for MCA %s, but it itself seems configured", mss::c_str(i_target)); return FAPI2_RC_SUCCESS; } // Safe, even though the VPD decoder can get us here before the rest of eff_config has completed. // We'll only use the master rank information to enforce the rank config rules (which will have been // decoded and are valid before VPD was asked for.) const auto l_dimm_kinds = mss::dimm::kind::vector(l_dimms); uint64_t l_ranks_override = 0; // The user can avoid plug rules with an attribute. This is handy in partial good scenarios uint8_t l_ignore_plug_rules = 0; FAPI_TRY( mss::ignore_plug_rules(mss::find_target<TARGET_TYPE_MCS>(i_target), l_ignore_plug_rules) ); if (fapi2::ENUM_ATTR_MSS_IGNORE_PLUG_RULES_YES == l_ignore_plug_rules) { FAPI_INF("attribute set to ignore plug rules"); return FAPI2_RC_SUCCESS; } FAPI_TRY( check_gen( l_dimm_kinds ) ); FAPI_TRY( dimm_type_mixing( i_target, l_dimm_kinds ) ); // Get the MRW blacklist for rank configurations FAPI_TRY( mss::mrw_unsupported_rank_config(i_target, l_ranks_override) ); // Note that we do limited rank config checking here. Most of the checking is done via VPD decoding, // meaning that if the VPD decoded the config then there's only a few rank related issues we need // to check here. FAPI_TRY( plug_rule::check_rank_config(i_target, l_dimm_kinds, l_ranks_override) ); fapi_try_exit: return fapi2::current_err; }
/* * par_main() * Endless loop to receive and serve requests */ static void par_main() { struct msg msg; int x; struct file *f; loop: /* * Receive a message, log an error and then keep going */ x = msg_receive(lp_port, &msg); if (x < 0) { syslog(LOG_ERR, "msg_receive"); goto loop; } /* * All incoming data should fit in one buffer */ if (msg.m_nseg > 1) { msg_err(msg.m_sender, EINVAL); goto loop; } /* * Categorize by basic message operation */ f = hash_lookup(filehash, msg.m_sender); switch (msg.m_op & MSG_MASK) { case M_CONNECT: /* New client */ new_client(&msg); break; case M_DISCONNECT: /* Client done */ dead_client(&msg, f); break; case M_DUP: /* File handle dup during exec() */ dup_client(&msg, f); break; case M_ABORT: /* Aborted operation */ /* * We are synchronous. At the time we handle this * message, any I/O is completed. Just answer * with an abort message. */ msg_reply(msg.m_sender, &msg); break; case FS_WRITE: /* Write */ if (check_gen(&msg, f)) { break; } par_write(&msg, f); break; case FS_STAT: /* Get stat of file */ if (check_gen(&msg, f)) { break; } par_stat(&msg, f); break; case FS_WSTAT: /* Writes stats */ if (check_gen(&msg, f)) { break; } par_wstat(&msg, f); break; default: /* Unknown */ msg_err(msg.m_sender, EINVAL); break; } goto loop; }