📄 ipmi_poweroff.c
字号:
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. */#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}static int ipmi_dell_chassis_detect (ipmi_user_t user){ const char ipmi_version_major = ipmi_version & 0xF; const char ipmi_version_minor = (ipmi_version >> 4) & 0xF; const char mfr[3]=DELL_IANA_MFR_ID; if (!memcmp(mfr, &mfg_id, sizeof(mfr)) && ipmi_version_major <= 1 && ipmi_version_minor < 5) return 1; return 0;}/* * Standard chassis support */#define IPMI_NETFN_CHASSIS_REQUEST 0#define IPMI_CHASSIS_CONTROL_CMD 0x02static int ipmi_chassis_detect (ipmi_user_t user){ /* Chassis support, use it. */ return (capabilities & 0x80);}static void ipmi_poweroff_chassis (ipmi_user_t user){ struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[1]; /* * 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: printk(KERN_INFO PFX "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 */ printk(KERN_ERR PFX "Unable to send chassis power " \ "cycle message, IPMI error 0x%x\n", rv); poweroff_powercycle = 0; goto powercyclefailed; } printk(KERN_ERR PFX "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)(ipmi_user_t user); void (*poweroff_func)(ipmi_user_t user);};static struct 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 }, /* 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 (sizeof(poweroff_functions) \ / sizeof(struct poweroff_function))/* Our local state. */static int ready = 0;static ipmi_user_t ipmi_user;static void (*specific_poweroff_func)(ipmi_user_t user) = NULL;/* Holds the old poweroff function so we can restore it on removal. */static void (*old_poweroff_func)(void);/* Called on a powerdown request. */static void ipmi_poweroff_function (void){ if (!ready) return; /* Use run-to-completion mode, since interrupts may be off. */ ipmi_user_set_run_to_completion(ipmi_user, 1); specific_poweroff_func(ipmi_user); ipmi_user_set_run_to_completion(ipmi_user, 0);}/* Wait for an IPMI interface to be installed, the first one installed will be grabbed by this code and used to perform the powerdown. */static void ipmi_po_new_smi(int if_num){ struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; int i; if (ready) return; rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user); if (rv) { printk(KERN_ERR PFX "could not create IPMI user, error %d\n", rv); return; } /* * 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) { printk(KERN_ERR PFX "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) { printk(KERN_ERR PFX "(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; } mfg_id = (halt_recv_msg.msg.data[7] | (halt_recv_msg.msg.data[8] << 8) | (halt_recv_msg.msg.data[9] << 16)); prod_id = (halt_recv_msg.msg.data[10] | (halt_recv_msg.msg.data[11] << 8)); capabilities = halt_recv_msg.msg.data[6]; ipmi_version = halt_recv_msg.msg.data[5]; /* Scan for a poweroff method */ for (i = 0; i < NUM_PO_FUNCS; i++) { if (poweroff_functions[i].detect(ipmi_user)) goto found; } out_err: printk(KERN_ERR PFX "Unable to find a poweroff function that" " will work, giving up\n"); ipmi_destroy_user(ipmi_user); return; found: printk(KERN_INFO PFX "Found a %s style poweroff function\n", poweroff_functions[i].platform_type); specific_poweroff_func = poweroff_functions[i].poweroff_func; old_poweroff_func = pm_power_off; pm_power_off = ipmi_poweroff_function; ready = 1;}static void ipmi_po_smi_gone(int if_num){ /* This can never be called, because once poweroff driver is registered, the interface can't go away until the power driver is unregistered. */}static struct ipmi_smi_watcher smi_watcher ={ .owner = THIS_MODULE, .new_smi = ipmi_po_new_smi, .smi_gone = ipmi_po_smi_gone};#ifdef CONFIG_PROC_FS#include <linux/sysctl.h>static ctl_table ipmi_table[] = { { .ctl_name = DEV_IPMI_POWEROFF_POWERCYCLE, .procname = "poweroff_powercycle", .data = &poweroff_powercycle, .maxlen = sizeof(poweroff_powercycle), .mode = 0644, .proc_handler = &proc_dointvec }, { }};static ctl_table ipmi_dir_table[] = { { .ctl_name = DEV_IPMI, .procname = "ipmi", .mode = 0555, .child = ipmi_table }, { }};static ctl_table ipmi_root_table[] = { { .ctl_name = CTL_DEV, .procname = "dev", .mode = 0555, .child = ipmi_dir_table }, { }};static struct ctl_table_header *ipmi_table_header;#endif /* CONFIG_PROC_FS *//* * Startup and shutdown functions. */static int ipmi_poweroff_init (void){ int rv; printk ("Copyright (C) 2004 MontaVista Software -" " IPMI Powerdown via sys_reboot.\n"); if (poweroff_powercycle) printk(KERN_INFO PFX "Power cycle is enabled.\n");#ifdef CONFIG_PROC_FS ipmi_table_header = register_sysctl_table(ipmi_root_table, 1); if (!ipmi_table_header) { printk(KERN_ERR PFX "Unable to register powercycle sysctl\n"); rv = -ENOMEM; goto out_err; }#endif rv = ipmi_smi_watcher_register(&smi_watcher); if (rv) { unregister_sysctl_table(ipmi_table_header); printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); goto out_err; } out_err: return rv;}#ifdef MODULEstatic __exit void ipmi_poweroff_cleanup(void){ int rv;#ifdef CONFIG_PROC_FS unregister_sysctl_table(ipmi_table_header);#endif ipmi_smi_watcher_unregister(&smi_watcher); if (ready) { rv = ipmi_destroy_user(ipmi_user); if (rv) printk(KERN_ERR PFX "could not cleanup the IPMI" " user: 0x%x\n", rv); pm_power_off = old_poweroff_func; }}module_exit(ipmi_poweroff_cleanup);#endifmodule_init(ipmi_poweroff_init);MODULE_LICENSE("GPL");MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");MODULE_DESCRIPTION("IPMI Poweroff extension to sys_reboot");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -