mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-28 11:57:28 +00:00
Implement IPMI support for RB_POWRECYCLE
Some BMCs support power cycling the chassis via the chassis control command 2 subcommand 2 (ipmitool called it 'chassis power cycle'). If the BMC supports the chassis device, register a shutdown_final handler that sends the power cycle command if request and waits up to 10s for it to take effect. To minimize stack strain, we preallocate a ipmi request in the softc. At the moment, we're verbose about what we're doing. Sponsored by: Netflix
This commit is contained in:
parent
6a9fbe3a70
commit
1170c2fecc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=324990
@ -90,6 +90,17 @@ is heavily adopted from the standard and
|
||||
.Tn Linux
|
||||
driver; however, not all features described in the
|
||||
standard are supported.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
driver implements the power cycling option to
|
||||
.Xr shutdown 8
|
||||
to implement power cycling of the system.
|
||||
The motherboard's BMC must support the chassis device and the optional
|
||||
power cycle subcomand of the chassis control command as described in section 28.3
|
||||
if the IPMI standard.
|
||||
The length of time the system is off will be at least one second, but
|
||||
may be longer if the power cycle interval has been set (see section 28.9).
|
||||
.Sh IOCTLS
|
||||
Sending and receiving messages through the
|
||||
.Nm
|
||||
@ -179,6 +190,8 @@ An address supplied was invalid.
|
||||
.Sh SEE ALSO
|
||||
.Xr ioctl 2 ,
|
||||
.Xr watchdog 4 ,
|
||||
.Xr reboot 8 ,
|
||||
.Xr shutdown 8 ,
|
||||
.Xr watchdog 8 ,
|
||||
.Xr watchdogd 8 ,
|
||||
.Xr watchdog 9
|
||||
|
@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/selinfo.h>
|
||||
#include <sys/sysctl.h>
|
||||
@ -689,6 +690,45 @@ ipmi_wd_event(void *arg, unsigned int cmd, int *error)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ipmi_power_cycle(void *arg, int howto)
|
||||
{
|
||||
struct ipmi_softc *sc = arg;
|
||||
struct ipmi_request *req;
|
||||
|
||||
/*
|
||||
* Ignore everything except power cycling requests
|
||||
*/
|
||||
if ((howto & RB_POWERCYCLE) == 0)
|
||||
return;
|
||||
|
||||
device_printf(sc->ipmi_dev, "Power cycling using IPMI\n");
|
||||
|
||||
/*
|
||||
* Send a CHASSIS_CONTROL command to the CHASSIS device, subcommand 2
|
||||
* as described in IPMI v2.0 spec section 28.3.
|
||||
*/
|
||||
IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_CHASSIS_REQUEST, 0),
|
||||
IPMI_CHASSIS_CONTROL, 1, 0);
|
||||
req->ir_request[0] = IPMI_CC_POWER_CYCLE;
|
||||
|
||||
ipmi_submit_driver_request(sc, req, MAX_TIMEOUT);
|
||||
|
||||
if (req->ir_error != 0 || req->ir_compcode != 0) {
|
||||
device_printf(sc->ipmi_dev, "Power cycling via IPMI failed code %#x %#x\n",
|
||||
req->ir_error, req->ir_compcode);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* BMCs are notoriously slow, give it up to 10s to effect the power
|
||||
* down leg of the power cycle. If that fails, fallback to the next
|
||||
* hanlder in the shutdown_final chain and/or the platform failsafe.
|
||||
*/
|
||||
DELAY(10 * 1000 * 1000);
|
||||
device_printf(sc->ipmi_dev, "Power cycling via IPMI timed out\n");
|
||||
}
|
||||
|
||||
static void
|
||||
ipmi_startup(void *arg)
|
||||
{
|
||||
@ -737,10 +777,12 @@ ipmi_startup(void *arg)
|
||||
}
|
||||
|
||||
device_printf(dev, "IPMI device rev. %d, firmware rev. %d.%d%d, "
|
||||
"version %d.%d\n",
|
||||
req->ir_reply[1] & 0x0f,
|
||||
req->ir_reply[2] & 0x7f, req->ir_reply[3] >> 4, req->ir_reply[3] & 0x0f,
|
||||
req->ir_reply[4] & 0x0f, req->ir_reply[4] >> 4);
|
||||
"version %d.%d, device support mask %#x\n",
|
||||
req->ir_reply[1] & 0x0f,
|
||||
req->ir_reply[2] & 0x7f, req->ir_reply[3] >> 4, req->ir_reply[3] & 0x0f,
|
||||
req->ir_reply[4] & 0x0f, req->ir_reply[4] >> 4, req->ir_reply[5]);
|
||||
|
||||
sc->ipmi_dev_support = req->ir_reply[5];
|
||||
|
||||
IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
|
||||
IPMI_CLEAR_FLAGS, 1, 0);
|
||||
@ -792,6 +834,17 @@ ipmi_startup(void *arg)
|
||||
return;
|
||||
}
|
||||
sc->ipmi_cdev->si_drv1 = sc;
|
||||
|
||||
/*
|
||||
* Power cycle the system off using IPMI. We use last - 1 since we don't
|
||||
* handle all the other kinds of reboots. We'll let others handle them.
|
||||
* We only try to do this if the BMC supports the Chassis device.
|
||||
*/
|
||||
if (sc->ipmi_dev_support & IPMI_ADS_CHASSIS) {
|
||||
device_printf(dev, "Establishing power cycle handler\n");
|
||||
sc->ipmi_power_cycle_tag = EVENTHANDLER_REGISTER(shutdown_final,
|
||||
ipmi_power_cycle, sc, SHUTDOWN_PRI_LAST - 1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
@ -844,6 +897,10 @@ ipmi_detach(device_t dev)
|
||||
ipmi_set_watchdog(sc, 0);
|
||||
}
|
||||
|
||||
/* Detach from shutdown handling for power cycle reboot */
|
||||
if (sc->ipmi_power_cycle_tag)
|
||||
EVENTHANDLER_DEREGISTER(shutdown_final, sc->ipmi_power_cycle_tag);
|
||||
|
||||
/* XXX: should use shutdown callout I think. */
|
||||
/* If the backend uses a kthread, shut it down. */
|
||||
IPMI_LOCK(sc);
|
||||
|
@ -103,9 +103,11 @@ struct ipmi_softc {
|
||||
void *ipmi_irq;
|
||||
int ipmi_detaching;
|
||||
int ipmi_opened;
|
||||
uint8_t ipmi_dev_support; /* IPMI_ADS_* */
|
||||
struct cdev *ipmi_cdev;
|
||||
TAILQ_HEAD(,ipmi_request) ipmi_pending_requests;
|
||||
int ipmi_driver_requests_polled;
|
||||
eventhandler_tag ipmi_power_cycle_tag;
|
||||
eventhandler_tag ipmi_watchdog_tag;
|
||||
int ipmi_watchdog_active;
|
||||
struct intr_config_hook ipmi_ich;
|
||||
|
@ -56,8 +56,25 @@
|
||||
#define IPMI_ASYNC_EVENT_RECV_TYPE 2
|
||||
#define IPMI_CMD_RECV_TYPE 3
|
||||
|
||||
#define IPMI_CHASSIS_REQUEST 0x00
|
||||
# define IPMI_CHASSIS_CONTROL 0x02
|
||||
# define IPMI_CC_POWER_DOWN 0x0
|
||||
# define IPMI_CC_POWER_UP 0x1
|
||||
# define IPMI_CC_POWER_CYCLE 0x2
|
||||
# define IPMI_CC_HARD_RESET 0x3
|
||||
# define IPMI_CC_PULSE_DI 0x4
|
||||
# define IPMI_CC_SOFT_OVERTEMP 0x5
|
||||
|
||||
#define IPMI_APP_REQUEST 0x06
|
||||
#define IPMI_GET_DEVICE_ID 0x01
|
||||
# define IPMI_ADS_CHASSIS 0x80
|
||||
# define IPMI_ADS_BRIDGE 0x40
|
||||
# define IPMI_ADS_EVENT_GEN 0x20
|
||||
# define IPMI_ADS_EVENT_RCV 0x10
|
||||
# define IPMI_ADS_FRU_INV 0x08
|
||||
# define IPMI_ADS_SEL 0x04
|
||||
# define IPMI_ADS_SDR 0x02
|
||||
# define IPMI_ADS_SENSOR 0x01
|
||||
#define IPMI_CLEAR_FLAGS 0x30
|
||||
#define IPMI_GET_MSG_FLAGS 0x31
|
||||
# define IPMI_MSG_AVAILABLE 0x01
|
||||
|
Loading…
Reference in New Issue
Block a user