/* Definitions for controlling power off (if the system supports it). It
* conveniently matches the IPMI chassis control values. */ #define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */ #define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */
/* the IPMI data command */ staticint poweroff_powercycle;
/* Which interface to use, -1 means the first we see. */ staticint ifnum_to_use = -1;
module_param_call(ifnum_to_use, set_param_ifnum, param_get_int,
&ifnum_to_use, 0644);
MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " "timer. Setting to -1 defaults to the first registered " "interface");
/* parameter definition to allow user to flag power cycle */
module_param(poweroff_powercycle, int, 0644);
MODULE_PARM_DESC(poweroff_powercycle, " Set to non-zero to enable power cycle instead of power" " down. Power cycle is contingent on hardware support," " otherwise it defaults back to power down.");
/* Stuff from the get device id command. */ staticunsignedint mfg_id; staticunsignedint prod_id; staticunsignedchar capabilities; staticunsignedchar ipmi_version;
/* * We use our own messages for this operation, we don't let the system * allocate them, since we may be in a panic situation. The whole * thing is single-threaded, anyway, so multiple messages are not * required.
*/ static atomic_t dummy_count = ATOMIC_INIT(0); staticvoid dummy_smi_free(struct ipmi_smi_msg *msg)
{
atomic_dec(&dummy_count);
} staticvoid dummy_recv_free(struct ipmi_recv_msg *msg)
{
atomic_dec(&dummy_count);
} staticstruct ipmi_smi_msg halt_smi_msg = INIT_IPMI_SMI_MSG(dummy_smi_free); staticstruct ipmi_recv_msg halt_recv_msg = INIT_IPMI_RECV_MSG(dummy_recv_free);
/* * Code to send a message and wait for the response.
*/
/* * Configure IPMI address for local access
*/
smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
/* * Use get address info to check and see if we are ATCA
*/
send_msg.netfn = IPMI_NETFN_ATCA;
send_msg.cmd = IPMI_ATCA_GET_ADDR_INFO_CMD;
data[0] = IPMI_PICMG_ID;
send_msg.data = data;
send_msg.data_len = sizeof(data);
rv = ipmi_request_wait_for_response(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
pr_info("ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id); if ((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID)
&& (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) {
pr_info("Installing Pigeon Point Systems Poweroff Hook\n");
atca_oem_poweroff_hook = pps_poweroff_atca;
} return !rv;
}
/* * Configure IPMI address for local access
*/
smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
pr_info("Powering down via ATCA power command\n");
/* * Power down
*/
send_msg.netfn = IPMI_NETFN_ATCA;
send_msg.cmd = IPMI_ATCA_SET_POWER_CMD;
data[0] = IPMI_PICMG_ID;
data[1] = 0; /* FRU id */
data[2] = 0; /* Power Level */
data[3] = 0; /* Don't change saved presets */
send_msg.data = data;
send_msg.data_len = sizeof(data);
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg); /* * At this point, the system may be shutting down, and most * serial drivers (if used) will have interrupts turned off * it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE * return code
*/ if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
pr_err("Unable to send ATCA powerdown message, IPMI error 0x%x\n",
rv); goto out;
}
if (atca_oem_poweroff_hook)
atca_oem_poweroff_hook(user);
out: return;
}
/* * Power down
*/
send_msg.netfn = IPMI_NETFN_OEM_1 >> 2;
send_msg.cmd = OEM_GRP_CMD_SET_POWER_STATE;
send_msg.data = data;
data[0] = 1; /* Power down state */
send_msg.data_len = 1;
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg); if (rv) goto out;
out: return;
}
/* * ipmi_dell_chassis_detect() * Dell systems with IPMI < 1.5 don't set the chassis capability bit * but they can handle a chassis poweroff or powercycle command.
*/
/* * ipmi_hp_chassis_detect() * HP PA-RISC servers rp3410/rp3440, the C8000 workstation and the rx2600 and * zx6000 machines support IPMI vers 1 and don't set the chassis capability bit * but they can handle a chassis poweroff or powercycle command.
*/
/* * Configure IPMI address for local access
*/
smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
powercyclefailed:
pr_info("Powering %s via IPMI chassis control command\n",
(poweroff_powercycle ? "cycle" : "down"));
/* * Power down
*/
send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; if (poweroff_powercycle)
data[0] = IPMI_CHASSIS_POWER_CYCLE; else
data[0] = IPMI_CHASSIS_POWER_DOWN;
send_msg.data = data;
send_msg.data_len = sizeof(data);
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg); if (rv) { if (poweroff_powercycle) { /* power cycle failed, default to power down */
pr_err("Unable to send chassis power cycle message, IPMI error 0x%x\n",
rv);
poweroff_powercycle = 0; goto powercyclefailed;
}
pr_err("Unable to send chassis power down message, IPMI error 0x%x\n",
rv);
}
}
/* Table of possible power off functions. */ struct poweroff_function { char *platform_type; int (*detect)(struct ipmi_user *user); void (*poweroff_func)(struct ipmi_user *user);
};
staticstruct poweroff_function poweroff_functions[] = {
{ .platform_type = "ATCA",
.detect = ipmi_atca_detect,
.poweroff_func = ipmi_poweroff_atca },
{ .platform_type = "CPI1",
.detect = ipmi_cpi1_detect,
.poweroff_func = ipmi_poweroff_cpi1 },
{ .platform_type = "chassis",
.detect = ipmi_dell_chassis_detect,
.poweroff_func = ipmi_poweroff_chassis },
{ .platform_type = "chassis",
.detect = ipmi_hp_chassis_detect,
.poweroff_func = ipmi_poweroff_chassis }, /* Chassis should generally be last, other things should override
it. */
{ .platform_type = "chassis",
.detect = ipmi_chassis_detect,
.poweroff_func = ipmi_poweroff_chassis },
}; #define NUM_PO_FUNCS ARRAY_SIZE(poweroff_functions)
/* Called on a powerdown request. */ staticvoid ipmi_poweroff_function(void)
{ if (!ready) return;
/* Use run-to-completion mode, since interrupts may be off. */
specific_poweroff_func(ipmi_user);
}
/* Wait for an IPMI interface to be installed, the first one installed
will be grabbed by this code and used to perform the powerdown. */ staticvoid ipmi_po_new_smi(int if_num, struct device *device)
{ struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; int i;
if (ready) return;
if ((ifnum_to_use >= 0) && (ifnum_to_use != if_num)) return;
rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL,
&ipmi_user); if (rv) {
pr_err("could not create IPMI user, error %d\n", rv); return;
}
ipmi_ifnum = if_num;
/* * Do a get device ide and store some results, since this is * used by several functions.
*/
smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
send_msg.netfn = IPMI_NETFN_APP_REQUEST;
send_msg.cmd = IPMI_GET_DEVICE_ID_CMD;
send_msg.data = NULL;
send_msg.data_len = 0;
rv = ipmi_request_wait_for_response(ipmi_user,
(struct ipmi_addr *) &smi_addr,
&send_msg); if (rv) {
pr_err("Unable to send IPMI get device id info, IPMI error 0x%x\n",
rv); goto out_err;
}
if (halt_recv_msg.msg.data_len < 12) {
pr_err("(chassis) IPMI get device id info too short, was %d bytes, needed %d bytes\n",
halt_recv_msg.msg.data_len, 12); goto out_err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.