1243ac210SCorey Minyard /* SPDX-License-Identifier: GPL-2.0+ */
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * ipmi_smi.h
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * MontaVista IPMI system management interface
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Author: MontaVista Software, Inc.
81da177e4SLinus Torvalds * Corey Minyard <minyard@mvista.com>
91da177e4SLinus Torvalds * source@mvista.com
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * Copyright 2002 MontaVista Software Inc.
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds */
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds #ifndef __LINUX_IPMI_SMI_H
161da177e4SLinus Torvalds #define __LINUX_IPMI_SMI_H
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds #include <linux/ipmi_msgdefs.h>
191da177e4SLinus Torvalds #include <linux/proc_fs.h>
2050c812b2SCorey Minyard #include <linux/platform_device.h>
2116f4232cSZhao Yakui #include <linux/ipmi.h>
221da177e4SLinus Torvalds
23313162d0SPaul Gortmaker struct device;
24313162d0SPaul Gortmaker
256dc1181fSCorey Minyard /*
266dc1181fSCorey Minyard * This files describes the interface for IPMI system management interface
276dc1181fSCorey Minyard * drivers to bind into the IPMI message handler.
286dc1181fSCorey Minyard */
291da177e4SLinus Torvalds
301da177e4SLinus Torvalds /* Structure for the low-level drivers. */
314372ea94SCorey Minyard struct ipmi_smi;
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds /*
34c65ea996SCorey Minyard * Flags for set_check_watch() below. Tells if the SMI should be
35e1891cffSCorey Minyard * waiting for watchdog timeouts, commands and/or messages.
36c65ea996SCorey Minyard */
37e1891cffSCorey Minyard #define IPMI_WATCH_MASK_CHECK_MESSAGES (1 << 0)
38e1891cffSCorey Minyard #define IPMI_WATCH_MASK_CHECK_WATCHDOG (1 << 1)
39e1891cffSCorey Minyard #define IPMI_WATCH_MASK_CHECK_COMMANDS (1 << 2)
40c65ea996SCorey Minyard
41c65ea996SCorey Minyard /*
42059747c2SCorey Minyard * SMI messages
43059747c2SCorey Minyard *
44059747c2SCorey Minyard * When communicating with an SMI, messages come in two formats:
45059747c2SCorey Minyard *
46059747c2SCorey Minyard * * Normal (to a BMC over a BMC interface)
47059747c2SCorey Minyard *
48059747c2SCorey Minyard * * IPMB (over a IPMB to another MC)
49059747c2SCorey Minyard *
50059747c2SCorey Minyard * When normal, commands are sent using the format defined by a
51059747c2SCorey Minyard * standard message over KCS (NetFn must be even):
52059747c2SCorey Minyard *
53059747c2SCorey Minyard * +-----------+-----+------+
54059747c2SCorey Minyard * | NetFn/LUN | Cmd | Data |
55059747c2SCorey Minyard * +-----------+-----+------+
56059747c2SCorey Minyard *
57059747c2SCorey Minyard * And responses, similarly, with an completion code added (NetFn must
58059747c2SCorey Minyard * be odd):
59059747c2SCorey Minyard *
60059747c2SCorey Minyard * +-----------+-----+------+------+
61059747c2SCorey Minyard * | NetFn/LUN | Cmd | CC | Data |
62059747c2SCorey Minyard * +-----------+-----+------+------+
63059747c2SCorey Minyard *
64059747c2SCorey Minyard * With normal messages, only commands are sent and only responses are
65059747c2SCorey Minyard * received.
66059747c2SCorey Minyard *
67059747c2SCorey Minyard * In IPMB mode, we are acting as an IPMB device. Commands will be in
68059747c2SCorey Minyard * the following format (NetFn must be even):
69059747c2SCorey Minyard *
70059747c2SCorey Minyard * +-------------+------+-------------+-----+------+
71059747c2SCorey Minyard * | NetFn/rsLUN | Addr | rqSeq/rqLUN | Cmd | Data |
72059747c2SCorey Minyard * +-------------+------+-------------+-----+------+
73059747c2SCorey Minyard *
74059747c2SCorey Minyard * Responses will using the following format:
75059747c2SCorey Minyard *
76059747c2SCorey Minyard * +-------------+------+-------------+-----+------+------+
77059747c2SCorey Minyard * | NetFn/rqLUN | Addr | rqSeq/rsLUN | Cmd | CC | Data |
78059747c2SCorey Minyard * +-------------+------+-------------+-----+------+------+
79059747c2SCorey Minyard *
80059747c2SCorey Minyard * This is similar to the format defined in the IPMB manual section
81059747c2SCorey Minyard * 2.11.1 with the checksums and the first address removed. Also, the
82059747c2SCorey Minyard * address is always the remote address.
83059747c2SCorey Minyard *
84059747c2SCorey Minyard * IPMB messages can be commands and responses in both directions.
85059747c2SCorey Minyard * Received commands are handled as received commands from the message
86059747c2SCorey Minyard * queue.
87059747c2SCorey Minyard */
88059747c2SCorey Minyard
89059747c2SCorey Minyard enum ipmi_smi_msg_type {
90059747c2SCorey Minyard IPMI_SMI_MSG_TYPE_NORMAL = 0,
91059747c2SCorey Minyard IPMI_SMI_MSG_TYPE_IPMB_DIRECT
92059747c2SCorey Minyard };
93059747c2SCorey Minyard
94059747c2SCorey Minyard /*
951da177e4SLinus Torvalds * Messages to/from the lower layer. The smi interface will take one
961da177e4SLinus Torvalds * of these to send. After the send has occurred and a response has
971da177e4SLinus Torvalds * been received, it will report this same data structure back up to
981da177e4SLinus Torvalds * the upper layer. If an error occurs, it should fill in the
991da177e4SLinus Torvalds * response with an error code in the completion code location. When
1001da177e4SLinus Torvalds * asynchronous data is received, one of these is allocated, the
1011da177e4SLinus Torvalds * data_size is set to zero and the response holds the data from the
1021da177e4SLinus Torvalds * get message or get event command that the interface initiated.
1031da177e4SLinus Torvalds * Note that it is the interfaces responsibility to detect
1041da177e4SLinus Torvalds * asynchronous data and messages and request them from the
1051da177e4SLinus Torvalds * interface.
1061da177e4SLinus Torvalds */
107c70d7499SCorey Minyard struct ipmi_smi_msg {
1081da177e4SLinus Torvalds struct list_head link;
1091da177e4SLinus Torvalds
110059747c2SCorey Minyard enum ipmi_smi_msg_type type;
111059747c2SCorey Minyard
1121da177e4SLinus Torvalds long msgid;
1131da177e4SLinus Torvalds void *user_data;
1141da177e4SLinus Torvalds
1151da177e4SLinus Torvalds int data_size;
1161da177e4SLinus Torvalds unsigned char data[IPMI_MAX_MSG_LENGTH];
1171da177e4SLinus Torvalds
1181da177e4SLinus Torvalds int rsp_size;
1191da177e4SLinus Torvalds unsigned char rsp[IPMI_MAX_MSG_LENGTH];
1201da177e4SLinus Torvalds
121c65ea996SCorey Minyard /*
122c65ea996SCorey Minyard * Will be called when the system is done with the message
123c65ea996SCorey Minyard * (presumably to free it).
124c65ea996SCorey Minyard */
1251da177e4SLinus Torvalds void (*done)(struct ipmi_smi_msg *msg);
1261da177e4SLinus Torvalds };
1271da177e4SLinus Torvalds
128*9824117dSCorey Minyard #define INIT_IPMI_SMI_MSG(done_handler) \
129*9824117dSCorey Minyard { \
130*9824117dSCorey Minyard .done = done_handler, \
131*9824117dSCorey Minyard .type = IPMI_SMI_MSG_TYPE_NORMAL \
132*9824117dSCorey Minyard }
133*9824117dSCorey Minyard
134c70d7499SCorey Minyard struct ipmi_smi_handlers {
1351da177e4SLinus Torvalds struct module *owner;
1361da177e4SLinus Torvalds
137059747c2SCorey Minyard /* Capabilities of the SMI. */
138059747c2SCorey Minyard #define IPMI_SMI_CAN_HANDLE_IPMB_DIRECT (1 << 0)
139059747c2SCorey Minyard unsigned int flags;
140059747c2SCorey Minyard
1416dc1181fSCorey Minyard /*
1426dc1181fSCorey Minyard * The low-level interface cannot start sending messages to
1436dc1181fSCorey Minyard * the upper layer until this function is called. This may
1446dc1181fSCorey Minyard * not be NULL, the lower layer must take the interface from
1456dc1181fSCorey Minyard * this call.
1466dc1181fSCorey Minyard */
147453823baSCorey Minyard int (*start_processing)(void *send_info,
1485ce1a7dcSCorey Minyard struct ipmi_smi *new_intf);
149453823baSCorey Minyard
15016f4232cSZhao Yakui /*
151b7780dabSCorey Minyard * When called, the low-level interface should disable all
152b7780dabSCorey Minyard * processing, it should be complete shut down when it returns.
153b7780dabSCorey Minyard */
154b7780dabSCorey Minyard void (*shutdown)(void *send_info);
155b7780dabSCorey Minyard
156b7780dabSCorey Minyard /*
15716f4232cSZhao Yakui * Get the detailed private info of the low level interface and store
15816f4232cSZhao Yakui * it into the structure of ipmi_smi_data. For example: the
15916f4232cSZhao Yakui * ACPI device handle will be returned for the pnp_acpi IPMI device.
16016f4232cSZhao Yakui */
16116f4232cSZhao Yakui int (*get_smi_info)(void *send_info, struct ipmi_smi_info *data);
16216f4232cSZhao Yakui
1636dc1181fSCorey Minyard /*
1646dc1181fSCorey Minyard * Called to enqueue an SMI message to be sent. This
1656dc1181fSCorey Minyard * operation is not allowed to fail. If an error occurs, it
1666dc1181fSCorey Minyard * should report back the error in a received message. It may
1676dc1181fSCorey Minyard * do this in the current call context, since no write locks
1686dc1181fSCorey Minyard * are held when this is run. Message are delivered one at
1696dc1181fSCorey Minyard * a time by the message handler, a new message will not be
1706dc1181fSCorey Minyard * delivered until the previous message is returned.
1716dc1181fSCorey Minyard */
1721da177e4SLinus Torvalds void (*sender)(void *send_info,
17399ab32f3SCorey Minyard struct ipmi_smi_msg *msg);
1741da177e4SLinus Torvalds
1756dc1181fSCorey Minyard /*
1766dc1181fSCorey Minyard * Called by the upper layer to request that we try to get
1776dc1181fSCorey Minyard * events from the BMC we are attached to.
1786dc1181fSCorey Minyard */
1791da177e4SLinus Torvalds void (*request_events)(void *send_info);
1801da177e4SLinus Torvalds
1816dc1181fSCorey Minyard /*
1826dc1181fSCorey Minyard * Called by the upper layer when some user requires that the
183c65ea996SCorey Minyard * interface watch for received messages and watchdog
184c65ea996SCorey Minyard * pretimeouts (basically do a "Get Flags", or not. Used by
185c65ea996SCorey Minyard * the SMI to know if it should watch for these. This may be
186c65ea996SCorey Minyard * NULL if the SMI does not implement it. watch_mask is from
187c65ea996SCorey Minyard * IPMI_WATCH_MASK_xxx above. The interface should run slower
188c65ea996SCorey Minyard * timeouts for just watchdog checking or faster timeouts when
189c65ea996SCorey Minyard * waiting for the message queue.
1906dc1181fSCorey Minyard */
191c65ea996SCorey Minyard void (*set_need_watch)(void *send_info, unsigned int watch_mask);
19289986496SCorey Minyard
19382802f96SHidehiro Kawai /*
19482802f96SHidehiro Kawai * Called when flushing all pending messages.
19582802f96SHidehiro Kawai */
19682802f96SHidehiro Kawai void (*flush_messages)(void *send_info);
19782802f96SHidehiro Kawai
1986dc1181fSCorey Minyard /*
1996dc1181fSCorey Minyard * Called when the interface should go into "run to
2006dc1181fSCorey Minyard * completion" mode. If this call sets the value to true, the
2016dc1181fSCorey Minyard * interface should make sure that all messages are flushed
2026dc1181fSCorey Minyard * out and that none are pending, and any new requests are run
2036dc1181fSCorey Minyard * to completion immediately.
2046dc1181fSCorey Minyard */
2057aefac26SCorey Minyard void (*set_run_to_completion)(void *send_info, bool run_to_completion);
2061da177e4SLinus Torvalds
2076dc1181fSCorey Minyard /*
2086dc1181fSCorey Minyard * Called to poll for work to do. This is so upper layers can
2096dc1181fSCorey Minyard * poll for operations during things like crash dumps.
2106dc1181fSCorey Minyard */
2111da177e4SLinus Torvalds void (*poll)(void *send_info);
2121da177e4SLinus Torvalds
2136dc1181fSCorey Minyard /*
2146dc1181fSCorey Minyard * Enable/disable firmware maintenance mode. Note that this
2156dc1181fSCorey Minyard * is *not* the modes defined, this is simply an on/off
2166dc1181fSCorey Minyard * setting. The message handler does the mode handling. Note
2176dc1181fSCorey Minyard * that this is called from interrupt context, so it cannot
2186dc1181fSCorey Minyard * block.
2196dc1181fSCorey Minyard */
2207aefac26SCorey Minyard void (*set_maintenance_mode)(void *send_info, bool enable);
2211da177e4SLinus Torvalds };
2221da177e4SLinus Torvalds
22350c812b2SCorey Minyard struct ipmi_device_id {
22450c812b2SCorey Minyard unsigned char device_id;
22550c812b2SCorey Minyard unsigned char device_revision;
22650c812b2SCorey Minyard unsigned char firmware_revision_1;
22750c812b2SCorey Minyard unsigned char firmware_revision_2;
22850c812b2SCorey Minyard unsigned char ipmi_version;
22950c812b2SCorey Minyard unsigned char additional_device_support;
23050c812b2SCorey Minyard unsigned int manufacturer_id;
23150c812b2SCorey Minyard unsigned int product_id;
23250c812b2SCorey Minyard unsigned char aux_firmware_revision[4];
23350c812b2SCorey Minyard unsigned int aux_firmware_revision_set : 1;
23450c812b2SCorey Minyard };
23550c812b2SCorey Minyard
23650c812b2SCorey Minyard #define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
23750c812b2SCorey Minyard #define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
23850c812b2SCorey Minyard
2396dc1181fSCorey Minyard /*
2406dc1181fSCorey Minyard * Take a pointer to an IPMI response and extract device id information from
241c468f911SJeremy Kerr * it. @netfn is in the IPMI_NETFN_ format, so may need to be shifted from
242c468f911SJeremy Kerr * a SI response.
243c468f911SJeremy Kerr */
ipmi_demangle_device_id(uint8_t netfn,uint8_t cmd,const unsigned char * data,unsigned int data_len,struct ipmi_device_id * id)244c468f911SJeremy Kerr static inline int ipmi_demangle_device_id(uint8_t netfn, uint8_t cmd,
245c468f911SJeremy Kerr const unsigned char *data,
24650c812b2SCorey Minyard unsigned int data_len,
24750c812b2SCorey Minyard struct ipmi_device_id *id)
24850c812b2SCorey Minyard {
249c468f911SJeremy Kerr if (data_len < 7)
250d8c98618SCorey Minyard return -EINVAL;
251c468f911SJeremy Kerr if (netfn != IPMI_NETFN_APP_RESPONSE || cmd != IPMI_GET_DEVICE_ID_CMD)
252d8c98618SCorey Minyard /* Strange, didn't get the response we expected. */
253d8c98618SCorey Minyard return -EINVAL;
254c468f911SJeremy Kerr if (data[0] != 0)
255d8c98618SCorey Minyard /* That's odd, it shouldn't be able to fail. */
256d8c98618SCorey Minyard return -EINVAL;
257d8c98618SCorey Minyard
258c468f911SJeremy Kerr data++;
259c468f911SJeremy Kerr data_len--;
260c468f911SJeremy Kerr
26150c812b2SCorey Minyard id->device_id = data[0];
26250c812b2SCorey Minyard id->device_revision = data[1];
26350c812b2SCorey Minyard id->firmware_revision_1 = data[2];
26450c812b2SCorey Minyard id->firmware_revision_2 = data[3];
26550c812b2SCorey Minyard id->ipmi_version = data[4];
26650c812b2SCorey Minyard id->additional_device_support = data[5];
26764e862a5SCorey Minyard if (data_len >= 11) {
268d8c98618SCorey Minyard id->manufacturer_id = (data[6] | (data[7] << 8) |
269d8c98618SCorey Minyard (data[8] << 16));
27050c812b2SCorey Minyard id->product_id = data[9] | (data[10] << 8);
271d8c98618SCorey Minyard } else {
272d8c98618SCorey Minyard id->manufacturer_id = 0;
273d8c98618SCorey Minyard id->product_id = 0;
274d8c98618SCorey Minyard }
27550c812b2SCorey Minyard if (data_len >= 15) {
27650c812b2SCorey Minyard memcpy(id->aux_firmware_revision, data+11, 4);
27750c812b2SCorey Minyard id->aux_firmware_revision_set = 1;
27850c812b2SCorey Minyard } else
27950c812b2SCorey Minyard id->aux_firmware_revision_set = 0;
280d8c98618SCorey Minyard
281d8c98618SCorey Minyard return 0;
28250c812b2SCorey Minyard }
28350c812b2SCorey Minyard
2846dc1181fSCorey Minyard /*
2856dc1181fSCorey Minyard * Add a low-level interface to the IPMI driver. Note that if the
2866dc1181fSCorey Minyard * interface doesn't know its slave address, it should pass in zero.
2876dc1181fSCorey Minyard * The low-level interface should not deliver any messages to the
2886dc1181fSCorey Minyard * upper layer until the start_processing() function in the handlers
2896dc1181fSCorey Minyard * is called, and the lower layer must get the interface from that
2906dc1181fSCorey Minyard * call.
2916dc1181fSCorey Minyard */
292cbb79863SCorey Minyard int ipmi_add_smi(struct module *owner,
293cbb79863SCorey Minyard const struct ipmi_smi_handlers *handlers,
2941da177e4SLinus Torvalds void *send_info,
29550c812b2SCorey Minyard struct device *dev,
296453823baSCorey Minyard unsigned char slave_addr);
2971da177e4SLinus Torvalds
298cbb79863SCorey Minyard #define ipmi_register_smi(handlers, send_info, dev, slave_addr) \
299cbb79863SCorey Minyard ipmi_add_smi(THIS_MODULE, handlers, send_info, dev, slave_addr)
300cbb79863SCorey Minyard
3011da177e4SLinus Torvalds /*
3021da177e4SLinus Torvalds * Remove a low-level interface from the IPMI driver. This will
3031da177e4SLinus Torvalds * return an error if the interface is still in use by a user.
3041da177e4SLinus Torvalds */
3055ce1a7dcSCorey Minyard void ipmi_unregister_smi(struct ipmi_smi *intf);
3061da177e4SLinus Torvalds
3071da177e4SLinus Torvalds /*
3081da177e4SLinus Torvalds * The lower layer reports received messages through this interface.
309b3834be5SAdam Buchbinder * The data_size should be zero if this is an asynchronous message. If
3101da177e4SLinus Torvalds * the lower layer gets an error sending a message, it should format
3111da177e4SLinus Torvalds * an error response in the message response.
3121da177e4SLinus Torvalds */
3135ce1a7dcSCorey Minyard void ipmi_smi_msg_received(struct ipmi_smi *intf,
3141da177e4SLinus Torvalds struct ipmi_smi_msg *msg);
3151da177e4SLinus Torvalds
3161da177e4SLinus Torvalds /* The lower layer received a watchdog pre-timeout on interface. */
3175ce1a7dcSCorey Minyard void ipmi_smi_watchdog_pretimeout(struct ipmi_smi *intf);
3181da177e4SLinus Torvalds
3191da177e4SLinus Torvalds struct ipmi_smi_msg *ipmi_alloc_smi_msg(void);
ipmi_free_smi_msg(struct ipmi_smi_msg * msg)3201da177e4SLinus Torvalds static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg)
3211da177e4SLinus Torvalds {
3221da177e4SLinus Torvalds msg->done(msg);
3231da177e4SLinus Torvalds }
3241da177e4SLinus Torvalds
3251da177e4SLinus Torvalds #endif /* __LINUX_IPMI_SMI_H */
326