xref: /openbmc/linux/include/linux/ipmi_smi.h (revision 9824117d)
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