summaryrefslogtreecommitdiff
path: root/drivers/char/ipmi/ipmi_poweroff.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/ipmi/ipmi_poweroff.c')
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c178
1 files changed, 74 insertions, 104 deletions
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index 9f2e3be2c5b8..e63c316d8aaa 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* ipmi_poweroff.c
*
@@ -9,28 +10,10 @@
* source@mvista.com
*
* Copyright 2002,2004 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- *
- * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
+#define pr_fmt(fmt) "IPMI poweroff: " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
@@ -41,8 +24,6 @@
#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
-#define PFX "IPMI poweroff: "
-
static void ipmi_po_smi_gone(int if_num);
static void ipmi_po_new_smi(int if_num, struct device *device);
@@ -59,14 +40,14 @@ static int ifnum_to_use = -1;
/* Our local state. */
static int ready;
-static ipmi_user_t ipmi_user;
+static struct ipmi_user *ipmi_user;
static int ipmi_ifnum;
-static void (*specific_poweroff_func)(ipmi_user_t user);
+static void (*specific_poweroff_func)(struct ipmi_user *user);
/* Holds the old poweroff function so we can restore it on removal. */
static void (*old_poweroff_func)(void);
-static int set_param_ifnum(const char *val, struct kernel_param *kp)
+static int set_param_ifnum(const char *val, const struct kernel_param *kp)
{
int rv = param_set_int(val, kp);
if (rv)
@@ -113,12 +94,8 @@ static void dummy_recv_free(struct ipmi_recv_msg *msg)
{
atomic_dec(&dummy_count);
}
-static struct ipmi_smi_msg halt_smi_msg = {
- .done = dummy_smi_free
-};
-static struct ipmi_recv_msg halt_recv_msg = {
- .done = dummy_recv_free
-};
+static struct ipmi_smi_msg halt_smi_msg = INIT_IPMI_SMI_MSG(dummy_smi_free);
+static struct ipmi_recv_msg halt_recv_msg = INIT_IPMI_RECV_MSG(dummy_recv_free);
/*
@@ -133,12 +110,12 @@ static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data)
complete(comp);
}
-static struct ipmi_user_hndl ipmi_poweroff_handler = {
+static const struct ipmi_user_hndl ipmi_poweroff_handler = {
.ipmi_recv_hndl = receive_handler
};
-static int ipmi_request_wait_for_response(ipmi_user_t user,
+static int ipmi_request_wait_for_response(struct ipmi_user *user,
struct ipmi_addr *addr,
struct kernel_ipmi_msg *send_msg)
{
@@ -158,7 +135,7 @@ static int ipmi_request_wait_for_response(ipmi_user_t user,
}
/* Wait for message to complete, spinning. */
-static int ipmi_request_in_rc_mode(ipmi_user_t user,
+static int ipmi_request_in_rc_mode(struct ipmi_user *user,
struct ipmi_addr *addr,
struct kernel_ipmi_msg *send_msg)
{
@@ -198,9 +175,9 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user,
#define IPMI_MOTOROLA_MANUFACTURER_ID 0x0000A1
#define IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID 0x0051
-static void (*atca_oem_poweroff_hook)(ipmi_user_t user);
+static void (*atca_oem_poweroff_hook)(struct ipmi_user *user);
-static void pps_poweroff_atca(ipmi_user_t user)
+static void pps_poweroff_atca(struct ipmi_user *user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
@@ -212,7 +189,7 @@ static void pps_poweroff_atca(ipmi_user_t user)
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
- printk(KERN_INFO PFX "PPS powerdown hook used");
+ pr_info("PPS powerdown hook used\n");
send_msg.netfn = IPMI_NETFN_OEM;
send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART;
@@ -221,14 +198,13 @@ static void pps_poweroff_atca(ipmi_user_t user)
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
- if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
- printk(KERN_ERR PFX "Unable to send ATCA ,"
- " IPMI error 0x%x\n", rv);
- }
+ if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE)
+ pr_err("Unable to send ATCA, IPMI error 0x%x\n", rv);
+
return;
}
-static int ipmi_atca_detect(ipmi_user_t user)
+static int ipmi_atca_detect(struct ipmi_user *user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
@@ -254,18 +230,16 @@ static int ipmi_atca_detect(ipmi_user_t user)
(struct ipmi_addr *) &smi_addr,
&send_msg);
- printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n",
- mfg_id, prod_id);
+ 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)) {
- printk(KERN_INFO PFX
- "Installing Pigeon Point Systems Poweroff Hook\n");
+ pr_info("Installing Pigeon Point Systems Poweroff Hook\n");
atca_oem_poweroff_hook = pps_poweroff_atca;
}
return !rv;
}
-static void ipmi_poweroff_atca(ipmi_user_t user)
+static void ipmi_poweroff_atca(struct ipmi_user *user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
@@ -279,7 +253,7 @@ static void ipmi_poweroff_atca(ipmi_user_t user)
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
- printk(KERN_INFO PFX "Powering down via ATCA power command\n");
+ pr_info("Powering down via ATCA power command\n");
/*
* Power down
@@ -302,8 +276,8 @@ static void ipmi_poweroff_atca(ipmi_user_t user)
* return code
*/
if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
- printk(KERN_ERR PFX "Unable to send ATCA powerdown message,"
- " IPMI error 0x%x\n", rv);
+ pr_err("Unable to send ATCA powerdown message, IPMI error 0x%x\n",
+ rv);
goto out;
}
@@ -329,13 +303,13 @@ static void ipmi_poweroff_atca(ipmi_user_t user)
#define IPMI_CPI1_PRODUCT_ID 0x000157
#define IPMI_CPI1_MANUFACTURER_ID 0x0108
-static int ipmi_cpi1_detect(ipmi_user_t user)
+static int ipmi_cpi1_detect(struct ipmi_user *user)
{
return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID)
&& (prod_id == IPMI_CPI1_PRODUCT_ID));
}
-static void ipmi_poweroff_cpi1(ipmi_user_t user)
+static void ipmi_poweroff_cpi1(struct ipmi_user *user)
{
struct ipmi_system_interface_addr smi_addr;
struct ipmi_ipmb_addr ipmb_addr;
@@ -354,7 +328,7 @@ static void ipmi_poweroff_cpi1(ipmi_user_t user)
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
- printk(KERN_INFO PFX "Powering down via CPI1 power command\n");
+ pr_info("Powering down via CPI1 power command\n");
/*
* Get IPMI ipmb address
@@ -444,7 +418,7 @@ static void ipmi_poweroff_cpi1(ipmi_user_t user)
*/
#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
-static int ipmi_dell_chassis_detect(ipmi_user_t user)
+static int ipmi_dell_chassis_detect(struct ipmi_user *user)
{
const char ipmi_version_major = ipmi_version & 0xF;
const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
@@ -457,19 +431,37 @@ static int ipmi_dell_chassis_detect(ipmi_user_t user)
}
/*
+ * 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.
+ */
+
+#define HP_IANA_MFR_ID 0x0b
+#define HP_BMC_PROD_ID 0x8201
+static int ipmi_hp_chassis_detect(struct ipmi_user *user)
+{
+ if (mfg_id == HP_IANA_MFR_ID
+ && prod_id == HP_BMC_PROD_ID
+ && ipmi_version == 1)
+ return 1;
+ return 0;
+}
+
+/*
* Standard chassis support
*/
#define IPMI_NETFN_CHASSIS_REQUEST 0
#define IPMI_CHASSIS_CONTROL_CMD 0x02
-static int ipmi_chassis_detect(ipmi_user_t user)
+static int ipmi_chassis_detect(struct ipmi_user *user)
{
/* Chassis support, use it. */
return (capabilities & 0x80);
}
-static void ipmi_poweroff_chassis(ipmi_user_t user)
+static void ipmi_poweroff_chassis(struct ipmi_user *user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
@@ -484,7 +476,7 @@ static void ipmi_poweroff_chassis(ipmi_user_t user)
smi_addr.lun = 0;
powercyclefailed:
- printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
+ pr_info("Powering %s via IPMI chassis control command\n",
(poweroff_powercycle ? "cycle" : "down"));
/*
@@ -504,14 +496,14 @@ static void ipmi_poweroff_chassis(ipmi_user_t user)
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);
+ pr_err("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);
+ pr_err("Unable to send chassis power down message, IPMI error 0x%x\n",
+ rv);
}
}
@@ -519,8 +511,8 @@ static void ipmi_poweroff_chassis(ipmi_user_t user)
/* 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);
+ int (*detect)(struct ipmi_user *user);
+ void (*poweroff_func)(struct ipmi_user *user);
};
static struct poweroff_function poweroff_functions[] = {
@@ -533,14 +525,16 @@ static struct poweroff_function poweroff_functions[] = {
{ .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 (sizeof(poweroff_functions) \
- / sizeof(struct poweroff_function))
+#define NUM_PO_FUNCS ARRAY_SIZE(poweroff_functions)
/* Called on a powerdown request. */
@@ -571,8 +565,7 @@ static void ipmi_po_new_smi(int if_num, struct device *device)
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);
+ pr_err("could not create IPMI user, error %d\n", rv);
return;
}
@@ -594,14 +587,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device)
(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);
+ 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) {
- printk(KERN_ERR PFX "(chassis) IPMI get device id info too,"
- " short, was %d bytes, needed %d bytes\n",
+ 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;
}
@@ -622,14 +614,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device)
}
out_err:
- printk(KERN_ERR PFX "Unable to find a poweroff function that"
- " will work, giving up\n");
+ pr_err("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);
+ pr_info("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;
@@ -659,27 +650,12 @@ static struct ipmi_smi_watcher smi_watcher = {
#ifdef CONFIG_PROC_FS
#include <linux/sysctl.h>
-static struct ctl_table ipmi_table[] = {
+static const struct ctl_table ipmi_table[] = {
{ .procname = "poweroff_powercycle",
.data = &poweroff_powercycle,
.maxlen = sizeof(poweroff_powercycle),
.mode = 0644,
.proc_handler = proc_dointvec },
- { }
-};
-
-static struct ctl_table ipmi_dir_table[] = {
- { .procname = "ipmi",
- .mode = 0555,
- .child = ipmi_table },
- { }
-};
-
-static struct ctl_table ipmi_root_table[] = {
- { .procname = "dev",
- .mode = 0555,
- .child = ipmi_dir_table },
- { }
};
static struct ctl_table_header *ipmi_table_header;
@@ -692,16 +668,15 @@ static int __init ipmi_poweroff_init(void)
{
int rv;
- printk(KERN_INFO "Copyright (C) 2004 MontaVista Software -"
- " IPMI Powerdown via sys_reboot.\n");
+ pr_info("Copyright (C) 2004 MontaVista Software - IPMI Powerdown via sys_reboot\n");
if (poweroff_powercycle)
- printk(KERN_INFO PFX "Power cycle is enabled.\n");
+ pr_info("Power cycle is enabled\n");
#ifdef CONFIG_PROC_FS
- ipmi_table_header = register_sysctl_table(ipmi_root_table);
+ ipmi_table_header = register_sysctl("dev/ipmi", ipmi_table);
if (!ipmi_table_header) {
- printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
+ pr_err("Unable to register powercycle sysctl\n");
rv = -ENOMEM;
goto out_err;
}
@@ -712,7 +687,7 @@ static int __init ipmi_poweroff_init(void)
#ifdef CONFIG_PROC_FS
if (rv) {
unregister_sysctl_table(ipmi_table_header);
- printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
+ pr_err("Unable to register SMI watcher: %d\n", rv);
goto out_err;
}
@@ -724,8 +699,6 @@ static int __init ipmi_poweroff_init(void)
#ifdef MODULE
static void __exit ipmi_poweroff_cleanup(void)
{
- int rv;
-
#ifdef CONFIG_PROC_FS
unregister_sysctl_table(ipmi_table_header);
#endif
@@ -733,10 +706,7 @@ static void __exit ipmi_poweroff_cleanup(void)
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);
+ ipmi_destroy_user(ipmi_user);
pm_power_off = old_poweroff_func;
}
}