-
Notifications
You must be signed in to change notification settings - Fork 6
/
ipmi_chassis.go
158 lines (143 loc) · 4.89 KB
/
ipmi_chassis.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package virtualbmc
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"github.com/cybozu-go/log"
)
// Chassis Network Function
const (
ipmiCmdGetChassisCapabilities = 0x00
ipmiCmdGetChassisStatus = 0x01
ipmiCmdChassisControl = 0x02
ipmiCmdChassisReset = 0x03
ipmiCmdChassisIdentify = 0x04
ipmiCmdSetChassisCapabilities = 0x05
ipmiCmdSetPowerRestorePolicy = 0x06
ipmiCmdGetSystemRestartCause = 0x07
ipmiCmdSetSystemBootOptions = 0x08
ipmiCmdGetSystemBootOptions = 0x09
ipmiCmdGetPOHCounter = 0x0f
)
const (
chassisControlPowerDown = 0x00
chassisControlPowerUp = 0x01
chassisControlPowerCycle = 0x02
chassisControlHardReset = 0x03
chassisControlPulse = 0x04
chassisControlPowerSoft = 0x05
)
const chassisPowerStateBitmaskPowerOn = 0x01
type ipmiChassisControlRequest struct {
ChassisControl uint8
}
type ipmiGetChassisStatusResponse struct {
CurrentPowerState uint8
LastPowerEvent uint8
MiscChassisState uint8
FrontPanelButtonCapabilities uint8
}
func (i *ipmi) handleIPMIChassis(message *ipmiMessage) ([]byte, error) {
switch message.Command {
case ipmiCmdGetChassisStatus:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_GET_CHASSIS_STATUS", map[string]interface{}{})
return i.handleIPMIGetChassisStatus()
case ipmiCmdChassisControl:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_CHASSIS_CONTROL", map[string]interface{}{})
return nil, i.handleIPMIChassisControl(message)
case ipmiCmdGetChassisCapabilities:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_GET_CHASSIS_CAPABILITIES", map[string]interface{}{})
case ipmiCmdChassisReset:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_CHASSIS_RESET", map[string]interface{}{})
case ipmiCmdChassisIdentify:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_CHASSIS_IDENTIFY", map[string]interface{}{})
case ipmiCmdSetChassisCapabilities:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_SET_CHASSIS_CAPABILITIES", map[string]interface{}{})
case ipmiCmdSetPowerRestorePolicy:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_SET_POWER_RESTORE_POLICY", map[string]interface{}{})
case ipmiCmdGetSystemRestartCause:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_GET_SYSTEM_RESTART_CAUSE", map[string]interface{}{})
case ipmiCmdSetSystemBootOptions:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_SET_SYSTEM_BOOT_OPTIONS", map[string]interface{}{})
case ipmiCmdGetSystemBootOptions:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_GET_SYSTEM_BOOT_OPTIONS", map[string]interface{}{})
case ipmiCmdGetPOHCounter:
log.Info(" ipmi CHASSIS: Command = IPMI_CMD_GET_POH_COUNTER", map[string]interface{}{})
}
return nil, fmt.Errorf("unsupported Chassis command: %x", message.Command)
}
func (i *ipmi) handleIPMIGetChassisStatus() ([]byte, error) {
response := ipmiGetChassisStatusResponse{}
powerStatus, err := i.machine.PowerStatus()
if err != nil {
return nil, err
}
if powerStatus == PowerStatusOn || powerStatus == PowerStatusPoweringOn {
response.CurrentPowerState |= chassisPowerStateBitmaskPowerOn
}
response.LastPowerEvent = 0
response.MiscChassisState = 0
response.FrontPanelButtonCapabilities = 0
dataBuf := bytes.Buffer{}
if err := binary.Write(&dataBuf, binary.LittleEndian, response); err != nil {
return nil, err
}
return dataBuf.Bytes(), nil
}
func (i *ipmi) handleIPMIChassisControl(message *ipmiMessage) error {
buf := bytes.NewBuffer(message.Data)
request := ipmiChassisControlRequest{}
if err := binary.Read(buf, binary.LittleEndian, &request); err != nil {
return err
}
switch request.ChassisControl {
case chassisControlPowerDown:
powerState, err := i.machine.PowerStatus()
if err != nil {
return err
}
if powerState == PowerStatusOff || powerState == PowerStatusPoweringOff {
return errors.New("server is already powered off")
}
return i.machine.PowerOff()
case chassisControlPowerUp:
powerState, err := i.machine.PowerStatus()
if err != nil {
return err
}
if powerState == PowerStatusOn || powerState == PowerStatusPoweringOn {
return errors.New("server is already powered on")
}
return i.machine.PowerOn()
case chassisControlPowerCycle:
powerState, err := i.machine.PowerStatus()
if err != nil {
return err
}
if powerState == PowerStatusOff || powerState == PowerStatusPoweringOff {
return errors.New("server is already powered off")
}
if err := i.machine.PowerOff(); err != nil {
return err
}
return i.machine.PowerOn()
case chassisControlHardReset:
powerState, err := i.machine.PowerStatus()
if err != nil {
return err
}
if powerState == PowerStatusOff || powerState == PowerStatusPoweringOff {
return errors.New("server is already powered off")
}
if err := i.machine.PowerOff(); err != nil {
return err
}
return i.machine.PowerOn()
case chassisControlPulse:
// do nothing
case chassisControlPowerSoft:
// do nothing
}
return nil
}