1243ac210SCorey Minyard // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * ipmi_poweroff.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * MontaVista IPMI Poweroff extension to sys_reboot
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Author: MontaVista Software, Inc.
81da177e4SLinus Torvalds  *         Steven Dake <sdake@mvista.com>
91da177e4SLinus Torvalds  *         Corey Minyard <cminyard@mvista.com>
101da177e4SLinus Torvalds  *         source@mvista.com
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * Copyright 2002,2004 MontaVista Software Inc.
131da177e4SLinus Torvalds  */
1425880f7dSJoe Perches 
1525880f7dSJoe Perches #define pr_fmt(fmt) "IPMI poweroff: " fmt
1625880f7dSJoe Perches 
171da177e4SLinus Torvalds #include <linux/module.h>
183b625943SCorey Minyard #include <linux/moduleparam.h>
193b625943SCorey Minyard #include <linux/proc_fs.h>
201da177e4SLinus Torvalds #include <linux/string.h>
2177cf3973SCorey Minyard #include <linux/completion.h>
22e933b6d6SOlaf Hering #include <linux/pm.h>
2377cf3973SCorey Minyard #include <linux/kdev_t.h>
241da177e4SLinus Torvalds #include <linux/ipmi.h>
251da177e4SLinus Torvalds #include <linux/ipmi_smi.h>
261da177e4SLinus Torvalds 
27b2c03941SCorey Minyard static void ipmi_po_smi_gone(int if_num);
28b2c03941SCorey Minyard static void ipmi_po_new_smi(int if_num, struct device *device);
29b2c03941SCorey Minyard 
303b625943SCorey Minyard /* Definitions for controlling power off (if the system supports it).  It
313b625943SCorey Minyard  * conveniently matches the IPMI chassis control values. */
323b625943SCorey Minyard #define IPMI_CHASSIS_POWER_DOWN		0	/* power down, the default. */
333b625943SCorey Minyard #define IPMI_CHASSIS_POWER_CYCLE	0x02	/* power cycle */
343b625943SCorey Minyard 
353b625943SCorey Minyard /* the IPMI data command */
368c702e16SCorey Minyard static int poweroff_powercycle;
373b625943SCorey Minyard 
38b2c03941SCorey Minyard /* Which interface to use, -1 means the first we see. */
39b2c03941SCorey Minyard static int ifnum_to_use = -1;
40b2c03941SCorey Minyard 
41b2c03941SCorey Minyard /* Our local state. */
420c8204b3SRandy Dunlap static int ready;
432911c988SCorey Minyard static struct ipmi_user *ipmi_user;
44b2c03941SCorey Minyard static int ipmi_ifnum;
452911c988SCorey Minyard static void (*specific_poweroff_func)(struct ipmi_user *user);
46b2c03941SCorey Minyard 
47b2c03941SCorey Minyard /* Holds the old poweroff function so we can restore it on removal. */
48b2c03941SCorey Minyard static void (*old_poweroff_func)(void);
49b2c03941SCorey Minyard 
set_param_ifnum(const char * val,const struct kernel_param * kp)50e4dca7b7SKees Cook static int set_param_ifnum(const char *val, const struct kernel_param *kp)
51b2c03941SCorey Minyard {
52b2c03941SCorey Minyard 	int rv = param_set_int(val, kp);
53b2c03941SCorey Minyard 	if (rv)
54b2c03941SCorey Minyard 		return rv;
55b2c03941SCorey Minyard 	if ((ifnum_to_use < 0) || (ifnum_to_use == ipmi_ifnum))
56b2c03941SCorey Minyard 		return 0;
57b2c03941SCorey Minyard 
58b2c03941SCorey Minyard 	ipmi_po_smi_gone(ipmi_ifnum);
59b2c03941SCorey Minyard 	ipmi_po_new_smi(ifnum_to_use, NULL);
60b2c03941SCorey Minyard 	return 0;
61b2c03941SCorey Minyard }
62b2c03941SCorey Minyard 
63b2c03941SCorey Minyard module_param_call(ifnum_to_use, set_param_ifnum, param_get_int,
64b2c03941SCorey Minyard 		  &ifnum_to_use, 0644);
65b2c03941SCorey Minyard MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog "
66b2c03941SCorey Minyard 		 "timer.  Setting to -1 defaults to the first registered "
67b2c03941SCorey Minyard 		 "interface");
68b2c03941SCorey Minyard 
693b625943SCorey Minyard /* parameter definition to allow user to flag power cycle */
70a9d014afSCorey Minyard module_param(poweroff_powercycle, int, 0644);
7136c7dc44SCorey Minyard MODULE_PARM_DESC(poweroff_powercycle,
7236c7dc44SCorey Minyard 		 " Set to non-zero to enable power cycle instead of power"
7336c7dc44SCorey Minyard 		 " down. Power cycle is contingent on hardware support,"
7436c7dc44SCorey Minyard 		 " otherwise it defaults back to power down.");
753b625943SCorey Minyard 
761da177e4SLinus Torvalds /* Stuff from the get device id command. */
771da177e4SLinus Torvalds static unsigned int mfg_id;
781da177e4SLinus Torvalds static unsigned int prod_id;
791da177e4SLinus Torvalds static unsigned char capabilities;
80168524d6SCorey Minyard static unsigned char ipmi_version;
811da177e4SLinus Torvalds 
8236c7dc44SCorey Minyard /*
8336c7dc44SCorey Minyard  * We use our own messages for this operation, we don't let the system
8436c7dc44SCorey Minyard  * allocate them, since we may be in a panic situation.  The whole
8536c7dc44SCorey Minyard  * thing is single-threaded, anyway, so multiple messages are not
8636c7dc44SCorey Minyard  * required.
8736c7dc44SCorey Minyard  */
88bda4c30aSCorey Minyard static atomic_t dummy_count = ATOMIC_INIT(0);
dummy_smi_free(struct ipmi_smi_msg * msg)891da177e4SLinus Torvalds static void dummy_smi_free(struct ipmi_smi_msg *msg)
901da177e4SLinus Torvalds {
91bda4c30aSCorey Minyard 	atomic_dec(&dummy_count);
921da177e4SLinus Torvalds }
dummy_recv_free(struct ipmi_recv_msg * msg)931da177e4SLinus Torvalds static void dummy_recv_free(struct ipmi_recv_msg *msg)
941da177e4SLinus Torvalds {
95bda4c30aSCorey Minyard 	atomic_dec(&dummy_count);
961da177e4SLinus Torvalds }
979824117dSCorey Minyard static struct ipmi_smi_msg halt_smi_msg = INIT_IPMI_SMI_MSG(dummy_smi_free);
98f214549dSCorey Minyard static struct ipmi_recv_msg halt_recv_msg = INIT_IPMI_RECV_MSG(dummy_recv_free);
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds /*
10225985edcSLucas De Marchi  * Code to send a message and wait for the response.
1031da177e4SLinus Torvalds  */
1041da177e4SLinus Torvalds 
receive_handler(struct ipmi_recv_msg * recv_msg,void * handler_data)1051da177e4SLinus Torvalds static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data)
1061da177e4SLinus Torvalds {
10777cf3973SCorey Minyard 	struct completion *comp = recv_msg->user_msg_data;
1081da177e4SLinus Torvalds 
10977cf3973SCorey Minyard 	if (comp)
11077cf3973SCorey Minyard 		complete(comp);
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds 
113e6dd76a6SBhumika Goyal static const struct ipmi_user_hndl ipmi_poweroff_handler = {
1141da177e4SLinus Torvalds 	.ipmi_recv_hndl = receive_handler
1151da177e4SLinus Torvalds };
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds 
ipmi_request_wait_for_response(struct ipmi_user * user,struct ipmi_addr * addr,struct kernel_ipmi_msg * send_msg)1182911c988SCorey Minyard static int ipmi_request_wait_for_response(struct ipmi_user       *user,
1191da177e4SLinus Torvalds 					  struct ipmi_addr       *addr,
1201da177e4SLinus Torvalds 					  struct kernel_ipmi_msg *send_msg)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds 	int               rv;
12377cf3973SCorey Minyard 	struct completion comp;
1241da177e4SLinus Torvalds 
12577cf3973SCorey Minyard 	init_completion(&comp);
1261da177e4SLinus Torvalds 
12777cf3973SCorey Minyard 	rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &comp,
1281da177e4SLinus Torvalds 				      &halt_smi_msg, &halt_recv_msg, 0);
1291da177e4SLinus Torvalds 	if (rv)
1301da177e4SLinus Torvalds 		return rv;
1311da177e4SLinus Torvalds 
13277cf3973SCorey Minyard 	wait_for_completion(&comp);
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	return halt_recv_msg.msg.data[0];
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds 
137bda4c30aSCorey Minyard /* Wait for message to complete, spinning. */
ipmi_request_in_rc_mode(struct ipmi_user * user,struct ipmi_addr * addr,struct kernel_ipmi_msg * send_msg)1382911c988SCorey Minyard static int ipmi_request_in_rc_mode(struct ipmi_user       *user,
1391da177e4SLinus Torvalds 				   struct ipmi_addr       *addr,
1401da177e4SLinus Torvalds 				   struct kernel_ipmi_msg *send_msg)
1411da177e4SLinus Torvalds {
1421da177e4SLinus Torvalds 	int rv;
1431da177e4SLinus Torvalds 
144bda4c30aSCorey Minyard 	atomic_set(&dummy_count, 2);
1451da177e4SLinus Torvalds 	rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
1461da177e4SLinus Torvalds 				      &halt_smi_msg, &halt_recv_msg, 0);
147bda4c30aSCorey Minyard 	if (rv) {
148bda4c30aSCorey Minyard 		atomic_set(&dummy_count, 0);
1491da177e4SLinus Torvalds 		return rv;
150bda4c30aSCorey Minyard 	}
151bda4c30aSCorey Minyard 
152bda4c30aSCorey Minyard 	/*
153bda4c30aSCorey Minyard 	 * Spin until our message is done.
154bda4c30aSCorey Minyard 	 */
155bda4c30aSCorey Minyard 	while (atomic_read(&dummy_count) > 0) {
156bda4c30aSCorey Minyard 		ipmi_poll_interface(user);
157bda4c30aSCorey Minyard 		cpu_relax();
158bda4c30aSCorey Minyard 	}
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	return halt_recv_msg.msg.data[0];
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds /*
1641da177e4SLinus Torvalds  * ATCA Support
1651da177e4SLinus Torvalds  */
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds #define IPMI_NETFN_ATCA			0x2c
1681da177e4SLinus Torvalds #define IPMI_ATCA_SET_POWER_CMD		0x11
1691da177e4SLinus Torvalds #define IPMI_ATCA_GET_ADDR_INFO_CMD	0x01
1701da177e4SLinus Torvalds #define IPMI_PICMG_ID			0
1711da177e4SLinus Torvalds 
1727d8ba966SCorey Minyard #define IPMI_NETFN_OEM				0x2e
1737d8ba966SCorey Minyard #define IPMI_ATCA_PPS_GRACEFUL_RESTART		0x11
1747d8ba966SCorey Minyard #define IPMI_ATCA_PPS_IANA			"\x00\x40\x0A"
1757d8ba966SCorey Minyard #define IPMI_MOTOROLA_MANUFACTURER_ID		0x0000A1
1767d8ba966SCorey Minyard #define IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID	0x0051
1777d8ba966SCorey Minyard 
1782911c988SCorey Minyard static void (*atca_oem_poweroff_hook)(struct ipmi_user *user);
1797d8ba966SCorey Minyard 
pps_poweroff_atca(struct ipmi_user * user)1802911c988SCorey Minyard static void pps_poweroff_atca(struct ipmi_user *user)
1817d8ba966SCorey Minyard {
1827d8ba966SCorey Minyard 	struct ipmi_system_interface_addr smi_addr;
1837d8ba966SCorey Minyard 	struct kernel_ipmi_msg            send_msg;
1847d8ba966SCorey Minyard 	int                               rv;
1857d8ba966SCorey Minyard 	/*
1867d8ba966SCorey Minyard 	 * Configure IPMI address for local access
1877d8ba966SCorey Minyard 	 */
1887d8ba966SCorey Minyard 	smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
1897d8ba966SCorey Minyard 	smi_addr.channel = IPMI_BMC_CHANNEL;
1907d8ba966SCorey Minyard 	smi_addr.lun = 0;
1917d8ba966SCorey Minyard 
19225880f7dSJoe Perches 	pr_info("PPS powerdown hook used\n");
1937d8ba966SCorey Minyard 
1947d8ba966SCorey Minyard 	send_msg.netfn = IPMI_NETFN_OEM;
1957d8ba966SCorey Minyard 	send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART;
1967d8ba966SCorey Minyard 	send_msg.data = IPMI_ATCA_PPS_IANA;
1977d8ba966SCorey Minyard 	send_msg.data_len = 3;
1987d8ba966SCorey Minyard 	rv = ipmi_request_in_rc_mode(user,
1997d8ba966SCorey Minyard 				     (struct ipmi_addr *) &smi_addr,
2007d8ba966SCorey Minyard 				     &send_msg);
20125880f7dSJoe Perches 	if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE)
20225880f7dSJoe Perches 		pr_err("Unable to send ATCA, IPMI error 0x%x\n", rv);
20325880f7dSJoe Perches 
2047d8ba966SCorey Minyard 	return;
2057d8ba966SCorey Minyard }
2067d8ba966SCorey Minyard 
ipmi_atca_detect(struct ipmi_user * user)2072911c988SCorey Minyard static int ipmi_atca_detect(struct ipmi_user *user)
2081da177e4SLinus Torvalds {
2091da177e4SLinus Torvalds 	struct ipmi_system_interface_addr smi_addr;
2101da177e4SLinus Torvalds 	struct kernel_ipmi_msg            send_msg;
2111da177e4SLinus Torvalds 	int                               rv;
2121da177e4SLinus Torvalds 	unsigned char                     data[1];
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	/*
2151da177e4SLinus Torvalds 	 * Configure IPMI address for local access
2161da177e4SLinus Torvalds 	 */
2171da177e4SLinus Torvalds 	smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2181da177e4SLinus Torvalds 	smi_addr.channel = IPMI_BMC_CHANNEL;
2191da177e4SLinus Torvalds 	smi_addr.lun = 0;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	/*
2221da177e4SLinus Torvalds 	 * Use get address info to check and see if we are ATCA
2231da177e4SLinus Torvalds 	 */
2241da177e4SLinus Torvalds 	send_msg.netfn = IPMI_NETFN_ATCA;
2251da177e4SLinus Torvalds 	send_msg.cmd = IPMI_ATCA_GET_ADDR_INFO_CMD;
2261da177e4SLinus Torvalds 	data[0] = IPMI_PICMG_ID;
2271da177e4SLinus Torvalds 	send_msg.data = data;
2281da177e4SLinus Torvalds 	send_msg.data_len = sizeof(data);
2291da177e4SLinus Torvalds 	rv = ipmi_request_wait_for_response(user,
2301da177e4SLinus Torvalds 					    (struct ipmi_addr *) &smi_addr,
2311da177e4SLinus Torvalds 					    &send_msg);
2327d8ba966SCorey Minyard 
23325880f7dSJoe Perches 	pr_info("ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id);
2347d8ba966SCorey Minyard 	if ((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID)
2357d8ba966SCorey Minyard 	    && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) {
23625880f7dSJoe Perches 		pr_info("Installing Pigeon Point Systems Poweroff Hook\n");
2377d8ba966SCorey Minyard 		atca_oem_poweroff_hook = pps_poweroff_atca;
2387d8ba966SCorey Minyard 	}
2391da177e4SLinus Torvalds 	return !rv;
2401da177e4SLinus Torvalds }
2411da177e4SLinus Torvalds 
ipmi_poweroff_atca(struct ipmi_user * user)2422911c988SCorey Minyard static void ipmi_poweroff_atca(struct ipmi_user *user)
2431da177e4SLinus Torvalds {
2441da177e4SLinus Torvalds 	struct ipmi_system_interface_addr smi_addr;
2451da177e4SLinus Torvalds 	struct kernel_ipmi_msg            send_msg;
2461da177e4SLinus Torvalds 	int                               rv;
2471da177e4SLinus Torvalds 	unsigned char                     data[4];
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	/*
2501da177e4SLinus Torvalds 	 * Configure IPMI address for local access
2511da177e4SLinus Torvalds 	 */
2521da177e4SLinus Torvalds 	smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2531da177e4SLinus Torvalds 	smi_addr.channel = IPMI_BMC_CHANNEL;
2541da177e4SLinus Torvalds 	smi_addr.lun = 0;
2551da177e4SLinus Torvalds 
25625880f7dSJoe Perches 	pr_info("Powering down via ATCA power command\n");
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	/*
2591da177e4SLinus Torvalds 	 * Power down
2601da177e4SLinus Torvalds 	 */
2611da177e4SLinus Torvalds 	send_msg.netfn = IPMI_NETFN_ATCA;
2621da177e4SLinus Torvalds 	send_msg.cmd = IPMI_ATCA_SET_POWER_CMD;
2631da177e4SLinus Torvalds 	data[0] = IPMI_PICMG_ID;
2641da177e4SLinus Torvalds 	data[1] = 0; /* FRU id */
2651da177e4SLinus Torvalds 	data[2] = 0; /* Power Level */
2661da177e4SLinus Torvalds 	data[3] = 0; /* Don't change saved presets */
2671da177e4SLinus Torvalds 	send_msg.data = data;
2681da177e4SLinus Torvalds 	send_msg.data_len = sizeof(data);
2691da177e4SLinus Torvalds 	rv = ipmi_request_in_rc_mode(user,
2701da177e4SLinus Torvalds 				     (struct ipmi_addr *) &smi_addr,
2711da177e4SLinus Torvalds 				     &send_msg);
27236c7dc44SCorey Minyard 	/*
27336c7dc44SCorey Minyard 	 * At this point, the system may be shutting down, and most
27436c7dc44SCorey Minyard 	 * serial drivers (if used) will have interrupts turned off
27536c7dc44SCorey Minyard 	 * it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE
27636c7dc44SCorey Minyard 	 * return code
27736c7dc44SCorey Minyard 	 */
2787d8ba966SCorey Minyard 	if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
27925880f7dSJoe Perches 		pr_err("Unable to send ATCA powerdown message, IPMI error 0x%x\n",
28025880f7dSJoe Perches 		       rv);
2811da177e4SLinus Torvalds 		goto out;
2821da177e4SLinus Torvalds 	}
2831da177e4SLinus Torvalds 
2847d8ba966SCorey Minyard 	if (atca_oem_poweroff_hook)
285adf535eeSAdrian Bunk 		atca_oem_poweroff_hook(user);
2861da177e4SLinus Torvalds  out:
2871da177e4SLinus Torvalds 	return;
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds /*
2911da177e4SLinus Torvalds  * CPI1 Support
2921da177e4SLinus Torvalds  */
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds #define IPMI_NETFN_OEM_1				0xf8
2951da177e4SLinus Torvalds #define OEM_GRP_CMD_SET_RESET_STATE		0x84
2961da177e4SLinus Torvalds #define OEM_GRP_CMD_SET_POWER_STATE		0x82
2971da177e4SLinus Torvalds #define IPMI_NETFN_OEM_8				0xf8
2981da177e4SLinus Torvalds #define OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL	0x80
2991da177e4SLinus Torvalds #define OEM_GRP_CMD_GET_SLOT_GA			0xa3
3001da177e4SLinus Torvalds #define IPMI_NETFN_SENSOR_EVT			0x10
3011da177e4SLinus Torvalds #define IPMI_CMD_GET_EVENT_RECEIVER		0x01
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds #define IPMI_CPI1_PRODUCT_ID		0x000157
3041da177e4SLinus Torvalds #define IPMI_CPI1_MANUFACTURER_ID	0x0108
3051da177e4SLinus Torvalds 
ipmi_cpi1_detect(struct ipmi_user * user)3062911c988SCorey Minyard static int ipmi_cpi1_detect(struct ipmi_user *user)
3071da177e4SLinus Torvalds {
3081da177e4SLinus Torvalds 	return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID)
3091da177e4SLinus Torvalds 		&& (prod_id == IPMI_CPI1_PRODUCT_ID));
3101da177e4SLinus Torvalds }
3111da177e4SLinus Torvalds 
ipmi_poweroff_cpi1(struct ipmi_user * user)3122911c988SCorey Minyard static void ipmi_poweroff_cpi1(struct ipmi_user *user)
3131da177e4SLinus Torvalds {
3141da177e4SLinus Torvalds 	struct ipmi_system_interface_addr smi_addr;
3151da177e4SLinus Torvalds 	struct ipmi_ipmb_addr             ipmb_addr;
3161da177e4SLinus Torvalds 	struct kernel_ipmi_msg            send_msg;
3171da177e4SLinus Torvalds 	int                               rv;
3181da177e4SLinus Torvalds 	unsigned char                     data[1];
3191da177e4SLinus Torvalds 	int                               slot;
3201da177e4SLinus Torvalds 	unsigned char                     hotswap_ipmb;
3211da177e4SLinus Torvalds 	unsigned char                     aer_addr;
3221da177e4SLinus Torvalds 	unsigned char                     aer_lun;
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 	/*
3251da177e4SLinus Torvalds 	 * Configure IPMI address for local access
3261da177e4SLinus Torvalds 	 */
3271da177e4SLinus Torvalds 	smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3281da177e4SLinus Torvalds 	smi_addr.channel = IPMI_BMC_CHANNEL;
3291da177e4SLinus Torvalds 	smi_addr.lun = 0;
3301da177e4SLinus Torvalds 
33125880f7dSJoe Perches 	pr_info("Powering down via CPI1 power command\n");
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	/*
3341da177e4SLinus Torvalds 	 * Get IPMI ipmb address
3351da177e4SLinus Torvalds 	 */
3361da177e4SLinus Torvalds 	send_msg.netfn = IPMI_NETFN_OEM_8 >> 2;
3371da177e4SLinus Torvalds 	send_msg.cmd = OEM_GRP_CMD_GET_SLOT_GA;
3381da177e4SLinus Torvalds 	send_msg.data = NULL;
3391da177e4SLinus Torvalds 	send_msg.data_len = 0;
3401da177e4SLinus Torvalds 	rv = ipmi_request_in_rc_mode(user,
3411da177e4SLinus Torvalds 				     (struct ipmi_addr *) &smi_addr,
3421da177e4SLinus Torvalds 				     &send_msg);
3431da177e4SLinus Torvalds 	if (rv)
3441da177e4SLinus Torvalds 		goto out;
3451da177e4SLinus Torvalds 	slot = halt_recv_msg.msg.data[1];
3461da177e4SLinus Torvalds 	hotswap_ipmb = (slot > 9) ? (0xb0 + 2 * slot) : (0xae + 2 * slot);
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 	/*
3491da177e4SLinus Torvalds 	 * Get active event receiver
3501da177e4SLinus Torvalds 	 */
3511da177e4SLinus Torvalds 	send_msg.netfn = IPMI_NETFN_SENSOR_EVT >> 2;
3521da177e4SLinus Torvalds 	send_msg.cmd = IPMI_CMD_GET_EVENT_RECEIVER;
3531da177e4SLinus Torvalds 	send_msg.data = NULL;
3541da177e4SLinus Torvalds 	send_msg.data_len = 0;
3551da177e4SLinus Torvalds 	rv = ipmi_request_in_rc_mode(user,
3561da177e4SLinus Torvalds 				     (struct ipmi_addr *) &smi_addr,
3571da177e4SLinus Torvalds 				     &send_msg);
3581da177e4SLinus Torvalds 	if (rv)
3591da177e4SLinus Torvalds 		goto out;
3601da177e4SLinus Torvalds 	aer_addr = halt_recv_msg.msg.data[1];
3611da177e4SLinus Torvalds 	aer_lun = halt_recv_msg.msg.data[2];
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	/*
3641da177e4SLinus Torvalds 	 * Setup IPMB address target instead of local target
3651da177e4SLinus Torvalds 	 */
3661da177e4SLinus Torvalds 	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
3671da177e4SLinus Torvalds 	ipmb_addr.channel = 0;
3681da177e4SLinus Torvalds 	ipmb_addr.slave_addr = aer_addr;
3691da177e4SLinus Torvalds 	ipmb_addr.lun = aer_lun;
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	/*
3721da177e4SLinus Torvalds 	 * Send request hotswap control to remove blade from dpv
3731da177e4SLinus Torvalds 	 */
3741da177e4SLinus Torvalds 	send_msg.netfn = IPMI_NETFN_OEM_8 >> 2;
3751da177e4SLinus Torvalds 	send_msg.cmd = OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL;
3761da177e4SLinus Torvalds 	send_msg.data = &hotswap_ipmb;
3771da177e4SLinus Torvalds 	send_msg.data_len = 1;
3781da177e4SLinus Torvalds 	ipmi_request_in_rc_mode(user,
3791da177e4SLinus Torvalds 				(struct ipmi_addr *) &ipmb_addr,
3801da177e4SLinus Torvalds 				&send_msg);
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	/*
3831da177e4SLinus Torvalds 	 * Set reset asserted
3841da177e4SLinus Torvalds 	 */
3851da177e4SLinus Torvalds 	send_msg.netfn = IPMI_NETFN_OEM_1 >> 2;
3861da177e4SLinus Torvalds 	send_msg.cmd = OEM_GRP_CMD_SET_RESET_STATE;
3871da177e4SLinus Torvalds 	send_msg.data = data;
3881da177e4SLinus Torvalds 	data[0] = 1; /* Reset asserted state */
3891da177e4SLinus Torvalds 	send_msg.data_len = 1;
3901da177e4SLinus Torvalds 	rv = ipmi_request_in_rc_mode(user,
3911da177e4SLinus Torvalds 				     (struct ipmi_addr *) &smi_addr,
3921da177e4SLinus Torvalds 				     &send_msg);
3931da177e4SLinus Torvalds 	if (rv)
3941da177e4SLinus Torvalds 		goto out;
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	/*
3971da177e4SLinus Torvalds 	 * Power down
3981da177e4SLinus Torvalds 	 */
3991da177e4SLinus Torvalds 	send_msg.netfn = IPMI_NETFN_OEM_1 >> 2;
4001da177e4SLinus Torvalds 	send_msg.cmd = OEM_GRP_CMD_SET_POWER_STATE;
4011da177e4SLinus Torvalds 	send_msg.data = data;
4021da177e4SLinus Torvalds 	data[0] = 1; /* Power down state */
4031da177e4SLinus Torvalds 	send_msg.data_len = 1;
4041da177e4SLinus Torvalds 	rv = ipmi_request_in_rc_mode(user,
4051da177e4SLinus Torvalds 				     (struct ipmi_addr *) &smi_addr,
4061da177e4SLinus Torvalds 				     &send_msg);
4071da177e4SLinus Torvalds 	if (rv)
4081da177e4SLinus Torvalds 		goto out;
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds  out:
4111da177e4SLinus Torvalds 	return;
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds /*
415168524d6SCorey Minyard  * ipmi_dell_chassis_detect()
416168524d6SCorey Minyard  * Dell systems with IPMI < 1.5 don't set the chassis capability bit
417168524d6SCorey Minyard  * but they can handle a chassis poweroff or powercycle command.
418168524d6SCorey Minyard  */
419168524d6SCorey Minyard 
420168524d6SCorey Minyard #define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
ipmi_dell_chassis_detect(struct ipmi_user * user)4212911c988SCorey Minyard static int ipmi_dell_chassis_detect(struct ipmi_user *user)
422168524d6SCorey Minyard {
423168524d6SCorey Minyard 	const char ipmi_version_major = ipmi_version & 0xF;
424168524d6SCorey Minyard 	const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
425168524d6SCorey Minyard 	const char mfr[3] = DELL_IANA_MFR_ID;
426168524d6SCorey Minyard 	if (!memcmp(mfr, &mfg_id, sizeof(mfr)) &&
427168524d6SCorey Minyard 	    ipmi_version_major <= 1 &&
428168524d6SCorey Minyard 	    ipmi_version_minor < 5)
429168524d6SCorey Minyard 		return 1;
430168524d6SCorey Minyard 	return 0;
431168524d6SCorey Minyard }
432168524d6SCorey Minyard 
433168524d6SCorey Minyard /*
434c6185e28SHelge Deller  * ipmi_hp_chassis_detect()
435c6185e28SHelge Deller  * HP PA-RISC servers rp3410/rp3440, the C8000 workstation and the rx2600 and
436c6185e28SHelge Deller  * zx6000 machines support IPMI vers 1 and don't set the chassis capability bit
437c6185e28SHelge Deller  * but they can handle a chassis poweroff or powercycle command.
438c6185e28SHelge Deller  */
439c6185e28SHelge Deller 
440c6185e28SHelge Deller #define HP_IANA_MFR_ID 0x0b
441c6185e28SHelge Deller #define HP_BMC_PROD_ID 0x8201
ipmi_hp_chassis_detect(struct ipmi_user * user)4422911c988SCorey Minyard static int ipmi_hp_chassis_detect(struct ipmi_user *user)
443c6185e28SHelge Deller {
444c6185e28SHelge Deller 	if (mfg_id == HP_IANA_MFR_ID
445c6185e28SHelge Deller 		&& prod_id == HP_BMC_PROD_ID
446c6185e28SHelge Deller 		&& ipmi_version == 1)
447c6185e28SHelge Deller 		return 1;
448c6185e28SHelge Deller 	return 0;
449c6185e28SHelge Deller }
450c6185e28SHelge Deller 
451c6185e28SHelge Deller /*
4521da177e4SLinus Torvalds  * Standard chassis support
4531da177e4SLinus Torvalds  */
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds #define IPMI_NETFN_CHASSIS_REQUEST	0
4561da177e4SLinus Torvalds #define IPMI_CHASSIS_CONTROL_CMD	0x02
4571da177e4SLinus Torvalds 
ipmi_chassis_detect(struct ipmi_user * user)4582911c988SCorey Minyard static int ipmi_chassis_detect(struct ipmi_user *user)
4591da177e4SLinus Torvalds {
4601da177e4SLinus Torvalds 	/* Chassis support, use it. */
4611da177e4SLinus Torvalds 	return (capabilities & 0x80);
4621da177e4SLinus Torvalds }
4631da177e4SLinus Torvalds 
ipmi_poweroff_chassis(struct ipmi_user * user)4642911c988SCorey Minyard static void ipmi_poweroff_chassis(struct ipmi_user *user)
4651da177e4SLinus Torvalds {
4661da177e4SLinus Torvalds 	struct ipmi_system_interface_addr smi_addr;
4671da177e4SLinus Torvalds 	struct kernel_ipmi_msg            send_msg;
4681da177e4SLinus Torvalds 	int                               rv;
4691da177e4SLinus Torvalds 	unsigned char                     data[1];
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 	/*
4721da177e4SLinus Torvalds 	 * Configure IPMI address for local access
4731da177e4SLinus Torvalds 	 */
4741da177e4SLinus Torvalds 	smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
4751da177e4SLinus Torvalds 	smi_addr.channel = IPMI_BMC_CHANNEL;
4761da177e4SLinus Torvalds 	smi_addr.lun = 0;
4771da177e4SLinus Torvalds 
4783b625943SCorey Minyard  powercyclefailed:
47925880f7dSJoe Perches 	pr_info("Powering %s via IPMI chassis control command\n",
4808c702e16SCorey Minyard 		(poweroff_powercycle ? "cycle" : "down"));
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds 	/*
4831da177e4SLinus Torvalds 	 * Power down
4841da177e4SLinus Torvalds 	 */
4851da177e4SLinus Torvalds 	send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
4861da177e4SLinus Torvalds 	send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
4878c702e16SCorey Minyard 	if (poweroff_powercycle)
4888c702e16SCorey Minyard 		data[0] = IPMI_CHASSIS_POWER_CYCLE;
4898c702e16SCorey Minyard 	else
4908c702e16SCorey Minyard 		data[0] = IPMI_CHASSIS_POWER_DOWN;
4911da177e4SLinus Torvalds 	send_msg.data = data;
4921da177e4SLinus Torvalds 	send_msg.data_len = sizeof(data);
4931da177e4SLinus Torvalds 	rv = ipmi_request_in_rc_mode(user,
4941da177e4SLinus Torvalds 				     (struct ipmi_addr *) &smi_addr,
4951da177e4SLinus Torvalds 				     &send_msg);
4961da177e4SLinus Torvalds 	if (rv) {
4978c702e16SCorey Minyard 		if (poweroff_powercycle) {
4983b625943SCorey Minyard 			/* power cycle failed, default to power down */
49925880f7dSJoe Perches 			pr_err("Unable to send chassis power cycle message, IPMI error 0x%x\n",
50025880f7dSJoe Perches 			       rv);
5018c702e16SCorey Minyard 			poweroff_powercycle = 0;
5023b625943SCorey Minyard 			goto powercyclefailed;
5038c702e16SCorey Minyard 		}
5043b625943SCorey Minyard 
50525880f7dSJoe Perches 		pr_err("Unable to send chassis power down message, IPMI error 0x%x\n",
50625880f7dSJoe Perches 		       rv);
5073b625943SCorey Minyard 	}
5081da177e4SLinus Torvalds }
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds /* Table of possible power off functions. */
5121da177e4SLinus Torvalds struct poweroff_function {
5131da177e4SLinus Torvalds 	char *platform_type;
5142911c988SCorey Minyard 	int  (*detect)(struct ipmi_user *user);
5152911c988SCorey Minyard 	void (*poweroff_func)(struct ipmi_user *user);
5161da177e4SLinus Torvalds };
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds static struct poweroff_function poweroff_functions[] = {
5191da177e4SLinus Torvalds 	{ .platform_type	= "ATCA",
5201da177e4SLinus Torvalds 	  .detect		= ipmi_atca_detect,
5211da177e4SLinus Torvalds 	  .poweroff_func	= ipmi_poweroff_atca },
5221da177e4SLinus Torvalds 	{ .platform_type	= "CPI1",
5231da177e4SLinus Torvalds 	  .detect		= ipmi_cpi1_detect,
5241da177e4SLinus Torvalds 	  .poweroff_func	= ipmi_poweroff_cpi1 },
525168524d6SCorey Minyard 	{ .platform_type	= "chassis",
526168524d6SCorey Minyard 	  .detect		= ipmi_dell_chassis_detect,
527168524d6SCorey Minyard 	  .poweroff_func	= ipmi_poweroff_chassis },
528c6185e28SHelge Deller 	{ .platform_type	= "chassis",
529c6185e28SHelge Deller 	  .detect		= ipmi_hp_chassis_detect,
530c6185e28SHelge Deller 	  .poweroff_func	= ipmi_poweroff_chassis },
5311da177e4SLinus Torvalds 	/* Chassis should generally be last, other things should override
5321da177e4SLinus Torvalds 	   it. */
5331da177e4SLinus Torvalds 	{ .platform_type	= "chassis",
5341da177e4SLinus Torvalds 	  .detect		= ipmi_chassis_detect,
5351da177e4SLinus Torvalds 	  .poweroff_func	= ipmi_poweroff_chassis },
5361da177e4SLinus Torvalds };
537e8824babSColin Ian King #define NUM_PO_FUNCS ARRAY_SIZE(poweroff_functions)
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds /* Called on a powerdown request. */
ipmi_poweroff_function(void)5411da177e4SLinus Torvalds static void ipmi_poweroff_function(void)
5421da177e4SLinus Torvalds {
5431da177e4SLinus Torvalds 	if (!ready)
5441da177e4SLinus Torvalds 		return;
5451da177e4SLinus Torvalds 
5461da177e4SLinus Torvalds 	/* Use run-to-completion mode, since interrupts may be off. */
5471da177e4SLinus Torvalds 	specific_poweroff_func(ipmi_user);
5481da177e4SLinus Torvalds }
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds /* Wait for an IPMI interface to be installed, the first one installed
5511da177e4SLinus Torvalds    will be grabbed by this code and used to perform the powerdown. */
ipmi_po_new_smi(int if_num,struct device * device)55250c812b2SCorey Minyard static void ipmi_po_new_smi(int if_num, struct device *device)
5531da177e4SLinus Torvalds {
5541da177e4SLinus Torvalds 	struct ipmi_system_interface_addr smi_addr;
5551da177e4SLinus Torvalds 	struct kernel_ipmi_msg            send_msg;
5561da177e4SLinus Torvalds 	int                               rv;
5571da177e4SLinus Torvalds 	int                               i;
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds 	if (ready)
5601da177e4SLinus Torvalds 		return;
5611da177e4SLinus Torvalds 
562b2c03941SCorey Minyard 	if ((ifnum_to_use >= 0) && (ifnum_to_use != if_num))
563b2c03941SCorey Minyard 		return;
564b2c03941SCorey Minyard 
5653b625943SCorey Minyard 	rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL,
5663b625943SCorey Minyard 			      &ipmi_user);
5671da177e4SLinus Torvalds 	if (rv) {
56825880f7dSJoe Perches 		pr_err("could not create IPMI user, error %d\n", rv);
5691da177e4SLinus Torvalds 		return;
5701da177e4SLinus Torvalds 	}
5711da177e4SLinus Torvalds 
572b2c03941SCorey Minyard 	ipmi_ifnum = if_num;
573b2c03941SCorey Minyard 
5741da177e4SLinus Torvalds 	/*
5751da177e4SLinus Torvalds 	 * Do a get device ide and store some results, since this is
5761da177e4SLinus Torvalds 	 * used by several functions.
5771da177e4SLinus Torvalds 	 */
5781da177e4SLinus Torvalds 	smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
5791da177e4SLinus Torvalds 	smi_addr.channel = IPMI_BMC_CHANNEL;
5801da177e4SLinus Torvalds 	smi_addr.lun = 0;
5811da177e4SLinus Torvalds 
5821da177e4SLinus Torvalds 	send_msg.netfn = IPMI_NETFN_APP_REQUEST;
5831da177e4SLinus Torvalds 	send_msg.cmd = IPMI_GET_DEVICE_ID_CMD;
5841da177e4SLinus Torvalds 	send_msg.data = NULL;
5851da177e4SLinus Torvalds 	send_msg.data_len = 0;
5861da177e4SLinus Torvalds 	rv = ipmi_request_wait_for_response(ipmi_user,
5871da177e4SLinus Torvalds 					    (struct ipmi_addr *) &smi_addr,
5881da177e4SLinus Torvalds 					    &send_msg);
5891da177e4SLinus Torvalds 	if (rv) {
59025880f7dSJoe Perches 		pr_err("Unable to send IPMI get device id info, IPMI error 0x%x\n",
59125880f7dSJoe Perches 		       rv);
5921da177e4SLinus Torvalds 		goto out_err;
5931da177e4SLinus Torvalds 	}
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds 	if (halt_recv_msg.msg.data_len < 12) {
59625880f7dSJoe Perches 		pr_err("(chassis) IPMI get device id info too short, was %d bytes, needed %d bytes\n",
5971da177e4SLinus Torvalds 		       halt_recv_msg.msg.data_len, 12);
5981da177e4SLinus Torvalds 		goto out_err;
5991da177e4SLinus Torvalds 	}
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds 	mfg_id = (halt_recv_msg.msg.data[7]
6021da177e4SLinus Torvalds 		  | (halt_recv_msg.msg.data[8] << 8)
6031da177e4SLinus Torvalds 		  | (halt_recv_msg.msg.data[9] << 16));
6041da177e4SLinus Torvalds 	prod_id = (halt_recv_msg.msg.data[10]
6051da177e4SLinus Torvalds 		   | (halt_recv_msg.msg.data[11] << 8));
6061da177e4SLinus Torvalds 	capabilities = halt_recv_msg.msg.data[6];
607168524d6SCorey Minyard 	ipmi_version = halt_recv_msg.msg.data[5];
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 	/* Scan for a poweroff method */
6111da177e4SLinus Torvalds 	for (i = 0; i < NUM_PO_FUNCS; i++) {
6121da177e4SLinus Torvalds 		if (poweroff_functions[i].detect(ipmi_user))
6131da177e4SLinus Torvalds 			goto found;
6141da177e4SLinus Torvalds 	}
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds  out_err:
61725880f7dSJoe Perches 	pr_err("Unable to find a poweroff function that will work, giving up\n");
6181da177e4SLinus Torvalds 	ipmi_destroy_user(ipmi_user);
6191da177e4SLinus Torvalds 	return;
6201da177e4SLinus Torvalds 
6211da177e4SLinus Torvalds  found:
62225880f7dSJoe Perches 	pr_info("Found a %s style poweroff function\n",
6231da177e4SLinus Torvalds 		poweroff_functions[i].platform_type);
6241da177e4SLinus Torvalds 	specific_poweroff_func = poweroff_functions[i].poweroff_func;
6251da177e4SLinus Torvalds 	old_poweroff_func = pm_power_off;
6261da177e4SLinus Torvalds 	pm_power_off = ipmi_poweroff_function;
6271da177e4SLinus Torvalds 	ready = 1;
6281da177e4SLinus Torvalds }
6291da177e4SLinus Torvalds 
ipmi_po_smi_gone(int if_num)6301da177e4SLinus Torvalds static void ipmi_po_smi_gone(int if_num)
6311da177e4SLinus Torvalds {
632b2c03941SCorey Minyard 	if (!ready)
633b2c03941SCorey Minyard 		return;
634b2c03941SCorey Minyard 
635b2c03941SCorey Minyard 	if (ipmi_ifnum != if_num)
636b2c03941SCorey Minyard 		return;
637b2c03941SCorey Minyard 
638b2c03941SCorey Minyard 	ready = 0;
639b2c03941SCorey Minyard 	ipmi_destroy_user(ipmi_user);
640b2c03941SCorey Minyard 	pm_power_off = old_poweroff_func;
6411da177e4SLinus Torvalds }
6421da177e4SLinus Torvalds 
64336c7dc44SCorey Minyard static struct ipmi_smi_watcher smi_watcher = {
6441da177e4SLinus Torvalds 	.owner    = THIS_MODULE,
6451da177e4SLinus Torvalds 	.new_smi  = ipmi_po_new_smi,
6461da177e4SLinus Torvalds 	.smi_gone = ipmi_po_smi_gone
6471da177e4SLinus Torvalds };
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds 
6503b625943SCorey Minyard #ifdef CONFIG_PROC_FS
6518c702e16SCorey Minyard #include <linux/sysctl.h>
6523b625943SCorey Minyard 
653a151427eSJoe Perches static struct ctl_table ipmi_table[] = {
654894d2491SEric W. Biederman 	{ .procname	= "poweroff_powercycle",
6558c702e16SCorey Minyard 	  .data		= &poweroff_powercycle,
6568c702e16SCorey Minyard 	  .maxlen	= sizeof(poweroff_powercycle),
6578c702e16SCorey Minyard 	  .mode		= 0644,
6586d456111SEric W. Biederman 	  .proc_handler	= proc_dointvec },
6598c702e16SCorey Minyard 	{ }
6608c702e16SCorey Minyard };
6613b625943SCorey Minyard 
6628c702e16SCorey Minyard static struct ctl_table_header *ipmi_table_header;
6633b625943SCorey Minyard #endif /* CONFIG_PROC_FS */
6643b625943SCorey Minyard 
6651da177e4SLinus Torvalds /*
6661da177e4SLinus Torvalds  * Startup and shutdown functions.
6671da177e4SLinus Torvalds  */
ipmi_poweroff_init(void)6680e6b9e8cSPeter Huewe static int __init ipmi_poweroff_init(void)
6691da177e4SLinus Torvalds {
6701da177e4SLinus Torvalds 	int rv;
6711da177e4SLinus Torvalds 
67225880f7dSJoe Perches 	pr_info("Copyright (C) 2004 MontaVista Software - IPMI Powerdown via sys_reboot\n");
6731da177e4SLinus Torvalds 
6748c702e16SCorey Minyard 	if (poweroff_powercycle)
67525880f7dSJoe Perches 		pr_info("Power cycle is enabled\n");
6761da177e4SLinus Torvalds 
6778c702e16SCorey Minyard #ifdef CONFIG_PROC_FS
678*d352cb47SLuis Chamberlain 	ipmi_table_header = register_sysctl("dev/ipmi", ipmi_table);
6798c702e16SCorey Minyard 	if (!ipmi_table_header) {
68025880f7dSJoe Perches 		pr_err("Unable to register powercycle sysctl\n");
6818c702e16SCorey Minyard 		rv = -ENOMEM;
6828c702e16SCorey Minyard 		goto out_err;
6833b625943SCorey Minyard 	}
6848c702e16SCorey Minyard #endif
6853b625943SCorey Minyard 
6863b625943SCorey Minyard 	rv = ipmi_smi_watcher_register(&smi_watcher);
687be4f1bb2SAdrian Bunk 
688be4f1bb2SAdrian Bunk #ifdef CONFIG_PROC_FS
6893b625943SCorey Minyard 	if (rv) {
6908c702e16SCorey Minyard 		unregister_sysctl_table(ipmi_table_header);
69125880f7dSJoe Perches 		pr_err("Unable to register SMI watcher: %d\n", rv);
6923b625943SCorey Minyard 		goto out_err;
6933b625943SCorey Minyard 	}
6943b625943SCorey Minyard 
6953b625943SCorey Minyard  out_err:
6961aa16eeaSRandy Dunlap #endif
6971da177e4SLinus Torvalds 	return rv;
6981da177e4SLinus Torvalds }
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds #ifdef MODULE
ipmi_poweroff_cleanup(void)7010e6b9e8cSPeter Huewe static void __exit ipmi_poweroff_cleanup(void)
7021da177e4SLinus Torvalds {
7031da177e4SLinus Torvalds 	int rv;
7041da177e4SLinus Torvalds 
7053b625943SCorey Minyard #ifdef CONFIG_PROC_FS
7068c702e16SCorey Minyard 	unregister_sysctl_table(ipmi_table_header);
7073b625943SCorey Minyard #endif
7083b625943SCorey Minyard 
7091da177e4SLinus Torvalds 	ipmi_smi_watcher_unregister(&smi_watcher);
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	if (ready) {
7121da177e4SLinus Torvalds 		rv = ipmi_destroy_user(ipmi_user);
7131da177e4SLinus Torvalds 		if (rv)
71425880f7dSJoe Perches 			pr_err("could not cleanup the IPMI user: 0x%x\n", rv);
7151da177e4SLinus Torvalds 		pm_power_off = old_poweroff_func;
7161da177e4SLinus Torvalds 	}
7171da177e4SLinus Torvalds }
7181da177e4SLinus Torvalds module_exit(ipmi_poweroff_cleanup);
7191da177e4SLinus Torvalds #endif
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds module_init(ipmi_poweroff_init);
7221da177e4SLinus Torvalds MODULE_LICENSE("GPL");
7231fdd75bdSCorey Minyard MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
7241fdd75bdSCorey Minyard MODULE_DESCRIPTION("IPMI Poweroff extension to sys_reboot");
725