162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ipmi_msghandler.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Incoming and outgoing message routing for an IPMI interface.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: MontaVista Software, Inc.
862306a36Sopenharmony_ci *         Corey Minyard <minyard@mvista.com>
962306a36Sopenharmony_ci *         source@mvista.com
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Copyright 2002 MontaVista Software Inc.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define pr_fmt(fmt) "IPMI message handler: " fmt
1562306a36Sopenharmony_ci#define dev_fmt(fmt) pr_fmt(fmt)
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/errno.h>
1962306a36Sopenharmony_ci#include <linux/panic_notifier.h>
2062306a36Sopenharmony_ci#include <linux/poll.h>
2162306a36Sopenharmony_ci#include <linux/sched.h>
2262306a36Sopenharmony_ci#include <linux/seq_file.h>
2362306a36Sopenharmony_ci#include <linux/spinlock.h>
2462306a36Sopenharmony_ci#include <linux/mutex.h>
2562306a36Sopenharmony_ci#include <linux/slab.h>
2662306a36Sopenharmony_ci#include <linux/ipmi.h>
2762306a36Sopenharmony_ci#include <linux/ipmi_smi.h>
2862306a36Sopenharmony_ci#include <linux/notifier.h>
2962306a36Sopenharmony_ci#include <linux/init.h>
3062306a36Sopenharmony_ci#include <linux/proc_fs.h>
3162306a36Sopenharmony_ci#include <linux/rcupdate.h>
3262306a36Sopenharmony_ci#include <linux/interrupt.h>
3362306a36Sopenharmony_ci#include <linux/moduleparam.h>
3462306a36Sopenharmony_ci#include <linux/workqueue.h>
3562306a36Sopenharmony_ci#include <linux/uuid.h>
3662306a36Sopenharmony_ci#include <linux/nospec.h>
3762306a36Sopenharmony_ci#include <linux/vmalloc.h>
3862306a36Sopenharmony_ci#include <linux/delay.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define IPMI_DRIVER_VERSION "39.2"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
4362306a36Sopenharmony_cistatic int ipmi_init_msghandler(void);
4462306a36Sopenharmony_cistatic void smi_recv_tasklet(struct tasklet_struct *t);
4562306a36Sopenharmony_cistatic void handle_new_recv_msgs(struct ipmi_smi *intf);
4662306a36Sopenharmony_cistatic void need_waiter(struct ipmi_smi *intf);
4762306a36Sopenharmony_cistatic int handle_one_recv_msg(struct ipmi_smi *intf,
4862306a36Sopenharmony_ci			       struct ipmi_smi_msg *msg);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic bool initialized;
5162306a36Sopenharmony_cistatic bool drvregistered;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Numbers in this enumerator should be mapped to ipmi_panic_event_str */
5462306a36Sopenharmony_cienum ipmi_panic_event_op {
5562306a36Sopenharmony_ci	IPMI_SEND_PANIC_EVENT_NONE,
5662306a36Sopenharmony_ci	IPMI_SEND_PANIC_EVENT,
5762306a36Sopenharmony_ci	IPMI_SEND_PANIC_EVENT_STRING,
5862306a36Sopenharmony_ci	IPMI_SEND_PANIC_EVENT_MAX
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* Indices in this array should be mapped to enum ipmi_panic_event_op */
6262306a36Sopenharmony_cistatic const char *const ipmi_panic_event_str[] = { "none", "event", "string", NULL };
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#ifdef CONFIG_IPMI_PANIC_STRING
6562306a36Sopenharmony_ci#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_STRING
6662306a36Sopenharmony_ci#elif defined(CONFIG_IPMI_PANIC_EVENT)
6762306a36Sopenharmony_ci#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT
6862306a36Sopenharmony_ci#else
6962306a36Sopenharmony_ci#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_NONE
7062306a36Sopenharmony_ci#endif
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic enum ipmi_panic_event_op ipmi_send_panic_event = IPMI_PANIC_DEFAULT;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int panic_op_write_handler(const char *val,
7562306a36Sopenharmony_ci				  const struct kernel_param *kp)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	char valcp[16];
7862306a36Sopenharmony_ci	int e;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	strscpy(valcp, val, sizeof(valcp));
8162306a36Sopenharmony_ci	e = match_string(ipmi_panic_event_str, -1, strstrip(valcp));
8262306a36Sopenharmony_ci	if (e < 0)
8362306a36Sopenharmony_ci		return e;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	ipmi_send_panic_event = e;
8662306a36Sopenharmony_ci	return 0;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int panic_op_read_handler(char *buffer, const struct kernel_param *kp)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	const char *event_str;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (ipmi_send_panic_event >= IPMI_SEND_PANIC_EVENT_MAX)
9462306a36Sopenharmony_ci		event_str = "???";
9562306a36Sopenharmony_ci	else
9662306a36Sopenharmony_ci		event_str = ipmi_panic_event_str[ipmi_send_panic_event];
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return sprintf(buffer, "%s\n", event_str);
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic const struct kernel_param_ops panic_op_ops = {
10262306a36Sopenharmony_ci	.set = panic_op_write_handler,
10362306a36Sopenharmony_ci	.get = panic_op_read_handler
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_cimodule_param_cb(panic_op, &panic_op_ops, NULL, 0600);
10662306a36Sopenharmony_ciMODULE_PARM_DESC(panic_op, "Sets if the IPMI driver will attempt to store panic information in the event log in the event of a panic.  Set to 'none' for no, 'event' for a single event, or 'string' for a generic event and the panic string in IPMI OEM events.");
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define MAX_EVENTS_IN_QUEUE	25
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/* Remain in auto-maintenance mode for this amount of time (in ms). */
11262306a36Sopenharmony_cistatic unsigned long maintenance_mode_timeout_ms = 30000;
11362306a36Sopenharmony_cimodule_param(maintenance_mode_timeout_ms, ulong, 0644);
11462306a36Sopenharmony_ciMODULE_PARM_DESC(maintenance_mode_timeout_ms,
11562306a36Sopenharmony_ci		 "The time (milliseconds) after the last maintenance message that the connection stays in maintenance mode.");
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/*
11862306a36Sopenharmony_ci * Don't let a message sit in a queue forever, always time it with at lest
11962306a36Sopenharmony_ci * the max message timer.  This is in milliseconds.
12062306a36Sopenharmony_ci */
12162306a36Sopenharmony_ci#define MAX_MSG_TIMEOUT		60000
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/*
12462306a36Sopenharmony_ci * Timeout times below are in milliseconds, and are done off a 1
12562306a36Sopenharmony_ci * second timer.  So setting the value to 1000 would mean anything
12662306a36Sopenharmony_ci * between 0 and 1000ms.  So really the only reasonable minimum
12762306a36Sopenharmony_ci * setting it 2000ms, which is between 1 and 2 seconds.
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* The default timeout for message retries. */
13162306a36Sopenharmony_cistatic unsigned long default_retry_ms = 2000;
13262306a36Sopenharmony_cimodule_param(default_retry_ms, ulong, 0644);
13362306a36Sopenharmony_ciMODULE_PARM_DESC(default_retry_ms,
13462306a36Sopenharmony_ci		 "The time (milliseconds) between retry sends");
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* The default timeout for maintenance mode message retries. */
13762306a36Sopenharmony_cistatic unsigned long default_maintenance_retry_ms = 3000;
13862306a36Sopenharmony_cimodule_param(default_maintenance_retry_ms, ulong, 0644);
13962306a36Sopenharmony_ciMODULE_PARM_DESC(default_maintenance_retry_ms,
14062306a36Sopenharmony_ci		 "The time (milliseconds) between retry sends in maintenance mode");
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* The default maximum number of retries */
14362306a36Sopenharmony_cistatic unsigned int default_max_retries = 4;
14462306a36Sopenharmony_cimodule_param(default_max_retries, uint, 0644);
14562306a36Sopenharmony_ciMODULE_PARM_DESC(default_max_retries,
14662306a36Sopenharmony_ci		 "The time (milliseconds) between retry sends in maintenance mode");
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/* The default maximum number of users that may register. */
14962306a36Sopenharmony_cistatic unsigned int max_users = 30;
15062306a36Sopenharmony_cimodule_param(max_users, uint, 0644);
15162306a36Sopenharmony_ciMODULE_PARM_DESC(max_users,
15262306a36Sopenharmony_ci		 "The most users that may use the IPMI stack at one time.");
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/* The default maximum number of message a user may have outstanding. */
15562306a36Sopenharmony_cistatic unsigned int max_msgs_per_user = 100;
15662306a36Sopenharmony_cimodule_param(max_msgs_per_user, uint, 0644);
15762306a36Sopenharmony_ciMODULE_PARM_DESC(max_msgs_per_user,
15862306a36Sopenharmony_ci		 "The most message a user may have outstanding.");
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/* Call every ~1000 ms. */
16162306a36Sopenharmony_ci#define IPMI_TIMEOUT_TIME	1000
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/* How many jiffies does it take to get to the timeout time. */
16462306a36Sopenharmony_ci#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ) / 1000)
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/*
16762306a36Sopenharmony_ci * Request events from the queue every second (this is the number of
16862306a36Sopenharmony_ci * IPMI_TIMEOUT_TIMES between event requests).  Hopefully, in the
16962306a36Sopenharmony_ci * future, IPMI will add a way to know immediately if an event is in
17062306a36Sopenharmony_ci * the queue and this silliness can go away.
17162306a36Sopenharmony_ci */
17262306a36Sopenharmony_ci#define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME))
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/* How long should we cache dynamic device IDs? */
17562306a36Sopenharmony_ci#define IPMI_DYN_DEV_ID_EXPIRY	(10 * HZ)
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/*
17862306a36Sopenharmony_ci * The main "user" data structure.
17962306a36Sopenharmony_ci */
18062306a36Sopenharmony_cistruct ipmi_user {
18162306a36Sopenharmony_ci	struct list_head link;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/*
18462306a36Sopenharmony_ci	 * Set to NULL when the user is destroyed, a pointer to myself
18562306a36Sopenharmony_ci	 * so srcu_dereference can be used on it.
18662306a36Sopenharmony_ci	 */
18762306a36Sopenharmony_ci	struct ipmi_user *self;
18862306a36Sopenharmony_ci	struct srcu_struct release_barrier;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	struct kref refcount;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* The upper layer that handles receive messages. */
19362306a36Sopenharmony_ci	const struct ipmi_user_hndl *handler;
19462306a36Sopenharmony_ci	void             *handler_data;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* The interface this user is bound to. */
19762306a36Sopenharmony_ci	struct ipmi_smi *intf;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* Does this interface receive IPMI events? */
20062306a36Sopenharmony_ci	bool gets_events;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	atomic_t nr_msgs;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* Free must run in process context for RCU cleanup. */
20562306a36Sopenharmony_ci	struct work_struct remove_work;
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic struct workqueue_struct *remove_work_wq;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index)
21162306a36Sopenharmony_ci	__acquires(user->release_barrier)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct ipmi_user *ruser;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	*index = srcu_read_lock(&user->release_barrier);
21662306a36Sopenharmony_ci	ruser = srcu_dereference(user->self, &user->release_barrier);
21762306a36Sopenharmony_ci	if (!ruser)
21862306a36Sopenharmony_ci		srcu_read_unlock(&user->release_barrier, *index);
21962306a36Sopenharmony_ci	return ruser;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic void release_ipmi_user(struct ipmi_user *user, int index)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	srcu_read_unlock(&user->release_barrier, index);
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistruct cmd_rcvr {
22862306a36Sopenharmony_ci	struct list_head link;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	struct ipmi_user *user;
23162306a36Sopenharmony_ci	unsigned char netfn;
23262306a36Sopenharmony_ci	unsigned char cmd;
23362306a36Sopenharmony_ci	unsigned int  chans;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/*
23662306a36Sopenharmony_ci	 * This is used to form a linked lised during mass deletion.
23762306a36Sopenharmony_ci	 * Since this is in an RCU list, we cannot use the link above
23862306a36Sopenharmony_ci	 * or change any data until the RCU period completes.  So we
23962306a36Sopenharmony_ci	 * use this next variable during mass deletion so we can have
24062306a36Sopenharmony_ci	 * a list and don't have to wait and restart the search on
24162306a36Sopenharmony_ci	 * every individual deletion of a command.
24262306a36Sopenharmony_ci	 */
24362306a36Sopenharmony_ci	struct cmd_rcvr *next;
24462306a36Sopenharmony_ci};
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistruct seq_table {
24762306a36Sopenharmony_ci	unsigned int         inuse : 1;
24862306a36Sopenharmony_ci	unsigned int         broadcast : 1;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	unsigned long        timeout;
25162306a36Sopenharmony_ci	unsigned long        orig_timeout;
25262306a36Sopenharmony_ci	unsigned int         retries_left;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/*
25562306a36Sopenharmony_ci	 * To verify on an incoming send message response that this is
25662306a36Sopenharmony_ci	 * the message that the response is for, we keep a sequence id
25762306a36Sopenharmony_ci	 * and increment it every time we send a message.
25862306a36Sopenharmony_ci	 */
25962306a36Sopenharmony_ci	long                 seqid;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/*
26262306a36Sopenharmony_ci	 * This is held so we can properly respond to the message on a
26362306a36Sopenharmony_ci	 * timeout, and it is used to hold the temporary data for
26462306a36Sopenharmony_ci	 * retransmission, too.
26562306a36Sopenharmony_ci	 */
26662306a36Sopenharmony_ci	struct ipmi_recv_msg *recv_msg;
26762306a36Sopenharmony_ci};
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/*
27062306a36Sopenharmony_ci * Store the information in a msgid (long) to allow us to find a
27162306a36Sopenharmony_ci * sequence table entry from the msgid.
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_ci#define STORE_SEQ_IN_MSGID(seq, seqid) \
27462306a36Sopenharmony_ci	((((seq) & 0x3f) << 26) | ((seqid) & 0x3ffffff))
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
27762306a36Sopenharmony_ci	do {								\
27862306a36Sopenharmony_ci		seq = (((msgid) >> 26) & 0x3f);				\
27962306a36Sopenharmony_ci		seqid = ((msgid) & 0x3ffffff);				\
28062306a36Sopenharmony_ci	} while (0)
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3ffffff)
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci#define IPMI_MAX_CHANNELS       16
28562306a36Sopenharmony_cistruct ipmi_channel {
28662306a36Sopenharmony_ci	unsigned char medium;
28762306a36Sopenharmony_ci	unsigned char protocol;
28862306a36Sopenharmony_ci};
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistruct ipmi_channel_set {
29162306a36Sopenharmony_ci	struct ipmi_channel c[IPMI_MAX_CHANNELS];
29262306a36Sopenharmony_ci};
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistruct ipmi_my_addrinfo {
29562306a36Sopenharmony_ci	/*
29662306a36Sopenharmony_ci	 * My slave address.  This is initialized to IPMI_BMC_SLAVE_ADDR,
29762306a36Sopenharmony_ci	 * but may be changed by the user.
29862306a36Sopenharmony_ci	 */
29962306a36Sopenharmony_ci	unsigned char address;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/*
30262306a36Sopenharmony_ci	 * My LUN.  This should generally stay the SMS LUN, but just in
30362306a36Sopenharmony_ci	 * case...
30462306a36Sopenharmony_ci	 */
30562306a36Sopenharmony_ci	unsigned char lun;
30662306a36Sopenharmony_ci};
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci/*
30962306a36Sopenharmony_ci * Note that the product id, manufacturer id, guid, and device id are
31062306a36Sopenharmony_ci * immutable in this structure, so dyn_mutex is not required for
31162306a36Sopenharmony_ci * accessing those.  If those change on a BMC, a new BMC is allocated.
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_cistruct bmc_device {
31462306a36Sopenharmony_ci	struct platform_device pdev;
31562306a36Sopenharmony_ci	struct list_head       intfs; /* Interfaces on this BMC. */
31662306a36Sopenharmony_ci	struct ipmi_device_id  id;
31762306a36Sopenharmony_ci	struct ipmi_device_id  fetch_id;
31862306a36Sopenharmony_ci	int                    dyn_id_set;
31962306a36Sopenharmony_ci	unsigned long          dyn_id_expiry;
32062306a36Sopenharmony_ci	struct mutex           dyn_mutex; /* Protects id, intfs, & dyn* */
32162306a36Sopenharmony_ci	guid_t                 guid;
32262306a36Sopenharmony_ci	guid_t                 fetch_guid;
32362306a36Sopenharmony_ci	int                    dyn_guid_set;
32462306a36Sopenharmony_ci	struct kref	       usecount;
32562306a36Sopenharmony_ci	struct work_struct     remove_work;
32662306a36Sopenharmony_ci	unsigned char	       cc; /* completion code */
32762306a36Sopenharmony_ci};
32862306a36Sopenharmony_ci#define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev)
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic int bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc,
33162306a36Sopenharmony_ci			     struct ipmi_device_id *id,
33262306a36Sopenharmony_ci			     bool *guid_set, guid_t *guid);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/*
33562306a36Sopenharmony_ci * Various statistics for IPMI, these index stats[] in the ipmi_smi
33662306a36Sopenharmony_ci * structure.
33762306a36Sopenharmony_ci */
33862306a36Sopenharmony_cienum ipmi_stat_indexes {
33962306a36Sopenharmony_ci	/* Commands we got from the user that were invalid. */
34062306a36Sopenharmony_ci	IPMI_STAT_sent_invalid_commands = 0,
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Commands we sent to the MC. */
34362306a36Sopenharmony_ci	IPMI_STAT_sent_local_commands,
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Responses from the MC that were delivered to a user. */
34662306a36Sopenharmony_ci	IPMI_STAT_handled_local_responses,
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* Responses from the MC that were not delivered to a user. */
34962306a36Sopenharmony_ci	IPMI_STAT_unhandled_local_responses,
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Commands we sent out to the IPMB bus. */
35262306a36Sopenharmony_ci	IPMI_STAT_sent_ipmb_commands,
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* Commands sent on the IPMB that had errors on the SEND CMD */
35562306a36Sopenharmony_ci	IPMI_STAT_sent_ipmb_command_errs,
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* Each retransmit increments this count. */
35862306a36Sopenharmony_ci	IPMI_STAT_retransmitted_ipmb_commands,
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/*
36162306a36Sopenharmony_ci	 * When a message times out (runs out of retransmits) this is
36262306a36Sopenharmony_ci	 * incremented.
36362306a36Sopenharmony_ci	 */
36462306a36Sopenharmony_ci	IPMI_STAT_timed_out_ipmb_commands,
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/*
36762306a36Sopenharmony_ci	 * This is like above, but for broadcasts.  Broadcasts are
36862306a36Sopenharmony_ci	 * *not* included in the above count (they are expected to
36962306a36Sopenharmony_ci	 * time out).
37062306a36Sopenharmony_ci	 */
37162306a36Sopenharmony_ci	IPMI_STAT_timed_out_ipmb_broadcasts,
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Responses I have sent to the IPMB bus. */
37462306a36Sopenharmony_ci	IPMI_STAT_sent_ipmb_responses,
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	/* The response was delivered to the user. */
37762306a36Sopenharmony_ci	IPMI_STAT_handled_ipmb_responses,
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* The response had invalid data in it. */
38062306a36Sopenharmony_ci	IPMI_STAT_invalid_ipmb_responses,
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/* The response didn't have anyone waiting for it. */
38362306a36Sopenharmony_ci	IPMI_STAT_unhandled_ipmb_responses,
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* Commands we sent out to the IPMB bus. */
38662306a36Sopenharmony_ci	IPMI_STAT_sent_lan_commands,
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/* Commands sent on the IPMB that had errors on the SEND CMD */
38962306a36Sopenharmony_ci	IPMI_STAT_sent_lan_command_errs,
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* Each retransmit increments this count. */
39262306a36Sopenharmony_ci	IPMI_STAT_retransmitted_lan_commands,
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/*
39562306a36Sopenharmony_ci	 * When a message times out (runs out of retransmits) this is
39662306a36Sopenharmony_ci	 * incremented.
39762306a36Sopenharmony_ci	 */
39862306a36Sopenharmony_ci	IPMI_STAT_timed_out_lan_commands,
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* Responses I have sent to the IPMB bus. */
40162306a36Sopenharmony_ci	IPMI_STAT_sent_lan_responses,
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/* The response was delivered to the user. */
40462306a36Sopenharmony_ci	IPMI_STAT_handled_lan_responses,
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* The response had invalid data in it. */
40762306a36Sopenharmony_ci	IPMI_STAT_invalid_lan_responses,
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* The response didn't have anyone waiting for it. */
41062306a36Sopenharmony_ci	IPMI_STAT_unhandled_lan_responses,
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* The command was delivered to the user. */
41362306a36Sopenharmony_ci	IPMI_STAT_handled_commands,
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* The command had invalid data in it. */
41662306a36Sopenharmony_ci	IPMI_STAT_invalid_commands,
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* The command didn't have anyone waiting for it. */
41962306a36Sopenharmony_ci	IPMI_STAT_unhandled_commands,
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/* Invalid data in an event. */
42262306a36Sopenharmony_ci	IPMI_STAT_invalid_events,
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* Events that were received with the proper format. */
42562306a36Sopenharmony_ci	IPMI_STAT_events,
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* Retransmissions on IPMB that failed. */
42862306a36Sopenharmony_ci	IPMI_STAT_dropped_rexmit_ipmb_commands,
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	/* Retransmissions on LAN that failed. */
43162306a36Sopenharmony_ci	IPMI_STAT_dropped_rexmit_lan_commands,
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* This *must* remain last, add new values above this. */
43462306a36Sopenharmony_ci	IPMI_NUM_STATS
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci#define IPMI_IPMB_NUM_SEQ	64
43962306a36Sopenharmony_cistruct ipmi_smi {
44062306a36Sopenharmony_ci	struct module *owner;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	/* What interface number are we? */
44362306a36Sopenharmony_ci	int intf_num;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	struct kref refcount;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* Set when the interface is being unregistered. */
44862306a36Sopenharmony_ci	bool in_shutdown;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* Used for a list of interfaces. */
45162306a36Sopenharmony_ci	struct list_head link;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/*
45462306a36Sopenharmony_ci	 * The list of upper layers that are using me.  seq_lock write
45562306a36Sopenharmony_ci	 * protects this.  Read protection is with srcu.
45662306a36Sopenharmony_ci	 */
45762306a36Sopenharmony_ci	struct list_head users;
45862306a36Sopenharmony_ci	struct srcu_struct users_srcu;
45962306a36Sopenharmony_ci	atomic_t nr_users;
46062306a36Sopenharmony_ci	struct device_attribute nr_users_devattr;
46162306a36Sopenharmony_ci	struct device_attribute nr_msgs_devattr;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* Used for wake ups at startup. */
46562306a36Sopenharmony_ci	wait_queue_head_t waitq;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/*
46862306a36Sopenharmony_ci	 * Prevents the interface from being unregistered when the
46962306a36Sopenharmony_ci	 * interface is used by being looked up through the BMC
47062306a36Sopenharmony_ci	 * structure.
47162306a36Sopenharmony_ci	 */
47262306a36Sopenharmony_ci	struct mutex bmc_reg_mutex;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	struct bmc_device tmp_bmc;
47562306a36Sopenharmony_ci	struct bmc_device *bmc;
47662306a36Sopenharmony_ci	bool bmc_registered;
47762306a36Sopenharmony_ci	struct list_head bmc_link;
47862306a36Sopenharmony_ci	char *my_dev_name;
47962306a36Sopenharmony_ci	bool in_bmc_register;  /* Handle recursive situations.  Yuck. */
48062306a36Sopenharmony_ci	struct work_struct bmc_reg_work;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	const struct ipmi_smi_handlers *handlers;
48362306a36Sopenharmony_ci	void                     *send_info;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* Driver-model device for the system interface. */
48662306a36Sopenharmony_ci	struct device          *si_dev;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/*
48962306a36Sopenharmony_ci	 * A table of sequence numbers for this interface.  We use the
49062306a36Sopenharmony_ci	 * sequence numbers for IPMB messages that go out of the
49162306a36Sopenharmony_ci	 * interface to match them up with their responses.  A routine
49262306a36Sopenharmony_ci	 * is called periodically to time the items in this list.
49362306a36Sopenharmony_ci	 */
49462306a36Sopenharmony_ci	spinlock_t       seq_lock;
49562306a36Sopenharmony_ci	struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
49662306a36Sopenharmony_ci	int curr_seq;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/*
49962306a36Sopenharmony_ci	 * Messages queued for delivery.  If delivery fails (out of memory
50062306a36Sopenharmony_ci	 * for instance), They will stay in here to be processed later in a
50162306a36Sopenharmony_ci	 * periodic timer interrupt.  The tasklet is for handling received
50262306a36Sopenharmony_ci	 * messages directly from the handler.
50362306a36Sopenharmony_ci	 */
50462306a36Sopenharmony_ci	spinlock_t       waiting_rcv_msgs_lock;
50562306a36Sopenharmony_ci	struct list_head waiting_rcv_msgs;
50662306a36Sopenharmony_ci	atomic_t	 watchdog_pretimeouts_to_deliver;
50762306a36Sopenharmony_ci	struct tasklet_struct recv_tasklet;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	spinlock_t             xmit_msgs_lock;
51062306a36Sopenharmony_ci	struct list_head       xmit_msgs;
51162306a36Sopenharmony_ci	struct ipmi_smi_msg    *curr_msg;
51262306a36Sopenharmony_ci	struct list_head       hp_xmit_msgs;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/*
51562306a36Sopenharmony_ci	 * The list of command receivers that are registered for commands
51662306a36Sopenharmony_ci	 * on this interface.
51762306a36Sopenharmony_ci	 */
51862306a36Sopenharmony_ci	struct mutex     cmd_rcvrs_mutex;
51962306a36Sopenharmony_ci	struct list_head cmd_rcvrs;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/*
52262306a36Sopenharmony_ci	 * Events that were queues because no one was there to receive
52362306a36Sopenharmony_ci	 * them.
52462306a36Sopenharmony_ci	 */
52562306a36Sopenharmony_ci	spinlock_t       events_lock; /* For dealing with event stuff. */
52662306a36Sopenharmony_ci	struct list_head waiting_events;
52762306a36Sopenharmony_ci	unsigned int     waiting_events_count; /* How many events in queue? */
52862306a36Sopenharmony_ci	char             delivering_events;
52962306a36Sopenharmony_ci	char             event_msg_printed;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* How many users are waiting for events? */
53262306a36Sopenharmony_ci	atomic_t         event_waiters;
53362306a36Sopenharmony_ci	unsigned int     ticks_to_req_ev;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	spinlock_t       watch_lock; /* For dealing with watch stuff below. */
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* How many users are waiting for commands? */
53862306a36Sopenharmony_ci	unsigned int     command_waiters;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	/* How many users are waiting for watchdogs? */
54162306a36Sopenharmony_ci	unsigned int     watchdog_waiters;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* How many users are waiting for message responses? */
54462306a36Sopenharmony_ci	unsigned int     response_waiters;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	/*
54762306a36Sopenharmony_ci	 * Tells what the lower layer has last been asked to watch for,
54862306a36Sopenharmony_ci	 * messages and/or watchdogs.  Protected by watch_lock.
54962306a36Sopenharmony_ci	 */
55062306a36Sopenharmony_ci	unsigned int     last_watch_mask;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/*
55362306a36Sopenharmony_ci	 * The event receiver for my BMC, only really used at panic
55462306a36Sopenharmony_ci	 * shutdown as a place to store this.
55562306a36Sopenharmony_ci	 */
55662306a36Sopenharmony_ci	unsigned char event_receiver;
55762306a36Sopenharmony_ci	unsigned char event_receiver_lun;
55862306a36Sopenharmony_ci	unsigned char local_sel_device;
55962306a36Sopenharmony_ci	unsigned char local_event_generator;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/* For handling of maintenance mode. */
56262306a36Sopenharmony_ci	int maintenance_mode;
56362306a36Sopenharmony_ci	bool maintenance_mode_enable;
56462306a36Sopenharmony_ci	int auto_maintenance_timeout;
56562306a36Sopenharmony_ci	spinlock_t maintenance_mode_lock; /* Used in a timer... */
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/*
56862306a36Sopenharmony_ci	 * If we are doing maintenance on something on IPMB, extend
56962306a36Sopenharmony_ci	 * the timeout time to avoid timeouts writing firmware and
57062306a36Sopenharmony_ci	 * such.
57162306a36Sopenharmony_ci	 */
57262306a36Sopenharmony_ci	int ipmb_maintenance_mode_timeout;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/*
57562306a36Sopenharmony_ci	 * A cheap hack, if this is non-null and a message to an
57662306a36Sopenharmony_ci	 * interface comes in with a NULL user, call this routine with
57762306a36Sopenharmony_ci	 * it.  Note that the message will still be freed by the
57862306a36Sopenharmony_ci	 * caller.  This only works on the system interface.
57962306a36Sopenharmony_ci	 *
58062306a36Sopenharmony_ci	 * Protected by bmc_reg_mutex.
58162306a36Sopenharmony_ci	 */
58262306a36Sopenharmony_ci	void (*null_user_handler)(struct ipmi_smi *intf,
58362306a36Sopenharmony_ci				  struct ipmi_recv_msg *msg);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/*
58662306a36Sopenharmony_ci	 * When we are scanning the channels for an SMI, this will
58762306a36Sopenharmony_ci	 * tell which channel we are scanning.
58862306a36Sopenharmony_ci	 */
58962306a36Sopenharmony_ci	int curr_channel;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/* Channel information */
59262306a36Sopenharmony_ci	struct ipmi_channel_set *channel_list;
59362306a36Sopenharmony_ci	unsigned int curr_working_cset; /* First index into the following. */
59462306a36Sopenharmony_ci	struct ipmi_channel_set wchannels[2];
59562306a36Sopenharmony_ci	struct ipmi_my_addrinfo addrinfo[IPMI_MAX_CHANNELS];
59662306a36Sopenharmony_ci	bool channels_ready;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	atomic_t stats[IPMI_NUM_STATS];
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/*
60162306a36Sopenharmony_ci	 * run_to_completion duplicate of smb_info, smi_info
60262306a36Sopenharmony_ci	 * and ipmi_serial_info structures. Used to decrease numbers of
60362306a36Sopenharmony_ci	 * parameters passed by "low" level IPMI code.
60462306a36Sopenharmony_ci	 */
60562306a36Sopenharmony_ci	int run_to_completion;
60662306a36Sopenharmony_ci};
60762306a36Sopenharmony_ci#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic void __get_guid(struct ipmi_smi *intf);
61062306a36Sopenharmony_cistatic void __ipmi_bmc_unregister(struct ipmi_smi *intf);
61162306a36Sopenharmony_cistatic int __ipmi_bmc_register(struct ipmi_smi *intf,
61262306a36Sopenharmony_ci			       struct ipmi_device_id *id,
61362306a36Sopenharmony_ci			       bool guid_set, guid_t *guid, int intf_num);
61462306a36Sopenharmony_cistatic int __scan_channels(struct ipmi_smi *intf, struct ipmi_device_id *id);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci/*
61862306a36Sopenharmony_ci * The driver model view of the IPMI messaging driver.
61962306a36Sopenharmony_ci */
62062306a36Sopenharmony_cistatic struct platform_driver ipmidriver = {
62162306a36Sopenharmony_ci	.driver = {
62262306a36Sopenharmony_ci		.name = "ipmi",
62362306a36Sopenharmony_ci		.bus = &platform_bus_type
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci};
62662306a36Sopenharmony_ci/*
62762306a36Sopenharmony_ci * This mutex keeps us from adding the same BMC twice.
62862306a36Sopenharmony_ci */
62962306a36Sopenharmony_cistatic DEFINE_MUTEX(ipmidriver_mutex);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic LIST_HEAD(ipmi_interfaces);
63262306a36Sopenharmony_cistatic DEFINE_MUTEX(ipmi_interfaces_mutex);
63362306a36Sopenharmony_ci#define ipmi_interfaces_mutex_held() \
63462306a36Sopenharmony_ci	lockdep_is_held(&ipmi_interfaces_mutex)
63562306a36Sopenharmony_cistatic struct srcu_struct ipmi_interfaces_srcu;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci/*
63862306a36Sopenharmony_ci * List of watchers that want to know when smi's are added and deleted.
63962306a36Sopenharmony_ci */
64062306a36Sopenharmony_cistatic LIST_HEAD(smi_watchers);
64162306a36Sopenharmony_cistatic DEFINE_MUTEX(smi_watchers_mutex);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci#define ipmi_inc_stat(intf, stat) \
64462306a36Sopenharmony_ci	atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat])
64562306a36Sopenharmony_ci#define ipmi_get_stat(intf, stat) \
64662306a36Sopenharmony_ci	((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat]))
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic const char * const addr_src_to_str[] = {
64962306a36Sopenharmony_ci	"invalid", "hotmod", "hardcoded", "SPMI", "ACPI", "SMBIOS", "PCI",
65062306a36Sopenharmony_ci	"device-tree", "platform"
65162306a36Sopenharmony_ci};
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ciconst char *ipmi_addr_src_to_str(enum ipmi_addr_src src)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	if (src >= SI_LAST)
65662306a36Sopenharmony_ci		src = 0; /* Invalid */
65762306a36Sopenharmony_ci	return addr_src_to_str[src];
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_addr_src_to_str);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int is_lan_addr(struct ipmi_addr *addr)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	return addr->addr_type == IPMI_LAN_ADDR_TYPE;
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic int is_ipmb_addr(struct ipmi_addr *addr)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	return addr->addr_type == IPMI_IPMB_ADDR_TYPE;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic int is_ipmb_bcast_addr(struct ipmi_addr *addr)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	return addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE;
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic int is_ipmb_direct_addr(struct ipmi_addr *addr)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	return addr->addr_type == IPMI_IPMB_DIRECT_ADDR_TYPE;
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic void free_recv_msg_list(struct list_head *q)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	struct ipmi_recv_msg *msg, *msg2;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	list_for_each_entry_safe(msg, msg2, q, link) {
68662306a36Sopenharmony_ci		list_del(&msg->link);
68762306a36Sopenharmony_ci		ipmi_free_recv_msg(msg);
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic void free_smi_msg_list(struct list_head *q)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	struct ipmi_smi_msg *msg, *msg2;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	list_for_each_entry_safe(msg, msg2, q, link) {
69662306a36Sopenharmony_ci		list_del(&msg->link);
69762306a36Sopenharmony_ci		ipmi_free_smi_msg(msg);
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic void clean_up_interface_data(struct ipmi_smi *intf)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	int              i;
70462306a36Sopenharmony_ci	struct cmd_rcvr  *rcvr, *rcvr2;
70562306a36Sopenharmony_ci	struct list_head list;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	tasklet_kill(&intf->recv_tasklet);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	free_smi_msg_list(&intf->waiting_rcv_msgs);
71062306a36Sopenharmony_ci	free_recv_msg_list(&intf->waiting_events);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	/*
71362306a36Sopenharmony_ci	 * Wholesale remove all the entries from the list in the
71462306a36Sopenharmony_ci	 * interface and wait for RCU to know that none are in use.
71562306a36Sopenharmony_ci	 */
71662306a36Sopenharmony_ci	mutex_lock(&intf->cmd_rcvrs_mutex);
71762306a36Sopenharmony_ci	INIT_LIST_HEAD(&list);
71862306a36Sopenharmony_ci	list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu);
71962306a36Sopenharmony_ci	mutex_unlock(&intf->cmd_rcvrs_mutex);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	list_for_each_entry_safe(rcvr, rcvr2, &list, link)
72262306a36Sopenharmony_ci		kfree(rcvr);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
72562306a36Sopenharmony_ci		if ((intf->seq_table[i].inuse)
72662306a36Sopenharmony_ci					&& (intf->seq_table[i].recv_msg))
72762306a36Sopenharmony_ci			ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic void intf_free(struct kref *ref)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct ipmi_smi *intf = container_of(ref, struct ipmi_smi, refcount);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	clean_up_interface_data(intf);
73662306a36Sopenharmony_ci	kfree(intf);
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ciint ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	struct ipmi_smi *intf;
74262306a36Sopenharmony_ci	int index, rv;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	/*
74562306a36Sopenharmony_ci	 * Make sure the driver is actually initialized, this handles
74662306a36Sopenharmony_ci	 * problems with initialization order.
74762306a36Sopenharmony_ci	 */
74862306a36Sopenharmony_ci	rv = ipmi_init_msghandler();
74962306a36Sopenharmony_ci	if (rv)
75062306a36Sopenharmony_ci		return rv;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	mutex_lock(&smi_watchers_mutex);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	list_add(&watcher->link, &smi_watchers);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	index = srcu_read_lock(&ipmi_interfaces_srcu);
75762306a36Sopenharmony_ci	list_for_each_entry_rcu(intf, &ipmi_interfaces, link,
75862306a36Sopenharmony_ci			lockdep_is_held(&smi_watchers_mutex)) {
75962306a36Sopenharmony_ci		int intf_num = READ_ONCE(intf->intf_num);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		if (intf_num == -1)
76262306a36Sopenharmony_ci			continue;
76362306a36Sopenharmony_ci		watcher->new_smi(intf_num, intf->si_dev);
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci	srcu_read_unlock(&ipmi_interfaces_srcu, index);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	mutex_unlock(&smi_watchers_mutex);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	return 0;
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_smi_watcher_register);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ciint ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	mutex_lock(&smi_watchers_mutex);
77662306a36Sopenharmony_ci	list_del(&watcher->link);
77762306a36Sopenharmony_ci	mutex_unlock(&smi_watchers_mutex);
77862306a36Sopenharmony_ci	return 0;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_smi_watcher_unregister);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci/*
78362306a36Sopenharmony_ci * Must be called with smi_watchers_mutex held.
78462306a36Sopenharmony_ci */
78562306a36Sopenharmony_cistatic void
78662306a36Sopenharmony_cicall_smi_watchers(int i, struct device *dev)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	struct ipmi_smi_watcher *w;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	mutex_lock(&smi_watchers_mutex);
79162306a36Sopenharmony_ci	list_for_each_entry(w, &smi_watchers, link) {
79262306a36Sopenharmony_ci		if (try_module_get(w->owner)) {
79362306a36Sopenharmony_ci			w->new_smi(i, dev);
79462306a36Sopenharmony_ci			module_put(w->owner);
79562306a36Sopenharmony_ci		}
79662306a36Sopenharmony_ci	}
79762306a36Sopenharmony_ci	mutex_unlock(&smi_watchers_mutex);
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic int
80162306a36Sopenharmony_ciipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	if (addr1->addr_type != addr2->addr_type)
80462306a36Sopenharmony_ci		return 0;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (addr1->channel != addr2->channel)
80762306a36Sopenharmony_ci		return 0;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
81062306a36Sopenharmony_ci		struct ipmi_system_interface_addr *smi_addr1
81162306a36Sopenharmony_ci		    = (struct ipmi_system_interface_addr *) addr1;
81262306a36Sopenharmony_ci		struct ipmi_system_interface_addr *smi_addr2
81362306a36Sopenharmony_ci		    = (struct ipmi_system_interface_addr *) addr2;
81462306a36Sopenharmony_ci		return (smi_addr1->lun == smi_addr2->lun);
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	if (is_ipmb_addr(addr1) || is_ipmb_bcast_addr(addr1)) {
81862306a36Sopenharmony_ci		struct ipmi_ipmb_addr *ipmb_addr1
81962306a36Sopenharmony_ci		    = (struct ipmi_ipmb_addr *) addr1;
82062306a36Sopenharmony_ci		struct ipmi_ipmb_addr *ipmb_addr2
82162306a36Sopenharmony_ci		    = (struct ipmi_ipmb_addr *) addr2;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
82462306a36Sopenharmony_ci			&& (ipmb_addr1->lun == ipmb_addr2->lun));
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	if (is_ipmb_direct_addr(addr1)) {
82862306a36Sopenharmony_ci		struct ipmi_ipmb_direct_addr *daddr1
82962306a36Sopenharmony_ci			= (struct ipmi_ipmb_direct_addr *) addr1;
83062306a36Sopenharmony_ci		struct ipmi_ipmb_direct_addr *daddr2
83162306a36Sopenharmony_ci			= (struct ipmi_ipmb_direct_addr *) addr2;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		return daddr1->slave_addr == daddr2->slave_addr &&
83462306a36Sopenharmony_ci			daddr1->rq_lun == daddr2->rq_lun &&
83562306a36Sopenharmony_ci			daddr1->rs_lun == daddr2->rs_lun;
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (is_lan_addr(addr1)) {
83962306a36Sopenharmony_ci		struct ipmi_lan_addr *lan_addr1
84062306a36Sopenharmony_ci			= (struct ipmi_lan_addr *) addr1;
84162306a36Sopenharmony_ci		struct ipmi_lan_addr *lan_addr2
84262306a36Sopenharmony_ci		    = (struct ipmi_lan_addr *) addr2;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci		return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
84562306a36Sopenharmony_ci			&& (lan_addr1->local_SWID == lan_addr2->local_SWID)
84662306a36Sopenharmony_ci			&& (lan_addr1->session_handle
84762306a36Sopenharmony_ci			    == lan_addr2->session_handle)
84862306a36Sopenharmony_ci			&& (lan_addr1->lun == lan_addr2->lun));
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	return 1;
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ciint ipmi_validate_addr(struct ipmi_addr *addr, int len)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	if (len < sizeof(struct ipmi_system_interface_addr))
85762306a36Sopenharmony_ci		return -EINVAL;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
86062306a36Sopenharmony_ci		if (addr->channel != IPMI_BMC_CHANNEL)
86162306a36Sopenharmony_ci			return -EINVAL;
86262306a36Sopenharmony_ci		return 0;
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if ((addr->channel == IPMI_BMC_CHANNEL)
86662306a36Sopenharmony_ci	    || (addr->channel >= IPMI_MAX_CHANNELS)
86762306a36Sopenharmony_ci	    || (addr->channel < 0))
86862306a36Sopenharmony_ci		return -EINVAL;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) {
87162306a36Sopenharmony_ci		if (len < sizeof(struct ipmi_ipmb_addr))
87262306a36Sopenharmony_ci			return -EINVAL;
87362306a36Sopenharmony_ci		return 0;
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (is_ipmb_direct_addr(addr)) {
87762306a36Sopenharmony_ci		struct ipmi_ipmb_direct_addr *daddr = (void *) addr;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci		if (addr->channel != 0)
88062306a36Sopenharmony_ci			return -EINVAL;
88162306a36Sopenharmony_ci		if (len < sizeof(struct ipmi_ipmb_direct_addr))
88262306a36Sopenharmony_ci			return -EINVAL;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci		if (daddr->slave_addr & 0x01)
88562306a36Sopenharmony_ci			return -EINVAL;
88662306a36Sopenharmony_ci		if (daddr->rq_lun >= 4)
88762306a36Sopenharmony_ci			return -EINVAL;
88862306a36Sopenharmony_ci		if (daddr->rs_lun >= 4)
88962306a36Sopenharmony_ci			return -EINVAL;
89062306a36Sopenharmony_ci		return 0;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (is_lan_addr(addr)) {
89462306a36Sopenharmony_ci		if (len < sizeof(struct ipmi_lan_addr))
89562306a36Sopenharmony_ci			return -EINVAL;
89662306a36Sopenharmony_ci		return 0;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	return -EINVAL;
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_validate_addr);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ciunsigned int ipmi_addr_length(int addr_type)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
90662306a36Sopenharmony_ci		return sizeof(struct ipmi_system_interface_addr);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	if ((addr_type == IPMI_IPMB_ADDR_TYPE)
90962306a36Sopenharmony_ci			|| (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
91062306a36Sopenharmony_ci		return sizeof(struct ipmi_ipmb_addr);
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (addr_type == IPMI_IPMB_DIRECT_ADDR_TYPE)
91362306a36Sopenharmony_ci		return sizeof(struct ipmi_ipmb_direct_addr);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (addr_type == IPMI_LAN_ADDR_TYPE)
91662306a36Sopenharmony_ci		return sizeof(struct ipmi_lan_addr);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	return 0;
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_addr_length);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic int deliver_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	int rv = 0;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (!msg->user) {
92762306a36Sopenharmony_ci		/* Special handling for NULL users. */
92862306a36Sopenharmony_ci		if (intf->null_user_handler) {
92962306a36Sopenharmony_ci			intf->null_user_handler(intf, msg);
93062306a36Sopenharmony_ci		} else {
93162306a36Sopenharmony_ci			/* No handler, so give up. */
93262306a36Sopenharmony_ci			rv = -EINVAL;
93362306a36Sopenharmony_ci		}
93462306a36Sopenharmony_ci		ipmi_free_recv_msg(msg);
93562306a36Sopenharmony_ci	} else if (oops_in_progress) {
93662306a36Sopenharmony_ci		/*
93762306a36Sopenharmony_ci		 * If we are running in the panic context, calling the
93862306a36Sopenharmony_ci		 * receive handler doesn't much meaning and has a deadlock
93962306a36Sopenharmony_ci		 * risk.  At this moment, simply skip it in that case.
94062306a36Sopenharmony_ci		 */
94162306a36Sopenharmony_ci		ipmi_free_recv_msg(msg);
94262306a36Sopenharmony_ci		atomic_dec(&msg->user->nr_msgs);
94362306a36Sopenharmony_ci	} else {
94462306a36Sopenharmony_ci		int index;
94562306a36Sopenharmony_ci		struct ipmi_user *user = acquire_ipmi_user(msg->user, &index);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci		if (user) {
94862306a36Sopenharmony_ci			atomic_dec(&user->nr_msgs);
94962306a36Sopenharmony_ci			user->handler->ipmi_recv_hndl(msg, user->handler_data);
95062306a36Sopenharmony_ci			release_ipmi_user(user, index);
95162306a36Sopenharmony_ci		} else {
95262306a36Sopenharmony_ci			/* User went away, give up. */
95362306a36Sopenharmony_ci			ipmi_free_recv_msg(msg);
95462306a36Sopenharmony_ci			rv = -EINVAL;
95562306a36Sopenharmony_ci		}
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	return rv;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic void deliver_local_response(struct ipmi_smi *intf,
96262306a36Sopenharmony_ci				   struct ipmi_recv_msg *msg)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	if (deliver_response(intf, msg))
96562306a36Sopenharmony_ci		ipmi_inc_stat(intf, unhandled_local_responses);
96662306a36Sopenharmony_ci	else
96762306a36Sopenharmony_ci		ipmi_inc_stat(intf, handled_local_responses);
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic void deliver_err_response(struct ipmi_smi *intf,
97162306a36Sopenharmony_ci				 struct ipmi_recv_msg *msg, int err)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
97462306a36Sopenharmony_ci	msg->msg_data[0] = err;
97562306a36Sopenharmony_ci	msg->msg.netfn |= 1; /* Convert to a response. */
97662306a36Sopenharmony_ci	msg->msg.data_len = 1;
97762306a36Sopenharmony_ci	msg->msg.data = msg->msg_data;
97862306a36Sopenharmony_ci	deliver_local_response(intf, msg);
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic void smi_add_watch(struct ipmi_smi *intf, unsigned int flags)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	unsigned long iflags;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (!intf->handlers->set_need_watch)
98662306a36Sopenharmony_ci		return;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	spin_lock_irqsave(&intf->watch_lock, iflags);
98962306a36Sopenharmony_ci	if (flags & IPMI_WATCH_MASK_CHECK_MESSAGES)
99062306a36Sopenharmony_ci		intf->response_waiters++;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (flags & IPMI_WATCH_MASK_CHECK_WATCHDOG)
99362306a36Sopenharmony_ci		intf->watchdog_waiters++;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (flags & IPMI_WATCH_MASK_CHECK_COMMANDS)
99662306a36Sopenharmony_ci		intf->command_waiters++;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	if ((intf->last_watch_mask & flags) != flags) {
99962306a36Sopenharmony_ci		intf->last_watch_mask |= flags;
100062306a36Sopenharmony_ci		intf->handlers->set_need_watch(intf->send_info,
100162306a36Sopenharmony_ci					       intf->last_watch_mask);
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->watch_lock, iflags);
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cistatic void smi_remove_watch(struct ipmi_smi *intf, unsigned int flags)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	unsigned long iflags;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	if (!intf->handlers->set_need_watch)
101162306a36Sopenharmony_ci		return;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	spin_lock_irqsave(&intf->watch_lock, iflags);
101462306a36Sopenharmony_ci	if (flags & IPMI_WATCH_MASK_CHECK_MESSAGES)
101562306a36Sopenharmony_ci		intf->response_waiters--;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (flags & IPMI_WATCH_MASK_CHECK_WATCHDOG)
101862306a36Sopenharmony_ci		intf->watchdog_waiters--;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	if (flags & IPMI_WATCH_MASK_CHECK_COMMANDS)
102162306a36Sopenharmony_ci		intf->command_waiters--;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	flags = 0;
102462306a36Sopenharmony_ci	if (intf->response_waiters)
102562306a36Sopenharmony_ci		flags |= IPMI_WATCH_MASK_CHECK_MESSAGES;
102662306a36Sopenharmony_ci	if (intf->watchdog_waiters)
102762306a36Sopenharmony_ci		flags |= IPMI_WATCH_MASK_CHECK_WATCHDOG;
102862306a36Sopenharmony_ci	if (intf->command_waiters)
102962306a36Sopenharmony_ci		flags |= IPMI_WATCH_MASK_CHECK_COMMANDS;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	if (intf->last_watch_mask != flags) {
103262306a36Sopenharmony_ci		intf->last_watch_mask = flags;
103362306a36Sopenharmony_ci		intf->handlers->set_need_watch(intf->send_info,
103462306a36Sopenharmony_ci					       intf->last_watch_mask);
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->watch_lock, iflags);
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci/*
104062306a36Sopenharmony_ci * Find the next sequence number not being used and add the given
104162306a36Sopenharmony_ci * message with the given timeout to the sequence table.  This must be
104262306a36Sopenharmony_ci * called with the interface's seq_lock held.
104362306a36Sopenharmony_ci */
104462306a36Sopenharmony_cistatic int intf_next_seq(struct ipmi_smi      *intf,
104562306a36Sopenharmony_ci			 struct ipmi_recv_msg *recv_msg,
104662306a36Sopenharmony_ci			 unsigned long        timeout,
104762306a36Sopenharmony_ci			 int                  retries,
104862306a36Sopenharmony_ci			 int                  broadcast,
104962306a36Sopenharmony_ci			 unsigned char        *seq,
105062306a36Sopenharmony_ci			 long                 *seqid)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	int          rv = 0;
105362306a36Sopenharmony_ci	unsigned int i;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	if (timeout == 0)
105662306a36Sopenharmony_ci		timeout = default_retry_ms;
105762306a36Sopenharmony_ci	if (retries < 0)
105862306a36Sopenharmony_ci		retries = default_max_retries;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	for (i = intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
106162306a36Sopenharmony_ci					i = (i+1)%IPMI_IPMB_NUM_SEQ) {
106262306a36Sopenharmony_ci		if (!intf->seq_table[i].inuse)
106362306a36Sopenharmony_ci			break;
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	if (!intf->seq_table[i].inuse) {
106762306a36Sopenharmony_ci		intf->seq_table[i].recv_msg = recv_msg;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		/*
107062306a36Sopenharmony_ci		 * Start with the maximum timeout, when the send response
107162306a36Sopenharmony_ci		 * comes in we will start the real timer.
107262306a36Sopenharmony_ci		 */
107362306a36Sopenharmony_ci		intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
107462306a36Sopenharmony_ci		intf->seq_table[i].orig_timeout = timeout;
107562306a36Sopenharmony_ci		intf->seq_table[i].retries_left = retries;
107662306a36Sopenharmony_ci		intf->seq_table[i].broadcast = broadcast;
107762306a36Sopenharmony_ci		intf->seq_table[i].inuse = 1;
107862306a36Sopenharmony_ci		intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
107962306a36Sopenharmony_ci		*seq = i;
108062306a36Sopenharmony_ci		*seqid = intf->seq_table[i].seqid;
108162306a36Sopenharmony_ci		intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
108262306a36Sopenharmony_ci		smi_add_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
108362306a36Sopenharmony_ci		need_waiter(intf);
108462306a36Sopenharmony_ci	} else {
108562306a36Sopenharmony_ci		rv = -EAGAIN;
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	return rv;
108962306a36Sopenharmony_ci}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci/*
109262306a36Sopenharmony_ci * Return the receive message for the given sequence number and
109362306a36Sopenharmony_ci * release the sequence number so it can be reused.  Some other data
109462306a36Sopenharmony_ci * is passed in to be sure the message matches up correctly (to help
109562306a36Sopenharmony_ci * guard against message coming in after their timeout and the
109662306a36Sopenharmony_ci * sequence number being reused).
109762306a36Sopenharmony_ci */
109862306a36Sopenharmony_cistatic int intf_find_seq(struct ipmi_smi      *intf,
109962306a36Sopenharmony_ci			 unsigned char        seq,
110062306a36Sopenharmony_ci			 short                channel,
110162306a36Sopenharmony_ci			 unsigned char        cmd,
110262306a36Sopenharmony_ci			 unsigned char        netfn,
110362306a36Sopenharmony_ci			 struct ipmi_addr     *addr,
110462306a36Sopenharmony_ci			 struct ipmi_recv_msg **recv_msg)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	int           rv = -ENODEV;
110762306a36Sopenharmony_ci	unsigned long flags;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	if (seq >= IPMI_IPMB_NUM_SEQ)
111062306a36Sopenharmony_ci		return -EINVAL;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	spin_lock_irqsave(&intf->seq_lock, flags);
111362306a36Sopenharmony_ci	if (intf->seq_table[seq].inuse) {
111462306a36Sopenharmony_ci		struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci		if ((msg->addr.channel == channel) && (msg->msg.cmd == cmd)
111762306a36Sopenharmony_ci				&& (msg->msg.netfn == netfn)
111862306a36Sopenharmony_ci				&& (ipmi_addr_equal(addr, &msg->addr))) {
111962306a36Sopenharmony_ci			*recv_msg = msg;
112062306a36Sopenharmony_ci			intf->seq_table[seq].inuse = 0;
112162306a36Sopenharmony_ci			smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
112262306a36Sopenharmony_ci			rv = 0;
112362306a36Sopenharmony_ci		}
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->seq_lock, flags);
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	return rv;
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci/* Start the timer for a specific sequence table entry. */
113262306a36Sopenharmony_cistatic int intf_start_seq_timer(struct ipmi_smi *intf,
113362306a36Sopenharmony_ci				long       msgid)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	int           rv = -ENODEV;
113662306a36Sopenharmony_ci	unsigned long flags;
113762306a36Sopenharmony_ci	unsigned char seq;
113862306a36Sopenharmony_ci	unsigned long seqid;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	GET_SEQ_FROM_MSGID(msgid, seq, seqid);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	spin_lock_irqsave(&intf->seq_lock, flags);
114462306a36Sopenharmony_ci	/*
114562306a36Sopenharmony_ci	 * We do this verification because the user can be deleted
114662306a36Sopenharmony_ci	 * while a message is outstanding.
114762306a36Sopenharmony_ci	 */
114862306a36Sopenharmony_ci	if ((intf->seq_table[seq].inuse)
114962306a36Sopenharmony_ci				&& (intf->seq_table[seq].seqid == seqid)) {
115062306a36Sopenharmony_ci		struct seq_table *ent = &intf->seq_table[seq];
115162306a36Sopenharmony_ci		ent->timeout = ent->orig_timeout;
115262306a36Sopenharmony_ci		rv = 0;
115362306a36Sopenharmony_ci	}
115462306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->seq_lock, flags);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	return rv;
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci/* Got an error for the send message for a specific sequence number. */
116062306a36Sopenharmony_cistatic int intf_err_seq(struct ipmi_smi *intf,
116162306a36Sopenharmony_ci			long         msgid,
116262306a36Sopenharmony_ci			unsigned int err)
116362306a36Sopenharmony_ci{
116462306a36Sopenharmony_ci	int                  rv = -ENODEV;
116562306a36Sopenharmony_ci	unsigned long        flags;
116662306a36Sopenharmony_ci	unsigned char        seq;
116762306a36Sopenharmony_ci	unsigned long        seqid;
116862306a36Sopenharmony_ci	struct ipmi_recv_msg *msg = NULL;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	GET_SEQ_FROM_MSGID(msgid, seq, seqid);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	spin_lock_irqsave(&intf->seq_lock, flags);
117462306a36Sopenharmony_ci	/*
117562306a36Sopenharmony_ci	 * We do this verification because the user can be deleted
117662306a36Sopenharmony_ci	 * while a message is outstanding.
117762306a36Sopenharmony_ci	 */
117862306a36Sopenharmony_ci	if ((intf->seq_table[seq].inuse)
117962306a36Sopenharmony_ci				&& (intf->seq_table[seq].seqid == seqid)) {
118062306a36Sopenharmony_ci		struct seq_table *ent = &intf->seq_table[seq];
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci		ent->inuse = 0;
118362306a36Sopenharmony_ci		smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
118462306a36Sopenharmony_ci		msg = ent->recv_msg;
118562306a36Sopenharmony_ci		rv = 0;
118662306a36Sopenharmony_ci	}
118762306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->seq_lock, flags);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	if (msg)
119062306a36Sopenharmony_ci		deliver_err_response(intf, msg, err);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	return rv;
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_cistatic void free_user_work(struct work_struct *work)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	struct ipmi_user *user = container_of(work, struct ipmi_user,
119862306a36Sopenharmony_ci					      remove_work);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	cleanup_srcu_struct(&user->release_barrier);
120162306a36Sopenharmony_ci	vfree(user);
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ciint ipmi_create_user(unsigned int          if_num,
120562306a36Sopenharmony_ci		     const struct ipmi_user_hndl *handler,
120662306a36Sopenharmony_ci		     void                  *handler_data,
120762306a36Sopenharmony_ci		     struct ipmi_user      **user)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	unsigned long flags;
121062306a36Sopenharmony_ci	struct ipmi_user *new_user;
121162306a36Sopenharmony_ci	int           rv, index;
121262306a36Sopenharmony_ci	struct ipmi_smi *intf;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	/*
121562306a36Sopenharmony_ci	 * There is no module usecount here, because it's not
121662306a36Sopenharmony_ci	 * required.  Since this can only be used by and called from
121762306a36Sopenharmony_ci	 * other modules, they will implicitly use this module, and
121862306a36Sopenharmony_ci	 * thus this can't be removed unless the other modules are
121962306a36Sopenharmony_ci	 * removed.
122062306a36Sopenharmony_ci	 */
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	if (handler == NULL)
122362306a36Sopenharmony_ci		return -EINVAL;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/*
122662306a36Sopenharmony_ci	 * Make sure the driver is actually initialized, this handles
122762306a36Sopenharmony_ci	 * problems with initialization order.
122862306a36Sopenharmony_ci	 */
122962306a36Sopenharmony_ci	rv = ipmi_init_msghandler();
123062306a36Sopenharmony_ci	if (rv)
123162306a36Sopenharmony_ci		return rv;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	new_user = vzalloc(sizeof(*new_user));
123462306a36Sopenharmony_ci	if (!new_user)
123562306a36Sopenharmony_ci		return -ENOMEM;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	index = srcu_read_lock(&ipmi_interfaces_srcu);
123862306a36Sopenharmony_ci	list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
123962306a36Sopenharmony_ci		if (intf->intf_num == if_num)
124062306a36Sopenharmony_ci			goto found;
124162306a36Sopenharmony_ci	}
124262306a36Sopenharmony_ci	/* Not found, return an error */
124362306a36Sopenharmony_ci	rv = -EINVAL;
124462306a36Sopenharmony_ci	goto out_kfree;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci found:
124762306a36Sopenharmony_ci	if (atomic_add_return(1, &intf->nr_users) > max_users) {
124862306a36Sopenharmony_ci		rv = -EBUSY;
124962306a36Sopenharmony_ci		goto out_kfree;
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	INIT_WORK(&new_user->remove_work, free_user_work);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	rv = init_srcu_struct(&new_user->release_barrier);
125562306a36Sopenharmony_ci	if (rv)
125662306a36Sopenharmony_ci		goto out_kfree;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	if (!try_module_get(intf->owner)) {
125962306a36Sopenharmony_ci		rv = -ENODEV;
126062306a36Sopenharmony_ci		goto out_kfree;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	/* Note that each existing user holds a refcount to the interface. */
126462306a36Sopenharmony_ci	kref_get(&intf->refcount);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	atomic_set(&new_user->nr_msgs, 0);
126762306a36Sopenharmony_ci	kref_init(&new_user->refcount);
126862306a36Sopenharmony_ci	new_user->handler = handler;
126962306a36Sopenharmony_ci	new_user->handler_data = handler_data;
127062306a36Sopenharmony_ci	new_user->intf = intf;
127162306a36Sopenharmony_ci	new_user->gets_events = false;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	rcu_assign_pointer(new_user->self, new_user);
127462306a36Sopenharmony_ci	spin_lock_irqsave(&intf->seq_lock, flags);
127562306a36Sopenharmony_ci	list_add_rcu(&new_user->link, &intf->users);
127662306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->seq_lock, flags);
127762306a36Sopenharmony_ci	if (handler->ipmi_watchdog_pretimeout)
127862306a36Sopenharmony_ci		/* User wants pretimeouts, so make sure to watch for them. */
127962306a36Sopenharmony_ci		smi_add_watch(intf, IPMI_WATCH_MASK_CHECK_WATCHDOG);
128062306a36Sopenharmony_ci	srcu_read_unlock(&ipmi_interfaces_srcu, index);
128162306a36Sopenharmony_ci	*user = new_user;
128262306a36Sopenharmony_ci	return 0;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ciout_kfree:
128562306a36Sopenharmony_ci	atomic_dec(&intf->nr_users);
128662306a36Sopenharmony_ci	srcu_read_unlock(&ipmi_interfaces_srcu, index);
128762306a36Sopenharmony_ci	vfree(new_user);
128862306a36Sopenharmony_ci	return rv;
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_create_user);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ciint ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	int rv, index;
129562306a36Sopenharmony_ci	struct ipmi_smi *intf;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	index = srcu_read_lock(&ipmi_interfaces_srcu);
129862306a36Sopenharmony_ci	list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
129962306a36Sopenharmony_ci		if (intf->intf_num == if_num)
130062306a36Sopenharmony_ci			goto found;
130162306a36Sopenharmony_ci	}
130262306a36Sopenharmony_ci	srcu_read_unlock(&ipmi_interfaces_srcu, index);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/* Not found, return an error */
130562306a36Sopenharmony_ci	return -EINVAL;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_cifound:
130862306a36Sopenharmony_ci	if (!intf->handlers->get_smi_info)
130962306a36Sopenharmony_ci		rv = -ENOTTY;
131062306a36Sopenharmony_ci	else
131162306a36Sopenharmony_ci		rv = intf->handlers->get_smi_info(intf->send_info, data);
131262306a36Sopenharmony_ci	srcu_read_unlock(&ipmi_interfaces_srcu, index);
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	return rv;
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_get_smi_info);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_cistatic void free_user(struct kref *ref)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	/* SRCU cleanup must happen in task context. */
132362306a36Sopenharmony_ci	queue_work(remove_work_wq, &user->remove_work);
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistatic void _ipmi_destroy_user(struct ipmi_user *user)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	struct ipmi_smi  *intf = user->intf;
132962306a36Sopenharmony_ci	int              i;
133062306a36Sopenharmony_ci	unsigned long    flags;
133162306a36Sopenharmony_ci	struct cmd_rcvr  *rcvr;
133262306a36Sopenharmony_ci	struct cmd_rcvr  *rcvrs = NULL;
133362306a36Sopenharmony_ci	struct module    *owner;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	if (!acquire_ipmi_user(user, &i)) {
133662306a36Sopenharmony_ci		/*
133762306a36Sopenharmony_ci		 * The user has already been cleaned up, just make sure
133862306a36Sopenharmony_ci		 * nothing is using it and return.
133962306a36Sopenharmony_ci		 */
134062306a36Sopenharmony_ci		synchronize_srcu(&user->release_barrier);
134162306a36Sopenharmony_ci		return;
134262306a36Sopenharmony_ci	}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	rcu_assign_pointer(user->self, NULL);
134562306a36Sopenharmony_ci	release_ipmi_user(user, i);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	synchronize_srcu(&user->release_barrier);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	if (user->handler->shutdown)
135062306a36Sopenharmony_ci		user->handler->shutdown(user->handler_data);
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	if (user->handler->ipmi_watchdog_pretimeout)
135362306a36Sopenharmony_ci		smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_WATCHDOG);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	if (user->gets_events)
135662306a36Sopenharmony_ci		atomic_dec(&intf->event_waiters);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	/* Remove the user from the interface's sequence table. */
135962306a36Sopenharmony_ci	spin_lock_irqsave(&intf->seq_lock, flags);
136062306a36Sopenharmony_ci	list_del_rcu(&user->link);
136162306a36Sopenharmony_ci	atomic_dec(&intf->nr_users);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
136462306a36Sopenharmony_ci		if (intf->seq_table[i].inuse
136562306a36Sopenharmony_ci		    && (intf->seq_table[i].recv_msg->user == user)) {
136662306a36Sopenharmony_ci			intf->seq_table[i].inuse = 0;
136762306a36Sopenharmony_ci			smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
136862306a36Sopenharmony_ci			ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
136962306a36Sopenharmony_ci		}
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->seq_lock, flags);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	/*
137462306a36Sopenharmony_ci	 * Remove the user from the command receiver's table.  First
137562306a36Sopenharmony_ci	 * we build a list of everything (not using the standard link,
137662306a36Sopenharmony_ci	 * since other things may be using it till we do
137762306a36Sopenharmony_ci	 * synchronize_srcu()) then free everything in that list.
137862306a36Sopenharmony_ci	 */
137962306a36Sopenharmony_ci	mutex_lock(&intf->cmd_rcvrs_mutex);
138062306a36Sopenharmony_ci	list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
138162306a36Sopenharmony_ci				lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
138262306a36Sopenharmony_ci		if (rcvr->user == user) {
138362306a36Sopenharmony_ci			list_del_rcu(&rcvr->link);
138462306a36Sopenharmony_ci			rcvr->next = rcvrs;
138562306a36Sopenharmony_ci			rcvrs = rcvr;
138662306a36Sopenharmony_ci		}
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci	mutex_unlock(&intf->cmd_rcvrs_mutex);
138962306a36Sopenharmony_ci	synchronize_rcu();
139062306a36Sopenharmony_ci	while (rcvrs) {
139162306a36Sopenharmony_ci		rcvr = rcvrs;
139262306a36Sopenharmony_ci		rcvrs = rcvr->next;
139362306a36Sopenharmony_ci		kfree(rcvr);
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	owner = intf->owner;
139762306a36Sopenharmony_ci	kref_put(&intf->refcount, intf_free);
139862306a36Sopenharmony_ci	module_put(owner);
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ciint ipmi_destroy_user(struct ipmi_user *user)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	_ipmi_destroy_user(user);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	kref_put(&user->refcount, free_user);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	return 0;
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_destroy_user);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ciint ipmi_get_version(struct ipmi_user *user,
141262306a36Sopenharmony_ci		     unsigned char *major,
141362306a36Sopenharmony_ci		     unsigned char *minor)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	struct ipmi_device_id id;
141662306a36Sopenharmony_ci	int rv, index;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
141962306a36Sopenharmony_ci	if (!user)
142062306a36Sopenharmony_ci		return -ENODEV;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	rv = bmc_get_device_id(user->intf, NULL, &id, NULL, NULL);
142362306a36Sopenharmony_ci	if (!rv) {
142462306a36Sopenharmony_ci		*major = ipmi_version_major(&id);
142562306a36Sopenharmony_ci		*minor = ipmi_version_minor(&id);
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci	release_ipmi_user(user, index);
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	return rv;
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_get_version);
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ciint ipmi_set_my_address(struct ipmi_user *user,
143462306a36Sopenharmony_ci			unsigned int  channel,
143562306a36Sopenharmony_ci			unsigned char address)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	int index, rv = 0;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
144062306a36Sopenharmony_ci	if (!user)
144162306a36Sopenharmony_ci		return -ENODEV;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	if (channel >= IPMI_MAX_CHANNELS) {
144462306a36Sopenharmony_ci		rv = -EINVAL;
144562306a36Sopenharmony_ci	} else {
144662306a36Sopenharmony_ci		channel = array_index_nospec(channel, IPMI_MAX_CHANNELS);
144762306a36Sopenharmony_ci		user->intf->addrinfo[channel].address = address;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci	release_ipmi_user(user, index);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	return rv;
145262306a36Sopenharmony_ci}
145362306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_set_my_address);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ciint ipmi_get_my_address(struct ipmi_user *user,
145662306a36Sopenharmony_ci			unsigned int  channel,
145762306a36Sopenharmony_ci			unsigned char *address)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	int index, rv = 0;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
146262306a36Sopenharmony_ci	if (!user)
146362306a36Sopenharmony_ci		return -ENODEV;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	if (channel >= IPMI_MAX_CHANNELS) {
146662306a36Sopenharmony_ci		rv = -EINVAL;
146762306a36Sopenharmony_ci	} else {
146862306a36Sopenharmony_ci		channel = array_index_nospec(channel, IPMI_MAX_CHANNELS);
146962306a36Sopenharmony_ci		*address = user->intf->addrinfo[channel].address;
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci	release_ipmi_user(user, index);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	return rv;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_get_my_address);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ciint ipmi_set_my_LUN(struct ipmi_user *user,
147862306a36Sopenharmony_ci		    unsigned int  channel,
147962306a36Sopenharmony_ci		    unsigned char LUN)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	int index, rv = 0;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
148462306a36Sopenharmony_ci	if (!user)
148562306a36Sopenharmony_ci		return -ENODEV;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	if (channel >= IPMI_MAX_CHANNELS) {
148862306a36Sopenharmony_ci		rv = -EINVAL;
148962306a36Sopenharmony_ci	} else {
149062306a36Sopenharmony_ci		channel = array_index_nospec(channel, IPMI_MAX_CHANNELS);
149162306a36Sopenharmony_ci		user->intf->addrinfo[channel].lun = LUN & 0x3;
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci	release_ipmi_user(user, index);
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	return rv;
149662306a36Sopenharmony_ci}
149762306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_set_my_LUN);
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ciint ipmi_get_my_LUN(struct ipmi_user *user,
150062306a36Sopenharmony_ci		    unsigned int  channel,
150162306a36Sopenharmony_ci		    unsigned char *address)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	int index, rv = 0;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
150662306a36Sopenharmony_ci	if (!user)
150762306a36Sopenharmony_ci		return -ENODEV;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	if (channel >= IPMI_MAX_CHANNELS) {
151062306a36Sopenharmony_ci		rv = -EINVAL;
151162306a36Sopenharmony_ci	} else {
151262306a36Sopenharmony_ci		channel = array_index_nospec(channel, IPMI_MAX_CHANNELS);
151362306a36Sopenharmony_ci		*address = user->intf->addrinfo[channel].lun;
151462306a36Sopenharmony_ci	}
151562306a36Sopenharmony_ci	release_ipmi_user(user, index);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	return rv;
151862306a36Sopenharmony_ci}
151962306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_get_my_LUN);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ciint ipmi_get_maintenance_mode(struct ipmi_user *user)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	int mode, index;
152462306a36Sopenharmony_ci	unsigned long flags;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
152762306a36Sopenharmony_ci	if (!user)
152862306a36Sopenharmony_ci		return -ENODEV;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
153162306a36Sopenharmony_ci	mode = user->intf->maintenance_mode;
153262306a36Sopenharmony_ci	spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
153362306a36Sopenharmony_ci	release_ipmi_user(user, index);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	return mode;
153662306a36Sopenharmony_ci}
153762306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_get_maintenance_mode);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_cistatic void maintenance_mode_update(struct ipmi_smi *intf)
154062306a36Sopenharmony_ci{
154162306a36Sopenharmony_ci	if (intf->handlers->set_maintenance_mode)
154262306a36Sopenharmony_ci		intf->handlers->set_maintenance_mode(
154362306a36Sopenharmony_ci			intf->send_info, intf->maintenance_mode_enable);
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ciint ipmi_set_maintenance_mode(struct ipmi_user *user, int mode)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	int rv = 0, index;
154962306a36Sopenharmony_ci	unsigned long flags;
155062306a36Sopenharmony_ci	struct ipmi_smi *intf = user->intf;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
155362306a36Sopenharmony_ci	if (!user)
155462306a36Sopenharmony_ci		return -ENODEV;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
155762306a36Sopenharmony_ci	if (intf->maintenance_mode != mode) {
155862306a36Sopenharmony_ci		switch (mode) {
155962306a36Sopenharmony_ci		case IPMI_MAINTENANCE_MODE_AUTO:
156062306a36Sopenharmony_ci			intf->maintenance_mode_enable
156162306a36Sopenharmony_ci				= (intf->auto_maintenance_timeout > 0);
156262306a36Sopenharmony_ci			break;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci		case IPMI_MAINTENANCE_MODE_OFF:
156562306a36Sopenharmony_ci			intf->maintenance_mode_enable = false;
156662306a36Sopenharmony_ci			break;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci		case IPMI_MAINTENANCE_MODE_ON:
156962306a36Sopenharmony_ci			intf->maintenance_mode_enable = true;
157062306a36Sopenharmony_ci			break;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci		default:
157362306a36Sopenharmony_ci			rv = -EINVAL;
157462306a36Sopenharmony_ci			goto out_unlock;
157562306a36Sopenharmony_ci		}
157662306a36Sopenharmony_ci		intf->maintenance_mode = mode;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci		maintenance_mode_update(intf);
157962306a36Sopenharmony_ci	}
158062306a36Sopenharmony_ci out_unlock:
158162306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
158262306a36Sopenharmony_ci	release_ipmi_user(user, index);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	return rv;
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_set_maintenance_mode);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ciint ipmi_set_gets_events(struct ipmi_user *user, bool val)
158962306a36Sopenharmony_ci{
159062306a36Sopenharmony_ci	unsigned long        flags;
159162306a36Sopenharmony_ci	struct ipmi_smi      *intf = user->intf;
159262306a36Sopenharmony_ci	struct ipmi_recv_msg *msg, *msg2;
159362306a36Sopenharmony_ci	struct list_head     msgs;
159462306a36Sopenharmony_ci	int index;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
159762306a36Sopenharmony_ci	if (!user)
159862306a36Sopenharmony_ci		return -ENODEV;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	INIT_LIST_HEAD(&msgs);
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	spin_lock_irqsave(&intf->events_lock, flags);
160362306a36Sopenharmony_ci	if (user->gets_events == val)
160462306a36Sopenharmony_ci		goto out;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	user->gets_events = val;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	if (val) {
160962306a36Sopenharmony_ci		if (atomic_inc_return(&intf->event_waiters) == 1)
161062306a36Sopenharmony_ci			need_waiter(intf);
161162306a36Sopenharmony_ci	} else {
161262306a36Sopenharmony_ci		atomic_dec(&intf->event_waiters);
161362306a36Sopenharmony_ci	}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	if (intf->delivering_events)
161662306a36Sopenharmony_ci		/*
161762306a36Sopenharmony_ci		 * Another thread is delivering events for this, so
161862306a36Sopenharmony_ci		 * let it handle any new events.
161962306a36Sopenharmony_ci		 */
162062306a36Sopenharmony_ci		goto out;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	/* Deliver any queued events. */
162362306a36Sopenharmony_ci	while (user->gets_events && !list_empty(&intf->waiting_events)) {
162462306a36Sopenharmony_ci		list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
162562306a36Sopenharmony_ci			list_move_tail(&msg->link, &msgs);
162662306a36Sopenharmony_ci		intf->waiting_events_count = 0;
162762306a36Sopenharmony_ci		if (intf->event_msg_printed) {
162862306a36Sopenharmony_ci			dev_warn(intf->si_dev, "Event queue no longer full\n");
162962306a36Sopenharmony_ci			intf->event_msg_printed = 0;
163062306a36Sopenharmony_ci		}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci		intf->delivering_events = 1;
163362306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->events_lock, flags);
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci		list_for_each_entry_safe(msg, msg2, &msgs, link) {
163662306a36Sopenharmony_ci			msg->user = user;
163762306a36Sopenharmony_ci			kref_get(&user->refcount);
163862306a36Sopenharmony_ci			deliver_local_response(intf, msg);
163962306a36Sopenharmony_ci		}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci		spin_lock_irqsave(&intf->events_lock, flags);
164262306a36Sopenharmony_ci		intf->delivering_events = 0;
164362306a36Sopenharmony_ci	}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci out:
164662306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->events_lock, flags);
164762306a36Sopenharmony_ci	release_ipmi_user(user, index);
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	return 0;
165062306a36Sopenharmony_ci}
165162306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_set_gets_events);
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_cistatic struct cmd_rcvr *find_cmd_rcvr(struct ipmi_smi *intf,
165462306a36Sopenharmony_ci				      unsigned char netfn,
165562306a36Sopenharmony_ci				      unsigned char cmd,
165662306a36Sopenharmony_ci				      unsigned char chan)
165762306a36Sopenharmony_ci{
165862306a36Sopenharmony_ci	struct cmd_rcvr *rcvr;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
166162306a36Sopenharmony_ci				lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
166262306a36Sopenharmony_ci		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
166362306a36Sopenharmony_ci					&& (rcvr->chans & (1 << chan)))
166462306a36Sopenharmony_ci			return rcvr;
166562306a36Sopenharmony_ci	}
166662306a36Sopenharmony_ci	return NULL;
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_cistatic int is_cmd_rcvr_exclusive(struct ipmi_smi *intf,
167062306a36Sopenharmony_ci				 unsigned char netfn,
167162306a36Sopenharmony_ci				 unsigned char cmd,
167262306a36Sopenharmony_ci				 unsigned int  chans)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	struct cmd_rcvr *rcvr;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
167762306a36Sopenharmony_ci				lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
167862306a36Sopenharmony_ci		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
167962306a36Sopenharmony_ci					&& (rcvr->chans & chans))
168062306a36Sopenharmony_ci			return 0;
168162306a36Sopenharmony_ci	}
168262306a36Sopenharmony_ci	return 1;
168362306a36Sopenharmony_ci}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ciint ipmi_register_for_cmd(struct ipmi_user *user,
168662306a36Sopenharmony_ci			  unsigned char netfn,
168762306a36Sopenharmony_ci			  unsigned char cmd,
168862306a36Sopenharmony_ci			  unsigned int  chans)
168962306a36Sopenharmony_ci{
169062306a36Sopenharmony_ci	struct ipmi_smi *intf = user->intf;
169162306a36Sopenharmony_ci	struct cmd_rcvr *rcvr;
169262306a36Sopenharmony_ci	int rv = 0, index;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
169562306a36Sopenharmony_ci	if (!user)
169662306a36Sopenharmony_ci		return -ENODEV;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
169962306a36Sopenharmony_ci	if (!rcvr) {
170062306a36Sopenharmony_ci		rv = -ENOMEM;
170162306a36Sopenharmony_ci		goto out_release;
170262306a36Sopenharmony_ci	}
170362306a36Sopenharmony_ci	rcvr->cmd = cmd;
170462306a36Sopenharmony_ci	rcvr->netfn = netfn;
170562306a36Sopenharmony_ci	rcvr->chans = chans;
170662306a36Sopenharmony_ci	rcvr->user = user;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	mutex_lock(&intf->cmd_rcvrs_mutex);
170962306a36Sopenharmony_ci	/* Make sure the command/netfn is not already registered. */
171062306a36Sopenharmony_ci	if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
171162306a36Sopenharmony_ci		rv = -EBUSY;
171262306a36Sopenharmony_ci		goto out_unlock;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	smi_add_watch(intf, IPMI_WATCH_MASK_CHECK_COMMANDS);
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ciout_unlock:
172062306a36Sopenharmony_ci	mutex_unlock(&intf->cmd_rcvrs_mutex);
172162306a36Sopenharmony_ci	if (rv)
172262306a36Sopenharmony_ci		kfree(rcvr);
172362306a36Sopenharmony_ciout_release:
172462306a36Sopenharmony_ci	release_ipmi_user(user, index);
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	return rv;
172762306a36Sopenharmony_ci}
172862306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_register_for_cmd);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ciint ipmi_unregister_for_cmd(struct ipmi_user *user,
173162306a36Sopenharmony_ci			    unsigned char netfn,
173262306a36Sopenharmony_ci			    unsigned char cmd,
173362306a36Sopenharmony_ci			    unsigned int  chans)
173462306a36Sopenharmony_ci{
173562306a36Sopenharmony_ci	struct ipmi_smi *intf = user->intf;
173662306a36Sopenharmony_ci	struct cmd_rcvr *rcvr;
173762306a36Sopenharmony_ci	struct cmd_rcvr *rcvrs = NULL;
173862306a36Sopenharmony_ci	int i, rv = -ENOENT, index;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
174162306a36Sopenharmony_ci	if (!user)
174262306a36Sopenharmony_ci		return -ENODEV;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	mutex_lock(&intf->cmd_rcvrs_mutex);
174562306a36Sopenharmony_ci	for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
174662306a36Sopenharmony_ci		if (((1 << i) & chans) == 0)
174762306a36Sopenharmony_ci			continue;
174862306a36Sopenharmony_ci		rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
174962306a36Sopenharmony_ci		if (rcvr == NULL)
175062306a36Sopenharmony_ci			continue;
175162306a36Sopenharmony_ci		if (rcvr->user == user) {
175262306a36Sopenharmony_ci			rv = 0;
175362306a36Sopenharmony_ci			rcvr->chans &= ~chans;
175462306a36Sopenharmony_ci			if (rcvr->chans == 0) {
175562306a36Sopenharmony_ci				list_del_rcu(&rcvr->link);
175662306a36Sopenharmony_ci				rcvr->next = rcvrs;
175762306a36Sopenharmony_ci				rcvrs = rcvr;
175862306a36Sopenharmony_ci			}
175962306a36Sopenharmony_ci		}
176062306a36Sopenharmony_ci	}
176162306a36Sopenharmony_ci	mutex_unlock(&intf->cmd_rcvrs_mutex);
176262306a36Sopenharmony_ci	synchronize_rcu();
176362306a36Sopenharmony_ci	release_ipmi_user(user, index);
176462306a36Sopenharmony_ci	while (rcvrs) {
176562306a36Sopenharmony_ci		smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_COMMANDS);
176662306a36Sopenharmony_ci		rcvr = rcvrs;
176762306a36Sopenharmony_ci		rcvrs = rcvr->next;
176862306a36Sopenharmony_ci		kfree(rcvr);
176962306a36Sopenharmony_ci	}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	return rv;
177262306a36Sopenharmony_ci}
177362306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_unregister_for_cmd);
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ciunsigned char
177662306a36Sopenharmony_ciipmb_checksum(unsigned char *data, int size)
177762306a36Sopenharmony_ci{
177862306a36Sopenharmony_ci	unsigned char csum = 0;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	for (; size > 0; size--, data++)
178162306a36Sopenharmony_ci		csum += *data;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	return -csum;
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ciEXPORT_SYMBOL(ipmb_checksum);
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_cistatic inline void format_ipmb_msg(struct ipmi_smi_msg   *smi_msg,
178862306a36Sopenharmony_ci				   struct kernel_ipmi_msg *msg,
178962306a36Sopenharmony_ci				   struct ipmi_ipmb_addr *ipmb_addr,
179062306a36Sopenharmony_ci				   long                  msgid,
179162306a36Sopenharmony_ci				   unsigned char         ipmb_seq,
179262306a36Sopenharmony_ci				   int                   broadcast,
179362306a36Sopenharmony_ci				   unsigned char         source_address,
179462306a36Sopenharmony_ci				   unsigned char         source_lun)
179562306a36Sopenharmony_ci{
179662306a36Sopenharmony_ci	int i = broadcast;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	/* Format the IPMB header data. */
179962306a36Sopenharmony_ci	smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
180062306a36Sopenharmony_ci	smi_msg->data[1] = IPMI_SEND_MSG_CMD;
180162306a36Sopenharmony_ci	smi_msg->data[2] = ipmb_addr->channel;
180262306a36Sopenharmony_ci	if (broadcast)
180362306a36Sopenharmony_ci		smi_msg->data[3] = 0;
180462306a36Sopenharmony_ci	smi_msg->data[i+3] = ipmb_addr->slave_addr;
180562306a36Sopenharmony_ci	smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
180662306a36Sopenharmony_ci	smi_msg->data[i+5] = ipmb_checksum(&smi_msg->data[i + 3], 2);
180762306a36Sopenharmony_ci	smi_msg->data[i+6] = source_address;
180862306a36Sopenharmony_ci	smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
180962306a36Sopenharmony_ci	smi_msg->data[i+8] = msg->cmd;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	/* Now tack on the data to the message. */
181262306a36Sopenharmony_ci	if (msg->data_len > 0)
181362306a36Sopenharmony_ci		memcpy(&smi_msg->data[i + 9], msg->data, msg->data_len);
181462306a36Sopenharmony_ci	smi_msg->data_size = msg->data_len + 9;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	/* Now calculate the checksum and tack it on. */
181762306a36Sopenharmony_ci	smi_msg->data[i+smi_msg->data_size]
181862306a36Sopenharmony_ci		= ipmb_checksum(&smi_msg->data[i + 6], smi_msg->data_size - 6);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	/*
182162306a36Sopenharmony_ci	 * Add on the checksum size and the offset from the
182262306a36Sopenharmony_ci	 * broadcast.
182362306a36Sopenharmony_ci	 */
182462306a36Sopenharmony_ci	smi_msg->data_size += 1 + i;
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	smi_msg->msgid = msgid;
182762306a36Sopenharmony_ci}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_cistatic inline void format_lan_msg(struct ipmi_smi_msg   *smi_msg,
183062306a36Sopenharmony_ci				  struct kernel_ipmi_msg *msg,
183162306a36Sopenharmony_ci				  struct ipmi_lan_addr  *lan_addr,
183262306a36Sopenharmony_ci				  long                  msgid,
183362306a36Sopenharmony_ci				  unsigned char         ipmb_seq,
183462306a36Sopenharmony_ci				  unsigned char         source_lun)
183562306a36Sopenharmony_ci{
183662306a36Sopenharmony_ci	/* Format the IPMB header data. */
183762306a36Sopenharmony_ci	smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
183862306a36Sopenharmony_ci	smi_msg->data[1] = IPMI_SEND_MSG_CMD;
183962306a36Sopenharmony_ci	smi_msg->data[2] = lan_addr->channel;
184062306a36Sopenharmony_ci	smi_msg->data[3] = lan_addr->session_handle;
184162306a36Sopenharmony_ci	smi_msg->data[4] = lan_addr->remote_SWID;
184262306a36Sopenharmony_ci	smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
184362306a36Sopenharmony_ci	smi_msg->data[6] = ipmb_checksum(&smi_msg->data[4], 2);
184462306a36Sopenharmony_ci	smi_msg->data[7] = lan_addr->local_SWID;
184562306a36Sopenharmony_ci	smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
184662306a36Sopenharmony_ci	smi_msg->data[9] = msg->cmd;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	/* Now tack on the data to the message. */
184962306a36Sopenharmony_ci	if (msg->data_len > 0)
185062306a36Sopenharmony_ci		memcpy(&smi_msg->data[10], msg->data, msg->data_len);
185162306a36Sopenharmony_ci	smi_msg->data_size = msg->data_len + 10;
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	/* Now calculate the checksum and tack it on. */
185462306a36Sopenharmony_ci	smi_msg->data[smi_msg->data_size]
185562306a36Sopenharmony_ci		= ipmb_checksum(&smi_msg->data[7], smi_msg->data_size - 7);
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	/*
185862306a36Sopenharmony_ci	 * Add on the checksum size and the offset from the
185962306a36Sopenharmony_ci	 * broadcast.
186062306a36Sopenharmony_ci	 */
186162306a36Sopenharmony_ci	smi_msg->data_size += 1;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	smi_msg->msgid = msgid;
186462306a36Sopenharmony_ci}
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_cistatic struct ipmi_smi_msg *smi_add_send_msg(struct ipmi_smi *intf,
186762306a36Sopenharmony_ci					     struct ipmi_smi_msg *smi_msg,
186862306a36Sopenharmony_ci					     int priority)
186962306a36Sopenharmony_ci{
187062306a36Sopenharmony_ci	if (intf->curr_msg) {
187162306a36Sopenharmony_ci		if (priority > 0)
187262306a36Sopenharmony_ci			list_add_tail(&smi_msg->link, &intf->hp_xmit_msgs);
187362306a36Sopenharmony_ci		else
187462306a36Sopenharmony_ci			list_add_tail(&smi_msg->link, &intf->xmit_msgs);
187562306a36Sopenharmony_ci		smi_msg = NULL;
187662306a36Sopenharmony_ci	} else {
187762306a36Sopenharmony_ci		intf->curr_msg = smi_msg;
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	return smi_msg;
188162306a36Sopenharmony_ci}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_cistatic void smi_send(struct ipmi_smi *intf,
188462306a36Sopenharmony_ci		     const struct ipmi_smi_handlers *handlers,
188562306a36Sopenharmony_ci		     struct ipmi_smi_msg *smi_msg, int priority)
188662306a36Sopenharmony_ci{
188762306a36Sopenharmony_ci	int run_to_completion = intf->run_to_completion;
188862306a36Sopenharmony_ci	unsigned long flags = 0;
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	if (!run_to_completion)
189162306a36Sopenharmony_ci		spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
189262306a36Sopenharmony_ci	smi_msg = smi_add_send_msg(intf, smi_msg, priority);
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	if (!run_to_completion)
189562306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	if (smi_msg)
189862306a36Sopenharmony_ci		handlers->sender(intf->send_info, smi_msg);
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_cistatic bool is_maintenance_mode_cmd(struct kernel_ipmi_msg *msg)
190262306a36Sopenharmony_ci{
190362306a36Sopenharmony_ci	return (((msg->netfn == IPMI_NETFN_APP_REQUEST)
190462306a36Sopenharmony_ci		 && ((msg->cmd == IPMI_COLD_RESET_CMD)
190562306a36Sopenharmony_ci		     || (msg->cmd == IPMI_WARM_RESET_CMD)))
190662306a36Sopenharmony_ci		|| (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST));
190762306a36Sopenharmony_ci}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_cistatic int i_ipmi_req_sysintf(struct ipmi_smi        *intf,
191062306a36Sopenharmony_ci			      struct ipmi_addr       *addr,
191162306a36Sopenharmony_ci			      long                   msgid,
191262306a36Sopenharmony_ci			      struct kernel_ipmi_msg *msg,
191362306a36Sopenharmony_ci			      struct ipmi_smi_msg    *smi_msg,
191462306a36Sopenharmony_ci			      struct ipmi_recv_msg   *recv_msg,
191562306a36Sopenharmony_ci			      int                    retries,
191662306a36Sopenharmony_ci			      unsigned int           retry_time_ms)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	struct ipmi_system_interface_addr *smi_addr;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	if (msg->netfn & 1)
192162306a36Sopenharmony_ci		/* Responses are not allowed to the SMI. */
192262306a36Sopenharmony_ci		return -EINVAL;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	smi_addr = (struct ipmi_system_interface_addr *) addr;
192562306a36Sopenharmony_ci	if (smi_addr->lun > 3) {
192662306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
192762306a36Sopenharmony_ci		return -EINVAL;
192862306a36Sopenharmony_ci	}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
193362306a36Sopenharmony_ci	    && ((msg->cmd == IPMI_SEND_MSG_CMD)
193462306a36Sopenharmony_ci		|| (msg->cmd == IPMI_GET_MSG_CMD)
193562306a36Sopenharmony_ci		|| (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) {
193662306a36Sopenharmony_ci		/*
193762306a36Sopenharmony_ci		 * We don't let the user do these, since we manage
193862306a36Sopenharmony_ci		 * the sequence numbers.
193962306a36Sopenharmony_ci		 */
194062306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
194162306a36Sopenharmony_ci		return -EINVAL;
194262306a36Sopenharmony_ci	}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	if (is_maintenance_mode_cmd(msg)) {
194562306a36Sopenharmony_ci		unsigned long flags;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci		spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
194862306a36Sopenharmony_ci		intf->auto_maintenance_timeout
194962306a36Sopenharmony_ci			= maintenance_mode_timeout_ms;
195062306a36Sopenharmony_ci		if (!intf->maintenance_mode
195162306a36Sopenharmony_ci		    && !intf->maintenance_mode_enable) {
195262306a36Sopenharmony_ci			intf->maintenance_mode_enable = true;
195362306a36Sopenharmony_ci			maintenance_mode_update(intf);
195462306a36Sopenharmony_ci		}
195562306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->maintenance_mode_lock,
195662306a36Sopenharmony_ci				       flags);
195762306a36Sopenharmony_ci	}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	if (msg->data_len + 2 > IPMI_MAX_MSG_LENGTH) {
196062306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
196162306a36Sopenharmony_ci		return -EMSGSIZE;
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
196562306a36Sopenharmony_ci	smi_msg->data[1] = msg->cmd;
196662306a36Sopenharmony_ci	smi_msg->msgid = msgid;
196762306a36Sopenharmony_ci	smi_msg->user_data = recv_msg;
196862306a36Sopenharmony_ci	if (msg->data_len > 0)
196962306a36Sopenharmony_ci		memcpy(&smi_msg->data[2], msg->data, msg->data_len);
197062306a36Sopenharmony_ci	smi_msg->data_size = msg->data_len + 2;
197162306a36Sopenharmony_ci	ipmi_inc_stat(intf, sent_local_commands);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	return 0;
197462306a36Sopenharmony_ci}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_cistatic int i_ipmi_req_ipmb(struct ipmi_smi        *intf,
197762306a36Sopenharmony_ci			   struct ipmi_addr       *addr,
197862306a36Sopenharmony_ci			   long                   msgid,
197962306a36Sopenharmony_ci			   struct kernel_ipmi_msg *msg,
198062306a36Sopenharmony_ci			   struct ipmi_smi_msg    *smi_msg,
198162306a36Sopenharmony_ci			   struct ipmi_recv_msg   *recv_msg,
198262306a36Sopenharmony_ci			   unsigned char          source_address,
198362306a36Sopenharmony_ci			   unsigned char          source_lun,
198462306a36Sopenharmony_ci			   int                    retries,
198562306a36Sopenharmony_ci			   unsigned int           retry_time_ms)
198662306a36Sopenharmony_ci{
198762306a36Sopenharmony_ci	struct ipmi_ipmb_addr *ipmb_addr;
198862306a36Sopenharmony_ci	unsigned char ipmb_seq;
198962306a36Sopenharmony_ci	long seqid;
199062306a36Sopenharmony_ci	int broadcast = 0;
199162306a36Sopenharmony_ci	struct ipmi_channel *chans;
199262306a36Sopenharmony_ci	int rv = 0;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	if (addr->channel >= IPMI_MAX_CHANNELS) {
199562306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
199662306a36Sopenharmony_ci		return -EINVAL;
199762306a36Sopenharmony_ci	}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	chans = READ_ONCE(intf->channel_list)->c;
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	if (chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_IPMB) {
200262306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
200362306a36Sopenharmony_ci		return -EINVAL;
200462306a36Sopenharmony_ci	}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
200762306a36Sopenharmony_ci		/*
200862306a36Sopenharmony_ci		 * Broadcasts add a zero at the beginning of the
200962306a36Sopenharmony_ci		 * message, but otherwise is the same as an IPMB
201062306a36Sopenharmony_ci		 * address.
201162306a36Sopenharmony_ci		 */
201262306a36Sopenharmony_ci		addr->addr_type = IPMI_IPMB_ADDR_TYPE;
201362306a36Sopenharmony_ci		broadcast = 1;
201462306a36Sopenharmony_ci		retries = 0; /* Don't retry broadcasts. */
201562306a36Sopenharmony_ci	}
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	/*
201862306a36Sopenharmony_ci	 * 9 for the header and 1 for the checksum, plus
201962306a36Sopenharmony_ci	 * possibly one for the broadcast.
202062306a36Sopenharmony_ci	 */
202162306a36Sopenharmony_ci	if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
202262306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
202362306a36Sopenharmony_ci		return -EMSGSIZE;
202462306a36Sopenharmony_ci	}
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	ipmb_addr = (struct ipmi_ipmb_addr *) addr;
202762306a36Sopenharmony_ci	if (ipmb_addr->lun > 3) {
202862306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
202962306a36Sopenharmony_ci		return -EINVAL;
203062306a36Sopenharmony_ci	}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	if (recv_msg->msg.netfn & 0x1) {
203562306a36Sopenharmony_ci		/*
203662306a36Sopenharmony_ci		 * It's a response, so use the user's sequence
203762306a36Sopenharmony_ci		 * from msgid.
203862306a36Sopenharmony_ci		 */
203962306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_ipmb_responses);
204062306a36Sopenharmony_ci		format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
204162306a36Sopenharmony_ci				msgid, broadcast,
204262306a36Sopenharmony_ci				source_address, source_lun);
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci		/*
204562306a36Sopenharmony_ci		 * Save the receive message so we can use it
204662306a36Sopenharmony_ci		 * to deliver the response.
204762306a36Sopenharmony_ci		 */
204862306a36Sopenharmony_ci		smi_msg->user_data = recv_msg;
204962306a36Sopenharmony_ci	} else {
205062306a36Sopenharmony_ci		/* It's a command, so get a sequence for it. */
205162306a36Sopenharmony_ci		unsigned long flags;
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci		spin_lock_irqsave(&intf->seq_lock, flags);
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci		if (is_maintenance_mode_cmd(msg))
205662306a36Sopenharmony_ci			intf->ipmb_maintenance_mode_timeout =
205762306a36Sopenharmony_ci				maintenance_mode_timeout_ms;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci		if (intf->ipmb_maintenance_mode_timeout && retry_time_ms == 0)
206062306a36Sopenharmony_ci			/* Different default in maintenance mode */
206162306a36Sopenharmony_ci			retry_time_ms = default_maintenance_retry_ms;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci		/*
206462306a36Sopenharmony_ci		 * Create a sequence number with a 1 second
206562306a36Sopenharmony_ci		 * timeout and 4 retries.
206662306a36Sopenharmony_ci		 */
206762306a36Sopenharmony_ci		rv = intf_next_seq(intf,
206862306a36Sopenharmony_ci				   recv_msg,
206962306a36Sopenharmony_ci				   retry_time_ms,
207062306a36Sopenharmony_ci				   retries,
207162306a36Sopenharmony_ci				   broadcast,
207262306a36Sopenharmony_ci				   &ipmb_seq,
207362306a36Sopenharmony_ci				   &seqid);
207462306a36Sopenharmony_ci		if (rv)
207562306a36Sopenharmony_ci			/*
207662306a36Sopenharmony_ci			 * We have used up all the sequence numbers,
207762306a36Sopenharmony_ci			 * probably, so abort.
207862306a36Sopenharmony_ci			 */
207962306a36Sopenharmony_ci			goto out_err;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_ipmb_commands);
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci		/*
208462306a36Sopenharmony_ci		 * Store the sequence number in the message,
208562306a36Sopenharmony_ci		 * so that when the send message response
208662306a36Sopenharmony_ci		 * comes back we can start the timer.
208762306a36Sopenharmony_ci		 */
208862306a36Sopenharmony_ci		format_ipmb_msg(smi_msg, msg, ipmb_addr,
208962306a36Sopenharmony_ci				STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
209062306a36Sopenharmony_ci				ipmb_seq, broadcast,
209162306a36Sopenharmony_ci				source_address, source_lun);
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci		/*
209462306a36Sopenharmony_ci		 * Copy the message into the recv message data, so we
209562306a36Sopenharmony_ci		 * can retransmit it later if necessary.
209662306a36Sopenharmony_ci		 */
209762306a36Sopenharmony_ci		memcpy(recv_msg->msg_data, smi_msg->data,
209862306a36Sopenharmony_ci		       smi_msg->data_size);
209962306a36Sopenharmony_ci		recv_msg->msg.data = recv_msg->msg_data;
210062306a36Sopenharmony_ci		recv_msg->msg.data_len = smi_msg->data_size;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci		/*
210362306a36Sopenharmony_ci		 * We don't unlock until here, because we need
210462306a36Sopenharmony_ci		 * to copy the completed message into the
210562306a36Sopenharmony_ci		 * recv_msg before we release the lock.
210662306a36Sopenharmony_ci		 * Otherwise, race conditions may bite us.  I
210762306a36Sopenharmony_ci		 * know that's pretty paranoid, but I prefer
210862306a36Sopenharmony_ci		 * to be correct.
210962306a36Sopenharmony_ci		 */
211062306a36Sopenharmony_ciout_err:
211162306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->seq_lock, flags);
211262306a36Sopenharmony_ci	}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	return rv;
211562306a36Sopenharmony_ci}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_cistatic int i_ipmi_req_ipmb_direct(struct ipmi_smi        *intf,
211862306a36Sopenharmony_ci				  struct ipmi_addr       *addr,
211962306a36Sopenharmony_ci				  long			 msgid,
212062306a36Sopenharmony_ci				  struct kernel_ipmi_msg *msg,
212162306a36Sopenharmony_ci				  struct ipmi_smi_msg    *smi_msg,
212262306a36Sopenharmony_ci				  struct ipmi_recv_msg   *recv_msg,
212362306a36Sopenharmony_ci				  unsigned char          source_lun)
212462306a36Sopenharmony_ci{
212562306a36Sopenharmony_ci	struct ipmi_ipmb_direct_addr *daddr;
212662306a36Sopenharmony_ci	bool is_cmd = !(recv_msg->msg.netfn & 0x1);
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	if (!(intf->handlers->flags & IPMI_SMI_CAN_HANDLE_IPMB_DIRECT))
212962306a36Sopenharmony_ci		return -EAFNOSUPPORT;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	/* Responses must have a completion code. */
213262306a36Sopenharmony_ci	if (!is_cmd && msg->data_len < 1) {
213362306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
213462306a36Sopenharmony_ci		return -EINVAL;
213562306a36Sopenharmony_ci	}
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	if ((msg->data_len + 4) > IPMI_MAX_MSG_LENGTH) {
213862306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
213962306a36Sopenharmony_ci		return -EMSGSIZE;
214062306a36Sopenharmony_ci	}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	daddr = (struct ipmi_ipmb_direct_addr *) addr;
214362306a36Sopenharmony_ci	if (daddr->rq_lun > 3 || daddr->rs_lun > 3) {
214462306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
214562306a36Sopenharmony_ci		return -EINVAL;
214662306a36Sopenharmony_ci	}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	smi_msg->type = IPMI_SMI_MSG_TYPE_IPMB_DIRECT;
214962306a36Sopenharmony_ci	smi_msg->msgid = msgid;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	if (is_cmd) {
215262306a36Sopenharmony_ci		smi_msg->data[0] = msg->netfn << 2 | daddr->rs_lun;
215362306a36Sopenharmony_ci		smi_msg->data[2] = recv_msg->msgid << 2 | daddr->rq_lun;
215462306a36Sopenharmony_ci	} else {
215562306a36Sopenharmony_ci		smi_msg->data[0] = msg->netfn << 2 | daddr->rq_lun;
215662306a36Sopenharmony_ci		smi_msg->data[2] = recv_msg->msgid << 2 | daddr->rs_lun;
215762306a36Sopenharmony_ci	}
215862306a36Sopenharmony_ci	smi_msg->data[1] = daddr->slave_addr;
215962306a36Sopenharmony_ci	smi_msg->data[3] = msg->cmd;
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	memcpy(smi_msg->data + 4, msg->data, msg->data_len);
216262306a36Sopenharmony_ci	smi_msg->data_size = msg->data_len + 4;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	smi_msg->user_data = recv_msg;
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	return 0;
216762306a36Sopenharmony_ci}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_cistatic int i_ipmi_req_lan(struct ipmi_smi        *intf,
217062306a36Sopenharmony_ci			  struct ipmi_addr       *addr,
217162306a36Sopenharmony_ci			  long                   msgid,
217262306a36Sopenharmony_ci			  struct kernel_ipmi_msg *msg,
217362306a36Sopenharmony_ci			  struct ipmi_smi_msg    *smi_msg,
217462306a36Sopenharmony_ci			  struct ipmi_recv_msg   *recv_msg,
217562306a36Sopenharmony_ci			  unsigned char          source_lun,
217662306a36Sopenharmony_ci			  int                    retries,
217762306a36Sopenharmony_ci			  unsigned int           retry_time_ms)
217862306a36Sopenharmony_ci{
217962306a36Sopenharmony_ci	struct ipmi_lan_addr  *lan_addr;
218062306a36Sopenharmony_ci	unsigned char ipmb_seq;
218162306a36Sopenharmony_ci	long seqid;
218262306a36Sopenharmony_ci	struct ipmi_channel *chans;
218362306a36Sopenharmony_ci	int rv = 0;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	if (addr->channel >= IPMI_MAX_CHANNELS) {
218662306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
218762306a36Sopenharmony_ci		return -EINVAL;
218862306a36Sopenharmony_ci	}
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	chans = READ_ONCE(intf->channel_list)->c;
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	if ((chans[addr->channel].medium
219362306a36Sopenharmony_ci				!= IPMI_CHANNEL_MEDIUM_8023LAN)
219462306a36Sopenharmony_ci			&& (chans[addr->channel].medium
219562306a36Sopenharmony_ci			    != IPMI_CHANNEL_MEDIUM_ASYNC)) {
219662306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
219762306a36Sopenharmony_ci		return -EINVAL;
219862306a36Sopenharmony_ci	}
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	/* 11 for the header and 1 for the checksum. */
220162306a36Sopenharmony_ci	if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
220262306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
220362306a36Sopenharmony_ci		return -EMSGSIZE;
220462306a36Sopenharmony_ci	}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	lan_addr = (struct ipmi_lan_addr *) addr;
220762306a36Sopenharmony_ci	if (lan_addr->lun > 3) {
220862306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
220962306a36Sopenharmony_ci		return -EINVAL;
221062306a36Sopenharmony_ci	}
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	if (recv_msg->msg.netfn & 0x1) {
221562306a36Sopenharmony_ci		/*
221662306a36Sopenharmony_ci		 * It's a response, so use the user's sequence
221762306a36Sopenharmony_ci		 * from msgid.
221862306a36Sopenharmony_ci		 */
221962306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_lan_responses);
222062306a36Sopenharmony_ci		format_lan_msg(smi_msg, msg, lan_addr, msgid,
222162306a36Sopenharmony_ci			       msgid, source_lun);
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci		/*
222462306a36Sopenharmony_ci		 * Save the receive message so we can use it
222562306a36Sopenharmony_ci		 * to deliver the response.
222662306a36Sopenharmony_ci		 */
222762306a36Sopenharmony_ci		smi_msg->user_data = recv_msg;
222862306a36Sopenharmony_ci	} else {
222962306a36Sopenharmony_ci		/* It's a command, so get a sequence for it. */
223062306a36Sopenharmony_ci		unsigned long flags;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci		spin_lock_irqsave(&intf->seq_lock, flags);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci		/*
223562306a36Sopenharmony_ci		 * Create a sequence number with a 1 second
223662306a36Sopenharmony_ci		 * timeout and 4 retries.
223762306a36Sopenharmony_ci		 */
223862306a36Sopenharmony_ci		rv = intf_next_seq(intf,
223962306a36Sopenharmony_ci				   recv_msg,
224062306a36Sopenharmony_ci				   retry_time_ms,
224162306a36Sopenharmony_ci				   retries,
224262306a36Sopenharmony_ci				   0,
224362306a36Sopenharmony_ci				   &ipmb_seq,
224462306a36Sopenharmony_ci				   &seqid);
224562306a36Sopenharmony_ci		if (rv)
224662306a36Sopenharmony_ci			/*
224762306a36Sopenharmony_ci			 * We have used up all the sequence numbers,
224862306a36Sopenharmony_ci			 * probably, so abort.
224962306a36Sopenharmony_ci			 */
225062306a36Sopenharmony_ci			goto out_err;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_lan_commands);
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci		/*
225562306a36Sopenharmony_ci		 * Store the sequence number in the message,
225662306a36Sopenharmony_ci		 * so that when the send message response
225762306a36Sopenharmony_ci		 * comes back we can start the timer.
225862306a36Sopenharmony_ci		 */
225962306a36Sopenharmony_ci		format_lan_msg(smi_msg, msg, lan_addr,
226062306a36Sopenharmony_ci			       STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
226162306a36Sopenharmony_ci			       ipmb_seq, source_lun);
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci		/*
226462306a36Sopenharmony_ci		 * Copy the message into the recv message data, so we
226562306a36Sopenharmony_ci		 * can retransmit it later if necessary.
226662306a36Sopenharmony_ci		 */
226762306a36Sopenharmony_ci		memcpy(recv_msg->msg_data, smi_msg->data,
226862306a36Sopenharmony_ci		       smi_msg->data_size);
226962306a36Sopenharmony_ci		recv_msg->msg.data = recv_msg->msg_data;
227062306a36Sopenharmony_ci		recv_msg->msg.data_len = smi_msg->data_size;
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci		/*
227362306a36Sopenharmony_ci		 * We don't unlock until here, because we need
227462306a36Sopenharmony_ci		 * to copy the completed message into the
227562306a36Sopenharmony_ci		 * recv_msg before we release the lock.
227662306a36Sopenharmony_ci		 * Otherwise, race conditions may bite us.  I
227762306a36Sopenharmony_ci		 * know that's pretty paranoid, but I prefer
227862306a36Sopenharmony_ci		 * to be correct.
227962306a36Sopenharmony_ci		 */
228062306a36Sopenharmony_ciout_err:
228162306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->seq_lock, flags);
228262306a36Sopenharmony_ci	}
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	return rv;
228562306a36Sopenharmony_ci}
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci/*
228862306a36Sopenharmony_ci * Separate from ipmi_request so that the user does not have to be
228962306a36Sopenharmony_ci * supplied in certain circumstances (mainly at panic time).  If
229062306a36Sopenharmony_ci * messages are supplied, they will be freed, even if an error
229162306a36Sopenharmony_ci * occurs.
229262306a36Sopenharmony_ci */
229362306a36Sopenharmony_cistatic int i_ipmi_request(struct ipmi_user     *user,
229462306a36Sopenharmony_ci			  struct ipmi_smi      *intf,
229562306a36Sopenharmony_ci			  struct ipmi_addr     *addr,
229662306a36Sopenharmony_ci			  long                 msgid,
229762306a36Sopenharmony_ci			  struct kernel_ipmi_msg *msg,
229862306a36Sopenharmony_ci			  void                 *user_msg_data,
229962306a36Sopenharmony_ci			  void                 *supplied_smi,
230062306a36Sopenharmony_ci			  struct ipmi_recv_msg *supplied_recv,
230162306a36Sopenharmony_ci			  int                  priority,
230262306a36Sopenharmony_ci			  unsigned char        source_address,
230362306a36Sopenharmony_ci			  unsigned char        source_lun,
230462306a36Sopenharmony_ci			  int                  retries,
230562306a36Sopenharmony_ci			  unsigned int         retry_time_ms)
230662306a36Sopenharmony_ci{
230762306a36Sopenharmony_ci	struct ipmi_smi_msg *smi_msg;
230862306a36Sopenharmony_ci	struct ipmi_recv_msg *recv_msg;
230962306a36Sopenharmony_ci	int rv = 0;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	if (user) {
231262306a36Sopenharmony_ci		if (atomic_add_return(1, &user->nr_msgs) > max_msgs_per_user) {
231362306a36Sopenharmony_ci			/* Decrement will happen at the end of the routine. */
231462306a36Sopenharmony_ci			rv = -EBUSY;
231562306a36Sopenharmony_ci			goto out;
231662306a36Sopenharmony_ci		}
231762306a36Sopenharmony_ci	}
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	if (supplied_recv)
232062306a36Sopenharmony_ci		recv_msg = supplied_recv;
232162306a36Sopenharmony_ci	else {
232262306a36Sopenharmony_ci		recv_msg = ipmi_alloc_recv_msg();
232362306a36Sopenharmony_ci		if (recv_msg == NULL) {
232462306a36Sopenharmony_ci			rv = -ENOMEM;
232562306a36Sopenharmony_ci			goto out;
232662306a36Sopenharmony_ci		}
232762306a36Sopenharmony_ci	}
232862306a36Sopenharmony_ci	recv_msg->user_msg_data = user_msg_data;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	if (supplied_smi)
233162306a36Sopenharmony_ci		smi_msg = supplied_smi;
233262306a36Sopenharmony_ci	else {
233362306a36Sopenharmony_ci		smi_msg = ipmi_alloc_smi_msg();
233462306a36Sopenharmony_ci		if (smi_msg == NULL) {
233562306a36Sopenharmony_ci			if (!supplied_recv)
233662306a36Sopenharmony_ci				ipmi_free_recv_msg(recv_msg);
233762306a36Sopenharmony_ci			rv = -ENOMEM;
233862306a36Sopenharmony_ci			goto out;
233962306a36Sopenharmony_ci		}
234062306a36Sopenharmony_ci	}
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci	rcu_read_lock();
234362306a36Sopenharmony_ci	if (intf->in_shutdown) {
234462306a36Sopenharmony_ci		rv = -ENODEV;
234562306a36Sopenharmony_ci		goto out_err;
234662306a36Sopenharmony_ci	}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	recv_msg->user = user;
234962306a36Sopenharmony_ci	if (user)
235062306a36Sopenharmony_ci		/* The put happens when the message is freed. */
235162306a36Sopenharmony_ci		kref_get(&user->refcount);
235262306a36Sopenharmony_ci	recv_msg->msgid = msgid;
235362306a36Sopenharmony_ci	/*
235462306a36Sopenharmony_ci	 * Store the message to send in the receive message so timeout
235562306a36Sopenharmony_ci	 * responses can get the proper response data.
235662306a36Sopenharmony_ci	 */
235762306a36Sopenharmony_ci	recv_msg->msg = *msg;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
236062306a36Sopenharmony_ci		rv = i_ipmi_req_sysintf(intf, addr, msgid, msg, smi_msg,
236162306a36Sopenharmony_ci					recv_msg, retries, retry_time_ms);
236262306a36Sopenharmony_ci	} else if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) {
236362306a36Sopenharmony_ci		rv = i_ipmi_req_ipmb(intf, addr, msgid, msg, smi_msg, recv_msg,
236462306a36Sopenharmony_ci				     source_address, source_lun,
236562306a36Sopenharmony_ci				     retries, retry_time_ms);
236662306a36Sopenharmony_ci	} else if (is_ipmb_direct_addr(addr)) {
236762306a36Sopenharmony_ci		rv = i_ipmi_req_ipmb_direct(intf, addr, msgid, msg, smi_msg,
236862306a36Sopenharmony_ci					    recv_msg, source_lun);
236962306a36Sopenharmony_ci	} else if (is_lan_addr(addr)) {
237062306a36Sopenharmony_ci		rv = i_ipmi_req_lan(intf, addr, msgid, msg, smi_msg, recv_msg,
237162306a36Sopenharmony_ci				    source_lun, retries, retry_time_ms);
237262306a36Sopenharmony_ci	} else {
237362306a36Sopenharmony_ci	    /* Unknown address type. */
237462306a36Sopenharmony_ci		ipmi_inc_stat(intf, sent_invalid_commands);
237562306a36Sopenharmony_ci		rv = -EINVAL;
237662306a36Sopenharmony_ci	}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	if (rv) {
237962306a36Sopenharmony_ciout_err:
238062306a36Sopenharmony_ci		ipmi_free_smi_msg(smi_msg);
238162306a36Sopenharmony_ci		ipmi_free_recv_msg(recv_msg);
238262306a36Sopenharmony_ci	} else {
238362306a36Sopenharmony_ci		dev_dbg(intf->si_dev, "Send: %*ph\n",
238462306a36Sopenharmony_ci			smi_msg->data_size, smi_msg->data);
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci		smi_send(intf, intf->handlers, smi_msg, priority);
238762306a36Sopenharmony_ci	}
238862306a36Sopenharmony_ci	rcu_read_unlock();
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ciout:
239162306a36Sopenharmony_ci	if (rv && user)
239262306a36Sopenharmony_ci		atomic_dec(&user->nr_msgs);
239362306a36Sopenharmony_ci	return rv;
239462306a36Sopenharmony_ci}
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_cistatic int check_addr(struct ipmi_smi  *intf,
239762306a36Sopenharmony_ci		      struct ipmi_addr *addr,
239862306a36Sopenharmony_ci		      unsigned char    *saddr,
239962306a36Sopenharmony_ci		      unsigned char    *lun)
240062306a36Sopenharmony_ci{
240162306a36Sopenharmony_ci	if (addr->channel >= IPMI_MAX_CHANNELS)
240262306a36Sopenharmony_ci		return -EINVAL;
240362306a36Sopenharmony_ci	addr->channel = array_index_nospec(addr->channel, IPMI_MAX_CHANNELS);
240462306a36Sopenharmony_ci	*lun = intf->addrinfo[addr->channel].lun;
240562306a36Sopenharmony_ci	*saddr = intf->addrinfo[addr->channel].address;
240662306a36Sopenharmony_ci	return 0;
240762306a36Sopenharmony_ci}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ciint ipmi_request_settime(struct ipmi_user *user,
241062306a36Sopenharmony_ci			 struct ipmi_addr *addr,
241162306a36Sopenharmony_ci			 long             msgid,
241262306a36Sopenharmony_ci			 struct kernel_ipmi_msg  *msg,
241362306a36Sopenharmony_ci			 void             *user_msg_data,
241462306a36Sopenharmony_ci			 int              priority,
241562306a36Sopenharmony_ci			 int              retries,
241662306a36Sopenharmony_ci			 unsigned int     retry_time_ms)
241762306a36Sopenharmony_ci{
241862306a36Sopenharmony_ci	unsigned char saddr = 0, lun = 0;
241962306a36Sopenharmony_ci	int rv, index;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	if (!user)
242262306a36Sopenharmony_ci		return -EINVAL;
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
242562306a36Sopenharmony_ci	if (!user)
242662306a36Sopenharmony_ci		return -ENODEV;
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	rv = check_addr(user->intf, addr, &saddr, &lun);
242962306a36Sopenharmony_ci	if (!rv)
243062306a36Sopenharmony_ci		rv = i_ipmi_request(user,
243162306a36Sopenharmony_ci				    user->intf,
243262306a36Sopenharmony_ci				    addr,
243362306a36Sopenharmony_ci				    msgid,
243462306a36Sopenharmony_ci				    msg,
243562306a36Sopenharmony_ci				    user_msg_data,
243662306a36Sopenharmony_ci				    NULL, NULL,
243762306a36Sopenharmony_ci				    priority,
243862306a36Sopenharmony_ci				    saddr,
243962306a36Sopenharmony_ci				    lun,
244062306a36Sopenharmony_ci				    retries,
244162306a36Sopenharmony_ci				    retry_time_ms);
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	release_ipmi_user(user, index);
244462306a36Sopenharmony_ci	return rv;
244562306a36Sopenharmony_ci}
244662306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_request_settime);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ciint ipmi_request_supply_msgs(struct ipmi_user     *user,
244962306a36Sopenharmony_ci			     struct ipmi_addr     *addr,
245062306a36Sopenharmony_ci			     long                 msgid,
245162306a36Sopenharmony_ci			     struct kernel_ipmi_msg *msg,
245262306a36Sopenharmony_ci			     void                 *user_msg_data,
245362306a36Sopenharmony_ci			     void                 *supplied_smi,
245462306a36Sopenharmony_ci			     struct ipmi_recv_msg *supplied_recv,
245562306a36Sopenharmony_ci			     int                  priority)
245662306a36Sopenharmony_ci{
245762306a36Sopenharmony_ci	unsigned char saddr = 0, lun = 0;
245862306a36Sopenharmony_ci	int rv, index;
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci	if (!user)
246162306a36Sopenharmony_ci		return -EINVAL;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	user = acquire_ipmi_user(user, &index);
246462306a36Sopenharmony_ci	if (!user)
246562306a36Sopenharmony_ci		return -ENODEV;
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	rv = check_addr(user->intf, addr, &saddr, &lun);
246862306a36Sopenharmony_ci	if (!rv)
246962306a36Sopenharmony_ci		rv = i_ipmi_request(user,
247062306a36Sopenharmony_ci				    user->intf,
247162306a36Sopenharmony_ci				    addr,
247262306a36Sopenharmony_ci				    msgid,
247362306a36Sopenharmony_ci				    msg,
247462306a36Sopenharmony_ci				    user_msg_data,
247562306a36Sopenharmony_ci				    supplied_smi,
247662306a36Sopenharmony_ci				    supplied_recv,
247762306a36Sopenharmony_ci				    priority,
247862306a36Sopenharmony_ci				    saddr,
247962306a36Sopenharmony_ci				    lun,
248062306a36Sopenharmony_ci				    -1, 0);
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	release_ipmi_user(user, index);
248362306a36Sopenharmony_ci	return rv;
248462306a36Sopenharmony_ci}
248562306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_request_supply_msgs);
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_cistatic void bmc_device_id_handler(struct ipmi_smi *intf,
248862306a36Sopenharmony_ci				  struct ipmi_recv_msg *msg)
248962306a36Sopenharmony_ci{
249062306a36Sopenharmony_ci	int rv;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
249362306a36Sopenharmony_ci			|| (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
249462306a36Sopenharmony_ci			|| (msg->msg.cmd != IPMI_GET_DEVICE_ID_CMD)) {
249562306a36Sopenharmony_ci		dev_warn(intf->si_dev,
249662306a36Sopenharmony_ci			 "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n",
249762306a36Sopenharmony_ci			 msg->addr.addr_type, msg->msg.netfn, msg->msg.cmd);
249862306a36Sopenharmony_ci		return;
249962306a36Sopenharmony_ci	}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	if (msg->msg.data[0]) {
250262306a36Sopenharmony_ci		dev_warn(intf->si_dev, "device id fetch failed: 0x%2.2x\n",
250362306a36Sopenharmony_ci			 msg->msg.data[0]);
250462306a36Sopenharmony_ci		intf->bmc->dyn_id_set = 0;
250562306a36Sopenharmony_ci		goto out;
250662306a36Sopenharmony_ci	}
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	rv = ipmi_demangle_device_id(msg->msg.netfn, msg->msg.cmd,
250962306a36Sopenharmony_ci			msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id);
251062306a36Sopenharmony_ci	if (rv) {
251162306a36Sopenharmony_ci		dev_warn(intf->si_dev, "device id demangle failed: %d\n", rv);
251262306a36Sopenharmony_ci		/* record completion code when error */
251362306a36Sopenharmony_ci		intf->bmc->cc = msg->msg.data[0];
251462306a36Sopenharmony_ci		intf->bmc->dyn_id_set = 0;
251562306a36Sopenharmony_ci	} else {
251662306a36Sopenharmony_ci		/*
251762306a36Sopenharmony_ci		 * Make sure the id data is available before setting
251862306a36Sopenharmony_ci		 * dyn_id_set.
251962306a36Sopenharmony_ci		 */
252062306a36Sopenharmony_ci		smp_wmb();
252162306a36Sopenharmony_ci		intf->bmc->dyn_id_set = 1;
252262306a36Sopenharmony_ci	}
252362306a36Sopenharmony_ciout:
252462306a36Sopenharmony_ci	wake_up(&intf->waitq);
252562306a36Sopenharmony_ci}
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_cistatic int
252862306a36Sopenharmony_cisend_get_device_id_cmd(struct ipmi_smi *intf)
252962306a36Sopenharmony_ci{
253062306a36Sopenharmony_ci	struct ipmi_system_interface_addr si;
253162306a36Sopenharmony_ci	struct kernel_ipmi_msg msg;
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
253462306a36Sopenharmony_ci	si.channel = IPMI_BMC_CHANNEL;
253562306a36Sopenharmony_ci	si.lun = 0;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	msg.netfn = IPMI_NETFN_APP_REQUEST;
253862306a36Sopenharmony_ci	msg.cmd = IPMI_GET_DEVICE_ID_CMD;
253962306a36Sopenharmony_ci	msg.data = NULL;
254062306a36Sopenharmony_ci	msg.data_len = 0;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	return i_ipmi_request(NULL,
254362306a36Sopenharmony_ci			      intf,
254462306a36Sopenharmony_ci			      (struct ipmi_addr *) &si,
254562306a36Sopenharmony_ci			      0,
254662306a36Sopenharmony_ci			      &msg,
254762306a36Sopenharmony_ci			      intf,
254862306a36Sopenharmony_ci			      NULL,
254962306a36Sopenharmony_ci			      NULL,
255062306a36Sopenharmony_ci			      0,
255162306a36Sopenharmony_ci			      intf->addrinfo[0].address,
255262306a36Sopenharmony_ci			      intf->addrinfo[0].lun,
255362306a36Sopenharmony_ci			      -1, 0);
255462306a36Sopenharmony_ci}
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_cistatic int __get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc)
255762306a36Sopenharmony_ci{
255862306a36Sopenharmony_ci	int rv;
255962306a36Sopenharmony_ci	unsigned int retry_count = 0;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	intf->null_user_handler = bmc_device_id_handler;
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ciretry:
256462306a36Sopenharmony_ci	bmc->cc = 0;
256562306a36Sopenharmony_ci	bmc->dyn_id_set = 2;
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	rv = send_get_device_id_cmd(intf);
256862306a36Sopenharmony_ci	if (rv)
256962306a36Sopenharmony_ci		goto out_reset_handler;
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	wait_event(intf->waitq, bmc->dyn_id_set != 2);
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	if (!bmc->dyn_id_set) {
257462306a36Sopenharmony_ci		if (bmc->cc != IPMI_CC_NO_ERROR &&
257562306a36Sopenharmony_ci		    ++retry_count <= GET_DEVICE_ID_MAX_RETRY) {
257662306a36Sopenharmony_ci			msleep(500);
257762306a36Sopenharmony_ci			dev_warn(intf->si_dev,
257862306a36Sopenharmony_ci			    "BMC returned 0x%2.2x, retry get bmc device id\n",
257962306a36Sopenharmony_ci			    bmc->cc);
258062306a36Sopenharmony_ci			goto retry;
258162306a36Sopenharmony_ci		}
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci		rv = -EIO; /* Something went wrong in the fetch. */
258462306a36Sopenharmony_ci	}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	/* dyn_id_set makes the id data available. */
258762306a36Sopenharmony_ci	smp_rmb();
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ciout_reset_handler:
259062306a36Sopenharmony_ci	intf->null_user_handler = NULL;
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	return rv;
259362306a36Sopenharmony_ci}
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci/*
259662306a36Sopenharmony_ci * Fetch the device id for the bmc/interface.  You must pass in either
259762306a36Sopenharmony_ci * bmc or intf, this code will get the other one.  If the data has
259862306a36Sopenharmony_ci * been recently fetched, this will just use the cached data.  Otherwise
259962306a36Sopenharmony_ci * it will run a new fetch.
260062306a36Sopenharmony_ci *
260162306a36Sopenharmony_ci * Except for the first time this is called (in ipmi_add_smi()),
260262306a36Sopenharmony_ci * this will always return good data;
260362306a36Sopenharmony_ci */
260462306a36Sopenharmony_cistatic int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc,
260562306a36Sopenharmony_ci			       struct ipmi_device_id *id,
260662306a36Sopenharmony_ci			       bool *guid_set, guid_t *guid, int intf_num)
260762306a36Sopenharmony_ci{
260862306a36Sopenharmony_ci	int rv = 0;
260962306a36Sopenharmony_ci	int prev_dyn_id_set, prev_guid_set;
261062306a36Sopenharmony_ci	bool intf_set = intf != NULL;
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci	if (!intf) {
261362306a36Sopenharmony_ci		mutex_lock(&bmc->dyn_mutex);
261462306a36Sopenharmony_ciretry_bmc_lock:
261562306a36Sopenharmony_ci		if (list_empty(&bmc->intfs)) {
261662306a36Sopenharmony_ci			mutex_unlock(&bmc->dyn_mutex);
261762306a36Sopenharmony_ci			return -ENOENT;
261862306a36Sopenharmony_ci		}
261962306a36Sopenharmony_ci		intf = list_first_entry(&bmc->intfs, struct ipmi_smi,
262062306a36Sopenharmony_ci					bmc_link);
262162306a36Sopenharmony_ci		kref_get(&intf->refcount);
262262306a36Sopenharmony_ci		mutex_unlock(&bmc->dyn_mutex);
262362306a36Sopenharmony_ci		mutex_lock(&intf->bmc_reg_mutex);
262462306a36Sopenharmony_ci		mutex_lock(&bmc->dyn_mutex);
262562306a36Sopenharmony_ci		if (intf != list_first_entry(&bmc->intfs, struct ipmi_smi,
262662306a36Sopenharmony_ci					     bmc_link)) {
262762306a36Sopenharmony_ci			mutex_unlock(&intf->bmc_reg_mutex);
262862306a36Sopenharmony_ci			kref_put(&intf->refcount, intf_free);
262962306a36Sopenharmony_ci			goto retry_bmc_lock;
263062306a36Sopenharmony_ci		}
263162306a36Sopenharmony_ci	} else {
263262306a36Sopenharmony_ci		mutex_lock(&intf->bmc_reg_mutex);
263362306a36Sopenharmony_ci		bmc = intf->bmc;
263462306a36Sopenharmony_ci		mutex_lock(&bmc->dyn_mutex);
263562306a36Sopenharmony_ci		kref_get(&intf->refcount);
263662306a36Sopenharmony_ci	}
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci	/* If we have a valid and current ID, just return that. */
263962306a36Sopenharmony_ci	if (intf->in_bmc_register ||
264062306a36Sopenharmony_ci	    (bmc->dyn_id_set && time_is_after_jiffies(bmc->dyn_id_expiry)))
264162306a36Sopenharmony_ci		goto out_noprocessing;
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	prev_guid_set = bmc->dyn_guid_set;
264462306a36Sopenharmony_ci	__get_guid(intf);
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	prev_dyn_id_set = bmc->dyn_id_set;
264762306a36Sopenharmony_ci	rv = __get_device_id(intf, bmc);
264862306a36Sopenharmony_ci	if (rv)
264962306a36Sopenharmony_ci		goto out;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	/*
265262306a36Sopenharmony_ci	 * The guid, device id, manufacturer id, and product id should
265362306a36Sopenharmony_ci	 * not change on a BMC.  If it does we have to do some dancing.
265462306a36Sopenharmony_ci	 */
265562306a36Sopenharmony_ci	if (!intf->bmc_registered
265662306a36Sopenharmony_ci	    || (!prev_guid_set && bmc->dyn_guid_set)
265762306a36Sopenharmony_ci	    || (!prev_dyn_id_set && bmc->dyn_id_set)
265862306a36Sopenharmony_ci	    || (prev_guid_set && bmc->dyn_guid_set
265962306a36Sopenharmony_ci		&& !guid_equal(&bmc->guid, &bmc->fetch_guid))
266062306a36Sopenharmony_ci	    || bmc->id.device_id != bmc->fetch_id.device_id
266162306a36Sopenharmony_ci	    || bmc->id.manufacturer_id != bmc->fetch_id.manufacturer_id
266262306a36Sopenharmony_ci	    || bmc->id.product_id != bmc->fetch_id.product_id) {
266362306a36Sopenharmony_ci		struct ipmi_device_id id = bmc->fetch_id;
266462306a36Sopenharmony_ci		int guid_set = bmc->dyn_guid_set;
266562306a36Sopenharmony_ci		guid_t guid;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci		guid = bmc->fetch_guid;
266862306a36Sopenharmony_ci		mutex_unlock(&bmc->dyn_mutex);
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci		__ipmi_bmc_unregister(intf);
267162306a36Sopenharmony_ci		/* Fill in the temporary BMC for good measure. */
267262306a36Sopenharmony_ci		intf->bmc->id = id;
267362306a36Sopenharmony_ci		intf->bmc->dyn_guid_set = guid_set;
267462306a36Sopenharmony_ci		intf->bmc->guid = guid;
267562306a36Sopenharmony_ci		if (__ipmi_bmc_register(intf, &id, guid_set, &guid, intf_num))
267662306a36Sopenharmony_ci			need_waiter(intf); /* Retry later on an error. */
267762306a36Sopenharmony_ci		else
267862306a36Sopenharmony_ci			__scan_channels(intf, &id);
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci		if (!intf_set) {
268262306a36Sopenharmony_ci			/*
268362306a36Sopenharmony_ci			 * We weren't given the interface on the
268462306a36Sopenharmony_ci			 * command line, so restart the operation on
268562306a36Sopenharmony_ci			 * the next interface for the BMC.
268662306a36Sopenharmony_ci			 */
268762306a36Sopenharmony_ci			mutex_unlock(&intf->bmc_reg_mutex);
268862306a36Sopenharmony_ci			mutex_lock(&bmc->dyn_mutex);
268962306a36Sopenharmony_ci			goto retry_bmc_lock;
269062306a36Sopenharmony_ci		}
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci		/* We have a new BMC, set it up. */
269362306a36Sopenharmony_ci		bmc = intf->bmc;
269462306a36Sopenharmony_ci		mutex_lock(&bmc->dyn_mutex);
269562306a36Sopenharmony_ci		goto out_noprocessing;
269662306a36Sopenharmony_ci	} else if (memcmp(&bmc->fetch_id, &bmc->id, sizeof(bmc->id)))
269762306a36Sopenharmony_ci		/* Version info changes, scan the channels again. */
269862306a36Sopenharmony_ci		__scan_channels(intf, &bmc->fetch_id);
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci	bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ciout:
270362306a36Sopenharmony_ci	if (rv && prev_dyn_id_set) {
270462306a36Sopenharmony_ci		rv = 0; /* Ignore failures if we have previous data. */
270562306a36Sopenharmony_ci		bmc->dyn_id_set = prev_dyn_id_set;
270662306a36Sopenharmony_ci	}
270762306a36Sopenharmony_ci	if (!rv) {
270862306a36Sopenharmony_ci		bmc->id = bmc->fetch_id;
270962306a36Sopenharmony_ci		if (bmc->dyn_guid_set)
271062306a36Sopenharmony_ci			bmc->guid = bmc->fetch_guid;
271162306a36Sopenharmony_ci		else if (prev_guid_set)
271262306a36Sopenharmony_ci			/*
271362306a36Sopenharmony_ci			 * The guid used to be valid and it failed to fetch,
271462306a36Sopenharmony_ci			 * just use the cached value.
271562306a36Sopenharmony_ci			 */
271662306a36Sopenharmony_ci			bmc->dyn_guid_set = prev_guid_set;
271762306a36Sopenharmony_ci	}
271862306a36Sopenharmony_ciout_noprocessing:
271962306a36Sopenharmony_ci	if (!rv) {
272062306a36Sopenharmony_ci		if (id)
272162306a36Sopenharmony_ci			*id = bmc->id;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci		if (guid_set)
272462306a36Sopenharmony_ci			*guid_set = bmc->dyn_guid_set;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci		if (guid && bmc->dyn_guid_set)
272762306a36Sopenharmony_ci			*guid =  bmc->guid;
272862306a36Sopenharmony_ci	}
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci	mutex_unlock(&bmc->dyn_mutex);
273162306a36Sopenharmony_ci	mutex_unlock(&intf->bmc_reg_mutex);
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	kref_put(&intf->refcount, intf_free);
273462306a36Sopenharmony_ci	return rv;
273562306a36Sopenharmony_ci}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_cistatic int bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc,
273862306a36Sopenharmony_ci			     struct ipmi_device_id *id,
273962306a36Sopenharmony_ci			     bool *guid_set, guid_t *guid)
274062306a36Sopenharmony_ci{
274162306a36Sopenharmony_ci	return __bmc_get_device_id(intf, bmc, id, guid_set, guid, -1);
274262306a36Sopenharmony_ci}
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_cistatic ssize_t device_id_show(struct device *dev,
274562306a36Sopenharmony_ci			      struct device_attribute *attr,
274662306a36Sopenharmony_ci			      char *buf)
274762306a36Sopenharmony_ci{
274862306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
274962306a36Sopenharmony_ci	struct ipmi_device_id id;
275062306a36Sopenharmony_ci	int rv;
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
275362306a36Sopenharmony_ci	if (rv)
275462306a36Sopenharmony_ci		return rv;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", id.device_id);
275762306a36Sopenharmony_ci}
275862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(device_id);
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_cistatic ssize_t provides_device_sdrs_show(struct device *dev,
276162306a36Sopenharmony_ci					 struct device_attribute *attr,
276262306a36Sopenharmony_ci					 char *buf)
276362306a36Sopenharmony_ci{
276462306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
276562306a36Sopenharmony_ci	struct ipmi_device_id id;
276662306a36Sopenharmony_ci	int rv;
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
276962306a36Sopenharmony_ci	if (rv)
277062306a36Sopenharmony_ci		return rv;
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", (id.device_revision & 0x80) >> 7);
277362306a36Sopenharmony_ci}
277462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(provides_device_sdrs);
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_cistatic ssize_t revision_show(struct device *dev, struct device_attribute *attr,
277762306a36Sopenharmony_ci			     char *buf)
277862306a36Sopenharmony_ci{
277962306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
278062306a36Sopenharmony_ci	struct ipmi_device_id id;
278162306a36Sopenharmony_ci	int rv;
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
278462306a36Sopenharmony_ci	if (rv)
278562306a36Sopenharmony_ci		return rv;
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", id.device_revision & 0x0F);
278862306a36Sopenharmony_ci}
278962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(revision);
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_cistatic ssize_t firmware_revision_show(struct device *dev,
279262306a36Sopenharmony_ci				      struct device_attribute *attr,
279362306a36Sopenharmony_ci				      char *buf)
279462306a36Sopenharmony_ci{
279562306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
279662306a36Sopenharmony_ci	struct ipmi_device_id id;
279762306a36Sopenharmony_ci	int rv;
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
280062306a36Sopenharmony_ci	if (rv)
280162306a36Sopenharmony_ci		return rv;
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	return sysfs_emit(buf, "%u.%x\n", id.firmware_revision_1,
280462306a36Sopenharmony_ci			id.firmware_revision_2);
280562306a36Sopenharmony_ci}
280662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(firmware_revision);
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_cistatic ssize_t ipmi_version_show(struct device *dev,
280962306a36Sopenharmony_ci				 struct device_attribute *attr,
281062306a36Sopenharmony_ci				 char *buf)
281162306a36Sopenharmony_ci{
281262306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
281362306a36Sopenharmony_ci	struct ipmi_device_id id;
281462306a36Sopenharmony_ci	int rv;
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
281762306a36Sopenharmony_ci	if (rv)
281862306a36Sopenharmony_ci		return rv;
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci	return sysfs_emit(buf, "%u.%u\n",
282162306a36Sopenharmony_ci			ipmi_version_major(&id),
282262306a36Sopenharmony_ci			ipmi_version_minor(&id));
282362306a36Sopenharmony_ci}
282462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ipmi_version);
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_cistatic ssize_t add_dev_support_show(struct device *dev,
282762306a36Sopenharmony_ci				    struct device_attribute *attr,
282862306a36Sopenharmony_ci				    char *buf)
282962306a36Sopenharmony_ci{
283062306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
283162306a36Sopenharmony_ci	struct ipmi_device_id id;
283262306a36Sopenharmony_ci	int rv;
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
283562306a36Sopenharmony_ci	if (rv)
283662306a36Sopenharmony_ci		return rv;
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci	return sysfs_emit(buf, "0x%02x\n", id.additional_device_support);
283962306a36Sopenharmony_ci}
284062306a36Sopenharmony_cistatic DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show,
284162306a36Sopenharmony_ci		   NULL);
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_cistatic ssize_t manufacturer_id_show(struct device *dev,
284462306a36Sopenharmony_ci				    struct device_attribute *attr,
284562306a36Sopenharmony_ci				    char *buf)
284662306a36Sopenharmony_ci{
284762306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
284862306a36Sopenharmony_ci	struct ipmi_device_id id;
284962306a36Sopenharmony_ci	int rv;
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
285262306a36Sopenharmony_ci	if (rv)
285362306a36Sopenharmony_ci		return rv;
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	return sysfs_emit(buf, "0x%6.6x\n", id.manufacturer_id);
285662306a36Sopenharmony_ci}
285762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(manufacturer_id);
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_cistatic ssize_t product_id_show(struct device *dev,
286062306a36Sopenharmony_ci			       struct device_attribute *attr,
286162306a36Sopenharmony_ci			       char *buf)
286262306a36Sopenharmony_ci{
286362306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
286462306a36Sopenharmony_ci	struct ipmi_device_id id;
286562306a36Sopenharmony_ci	int rv;
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
286862306a36Sopenharmony_ci	if (rv)
286962306a36Sopenharmony_ci		return rv;
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	return sysfs_emit(buf, "0x%4.4x\n", id.product_id);
287262306a36Sopenharmony_ci}
287362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(product_id);
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_cistatic ssize_t aux_firmware_rev_show(struct device *dev,
287662306a36Sopenharmony_ci				     struct device_attribute *attr,
287762306a36Sopenharmony_ci				     char *buf)
287862306a36Sopenharmony_ci{
287962306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
288062306a36Sopenharmony_ci	struct ipmi_device_id id;
288162306a36Sopenharmony_ci	int rv;
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
288462306a36Sopenharmony_ci	if (rv)
288562306a36Sopenharmony_ci		return rv;
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	return sysfs_emit(buf, "0x%02x 0x%02x 0x%02x 0x%02x\n",
288862306a36Sopenharmony_ci			id.aux_firmware_revision[3],
288962306a36Sopenharmony_ci			id.aux_firmware_revision[2],
289062306a36Sopenharmony_ci			id.aux_firmware_revision[1],
289162306a36Sopenharmony_ci			id.aux_firmware_revision[0]);
289262306a36Sopenharmony_ci}
289362306a36Sopenharmony_cistatic DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL);
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_cistatic ssize_t guid_show(struct device *dev, struct device_attribute *attr,
289662306a36Sopenharmony_ci			 char *buf)
289762306a36Sopenharmony_ci{
289862306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
289962306a36Sopenharmony_ci	bool guid_set;
290062306a36Sopenharmony_ci	guid_t guid;
290162306a36Sopenharmony_ci	int rv;
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci	rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, &guid);
290462306a36Sopenharmony_ci	if (rv)
290562306a36Sopenharmony_ci		return rv;
290662306a36Sopenharmony_ci	if (!guid_set)
290762306a36Sopenharmony_ci		return -ENOENT;
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci	return sysfs_emit(buf, "%pUl\n", &guid);
291062306a36Sopenharmony_ci}
291162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(guid);
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_cistatic struct attribute *bmc_dev_attrs[] = {
291462306a36Sopenharmony_ci	&dev_attr_device_id.attr,
291562306a36Sopenharmony_ci	&dev_attr_provides_device_sdrs.attr,
291662306a36Sopenharmony_ci	&dev_attr_revision.attr,
291762306a36Sopenharmony_ci	&dev_attr_firmware_revision.attr,
291862306a36Sopenharmony_ci	&dev_attr_ipmi_version.attr,
291962306a36Sopenharmony_ci	&dev_attr_additional_device_support.attr,
292062306a36Sopenharmony_ci	&dev_attr_manufacturer_id.attr,
292162306a36Sopenharmony_ci	&dev_attr_product_id.attr,
292262306a36Sopenharmony_ci	&dev_attr_aux_firmware_revision.attr,
292362306a36Sopenharmony_ci	&dev_attr_guid.attr,
292462306a36Sopenharmony_ci	NULL
292562306a36Sopenharmony_ci};
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_cistatic umode_t bmc_dev_attr_is_visible(struct kobject *kobj,
292862306a36Sopenharmony_ci				       struct attribute *attr, int idx)
292962306a36Sopenharmony_ci{
293062306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
293162306a36Sopenharmony_ci	struct bmc_device *bmc = to_bmc_device(dev);
293262306a36Sopenharmony_ci	umode_t mode = attr->mode;
293362306a36Sopenharmony_ci	int rv;
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	if (attr == &dev_attr_aux_firmware_revision.attr) {
293662306a36Sopenharmony_ci		struct ipmi_device_id id;
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci		rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL);
293962306a36Sopenharmony_ci		return (!rv && id.aux_firmware_revision_set) ? mode : 0;
294062306a36Sopenharmony_ci	}
294162306a36Sopenharmony_ci	if (attr == &dev_attr_guid.attr) {
294262306a36Sopenharmony_ci		bool guid_set;
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci		rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, NULL);
294562306a36Sopenharmony_ci		return (!rv && guid_set) ? mode : 0;
294662306a36Sopenharmony_ci	}
294762306a36Sopenharmony_ci	return mode;
294862306a36Sopenharmony_ci}
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_cistatic const struct attribute_group bmc_dev_attr_group = {
295162306a36Sopenharmony_ci	.attrs		= bmc_dev_attrs,
295262306a36Sopenharmony_ci	.is_visible	= bmc_dev_attr_is_visible,
295362306a36Sopenharmony_ci};
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_cistatic const struct attribute_group *bmc_dev_attr_groups[] = {
295662306a36Sopenharmony_ci	&bmc_dev_attr_group,
295762306a36Sopenharmony_ci	NULL
295862306a36Sopenharmony_ci};
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_cistatic const struct device_type bmc_device_type = {
296162306a36Sopenharmony_ci	.groups		= bmc_dev_attr_groups,
296262306a36Sopenharmony_ci};
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_cistatic int __find_bmc_guid(struct device *dev, const void *data)
296562306a36Sopenharmony_ci{
296662306a36Sopenharmony_ci	const guid_t *guid = data;
296762306a36Sopenharmony_ci	struct bmc_device *bmc;
296862306a36Sopenharmony_ci	int rv;
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_ci	if (dev->type != &bmc_device_type)
297162306a36Sopenharmony_ci		return 0;
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci	bmc = to_bmc_device(dev);
297462306a36Sopenharmony_ci	rv = bmc->dyn_guid_set && guid_equal(&bmc->guid, guid);
297562306a36Sopenharmony_ci	if (rv)
297662306a36Sopenharmony_ci		rv = kref_get_unless_zero(&bmc->usecount);
297762306a36Sopenharmony_ci	return rv;
297862306a36Sopenharmony_ci}
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci/*
298162306a36Sopenharmony_ci * Returns with the bmc's usecount incremented, if it is non-NULL.
298262306a36Sopenharmony_ci */
298362306a36Sopenharmony_cistatic struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
298462306a36Sopenharmony_ci					     guid_t *guid)
298562306a36Sopenharmony_ci{
298662306a36Sopenharmony_ci	struct device *dev;
298762306a36Sopenharmony_ci	struct bmc_device *bmc = NULL;
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
299062306a36Sopenharmony_ci	if (dev) {
299162306a36Sopenharmony_ci		bmc = to_bmc_device(dev);
299262306a36Sopenharmony_ci		put_device(dev);
299362306a36Sopenharmony_ci	}
299462306a36Sopenharmony_ci	return bmc;
299562306a36Sopenharmony_ci}
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_cistruct prod_dev_id {
299862306a36Sopenharmony_ci	unsigned int  product_id;
299962306a36Sopenharmony_ci	unsigned char device_id;
300062306a36Sopenharmony_ci};
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_cistatic int __find_bmc_prod_dev_id(struct device *dev, const void *data)
300362306a36Sopenharmony_ci{
300462306a36Sopenharmony_ci	const struct prod_dev_id *cid = data;
300562306a36Sopenharmony_ci	struct bmc_device *bmc;
300662306a36Sopenharmony_ci	int rv;
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci	if (dev->type != &bmc_device_type)
300962306a36Sopenharmony_ci		return 0;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci	bmc = to_bmc_device(dev);
301262306a36Sopenharmony_ci	rv = (bmc->id.product_id == cid->product_id
301362306a36Sopenharmony_ci	      && bmc->id.device_id == cid->device_id);
301462306a36Sopenharmony_ci	if (rv)
301562306a36Sopenharmony_ci		rv = kref_get_unless_zero(&bmc->usecount);
301662306a36Sopenharmony_ci	return rv;
301762306a36Sopenharmony_ci}
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci/*
302062306a36Sopenharmony_ci * Returns with the bmc's usecount incremented, if it is non-NULL.
302162306a36Sopenharmony_ci */
302262306a36Sopenharmony_cistatic struct bmc_device *ipmi_find_bmc_prod_dev_id(
302362306a36Sopenharmony_ci	struct device_driver *drv,
302462306a36Sopenharmony_ci	unsigned int product_id, unsigned char device_id)
302562306a36Sopenharmony_ci{
302662306a36Sopenharmony_ci	struct prod_dev_id id = {
302762306a36Sopenharmony_ci		.product_id = product_id,
302862306a36Sopenharmony_ci		.device_id = device_id,
302962306a36Sopenharmony_ci	};
303062306a36Sopenharmony_ci	struct device *dev;
303162306a36Sopenharmony_ci	struct bmc_device *bmc = NULL;
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
303462306a36Sopenharmony_ci	if (dev) {
303562306a36Sopenharmony_ci		bmc = to_bmc_device(dev);
303662306a36Sopenharmony_ci		put_device(dev);
303762306a36Sopenharmony_ci	}
303862306a36Sopenharmony_ci	return bmc;
303962306a36Sopenharmony_ci}
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_cistatic DEFINE_IDA(ipmi_bmc_ida);
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_cistatic void
304462306a36Sopenharmony_cirelease_bmc_device(struct device *dev)
304562306a36Sopenharmony_ci{
304662306a36Sopenharmony_ci	kfree(to_bmc_device(dev));
304762306a36Sopenharmony_ci}
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_cistatic void cleanup_bmc_work(struct work_struct *work)
305062306a36Sopenharmony_ci{
305162306a36Sopenharmony_ci	struct bmc_device *bmc = container_of(work, struct bmc_device,
305262306a36Sopenharmony_ci					      remove_work);
305362306a36Sopenharmony_ci	int id = bmc->pdev.id; /* Unregister overwrites id */
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	platform_device_unregister(&bmc->pdev);
305662306a36Sopenharmony_ci	ida_simple_remove(&ipmi_bmc_ida, id);
305762306a36Sopenharmony_ci}
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_cistatic void
306062306a36Sopenharmony_cicleanup_bmc_device(struct kref *ref)
306162306a36Sopenharmony_ci{
306262306a36Sopenharmony_ci	struct bmc_device *bmc = container_of(ref, struct bmc_device, usecount);
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	/*
306562306a36Sopenharmony_ci	 * Remove the platform device in a work queue to avoid issues
306662306a36Sopenharmony_ci	 * with removing the device attributes while reading a device
306762306a36Sopenharmony_ci	 * attribute.
306862306a36Sopenharmony_ci	 */
306962306a36Sopenharmony_ci	queue_work(remove_work_wq, &bmc->remove_work);
307062306a36Sopenharmony_ci}
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci/*
307362306a36Sopenharmony_ci * Must be called with intf->bmc_reg_mutex held.
307462306a36Sopenharmony_ci */
307562306a36Sopenharmony_cistatic void __ipmi_bmc_unregister(struct ipmi_smi *intf)
307662306a36Sopenharmony_ci{
307762306a36Sopenharmony_ci	struct bmc_device *bmc = intf->bmc;
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci	if (!intf->bmc_registered)
308062306a36Sopenharmony_ci		return;
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	sysfs_remove_link(&intf->si_dev->kobj, "bmc");
308362306a36Sopenharmony_ci	sysfs_remove_link(&bmc->pdev.dev.kobj, intf->my_dev_name);
308462306a36Sopenharmony_ci	kfree(intf->my_dev_name);
308562306a36Sopenharmony_ci	intf->my_dev_name = NULL;
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	mutex_lock(&bmc->dyn_mutex);
308862306a36Sopenharmony_ci	list_del(&intf->bmc_link);
308962306a36Sopenharmony_ci	mutex_unlock(&bmc->dyn_mutex);
309062306a36Sopenharmony_ci	intf->bmc = &intf->tmp_bmc;
309162306a36Sopenharmony_ci	kref_put(&bmc->usecount, cleanup_bmc_device);
309262306a36Sopenharmony_ci	intf->bmc_registered = false;
309362306a36Sopenharmony_ci}
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_cistatic void ipmi_bmc_unregister(struct ipmi_smi *intf)
309662306a36Sopenharmony_ci{
309762306a36Sopenharmony_ci	mutex_lock(&intf->bmc_reg_mutex);
309862306a36Sopenharmony_ci	__ipmi_bmc_unregister(intf);
309962306a36Sopenharmony_ci	mutex_unlock(&intf->bmc_reg_mutex);
310062306a36Sopenharmony_ci}
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci/*
310362306a36Sopenharmony_ci * Must be called with intf->bmc_reg_mutex held.
310462306a36Sopenharmony_ci */
310562306a36Sopenharmony_cistatic int __ipmi_bmc_register(struct ipmi_smi *intf,
310662306a36Sopenharmony_ci			       struct ipmi_device_id *id,
310762306a36Sopenharmony_ci			       bool guid_set, guid_t *guid, int intf_num)
310862306a36Sopenharmony_ci{
310962306a36Sopenharmony_ci	int               rv;
311062306a36Sopenharmony_ci	struct bmc_device *bmc;
311162306a36Sopenharmony_ci	struct bmc_device *old_bmc;
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	/*
311462306a36Sopenharmony_ci	 * platform_device_register() can cause bmc_reg_mutex to
311562306a36Sopenharmony_ci	 * be claimed because of the is_visible functions of
311662306a36Sopenharmony_ci	 * the attributes.  Eliminate possible recursion and
311762306a36Sopenharmony_ci	 * release the lock.
311862306a36Sopenharmony_ci	 */
311962306a36Sopenharmony_ci	intf->in_bmc_register = true;
312062306a36Sopenharmony_ci	mutex_unlock(&intf->bmc_reg_mutex);
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	/*
312362306a36Sopenharmony_ci	 * Try to find if there is an bmc_device struct
312462306a36Sopenharmony_ci	 * representing the interfaced BMC already
312562306a36Sopenharmony_ci	 */
312662306a36Sopenharmony_ci	mutex_lock(&ipmidriver_mutex);
312762306a36Sopenharmony_ci	if (guid_set)
312862306a36Sopenharmony_ci		old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, guid);
312962306a36Sopenharmony_ci	else
313062306a36Sopenharmony_ci		old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver,
313162306a36Sopenharmony_ci						    id->product_id,
313262306a36Sopenharmony_ci						    id->device_id);
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	/*
313562306a36Sopenharmony_ci	 * If there is already an bmc_device, free the new one,
313662306a36Sopenharmony_ci	 * otherwise register the new BMC device
313762306a36Sopenharmony_ci	 */
313862306a36Sopenharmony_ci	if (old_bmc) {
313962306a36Sopenharmony_ci		bmc = old_bmc;
314062306a36Sopenharmony_ci		/*
314162306a36Sopenharmony_ci		 * Note: old_bmc already has usecount incremented by
314262306a36Sopenharmony_ci		 * the BMC find functions.
314362306a36Sopenharmony_ci		 */
314462306a36Sopenharmony_ci		intf->bmc = old_bmc;
314562306a36Sopenharmony_ci		mutex_lock(&bmc->dyn_mutex);
314662306a36Sopenharmony_ci		list_add_tail(&intf->bmc_link, &bmc->intfs);
314762306a36Sopenharmony_ci		mutex_unlock(&bmc->dyn_mutex);
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci		dev_info(intf->si_dev,
315062306a36Sopenharmony_ci			 "interfacing existing BMC (man_id: 0x%6.6x, prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
315162306a36Sopenharmony_ci			 bmc->id.manufacturer_id,
315262306a36Sopenharmony_ci			 bmc->id.product_id,
315362306a36Sopenharmony_ci			 bmc->id.device_id);
315462306a36Sopenharmony_ci	} else {
315562306a36Sopenharmony_ci		bmc = kzalloc(sizeof(*bmc), GFP_KERNEL);
315662306a36Sopenharmony_ci		if (!bmc) {
315762306a36Sopenharmony_ci			rv = -ENOMEM;
315862306a36Sopenharmony_ci			goto out;
315962306a36Sopenharmony_ci		}
316062306a36Sopenharmony_ci		INIT_LIST_HEAD(&bmc->intfs);
316162306a36Sopenharmony_ci		mutex_init(&bmc->dyn_mutex);
316262306a36Sopenharmony_ci		INIT_WORK(&bmc->remove_work, cleanup_bmc_work);
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci		bmc->id = *id;
316562306a36Sopenharmony_ci		bmc->dyn_id_set = 1;
316662306a36Sopenharmony_ci		bmc->dyn_guid_set = guid_set;
316762306a36Sopenharmony_ci		bmc->guid = *guid;
316862306a36Sopenharmony_ci		bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY;
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_ci		bmc->pdev.name = "ipmi_bmc";
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci		rv = ida_simple_get(&ipmi_bmc_ida, 0, 0, GFP_KERNEL);
317362306a36Sopenharmony_ci		if (rv < 0) {
317462306a36Sopenharmony_ci			kfree(bmc);
317562306a36Sopenharmony_ci			goto out;
317662306a36Sopenharmony_ci		}
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci		bmc->pdev.dev.driver = &ipmidriver.driver;
317962306a36Sopenharmony_ci		bmc->pdev.id = rv;
318062306a36Sopenharmony_ci		bmc->pdev.dev.release = release_bmc_device;
318162306a36Sopenharmony_ci		bmc->pdev.dev.type = &bmc_device_type;
318262306a36Sopenharmony_ci		kref_init(&bmc->usecount);
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci		intf->bmc = bmc;
318562306a36Sopenharmony_ci		mutex_lock(&bmc->dyn_mutex);
318662306a36Sopenharmony_ci		list_add_tail(&intf->bmc_link, &bmc->intfs);
318762306a36Sopenharmony_ci		mutex_unlock(&bmc->dyn_mutex);
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci		rv = platform_device_register(&bmc->pdev);
319062306a36Sopenharmony_ci		if (rv) {
319162306a36Sopenharmony_ci			dev_err(intf->si_dev,
319262306a36Sopenharmony_ci				"Unable to register bmc device: %d\n",
319362306a36Sopenharmony_ci				rv);
319462306a36Sopenharmony_ci			goto out_list_del;
319562306a36Sopenharmony_ci		}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci		dev_info(intf->si_dev,
319862306a36Sopenharmony_ci			 "Found new BMC (man_id: 0x%6.6x, prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
319962306a36Sopenharmony_ci			 bmc->id.manufacturer_id,
320062306a36Sopenharmony_ci			 bmc->id.product_id,
320162306a36Sopenharmony_ci			 bmc->id.device_id);
320262306a36Sopenharmony_ci	}
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci	/*
320562306a36Sopenharmony_ci	 * create symlink from system interface device to bmc device
320662306a36Sopenharmony_ci	 * and back.
320762306a36Sopenharmony_ci	 */
320862306a36Sopenharmony_ci	rv = sysfs_create_link(&intf->si_dev->kobj, &bmc->pdev.dev.kobj, "bmc");
320962306a36Sopenharmony_ci	if (rv) {
321062306a36Sopenharmony_ci		dev_err(intf->si_dev, "Unable to create bmc symlink: %d\n", rv);
321162306a36Sopenharmony_ci		goto out_put_bmc;
321262306a36Sopenharmony_ci	}
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ci	if (intf_num == -1)
321562306a36Sopenharmony_ci		intf_num = intf->intf_num;
321662306a36Sopenharmony_ci	intf->my_dev_name = kasprintf(GFP_KERNEL, "ipmi%d", intf_num);
321762306a36Sopenharmony_ci	if (!intf->my_dev_name) {
321862306a36Sopenharmony_ci		rv = -ENOMEM;
321962306a36Sopenharmony_ci		dev_err(intf->si_dev, "Unable to allocate link from BMC: %d\n",
322062306a36Sopenharmony_ci			rv);
322162306a36Sopenharmony_ci		goto out_unlink1;
322262306a36Sopenharmony_ci	}
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	rv = sysfs_create_link(&bmc->pdev.dev.kobj, &intf->si_dev->kobj,
322562306a36Sopenharmony_ci			       intf->my_dev_name);
322662306a36Sopenharmony_ci	if (rv) {
322762306a36Sopenharmony_ci		dev_err(intf->si_dev, "Unable to create symlink to bmc: %d\n",
322862306a36Sopenharmony_ci			rv);
322962306a36Sopenharmony_ci		goto out_free_my_dev_name;
323062306a36Sopenharmony_ci	}
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	intf->bmc_registered = true;
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ciout:
323562306a36Sopenharmony_ci	mutex_unlock(&ipmidriver_mutex);
323662306a36Sopenharmony_ci	mutex_lock(&intf->bmc_reg_mutex);
323762306a36Sopenharmony_ci	intf->in_bmc_register = false;
323862306a36Sopenharmony_ci	return rv;
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ciout_free_my_dev_name:
324262306a36Sopenharmony_ci	kfree(intf->my_dev_name);
324362306a36Sopenharmony_ci	intf->my_dev_name = NULL;
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_ciout_unlink1:
324662306a36Sopenharmony_ci	sysfs_remove_link(&intf->si_dev->kobj, "bmc");
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ciout_put_bmc:
324962306a36Sopenharmony_ci	mutex_lock(&bmc->dyn_mutex);
325062306a36Sopenharmony_ci	list_del(&intf->bmc_link);
325162306a36Sopenharmony_ci	mutex_unlock(&bmc->dyn_mutex);
325262306a36Sopenharmony_ci	intf->bmc = &intf->tmp_bmc;
325362306a36Sopenharmony_ci	kref_put(&bmc->usecount, cleanup_bmc_device);
325462306a36Sopenharmony_ci	goto out;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ciout_list_del:
325762306a36Sopenharmony_ci	mutex_lock(&bmc->dyn_mutex);
325862306a36Sopenharmony_ci	list_del(&intf->bmc_link);
325962306a36Sopenharmony_ci	mutex_unlock(&bmc->dyn_mutex);
326062306a36Sopenharmony_ci	intf->bmc = &intf->tmp_bmc;
326162306a36Sopenharmony_ci	put_device(&bmc->pdev.dev);
326262306a36Sopenharmony_ci	goto out;
326362306a36Sopenharmony_ci}
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_cistatic int
326662306a36Sopenharmony_cisend_guid_cmd(struct ipmi_smi *intf, int chan)
326762306a36Sopenharmony_ci{
326862306a36Sopenharmony_ci	struct kernel_ipmi_msg            msg;
326962306a36Sopenharmony_ci	struct ipmi_system_interface_addr si;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
327262306a36Sopenharmony_ci	si.channel = IPMI_BMC_CHANNEL;
327362306a36Sopenharmony_ci	si.lun = 0;
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	msg.netfn = IPMI_NETFN_APP_REQUEST;
327662306a36Sopenharmony_ci	msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
327762306a36Sopenharmony_ci	msg.data = NULL;
327862306a36Sopenharmony_ci	msg.data_len = 0;
327962306a36Sopenharmony_ci	return i_ipmi_request(NULL,
328062306a36Sopenharmony_ci			      intf,
328162306a36Sopenharmony_ci			      (struct ipmi_addr *) &si,
328262306a36Sopenharmony_ci			      0,
328362306a36Sopenharmony_ci			      &msg,
328462306a36Sopenharmony_ci			      intf,
328562306a36Sopenharmony_ci			      NULL,
328662306a36Sopenharmony_ci			      NULL,
328762306a36Sopenharmony_ci			      0,
328862306a36Sopenharmony_ci			      intf->addrinfo[0].address,
328962306a36Sopenharmony_ci			      intf->addrinfo[0].lun,
329062306a36Sopenharmony_ci			      -1, 0);
329162306a36Sopenharmony_ci}
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_cistatic void guid_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
329462306a36Sopenharmony_ci{
329562306a36Sopenharmony_ci	struct bmc_device *bmc = intf->bmc;
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
329862306a36Sopenharmony_ci	    || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
329962306a36Sopenharmony_ci	    || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
330062306a36Sopenharmony_ci		/* Not for me */
330162306a36Sopenharmony_ci		return;
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_ci	if (msg->msg.data[0] != 0) {
330462306a36Sopenharmony_ci		/* Error from getting the GUID, the BMC doesn't have one. */
330562306a36Sopenharmony_ci		bmc->dyn_guid_set = 0;
330662306a36Sopenharmony_ci		goto out;
330762306a36Sopenharmony_ci	}
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci	if (msg->msg.data_len < UUID_SIZE + 1) {
331062306a36Sopenharmony_ci		bmc->dyn_guid_set = 0;
331162306a36Sopenharmony_ci		dev_warn(intf->si_dev,
331262306a36Sopenharmony_ci			 "The GUID response from the BMC was too short, it was %d but should have been %d.  Assuming GUID is not available.\n",
331362306a36Sopenharmony_ci			 msg->msg.data_len, UUID_SIZE + 1);
331462306a36Sopenharmony_ci		goto out;
331562306a36Sopenharmony_ci	}
331662306a36Sopenharmony_ci
331762306a36Sopenharmony_ci	import_guid(&bmc->fetch_guid, msg->msg.data + 1);
331862306a36Sopenharmony_ci	/*
331962306a36Sopenharmony_ci	 * Make sure the guid data is available before setting
332062306a36Sopenharmony_ci	 * dyn_guid_set.
332162306a36Sopenharmony_ci	 */
332262306a36Sopenharmony_ci	smp_wmb();
332362306a36Sopenharmony_ci	bmc->dyn_guid_set = 1;
332462306a36Sopenharmony_ci out:
332562306a36Sopenharmony_ci	wake_up(&intf->waitq);
332662306a36Sopenharmony_ci}
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_cistatic void __get_guid(struct ipmi_smi *intf)
332962306a36Sopenharmony_ci{
333062306a36Sopenharmony_ci	int rv;
333162306a36Sopenharmony_ci	struct bmc_device *bmc = intf->bmc;
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	bmc->dyn_guid_set = 2;
333462306a36Sopenharmony_ci	intf->null_user_handler = guid_handler;
333562306a36Sopenharmony_ci	rv = send_guid_cmd(intf, 0);
333662306a36Sopenharmony_ci	if (rv)
333762306a36Sopenharmony_ci		/* Send failed, no GUID available. */
333862306a36Sopenharmony_ci		bmc->dyn_guid_set = 0;
333962306a36Sopenharmony_ci	else
334062306a36Sopenharmony_ci		wait_event(intf->waitq, bmc->dyn_guid_set != 2);
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	/* dyn_guid_set makes the guid data available. */
334362306a36Sopenharmony_ci	smp_rmb();
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_ci	intf->null_user_handler = NULL;
334662306a36Sopenharmony_ci}
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_cistatic int
334962306a36Sopenharmony_cisend_channel_info_cmd(struct ipmi_smi *intf, int chan)
335062306a36Sopenharmony_ci{
335162306a36Sopenharmony_ci	struct kernel_ipmi_msg            msg;
335262306a36Sopenharmony_ci	unsigned char                     data[1];
335362306a36Sopenharmony_ci	struct ipmi_system_interface_addr si;
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
335662306a36Sopenharmony_ci	si.channel = IPMI_BMC_CHANNEL;
335762306a36Sopenharmony_ci	si.lun = 0;
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci	msg.netfn = IPMI_NETFN_APP_REQUEST;
336062306a36Sopenharmony_ci	msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
336162306a36Sopenharmony_ci	msg.data = data;
336262306a36Sopenharmony_ci	msg.data_len = 1;
336362306a36Sopenharmony_ci	data[0] = chan;
336462306a36Sopenharmony_ci	return i_ipmi_request(NULL,
336562306a36Sopenharmony_ci			      intf,
336662306a36Sopenharmony_ci			      (struct ipmi_addr *) &si,
336762306a36Sopenharmony_ci			      0,
336862306a36Sopenharmony_ci			      &msg,
336962306a36Sopenharmony_ci			      intf,
337062306a36Sopenharmony_ci			      NULL,
337162306a36Sopenharmony_ci			      NULL,
337262306a36Sopenharmony_ci			      0,
337362306a36Sopenharmony_ci			      intf->addrinfo[0].address,
337462306a36Sopenharmony_ci			      intf->addrinfo[0].lun,
337562306a36Sopenharmony_ci			      -1, 0);
337662306a36Sopenharmony_ci}
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_cistatic void
337962306a36Sopenharmony_cichannel_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
338062306a36Sopenharmony_ci{
338162306a36Sopenharmony_ci	int rv = 0;
338262306a36Sopenharmony_ci	int ch;
338362306a36Sopenharmony_ci	unsigned int set = intf->curr_working_cset;
338462306a36Sopenharmony_ci	struct ipmi_channel *chans;
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci	if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
338762306a36Sopenharmony_ci	    && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
338862306a36Sopenharmony_ci	    && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) {
338962306a36Sopenharmony_ci		/* It's the one we want */
339062306a36Sopenharmony_ci		if (msg->msg.data[0] != 0) {
339162306a36Sopenharmony_ci			/* Got an error from the channel, just go on. */
339262306a36Sopenharmony_ci			if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
339362306a36Sopenharmony_ci				/*
339462306a36Sopenharmony_ci				 * If the MC does not support this
339562306a36Sopenharmony_ci				 * command, that is legal.  We just
339662306a36Sopenharmony_ci				 * assume it has one IPMB at channel
339762306a36Sopenharmony_ci				 * zero.
339862306a36Sopenharmony_ci				 */
339962306a36Sopenharmony_ci				intf->wchannels[set].c[0].medium
340062306a36Sopenharmony_ci					= IPMI_CHANNEL_MEDIUM_IPMB;
340162306a36Sopenharmony_ci				intf->wchannels[set].c[0].protocol
340262306a36Sopenharmony_ci					= IPMI_CHANNEL_PROTOCOL_IPMB;
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_ci				intf->channel_list = intf->wchannels + set;
340562306a36Sopenharmony_ci				intf->channels_ready = true;
340662306a36Sopenharmony_ci				wake_up(&intf->waitq);
340762306a36Sopenharmony_ci				goto out;
340862306a36Sopenharmony_ci			}
340962306a36Sopenharmony_ci			goto next_channel;
341062306a36Sopenharmony_ci		}
341162306a36Sopenharmony_ci		if (msg->msg.data_len < 4) {
341262306a36Sopenharmony_ci			/* Message not big enough, just go on. */
341362306a36Sopenharmony_ci			goto next_channel;
341462306a36Sopenharmony_ci		}
341562306a36Sopenharmony_ci		ch = intf->curr_channel;
341662306a36Sopenharmony_ci		chans = intf->wchannels[set].c;
341762306a36Sopenharmony_ci		chans[ch].medium = msg->msg.data[2] & 0x7f;
341862306a36Sopenharmony_ci		chans[ch].protocol = msg->msg.data[3] & 0x1f;
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci next_channel:
342162306a36Sopenharmony_ci		intf->curr_channel++;
342262306a36Sopenharmony_ci		if (intf->curr_channel >= IPMI_MAX_CHANNELS) {
342362306a36Sopenharmony_ci			intf->channel_list = intf->wchannels + set;
342462306a36Sopenharmony_ci			intf->channels_ready = true;
342562306a36Sopenharmony_ci			wake_up(&intf->waitq);
342662306a36Sopenharmony_ci		} else {
342762306a36Sopenharmony_ci			intf->channel_list = intf->wchannels + set;
342862306a36Sopenharmony_ci			intf->channels_ready = true;
342962306a36Sopenharmony_ci			rv = send_channel_info_cmd(intf, intf->curr_channel);
343062306a36Sopenharmony_ci		}
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci		if (rv) {
343362306a36Sopenharmony_ci			/* Got an error somehow, just give up. */
343462306a36Sopenharmony_ci			dev_warn(intf->si_dev,
343562306a36Sopenharmony_ci				 "Error sending channel information for channel %d: %d\n",
343662306a36Sopenharmony_ci				 intf->curr_channel, rv);
343762306a36Sopenharmony_ci
343862306a36Sopenharmony_ci			intf->channel_list = intf->wchannels + set;
343962306a36Sopenharmony_ci			intf->channels_ready = true;
344062306a36Sopenharmony_ci			wake_up(&intf->waitq);
344162306a36Sopenharmony_ci		}
344262306a36Sopenharmony_ci	}
344362306a36Sopenharmony_ci out:
344462306a36Sopenharmony_ci	return;
344562306a36Sopenharmony_ci}
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci/*
344862306a36Sopenharmony_ci * Must be holding intf->bmc_reg_mutex to call this.
344962306a36Sopenharmony_ci */
345062306a36Sopenharmony_cistatic int __scan_channels(struct ipmi_smi *intf, struct ipmi_device_id *id)
345162306a36Sopenharmony_ci{
345262306a36Sopenharmony_ci	int rv;
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	if (ipmi_version_major(id) > 1
345562306a36Sopenharmony_ci			|| (ipmi_version_major(id) == 1
345662306a36Sopenharmony_ci			    && ipmi_version_minor(id) >= 5)) {
345762306a36Sopenharmony_ci		unsigned int set;
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci		/*
346062306a36Sopenharmony_ci		 * Start scanning the channels to see what is
346162306a36Sopenharmony_ci		 * available.
346262306a36Sopenharmony_ci		 */
346362306a36Sopenharmony_ci		set = !intf->curr_working_cset;
346462306a36Sopenharmony_ci		intf->curr_working_cset = set;
346562306a36Sopenharmony_ci		memset(&intf->wchannels[set], 0,
346662306a36Sopenharmony_ci		       sizeof(struct ipmi_channel_set));
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci		intf->null_user_handler = channel_handler;
346962306a36Sopenharmony_ci		intf->curr_channel = 0;
347062306a36Sopenharmony_ci		rv = send_channel_info_cmd(intf, 0);
347162306a36Sopenharmony_ci		if (rv) {
347262306a36Sopenharmony_ci			dev_warn(intf->si_dev,
347362306a36Sopenharmony_ci				 "Error sending channel information for channel 0, %d\n",
347462306a36Sopenharmony_ci				 rv);
347562306a36Sopenharmony_ci			intf->null_user_handler = NULL;
347662306a36Sopenharmony_ci			return -EIO;
347762306a36Sopenharmony_ci		}
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_ci		/* Wait for the channel info to be read. */
348062306a36Sopenharmony_ci		wait_event(intf->waitq, intf->channels_ready);
348162306a36Sopenharmony_ci		intf->null_user_handler = NULL;
348262306a36Sopenharmony_ci	} else {
348362306a36Sopenharmony_ci		unsigned int set = intf->curr_working_cset;
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci		/* Assume a single IPMB channel at zero. */
348662306a36Sopenharmony_ci		intf->wchannels[set].c[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
348762306a36Sopenharmony_ci		intf->wchannels[set].c[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
348862306a36Sopenharmony_ci		intf->channel_list = intf->wchannels + set;
348962306a36Sopenharmony_ci		intf->channels_ready = true;
349062306a36Sopenharmony_ci	}
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ci	return 0;
349362306a36Sopenharmony_ci}
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_cistatic void ipmi_poll(struct ipmi_smi *intf)
349662306a36Sopenharmony_ci{
349762306a36Sopenharmony_ci	if (intf->handlers->poll)
349862306a36Sopenharmony_ci		intf->handlers->poll(intf->send_info);
349962306a36Sopenharmony_ci	/* In case something came in */
350062306a36Sopenharmony_ci	handle_new_recv_msgs(intf);
350162306a36Sopenharmony_ci}
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_civoid ipmi_poll_interface(struct ipmi_user *user)
350462306a36Sopenharmony_ci{
350562306a36Sopenharmony_ci	ipmi_poll(user->intf);
350662306a36Sopenharmony_ci}
350762306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_poll_interface);
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_cistatic ssize_t nr_users_show(struct device *dev,
351062306a36Sopenharmony_ci			     struct device_attribute *attr,
351162306a36Sopenharmony_ci			     char *buf)
351262306a36Sopenharmony_ci{
351362306a36Sopenharmony_ci	struct ipmi_smi *intf = container_of(attr,
351462306a36Sopenharmony_ci			 struct ipmi_smi, nr_users_devattr);
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", atomic_read(&intf->nr_users));
351762306a36Sopenharmony_ci}
351862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(nr_users);
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_cistatic ssize_t nr_msgs_show(struct device *dev,
352162306a36Sopenharmony_ci			    struct device_attribute *attr,
352262306a36Sopenharmony_ci			    char *buf)
352362306a36Sopenharmony_ci{
352462306a36Sopenharmony_ci	struct ipmi_smi *intf = container_of(attr,
352562306a36Sopenharmony_ci			 struct ipmi_smi, nr_msgs_devattr);
352662306a36Sopenharmony_ci	struct ipmi_user *user;
352762306a36Sopenharmony_ci	int index;
352862306a36Sopenharmony_ci	unsigned int count = 0;
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci	index = srcu_read_lock(&intf->users_srcu);
353162306a36Sopenharmony_ci	list_for_each_entry_rcu(user, &intf->users, link)
353262306a36Sopenharmony_ci		count += atomic_read(&user->nr_msgs);
353362306a36Sopenharmony_ci	srcu_read_unlock(&intf->users_srcu, index);
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", count);
353662306a36Sopenharmony_ci}
353762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(nr_msgs);
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_cistatic void redo_bmc_reg(struct work_struct *work)
354062306a36Sopenharmony_ci{
354162306a36Sopenharmony_ci	struct ipmi_smi *intf = container_of(work, struct ipmi_smi,
354262306a36Sopenharmony_ci					     bmc_reg_work);
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	if (!intf->in_shutdown)
354562306a36Sopenharmony_ci		bmc_get_device_id(intf, NULL, NULL, NULL, NULL);
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci	kref_put(&intf->refcount, intf_free);
354862306a36Sopenharmony_ci}
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ciint ipmi_add_smi(struct module         *owner,
355162306a36Sopenharmony_ci		 const struct ipmi_smi_handlers *handlers,
355262306a36Sopenharmony_ci		 void		       *send_info,
355362306a36Sopenharmony_ci		 struct device         *si_dev,
355462306a36Sopenharmony_ci		 unsigned char         slave_addr)
355562306a36Sopenharmony_ci{
355662306a36Sopenharmony_ci	int              i, j;
355762306a36Sopenharmony_ci	int              rv;
355862306a36Sopenharmony_ci	struct ipmi_smi *intf, *tintf;
355962306a36Sopenharmony_ci	struct list_head *link;
356062306a36Sopenharmony_ci	struct ipmi_device_id id;
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci	/*
356362306a36Sopenharmony_ci	 * Make sure the driver is actually initialized, this handles
356462306a36Sopenharmony_ci	 * problems with initialization order.
356562306a36Sopenharmony_ci	 */
356662306a36Sopenharmony_ci	rv = ipmi_init_msghandler();
356762306a36Sopenharmony_ci	if (rv)
356862306a36Sopenharmony_ci		return rv;
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	intf = kzalloc(sizeof(*intf), GFP_KERNEL);
357162306a36Sopenharmony_ci	if (!intf)
357262306a36Sopenharmony_ci		return -ENOMEM;
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_ci	rv = init_srcu_struct(&intf->users_srcu);
357562306a36Sopenharmony_ci	if (rv) {
357662306a36Sopenharmony_ci		kfree(intf);
357762306a36Sopenharmony_ci		return rv;
357862306a36Sopenharmony_ci	}
357962306a36Sopenharmony_ci
358062306a36Sopenharmony_ci	intf->owner = owner;
358162306a36Sopenharmony_ci	intf->bmc = &intf->tmp_bmc;
358262306a36Sopenharmony_ci	INIT_LIST_HEAD(&intf->bmc->intfs);
358362306a36Sopenharmony_ci	mutex_init(&intf->bmc->dyn_mutex);
358462306a36Sopenharmony_ci	INIT_LIST_HEAD(&intf->bmc_link);
358562306a36Sopenharmony_ci	mutex_init(&intf->bmc_reg_mutex);
358662306a36Sopenharmony_ci	intf->intf_num = -1; /* Mark it invalid for now. */
358762306a36Sopenharmony_ci	kref_init(&intf->refcount);
358862306a36Sopenharmony_ci	INIT_WORK(&intf->bmc_reg_work, redo_bmc_reg);
358962306a36Sopenharmony_ci	intf->si_dev = si_dev;
359062306a36Sopenharmony_ci	for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
359162306a36Sopenharmony_ci		intf->addrinfo[j].address = IPMI_BMC_SLAVE_ADDR;
359262306a36Sopenharmony_ci		intf->addrinfo[j].lun = 2;
359362306a36Sopenharmony_ci	}
359462306a36Sopenharmony_ci	if (slave_addr != 0)
359562306a36Sopenharmony_ci		intf->addrinfo[0].address = slave_addr;
359662306a36Sopenharmony_ci	INIT_LIST_HEAD(&intf->users);
359762306a36Sopenharmony_ci	atomic_set(&intf->nr_users, 0);
359862306a36Sopenharmony_ci	intf->handlers = handlers;
359962306a36Sopenharmony_ci	intf->send_info = send_info;
360062306a36Sopenharmony_ci	spin_lock_init(&intf->seq_lock);
360162306a36Sopenharmony_ci	for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
360262306a36Sopenharmony_ci		intf->seq_table[j].inuse = 0;
360362306a36Sopenharmony_ci		intf->seq_table[j].seqid = 0;
360462306a36Sopenharmony_ci	}
360562306a36Sopenharmony_ci	intf->curr_seq = 0;
360662306a36Sopenharmony_ci	spin_lock_init(&intf->waiting_rcv_msgs_lock);
360762306a36Sopenharmony_ci	INIT_LIST_HEAD(&intf->waiting_rcv_msgs);
360862306a36Sopenharmony_ci	tasklet_setup(&intf->recv_tasklet,
360962306a36Sopenharmony_ci		     smi_recv_tasklet);
361062306a36Sopenharmony_ci	atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0);
361162306a36Sopenharmony_ci	spin_lock_init(&intf->xmit_msgs_lock);
361262306a36Sopenharmony_ci	INIT_LIST_HEAD(&intf->xmit_msgs);
361362306a36Sopenharmony_ci	INIT_LIST_HEAD(&intf->hp_xmit_msgs);
361462306a36Sopenharmony_ci	spin_lock_init(&intf->events_lock);
361562306a36Sopenharmony_ci	spin_lock_init(&intf->watch_lock);
361662306a36Sopenharmony_ci	atomic_set(&intf->event_waiters, 0);
361762306a36Sopenharmony_ci	intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
361862306a36Sopenharmony_ci	INIT_LIST_HEAD(&intf->waiting_events);
361962306a36Sopenharmony_ci	intf->waiting_events_count = 0;
362062306a36Sopenharmony_ci	mutex_init(&intf->cmd_rcvrs_mutex);
362162306a36Sopenharmony_ci	spin_lock_init(&intf->maintenance_mode_lock);
362262306a36Sopenharmony_ci	INIT_LIST_HEAD(&intf->cmd_rcvrs);
362362306a36Sopenharmony_ci	init_waitqueue_head(&intf->waitq);
362462306a36Sopenharmony_ci	for (i = 0; i < IPMI_NUM_STATS; i++)
362562306a36Sopenharmony_ci		atomic_set(&intf->stats[i], 0);
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	mutex_lock(&ipmi_interfaces_mutex);
362862306a36Sopenharmony_ci	/* Look for a hole in the numbers. */
362962306a36Sopenharmony_ci	i = 0;
363062306a36Sopenharmony_ci	link = &ipmi_interfaces;
363162306a36Sopenharmony_ci	list_for_each_entry_rcu(tintf, &ipmi_interfaces, link,
363262306a36Sopenharmony_ci				ipmi_interfaces_mutex_held()) {
363362306a36Sopenharmony_ci		if (tintf->intf_num != i) {
363462306a36Sopenharmony_ci			link = &tintf->link;
363562306a36Sopenharmony_ci			break;
363662306a36Sopenharmony_ci		}
363762306a36Sopenharmony_ci		i++;
363862306a36Sopenharmony_ci	}
363962306a36Sopenharmony_ci	/* Add the new interface in numeric order. */
364062306a36Sopenharmony_ci	if (i == 0)
364162306a36Sopenharmony_ci		list_add_rcu(&intf->link, &ipmi_interfaces);
364262306a36Sopenharmony_ci	else
364362306a36Sopenharmony_ci		list_add_tail_rcu(&intf->link, link);
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci	rv = handlers->start_processing(send_info, intf);
364662306a36Sopenharmony_ci	if (rv)
364762306a36Sopenharmony_ci		goto out_err;
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci	rv = __bmc_get_device_id(intf, NULL, &id, NULL, NULL, i);
365062306a36Sopenharmony_ci	if (rv) {
365162306a36Sopenharmony_ci		dev_err(si_dev, "Unable to get the device id: %d\n", rv);
365262306a36Sopenharmony_ci		goto out_err_started;
365362306a36Sopenharmony_ci	}
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci	mutex_lock(&intf->bmc_reg_mutex);
365662306a36Sopenharmony_ci	rv = __scan_channels(intf, &id);
365762306a36Sopenharmony_ci	mutex_unlock(&intf->bmc_reg_mutex);
365862306a36Sopenharmony_ci	if (rv)
365962306a36Sopenharmony_ci		goto out_err_bmc_reg;
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci	intf->nr_users_devattr = dev_attr_nr_users;
366262306a36Sopenharmony_ci	sysfs_attr_init(&intf->nr_users_devattr.attr);
366362306a36Sopenharmony_ci	rv = device_create_file(intf->si_dev, &intf->nr_users_devattr);
366462306a36Sopenharmony_ci	if (rv)
366562306a36Sopenharmony_ci		goto out_err_bmc_reg;
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci	intf->nr_msgs_devattr = dev_attr_nr_msgs;
366862306a36Sopenharmony_ci	sysfs_attr_init(&intf->nr_msgs_devattr.attr);
366962306a36Sopenharmony_ci	rv = device_create_file(intf->si_dev, &intf->nr_msgs_devattr);
367062306a36Sopenharmony_ci	if (rv) {
367162306a36Sopenharmony_ci		device_remove_file(intf->si_dev, &intf->nr_users_devattr);
367262306a36Sopenharmony_ci		goto out_err_bmc_reg;
367362306a36Sopenharmony_ci	}
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci	/*
367662306a36Sopenharmony_ci	 * Keep memory order straight for RCU readers.  Make
367762306a36Sopenharmony_ci	 * sure everything else is committed to memory before
367862306a36Sopenharmony_ci	 * setting intf_num to mark the interface valid.
367962306a36Sopenharmony_ci	 */
368062306a36Sopenharmony_ci	smp_wmb();
368162306a36Sopenharmony_ci	intf->intf_num = i;
368262306a36Sopenharmony_ci	mutex_unlock(&ipmi_interfaces_mutex);
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci	/* After this point the interface is legal to use. */
368562306a36Sopenharmony_ci	call_smi_watchers(i, intf->si_dev);
368662306a36Sopenharmony_ci
368762306a36Sopenharmony_ci	return 0;
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ci out_err_bmc_reg:
369062306a36Sopenharmony_ci	ipmi_bmc_unregister(intf);
369162306a36Sopenharmony_ci out_err_started:
369262306a36Sopenharmony_ci	if (intf->handlers->shutdown)
369362306a36Sopenharmony_ci		intf->handlers->shutdown(intf->send_info);
369462306a36Sopenharmony_ci out_err:
369562306a36Sopenharmony_ci	list_del_rcu(&intf->link);
369662306a36Sopenharmony_ci	mutex_unlock(&ipmi_interfaces_mutex);
369762306a36Sopenharmony_ci	synchronize_srcu(&ipmi_interfaces_srcu);
369862306a36Sopenharmony_ci	cleanup_srcu_struct(&intf->users_srcu);
369962306a36Sopenharmony_ci	kref_put(&intf->refcount, intf_free);
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	return rv;
370262306a36Sopenharmony_ci}
370362306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_add_smi);
370462306a36Sopenharmony_ci
370562306a36Sopenharmony_cistatic void deliver_smi_err_response(struct ipmi_smi *intf,
370662306a36Sopenharmony_ci				     struct ipmi_smi_msg *msg,
370762306a36Sopenharmony_ci				     unsigned char err)
370862306a36Sopenharmony_ci{
370962306a36Sopenharmony_ci	int rv;
371062306a36Sopenharmony_ci	msg->rsp[0] = msg->data[0] | 4;
371162306a36Sopenharmony_ci	msg->rsp[1] = msg->data[1];
371262306a36Sopenharmony_ci	msg->rsp[2] = err;
371362306a36Sopenharmony_ci	msg->rsp_size = 3;
371462306a36Sopenharmony_ci
371562306a36Sopenharmony_ci	/* This will never requeue, but it may ask us to free the message. */
371662306a36Sopenharmony_ci	rv = handle_one_recv_msg(intf, msg);
371762306a36Sopenharmony_ci	if (rv == 0)
371862306a36Sopenharmony_ci		ipmi_free_smi_msg(msg);
371962306a36Sopenharmony_ci}
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_cistatic void cleanup_smi_msgs(struct ipmi_smi *intf)
372262306a36Sopenharmony_ci{
372362306a36Sopenharmony_ci	int              i;
372462306a36Sopenharmony_ci	struct seq_table *ent;
372562306a36Sopenharmony_ci	struct ipmi_smi_msg *msg;
372662306a36Sopenharmony_ci	struct list_head *entry;
372762306a36Sopenharmony_ci	struct list_head tmplist;
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	/* Clear out our transmit queues and hold the messages. */
373062306a36Sopenharmony_ci	INIT_LIST_HEAD(&tmplist);
373162306a36Sopenharmony_ci	list_splice_tail(&intf->hp_xmit_msgs, &tmplist);
373262306a36Sopenharmony_ci	list_splice_tail(&intf->xmit_msgs, &tmplist);
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci	/* Current message first, to preserve order */
373562306a36Sopenharmony_ci	while (intf->curr_msg && !list_empty(&intf->waiting_rcv_msgs)) {
373662306a36Sopenharmony_ci		/* Wait for the message to clear out. */
373762306a36Sopenharmony_ci		schedule_timeout(1);
373862306a36Sopenharmony_ci	}
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci	/* No need for locks, the interface is down. */
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ci	/*
374362306a36Sopenharmony_ci	 * Return errors for all pending messages in queue and in the
374462306a36Sopenharmony_ci	 * tables waiting for remote responses.
374562306a36Sopenharmony_ci	 */
374662306a36Sopenharmony_ci	while (!list_empty(&tmplist)) {
374762306a36Sopenharmony_ci		entry = tmplist.next;
374862306a36Sopenharmony_ci		list_del(entry);
374962306a36Sopenharmony_ci		msg = list_entry(entry, struct ipmi_smi_msg, link);
375062306a36Sopenharmony_ci		deliver_smi_err_response(intf, msg, IPMI_ERR_UNSPECIFIED);
375162306a36Sopenharmony_ci	}
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
375462306a36Sopenharmony_ci		ent = &intf->seq_table[i];
375562306a36Sopenharmony_ci		if (!ent->inuse)
375662306a36Sopenharmony_ci			continue;
375762306a36Sopenharmony_ci		deliver_err_response(intf, ent->recv_msg, IPMI_ERR_UNSPECIFIED);
375862306a36Sopenharmony_ci	}
375962306a36Sopenharmony_ci}
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_civoid ipmi_unregister_smi(struct ipmi_smi *intf)
376262306a36Sopenharmony_ci{
376362306a36Sopenharmony_ci	struct ipmi_smi_watcher *w;
376462306a36Sopenharmony_ci	int intf_num, index;
376562306a36Sopenharmony_ci
376662306a36Sopenharmony_ci	if (!intf)
376762306a36Sopenharmony_ci		return;
376862306a36Sopenharmony_ci	intf_num = intf->intf_num;
376962306a36Sopenharmony_ci	mutex_lock(&ipmi_interfaces_mutex);
377062306a36Sopenharmony_ci	intf->intf_num = -1;
377162306a36Sopenharmony_ci	intf->in_shutdown = true;
377262306a36Sopenharmony_ci	list_del_rcu(&intf->link);
377362306a36Sopenharmony_ci	mutex_unlock(&ipmi_interfaces_mutex);
377462306a36Sopenharmony_ci	synchronize_srcu(&ipmi_interfaces_srcu);
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	/* At this point no users can be added to the interface. */
377762306a36Sopenharmony_ci
377862306a36Sopenharmony_ci	device_remove_file(intf->si_dev, &intf->nr_msgs_devattr);
377962306a36Sopenharmony_ci	device_remove_file(intf->si_dev, &intf->nr_users_devattr);
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci	/*
378262306a36Sopenharmony_ci	 * Call all the watcher interfaces to tell them that
378362306a36Sopenharmony_ci	 * an interface is going away.
378462306a36Sopenharmony_ci	 */
378562306a36Sopenharmony_ci	mutex_lock(&smi_watchers_mutex);
378662306a36Sopenharmony_ci	list_for_each_entry(w, &smi_watchers, link)
378762306a36Sopenharmony_ci		w->smi_gone(intf_num);
378862306a36Sopenharmony_ci	mutex_unlock(&smi_watchers_mutex);
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci	index = srcu_read_lock(&intf->users_srcu);
379162306a36Sopenharmony_ci	while (!list_empty(&intf->users)) {
379262306a36Sopenharmony_ci		struct ipmi_user *user =
379362306a36Sopenharmony_ci			container_of(list_next_rcu(&intf->users),
379462306a36Sopenharmony_ci				     struct ipmi_user, link);
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ci		_ipmi_destroy_user(user);
379762306a36Sopenharmony_ci	}
379862306a36Sopenharmony_ci	srcu_read_unlock(&intf->users_srcu, index);
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_ci	if (intf->handlers->shutdown)
380162306a36Sopenharmony_ci		intf->handlers->shutdown(intf->send_info);
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	cleanup_smi_msgs(intf);
380462306a36Sopenharmony_ci
380562306a36Sopenharmony_ci	ipmi_bmc_unregister(intf);
380662306a36Sopenharmony_ci
380762306a36Sopenharmony_ci	cleanup_srcu_struct(&intf->users_srcu);
380862306a36Sopenharmony_ci	kref_put(&intf->refcount, intf_free);
380962306a36Sopenharmony_ci}
381062306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_unregister_smi);
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_cistatic int handle_ipmb_get_msg_rsp(struct ipmi_smi *intf,
381362306a36Sopenharmony_ci				   struct ipmi_smi_msg *msg)
381462306a36Sopenharmony_ci{
381562306a36Sopenharmony_ci	struct ipmi_ipmb_addr ipmb_addr;
381662306a36Sopenharmony_ci	struct ipmi_recv_msg  *recv_msg;
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ci	/*
381962306a36Sopenharmony_ci	 * This is 11, not 10, because the response must contain a
382062306a36Sopenharmony_ci	 * completion code.
382162306a36Sopenharmony_ci	 */
382262306a36Sopenharmony_ci	if (msg->rsp_size < 11) {
382362306a36Sopenharmony_ci		/* Message not big enough, just ignore it. */
382462306a36Sopenharmony_ci		ipmi_inc_stat(intf, invalid_ipmb_responses);
382562306a36Sopenharmony_ci		return 0;
382662306a36Sopenharmony_ci	}
382762306a36Sopenharmony_ci
382862306a36Sopenharmony_ci	if (msg->rsp[2] != 0) {
382962306a36Sopenharmony_ci		/* An error getting the response, just ignore it. */
383062306a36Sopenharmony_ci		return 0;
383162306a36Sopenharmony_ci	}
383262306a36Sopenharmony_ci
383362306a36Sopenharmony_ci	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
383462306a36Sopenharmony_ci	ipmb_addr.slave_addr = msg->rsp[6];
383562306a36Sopenharmony_ci	ipmb_addr.channel = msg->rsp[3] & 0x0f;
383662306a36Sopenharmony_ci	ipmb_addr.lun = msg->rsp[7] & 3;
383762306a36Sopenharmony_ci
383862306a36Sopenharmony_ci	/*
383962306a36Sopenharmony_ci	 * It's a response from a remote entity.  Look up the sequence
384062306a36Sopenharmony_ci	 * number and handle the response.
384162306a36Sopenharmony_ci	 */
384262306a36Sopenharmony_ci	if (intf_find_seq(intf,
384362306a36Sopenharmony_ci			  msg->rsp[7] >> 2,
384462306a36Sopenharmony_ci			  msg->rsp[3] & 0x0f,
384562306a36Sopenharmony_ci			  msg->rsp[8],
384662306a36Sopenharmony_ci			  (msg->rsp[4] >> 2) & (~1),
384762306a36Sopenharmony_ci			  (struct ipmi_addr *) &ipmb_addr,
384862306a36Sopenharmony_ci			  &recv_msg)) {
384962306a36Sopenharmony_ci		/*
385062306a36Sopenharmony_ci		 * We were unable to find the sequence number,
385162306a36Sopenharmony_ci		 * so just nuke the message.
385262306a36Sopenharmony_ci		 */
385362306a36Sopenharmony_ci		ipmi_inc_stat(intf, unhandled_ipmb_responses);
385462306a36Sopenharmony_ci		return 0;
385562306a36Sopenharmony_ci	}
385662306a36Sopenharmony_ci
385762306a36Sopenharmony_ci	memcpy(recv_msg->msg_data, &msg->rsp[9], msg->rsp_size - 9);
385862306a36Sopenharmony_ci	/*
385962306a36Sopenharmony_ci	 * The other fields matched, so no need to set them, except
386062306a36Sopenharmony_ci	 * for netfn, which needs to be the response that was
386162306a36Sopenharmony_ci	 * returned, not the request value.
386262306a36Sopenharmony_ci	 */
386362306a36Sopenharmony_ci	recv_msg->msg.netfn = msg->rsp[4] >> 2;
386462306a36Sopenharmony_ci	recv_msg->msg.data = recv_msg->msg_data;
386562306a36Sopenharmony_ci	recv_msg->msg.data_len = msg->rsp_size - 10;
386662306a36Sopenharmony_ci	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
386762306a36Sopenharmony_ci	if (deliver_response(intf, recv_msg))
386862306a36Sopenharmony_ci		ipmi_inc_stat(intf, unhandled_ipmb_responses);
386962306a36Sopenharmony_ci	else
387062306a36Sopenharmony_ci		ipmi_inc_stat(intf, handled_ipmb_responses);
387162306a36Sopenharmony_ci
387262306a36Sopenharmony_ci	return 0;
387362306a36Sopenharmony_ci}
387462306a36Sopenharmony_ci
387562306a36Sopenharmony_cistatic int handle_ipmb_get_msg_cmd(struct ipmi_smi *intf,
387662306a36Sopenharmony_ci				   struct ipmi_smi_msg *msg)
387762306a36Sopenharmony_ci{
387862306a36Sopenharmony_ci	struct cmd_rcvr          *rcvr;
387962306a36Sopenharmony_ci	int                      rv = 0;
388062306a36Sopenharmony_ci	unsigned char            netfn;
388162306a36Sopenharmony_ci	unsigned char            cmd;
388262306a36Sopenharmony_ci	unsigned char            chan;
388362306a36Sopenharmony_ci	struct ipmi_user         *user = NULL;
388462306a36Sopenharmony_ci	struct ipmi_ipmb_addr    *ipmb_addr;
388562306a36Sopenharmony_ci	struct ipmi_recv_msg     *recv_msg;
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci	if (msg->rsp_size < 10) {
388862306a36Sopenharmony_ci		/* Message not big enough, just ignore it. */
388962306a36Sopenharmony_ci		ipmi_inc_stat(intf, invalid_commands);
389062306a36Sopenharmony_ci		return 0;
389162306a36Sopenharmony_ci	}
389262306a36Sopenharmony_ci
389362306a36Sopenharmony_ci	if (msg->rsp[2] != 0) {
389462306a36Sopenharmony_ci		/* An error getting the response, just ignore it. */
389562306a36Sopenharmony_ci		return 0;
389662306a36Sopenharmony_ci	}
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	netfn = msg->rsp[4] >> 2;
389962306a36Sopenharmony_ci	cmd = msg->rsp[8];
390062306a36Sopenharmony_ci	chan = msg->rsp[3] & 0xf;
390162306a36Sopenharmony_ci
390262306a36Sopenharmony_ci	rcu_read_lock();
390362306a36Sopenharmony_ci	rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
390462306a36Sopenharmony_ci	if (rcvr) {
390562306a36Sopenharmony_ci		user = rcvr->user;
390662306a36Sopenharmony_ci		kref_get(&user->refcount);
390762306a36Sopenharmony_ci	} else
390862306a36Sopenharmony_ci		user = NULL;
390962306a36Sopenharmony_ci	rcu_read_unlock();
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	if (user == NULL) {
391262306a36Sopenharmony_ci		/* We didn't find a user, deliver an error response. */
391362306a36Sopenharmony_ci		ipmi_inc_stat(intf, unhandled_commands);
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_ci		msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
391662306a36Sopenharmony_ci		msg->data[1] = IPMI_SEND_MSG_CMD;
391762306a36Sopenharmony_ci		msg->data[2] = msg->rsp[3];
391862306a36Sopenharmony_ci		msg->data[3] = msg->rsp[6];
391962306a36Sopenharmony_ci		msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
392062306a36Sopenharmony_ci		msg->data[5] = ipmb_checksum(&msg->data[3], 2);
392162306a36Sopenharmony_ci		msg->data[6] = intf->addrinfo[msg->rsp[3] & 0xf].address;
392262306a36Sopenharmony_ci		/* rqseq/lun */
392362306a36Sopenharmony_ci		msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
392462306a36Sopenharmony_ci		msg->data[8] = msg->rsp[8]; /* cmd */
392562306a36Sopenharmony_ci		msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
392662306a36Sopenharmony_ci		msg->data[10] = ipmb_checksum(&msg->data[6], 4);
392762306a36Sopenharmony_ci		msg->data_size = 11;
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci		dev_dbg(intf->si_dev, "Invalid command: %*ph\n",
393062306a36Sopenharmony_ci			msg->data_size, msg->data);
393162306a36Sopenharmony_ci
393262306a36Sopenharmony_ci		rcu_read_lock();
393362306a36Sopenharmony_ci		if (!intf->in_shutdown) {
393462306a36Sopenharmony_ci			smi_send(intf, intf->handlers, msg, 0);
393562306a36Sopenharmony_ci			/*
393662306a36Sopenharmony_ci			 * We used the message, so return the value
393762306a36Sopenharmony_ci			 * that causes it to not be freed or
393862306a36Sopenharmony_ci			 * queued.
393962306a36Sopenharmony_ci			 */
394062306a36Sopenharmony_ci			rv = -1;
394162306a36Sopenharmony_ci		}
394262306a36Sopenharmony_ci		rcu_read_unlock();
394362306a36Sopenharmony_ci	} else {
394462306a36Sopenharmony_ci		recv_msg = ipmi_alloc_recv_msg();
394562306a36Sopenharmony_ci		if (!recv_msg) {
394662306a36Sopenharmony_ci			/*
394762306a36Sopenharmony_ci			 * We couldn't allocate memory for the
394862306a36Sopenharmony_ci			 * message, so requeue it for handling
394962306a36Sopenharmony_ci			 * later.
395062306a36Sopenharmony_ci			 */
395162306a36Sopenharmony_ci			rv = 1;
395262306a36Sopenharmony_ci			kref_put(&user->refcount, free_user);
395362306a36Sopenharmony_ci		} else {
395462306a36Sopenharmony_ci			/* Extract the source address from the data. */
395562306a36Sopenharmony_ci			ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
395662306a36Sopenharmony_ci			ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
395762306a36Sopenharmony_ci			ipmb_addr->slave_addr = msg->rsp[6];
395862306a36Sopenharmony_ci			ipmb_addr->lun = msg->rsp[7] & 3;
395962306a36Sopenharmony_ci			ipmb_addr->channel = msg->rsp[3] & 0xf;
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci			/*
396262306a36Sopenharmony_ci			 * Extract the rest of the message information
396362306a36Sopenharmony_ci			 * from the IPMB header.
396462306a36Sopenharmony_ci			 */
396562306a36Sopenharmony_ci			recv_msg->user = user;
396662306a36Sopenharmony_ci			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
396762306a36Sopenharmony_ci			recv_msg->msgid = msg->rsp[7] >> 2;
396862306a36Sopenharmony_ci			recv_msg->msg.netfn = msg->rsp[4] >> 2;
396962306a36Sopenharmony_ci			recv_msg->msg.cmd = msg->rsp[8];
397062306a36Sopenharmony_ci			recv_msg->msg.data = recv_msg->msg_data;
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_ci			/*
397362306a36Sopenharmony_ci			 * We chop off 10, not 9 bytes because the checksum
397462306a36Sopenharmony_ci			 * at the end also needs to be removed.
397562306a36Sopenharmony_ci			 */
397662306a36Sopenharmony_ci			recv_msg->msg.data_len = msg->rsp_size - 10;
397762306a36Sopenharmony_ci			memcpy(recv_msg->msg_data, &msg->rsp[9],
397862306a36Sopenharmony_ci			       msg->rsp_size - 10);
397962306a36Sopenharmony_ci			if (deliver_response(intf, recv_msg))
398062306a36Sopenharmony_ci				ipmi_inc_stat(intf, unhandled_commands);
398162306a36Sopenharmony_ci			else
398262306a36Sopenharmony_ci				ipmi_inc_stat(intf, handled_commands);
398362306a36Sopenharmony_ci		}
398462306a36Sopenharmony_ci	}
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_ci	return rv;
398762306a36Sopenharmony_ci}
398862306a36Sopenharmony_ci
398962306a36Sopenharmony_cistatic int handle_ipmb_direct_rcv_cmd(struct ipmi_smi *intf,
399062306a36Sopenharmony_ci				      struct ipmi_smi_msg *msg)
399162306a36Sopenharmony_ci{
399262306a36Sopenharmony_ci	struct cmd_rcvr          *rcvr;
399362306a36Sopenharmony_ci	int                      rv = 0;
399462306a36Sopenharmony_ci	struct ipmi_user         *user = NULL;
399562306a36Sopenharmony_ci	struct ipmi_ipmb_direct_addr *daddr;
399662306a36Sopenharmony_ci	struct ipmi_recv_msg     *recv_msg;
399762306a36Sopenharmony_ci	unsigned char netfn = msg->rsp[0] >> 2;
399862306a36Sopenharmony_ci	unsigned char cmd = msg->rsp[3];
399962306a36Sopenharmony_ci
400062306a36Sopenharmony_ci	rcu_read_lock();
400162306a36Sopenharmony_ci	/* We always use channel 0 for direct messages. */
400262306a36Sopenharmony_ci	rcvr = find_cmd_rcvr(intf, netfn, cmd, 0);
400362306a36Sopenharmony_ci	if (rcvr) {
400462306a36Sopenharmony_ci		user = rcvr->user;
400562306a36Sopenharmony_ci		kref_get(&user->refcount);
400662306a36Sopenharmony_ci	} else
400762306a36Sopenharmony_ci		user = NULL;
400862306a36Sopenharmony_ci	rcu_read_unlock();
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_ci	if (user == NULL) {
401162306a36Sopenharmony_ci		/* We didn't find a user, deliver an error response. */
401262306a36Sopenharmony_ci		ipmi_inc_stat(intf, unhandled_commands);
401362306a36Sopenharmony_ci
401462306a36Sopenharmony_ci		msg->data[0] = (netfn + 1) << 2;
401562306a36Sopenharmony_ci		msg->data[0] |= msg->rsp[2] & 0x3; /* rqLUN */
401662306a36Sopenharmony_ci		msg->data[1] = msg->rsp[1]; /* Addr */
401762306a36Sopenharmony_ci		msg->data[2] = msg->rsp[2] & ~0x3; /* rqSeq */
401862306a36Sopenharmony_ci		msg->data[2] |= msg->rsp[0] & 0x3; /* rsLUN */
401962306a36Sopenharmony_ci		msg->data[3] = cmd;
402062306a36Sopenharmony_ci		msg->data[4] = IPMI_INVALID_CMD_COMPLETION_CODE;
402162306a36Sopenharmony_ci		msg->data_size = 5;
402262306a36Sopenharmony_ci
402362306a36Sopenharmony_ci		rcu_read_lock();
402462306a36Sopenharmony_ci		if (!intf->in_shutdown) {
402562306a36Sopenharmony_ci			smi_send(intf, intf->handlers, msg, 0);
402662306a36Sopenharmony_ci			/*
402762306a36Sopenharmony_ci			 * We used the message, so return the value
402862306a36Sopenharmony_ci			 * that causes it to not be freed or
402962306a36Sopenharmony_ci			 * queued.
403062306a36Sopenharmony_ci			 */
403162306a36Sopenharmony_ci			rv = -1;
403262306a36Sopenharmony_ci		}
403362306a36Sopenharmony_ci		rcu_read_unlock();
403462306a36Sopenharmony_ci	} else {
403562306a36Sopenharmony_ci		recv_msg = ipmi_alloc_recv_msg();
403662306a36Sopenharmony_ci		if (!recv_msg) {
403762306a36Sopenharmony_ci			/*
403862306a36Sopenharmony_ci			 * We couldn't allocate memory for the
403962306a36Sopenharmony_ci			 * message, so requeue it for handling
404062306a36Sopenharmony_ci			 * later.
404162306a36Sopenharmony_ci			 */
404262306a36Sopenharmony_ci			rv = 1;
404362306a36Sopenharmony_ci			kref_put(&user->refcount, free_user);
404462306a36Sopenharmony_ci		} else {
404562306a36Sopenharmony_ci			/* Extract the source address from the data. */
404662306a36Sopenharmony_ci			daddr = (struct ipmi_ipmb_direct_addr *)&recv_msg->addr;
404762306a36Sopenharmony_ci			daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE;
404862306a36Sopenharmony_ci			daddr->channel = 0;
404962306a36Sopenharmony_ci			daddr->slave_addr = msg->rsp[1];
405062306a36Sopenharmony_ci			daddr->rs_lun = msg->rsp[0] & 3;
405162306a36Sopenharmony_ci			daddr->rq_lun = msg->rsp[2] & 3;
405262306a36Sopenharmony_ci
405362306a36Sopenharmony_ci			/*
405462306a36Sopenharmony_ci			 * Extract the rest of the message information
405562306a36Sopenharmony_ci			 * from the IPMB header.
405662306a36Sopenharmony_ci			 */
405762306a36Sopenharmony_ci			recv_msg->user = user;
405862306a36Sopenharmony_ci			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
405962306a36Sopenharmony_ci			recv_msg->msgid = (msg->rsp[2] >> 2);
406062306a36Sopenharmony_ci			recv_msg->msg.netfn = msg->rsp[0] >> 2;
406162306a36Sopenharmony_ci			recv_msg->msg.cmd = msg->rsp[3];
406262306a36Sopenharmony_ci			recv_msg->msg.data = recv_msg->msg_data;
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_ci			recv_msg->msg.data_len = msg->rsp_size - 4;
406562306a36Sopenharmony_ci			memcpy(recv_msg->msg_data, msg->rsp + 4,
406662306a36Sopenharmony_ci			       msg->rsp_size - 4);
406762306a36Sopenharmony_ci			if (deliver_response(intf, recv_msg))
406862306a36Sopenharmony_ci				ipmi_inc_stat(intf, unhandled_commands);
406962306a36Sopenharmony_ci			else
407062306a36Sopenharmony_ci				ipmi_inc_stat(intf, handled_commands);
407162306a36Sopenharmony_ci		}
407262306a36Sopenharmony_ci	}
407362306a36Sopenharmony_ci
407462306a36Sopenharmony_ci	return rv;
407562306a36Sopenharmony_ci}
407662306a36Sopenharmony_ci
407762306a36Sopenharmony_cistatic int handle_ipmb_direct_rcv_rsp(struct ipmi_smi *intf,
407862306a36Sopenharmony_ci				      struct ipmi_smi_msg *msg)
407962306a36Sopenharmony_ci{
408062306a36Sopenharmony_ci	struct ipmi_recv_msg *recv_msg;
408162306a36Sopenharmony_ci	struct ipmi_ipmb_direct_addr *daddr;
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	recv_msg = msg->user_data;
408462306a36Sopenharmony_ci	if (recv_msg == NULL) {
408562306a36Sopenharmony_ci		dev_warn(intf->si_dev,
408662306a36Sopenharmony_ci			 "IPMI direct message received with no owner. This could be because of a malformed message, or because of a hardware error.  Contact your hardware vendor for assistance.\n");
408762306a36Sopenharmony_ci		return 0;
408862306a36Sopenharmony_ci	}
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_ci	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
409162306a36Sopenharmony_ci	recv_msg->msgid = msg->msgid;
409262306a36Sopenharmony_ci	daddr = (struct ipmi_ipmb_direct_addr *) &recv_msg->addr;
409362306a36Sopenharmony_ci	daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE;
409462306a36Sopenharmony_ci	daddr->channel = 0;
409562306a36Sopenharmony_ci	daddr->slave_addr = msg->rsp[1];
409662306a36Sopenharmony_ci	daddr->rq_lun = msg->rsp[0] & 3;
409762306a36Sopenharmony_ci	daddr->rs_lun = msg->rsp[2] & 3;
409862306a36Sopenharmony_ci	recv_msg->msg.netfn = msg->rsp[0] >> 2;
409962306a36Sopenharmony_ci	recv_msg->msg.cmd = msg->rsp[3];
410062306a36Sopenharmony_ci	memcpy(recv_msg->msg_data, &msg->rsp[4], msg->rsp_size - 4);
410162306a36Sopenharmony_ci	recv_msg->msg.data = recv_msg->msg_data;
410262306a36Sopenharmony_ci	recv_msg->msg.data_len = msg->rsp_size - 4;
410362306a36Sopenharmony_ci	deliver_local_response(intf, recv_msg);
410462306a36Sopenharmony_ci
410562306a36Sopenharmony_ci	return 0;
410662306a36Sopenharmony_ci}
410762306a36Sopenharmony_ci
410862306a36Sopenharmony_cistatic int handle_lan_get_msg_rsp(struct ipmi_smi *intf,
410962306a36Sopenharmony_ci				  struct ipmi_smi_msg *msg)
411062306a36Sopenharmony_ci{
411162306a36Sopenharmony_ci	struct ipmi_lan_addr  lan_addr;
411262306a36Sopenharmony_ci	struct ipmi_recv_msg  *recv_msg;
411362306a36Sopenharmony_ci
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_ci	/*
411662306a36Sopenharmony_ci	 * This is 13, not 12, because the response must contain a
411762306a36Sopenharmony_ci	 * completion code.
411862306a36Sopenharmony_ci	 */
411962306a36Sopenharmony_ci	if (msg->rsp_size < 13) {
412062306a36Sopenharmony_ci		/* Message not big enough, just ignore it. */
412162306a36Sopenharmony_ci		ipmi_inc_stat(intf, invalid_lan_responses);
412262306a36Sopenharmony_ci		return 0;
412362306a36Sopenharmony_ci	}
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci	if (msg->rsp[2] != 0) {
412662306a36Sopenharmony_ci		/* An error getting the response, just ignore it. */
412762306a36Sopenharmony_ci		return 0;
412862306a36Sopenharmony_ci	}
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_ci	lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
413162306a36Sopenharmony_ci	lan_addr.session_handle = msg->rsp[4];
413262306a36Sopenharmony_ci	lan_addr.remote_SWID = msg->rsp[8];
413362306a36Sopenharmony_ci	lan_addr.local_SWID = msg->rsp[5];
413462306a36Sopenharmony_ci	lan_addr.channel = msg->rsp[3] & 0x0f;
413562306a36Sopenharmony_ci	lan_addr.privilege = msg->rsp[3] >> 4;
413662306a36Sopenharmony_ci	lan_addr.lun = msg->rsp[9] & 3;
413762306a36Sopenharmony_ci
413862306a36Sopenharmony_ci	/*
413962306a36Sopenharmony_ci	 * It's a response from a remote entity.  Look up the sequence
414062306a36Sopenharmony_ci	 * number and handle the response.
414162306a36Sopenharmony_ci	 */
414262306a36Sopenharmony_ci	if (intf_find_seq(intf,
414362306a36Sopenharmony_ci			  msg->rsp[9] >> 2,
414462306a36Sopenharmony_ci			  msg->rsp[3] & 0x0f,
414562306a36Sopenharmony_ci			  msg->rsp[10],
414662306a36Sopenharmony_ci			  (msg->rsp[6] >> 2) & (~1),
414762306a36Sopenharmony_ci			  (struct ipmi_addr *) &lan_addr,
414862306a36Sopenharmony_ci			  &recv_msg)) {
414962306a36Sopenharmony_ci		/*
415062306a36Sopenharmony_ci		 * We were unable to find the sequence number,
415162306a36Sopenharmony_ci		 * so just nuke the message.
415262306a36Sopenharmony_ci		 */
415362306a36Sopenharmony_ci		ipmi_inc_stat(intf, unhandled_lan_responses);
415462306a36Sopenharmony_ci		return 0;
415562306a36Sopenharmony_ci	}
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_ci	memcpy(recv_msg->msg_data, &msg->rsp[11], msg->rsp_size - 11);
415862306a36Sopenharmony_ci	/*
415962306a36Sopenharmony_ci	 * The other fields matched, so no need to set them, except
416062306a36Sopenharmony_ci	 * for netfn, which needs to be the response that was
416162306a36Sopenharmony_ci	 * returned, not the request value.
416262306a36Sopenharmony_ci	 */
416362306a36Sopenharmony_ci	recv_msg->msg.netfn = msg->rsp[6] >> 2;
416462306a36Sopenharmony_ci	recv_msg->msg.data = recv_msg->msg_data;
416562306a36Sopenharmony_ci	recv_msg->msg.data_len = msg->rsp_size - 12;
416662306a36Sopenharmony_ci	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
416762306a36Sopenharmony_ci	if (deliver_response(intf, recv_msg))
416862306a36Sopenharmony_ci		ipmi_inc_stat(intf, unhandled_lan_responses);
416962306a36Sopenharmony_ci	else
417062306a36Sopenharmony_ci		ipmi_inc_stat(intf, handled_lan_responses);
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_ci	return 0;
417362306a36Sopenharmony_ci}
417462306a36Sopenharmony_ci
417562306a36Sopenharmony_cistatic int handle_lan_get_msg_cmd(struct ipmi_smi *intf,
417662306a36Sopenharmony_ci				  struct ipmi_smi_msg *msg)
417762306a36Sopenharmony_ci{
417862306a36Sopenharmony_ci	struct cmd_rcvr          *rcvr;
417962306a36Sopenharmony_ci	int                      rv = 0;
418062306a36Sopenharmony_ci	unsigned char            netfn;
418162306a36Sopenharmony_ci	unsigned char            cmd;
418262306a36Sopenharmony_ci	unsigned char            chan;
418362306a36Sopenharmony_ci	struct ipmi_user         *user = NULL;
418462306a36Sopenharmony_ci	struct ipmi_lan_addr     *lan_addr;
418562306a36Sopenharmony_ci	struct ipmi_recv_msg     *recv_msg;
418662306a36Sopenharmony_ci
418762306a36Sopenharmony_ci	if (msg->rsp_size < 12) {
418862306a36Sopenharmony_ci		/* Message not big enough, just ignore it. */
418962306a36Sopenharmony_ci		ipmi_inc_stat(intf, invalid_commands);
419062306a36Sopenharmony_ci		return 0;
419162306a36Sopenharmony_ci	}
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	if (msg->rsp[2] != 0) {
419462306a36Sopenharmony_ci		/* An error getting the response, just ignore it. */
419562306a36Sopenharmony_ci		return 0;
419662306a36Sopenharmony_ci	}
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_ci	netfn = msg->rsp[6] >> 2;
419962306a36Sopenharmony_ci	cmd = msg->rsp[10];
420062306a36Sopenharmony_ci	chan = msg->rsp[3] & 0xf;
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci	rcu_read_lock();
420362306a36Sopenharmony_ci	rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
420462306a36Sopenharmony_ci	if (rcvr) {
420562306a36Sopenharmony_ci		user = rcvr->user;
420662306a36Sopenharmony_ci		kref_get(&user->refcount);
420762306a36Sopenharmony_ci	} else
420862306a36Sopenharmony_ci		user = NULL;
420962306a36Sopenharmony_ci	rcu_read_unlock();
421062306a36Sopenharmony_ci
421162306a36Sopenharmony_ci	if (user == NULL) {
421262306a36Sopenharmony_ci		/* We didn't find a user, just give up. */
421362306a36Sopenharmony_ci		ipmi_inc_stat(intf, unhandled_commands);
421462306a36Sopenharmony_ci
421562306a36Sopenharmony_ci		/*
421662306a36Sopenharmony_ci		 * Don't do anything with these messages, just allow
421762306a36Sopenharmony_ci		 * them to be freed.
421862306a36Sopenharmony_ci		 */
421962306a36Sopenharmony_ci		rv = 0;
422062306a36Sopenharmony_ci	} else {
422162306a36Sopenharmony_ci		recv_msg = ipmi_alloc_recv_msg();
422262306a36Sopenharmony_ci		if (!recv_msg) {
422362306a36Sopenharmony_ci			/*
422462306a36Sopenharmony_ci			 * We couldn't allocate memory for the
422562306a36Sopenharmony_ci			 * message, so requeue it for handling later.
422662306a36Sopenharmony_ci			 */
422762306a36Sopenharmony_ci			rv = 1;
422862306a36Sopenharmony_ci			kref_put(&user->refcount, free_user);
422962306a36Sopenharmony_ci		} else {
423062306a36Sopenharmony_ci			/* Extract the source address from the data. */
423162306a36Sopenharmony_ci			lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
423262306a36Sopenharmony_ci			lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
423362306a36Sopenharmony_ci			lan_addr->session_handle = msg->rsp[4];
423462306a36Sopenharmony_ci			lan_addr->remote_SWID = msg->rsp[8];
423562306a36Sopenharmony_ci			lan_addr->local_SWID = msg->rsp[5];
423662306a36Sopenharmony_ci			lan_addr->lun = msg->rsp[9] & 3;
423762306a36Sopenharmony_ci			lan_addr->channel = msg->rsp[3] & 0xf;
423862306a36Sopenharmony_ci			lan_addr->privilege = msg->rsp[3] >> 4;
423962306a36Sopenharmony_ci
424062306a36Sopenharmony_ci			/*
424162306a36Sopenharmony_ci			 * Extract the rest of the message information
424262306a36Sopenharmony_ci			 * from the IPMB header.
424362306a36Sopenharmony_ci			 */
424462306a36Sopenharmony_ci			recv_msg->user = user;
424562306a36Sopenharmony_ci			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
424662306a36Sopenharmony_ci			recv_msg->msgid = msg->rsp[9] >> 2;
424762306a36Sopenharmony_ci			recv_msg->msg.netfn = msg->rsp[6] >> 2;
424862306a36Sopenharmony_ci			recv_msg->msg.cmd = msg->rsp[10];
424962306a36Sopenharmony_ci			recv_msg->msg.data = recv_msg->msg_data;
425062306a36Sopenharmony_ci
425162306a36Sopenharmony_ci			/*
425262306a36Sopenharmony_ci			 * We chop off 12, not 11 bytes because the checksum
425362306a36Sopenharmony_ci			 * at the end also needs to be removed.
425462306a36Sopenharmony_ci			 */
425562306a36Sopenharmony_ci			recv_msg->msg.data_len = msg->rsp_size - 12;
425662306a36Sopenharmony_ci			memcpy(recv_msg->msg_data, &msg->rsp[11],
425762306a36Sopenharmony_ci			       msg->rsp_size - 12);
425862306a36Sopenharmony_ci			if (deliver_response(intf, recv_msg))
425962306a36Sopenharmony_ci				ipmi_inc_stat(intf, unhandled_commands);
426062306a36Sopenharmony_ci			else
426162306a36Sopenharmony_ci				ipmi_inc_stat(intf, handled_commands);
426262306a36Sopenharmony_ci		}
426362306a36Sopenharmony_ci	}
426462306a36Sopenharmony_ci
426562306a36Sopenharmony_ci	return rv;
426662306a36Sopenharmony_ci}
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_ci/*
426962306a36Sopenharmony_ci * This routine will handle "Get Message" command responses with
427062306a36Sopenharmony_ci * channels that use an OEM Medium. The message format belongs to
427162306a36Sopenharmony_ci * the OEM.  See IPMI 2.0 specification, Chapter 6 and
427262306a36Sopenharmony_ci * Chapter 22, sections 22.6 and 22.24 for more details.
427362306a36Sopenharmony_ci */
427462306a36Sopenharmony_cistatic int handle_oem_get_msg_cmd(struct ipmi_smi *intf,
427562306a36Sopenharmony_ci				  struct ipmi_smi_msg *msg)
427662306a36Sopenharmony_ci{
427762306a36Sopenharmony_ci	struct cmd_rcvr       *rcvr;
427862306a36Sopenharmony_ci	int                   rv = 0;
427962306a36Sopenharmony_ci	unsigned char         netfn;
428062306a36Sopenharmony_ci	unsigned char         cmd;
428162306a36Sopenharmony_ci	unsigned char         chan;
428262306a36Sopenharmony_ci	struct ipmi_user *user = NULL;
428362306a36Sopenharmony_ci	struct ipmi_system_interface_addr *smi_addr;
428462306a36Sopenharmony_ci	struct ipmi_recv_msg  *recv_msg;
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_ci	/*
428762306a36Sopenharmony_ci	 * We expect the OEM SW to perform error checking
428862306a36Sopenharmony_ci	 * so we just do some basic sanity checks
428962306a36Sopenharmony_ci	 */
429062306a36Sopenharmony_ci	if (msg->rsp_size < 4) {
429162306a36Sopenharmony_ci		/* Message not big enough, just ignore it. */
429262306a36Sopenharmony_ci		ipmi_inc_stat(intf, invalid_commands);
429362306a36Sopenharmony_ci		return 0;
429462306a36Sopenharmony_ci	}
429562306a36Sopenharmony_ci
429662306a36Sopenharmony_ci	if (msg->rsp[2] != 0) {
429762306a36Sopenharmony_ci		/* An error getting the response, just ignore it. */
429862306a36Sopenharmony_ci		return 0;
429962306a36Sopenharmony_ci	}
430062306a36Sopenharmony_ci
430162306a36Sopenharmony_ci	/*
430262306a36Sopenharmony_ci	 * This is an OEM Message so the OEM needs to know how
430362306a36Sopenharmony_ci	 * handle the message. We do no interpretation.
430462306a36Sopenharmony_ci	 */
430562306a36Sopenharmony_ci	netfn = msg->rsp[0] >> 2;
430662306a36Sopenharmony_ci	cmd = msg->rsp[1];
430762306a36Sopenharmony_ci	chan = msg->rsp[3] & 0xf;
430862306a36Sopenharmony_ci
430962306a36Sopenharmony_ci	rcu_read_lock();
431062306a36Sopenharmony_ci	rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
431162306a36Sopenharmony_ci	if (rcvr) {
431262306a36Sopenharmony_ci		user = rcvr->user;
431362306a36Sopenharmony_ci		kref_get(&user->refcount);
431462306a36Sopenharmony_ci	} else
431562306a36Sopenharmony_ci		user = NULL;
431662306a36Sopenharmony_ci	rcu_read_unlock();
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ci	if (user == NULL) {
431962306a36Sopenharmony_ci		/* We didn't find a user, just give up. */
432062306a36Sopenharmony_ci		ipmi_inc_stat(intf, unhandled_commands);
432162306a36Sopenharmony_ci
432262306a36Sopenharmony_ci		/*
432362306a36Sopenharmony_ci		 * Don't do anything with these messages, just allow
432462306a36Sopenharmony_ci		 * them to be freed.
432562306a36Sopenharmony_ci		 */
432662306a36Sopenharmony_ci
432762306a36Sopenharmony_ci		rv = 0;
432862306a36Sopenharmony_ci	} else {
432962306a36Sopenharmony_ci		recv_msg = ipmi_alloc_recv_msg();
433062306a36Sopenharmony_ci		if (!recv_msg) {
433162306a36Sopenharmony_ci			/*
433262306a36Sopenharmony_ci			 * We couldn't allocate memory for the
433362306a36Sopenharmony_ci			 * message, so requeue it for handling
433462306a36Sopenharmony_ci			 * later.
433562306a36Sopenharmony_ci			 */
433662306a36Sopenharmony_ci			rv = 1;
433762306a36Sopenharmony_ci			kref_put(&user->refcount, free_user);
433862306a36Sopenharmony_ci		} else {
433962306a36Sopenharmony_ci			/*
434062306a36Sopenharmony_ci			 * OEM Messages are expected to be delivered via
434162306a36Sopenharmony_ci			 * the system interface to SMS software.  We might
434262306a36Sopenharmony_ci			 * need to visit this again depending on OEM
434362306a36Sopenharmony_ci			 * requirements
434462306a36Sopenharmony_ci			 */
434562306a36Sopenharmony_ci			smi_addr = ((struct ipmi_system_interface_addr *)
434662306a36Sopenharmony_ci				    &recv_msg->addr);
434762306a36Sopenharmony_ci			smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
434862306a36Sopenharmony_ci			smi_addr->channel = IPMI_BMC_CHANNEL;
434962306a36Sopenharmony_ci			smi_addr->lun = msg->rsp[0] & 3;
435062306a36Sopenharmony_ci
435162306a36Sopenharmony_ci			recv_msg->user = user;
435262306a36Sopenharmony_ci			recv_msg->user_msg_data = NULL;
435362306a36Sopenharmony_ci			recv_msg->recv_type = IPMI_OEM_RECV_TYPE;
435462306a36Sopenharmony_ci			recv_msg->msg.netfn = msg->rsp[0] >> 2;
435562306a36Sopenharmony_ci			recv_msg->msg.cmd = msg->rsp[1];
435662306a36Sopenharmony_ci			recv_msg->msg.data = recv_msg->msg_data;
435762306a36Sopenharmony_ci
435862306a36Sopenharmony_ci			/*
435962306a36Sopenharmony_ci			 * The message starts at byte 4 which follows the
436062306a36Sopenharmony_ci			 * Channel Byte in the "GET MESSAGE" command
436162306a36Sopenharmony_ci			 */
436262306a36Sopenharmony_ci			recv_msg->msg.data_len = msg->rsp_size - 4;
436362306a36Sopenharmony_ci			memcpy(recv_msg->msg_data, &msg->rsp[4],
436462306a36Sopenharmony_ci			       msg->rsp_size - 4);
436562306a36Sopenharmony_ci			if (deliver_response(intf, recv_msg))
436662306a36Sopenharmony_ci				ipmi_inc_stat(intf, unhandled_commands);
436762306a36Sopenharmony_ci			else
436862306a36Sopenharmony_ci				ipmi_inc_stat(intf, handled_commands);
436962306a36Sopenharmony_ci		}
437062306a36Sopenharmony_ci	}
437162306a36Sopenharmony_ci
437262306a36Sopenharmony_ci	return rv;
437362306a36Sopenharmony_ci}
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_cistatic void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
437662306a36Sopenharmony_ci				     struct ipmi_smi_msg  *msg)
437762306a36Sopenharmony_ci{
437862306a36Sopenharmony_ci	struct ipmi_system_interface_addr *smi_addr;
437962306a36Sopenharmony_ci
438062306a36Sopenharmony_ci	recv_msg->msgid = 0;
438162306a36Sopenharmony_ci	smi_addr = (struct ipmi_system_interface_addr *) &recv_msg->addr;
438262306a36Sopenharmony_ci	smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
438362306a36Sopenharmony_ci	smi_addr->channel = IPMI_BMC_CHANNEL;
438462306a36Sopenharmony_ci	smi_addr->lun = msg->rsp[0] & 3;
438562306a36Sopenharmony_ci	recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
438662306a36Sopenharmony_ci	recv_msg->msg.netfn = msg->rsp[0] >> 2;
438762306a36Sopenharmony_ci	recv_msg->msg.cmd = msg->rsp[1];
438862306a36Sopenharmony_ci	memcpy(recv_msg->msg_data, &msg->rsp[3], msg->rsp_size - 3);
438962306a36Sopenharmony_ci	recv_msg->msg.data = recv_msg->msg_data;
439062306a36Sopenharmony_ci	recv_msg->msg.data_len = msg->rsp_size - 3;
439162306a36Sopenharmony_ci}
439262306a36Sopenharmony_ci
439362306a36Sopenharmony_cistatic int handle_read_event_rsp(struct ipmi_smi *intf,
439462306a36Sopenharmony_ci				 struct ipmi_smi_msg *msg)
439562306a36Sopenharmony_ci{
439662306a36Sopenharmony_ci	struct ipmi_recv_msg *recv_msg, *recv_msg2;
439762306a36Sopenharmony_ci	struct list_head     msgs;
439862306a36Sopenharmony_ci	struct ipmi_user     *user;
439962306a36Sopenharmony_ci	int rv = 0, deliver_count = 0, index;
440062306a36Sopenharmony_ci	unsigned long        flags;
440162306a36Sopenharmony_ci
440262306a36Sopenharmony_ci	if (msg->rsp_size < 19) {
440362306a36Sopenharmony_ci		/* Message is too small to be an IPMB event. */
440462306a36Sopenharmony_ci		ipmi_inc_stat(intf, invalid_events);
440562306a36Sopenharmony_ci		return 0;
440662306a36Sopenharmony_ci	}
440762306a36Sopenharmony_ci
440862306a36Sopenharmony_ci	if (msg->rsp[2] != 0) {
440962306a36Sopenharmony_ci		/* An error getting the event, just ignore it. */
441062306a36Sopenharmony_ci		return 0;
441162306a36Sopenharmony_ci	}
441262306a36Sopenharmony_ci
441362306a36Sopenharmony_ci	INIT_LIST_HEAD(&msgs);
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_ci	spin_lock_irqsave(&intf->events_lock, flags);
441662306a36Sopenharmony_ci
441762306a36Sopenharmony_ci	ipmi_inc_stat(intf, events);
441862306a36Sopenharmony_ci
441962306a36Sopenharmony_ci	/*
442062306a36Sopenharmony_ci	 * Allocate and fill in one message for every user that is
442162306a36Sopenharmony_ci	 * getting events.
442262306a36Sopenharmony_ci	 */
442362306a36Sopenharmony_ci	index = srcu_read_lock(&intf->users_srcu);
442462306a36Sopenharmony_ci	list_for_each_entry_rcu(user, &intf->users, link) {
442562306a36Sopenharmony_ci		if (!user->gets_events)
442662306a36Sopenharmony_ci			continue;
442762306a36Sopenharmony_ci
442862306a36Sopenharmony_ci		recv_msg = ipmi_alloc_recv_msg();
442962306a36Sopenharmony_ci		if (!recv_msg) {
443062306a36Sopenharmony_ci			rcu_read_unlock();
443162306a36Sopenharmony_ci			list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
443262306a36Sopenharmony_ci						 link) {
443362306a36Sopenharmony_ci				list_del(&recv_msg->link);
443462306a36Sopenharmony_ci				ipmi_free_recv_msg(recv_msg);
443562306a36Sopenharmony_ci			}
443662306a36Sopenharmony_ci			/*
443762306a36Sopenharmony_ci			 * We couldn't allocate memory for the
443862306a36Sopenharmony_ci			 * message, so requeue it for handling
443962306a36Sopenharmony_ci			 * later.
444062306a36Sopenharmony_ci			 */
444162306a36Sopenharmony_ci			rv = 1;
444262306a36Sopenharmony_ci			goto out;
444362306a36Sopenharmony_ci		}
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_ci		deliver_count++;
444662306a36Sopenharmony_ci
444762306a36Sopenharmony_ci		copy_event_into_recv_msg(recv_msg, msg);
444862306a36Sopenharmony_ci		recv_msg->user = user;
444962306a36Sopenharmony_ci		kref_get(&user->refcount);
445062306a36Sopenharmony_ci		list_add_tail(&recv_msg->link, &msgs);
445162306a36Sopenharmony_ci	}
445262306a36Sopenharmony_ci	srcu_read_unlock(&intf->users_srcu, index);
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ci	if (deliver_count) {
445562306a36Sopenharmony_ci		/* Now deliver all the messages. */
445662306a36Sopenharmony_ci		list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
445762306a36Sopenharmony_ci			list_del(&recv_msg->link);
445862306a36Sopenharmony_ci			deliver_local_response(intf, recv_msg);
445962306a36Sopenharmony_ci		}
446062306a36Sopenharmony_ci	} else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
446162306a36Sopenharmony_ci		/*
446262306a36Sopenharmony_ci		 * No one to receive the message, put it in queue if there's
446362306a36Sopenharmony_ci		 * not already too many things in the queue.
446462306a36Sopenharmony_ci		 */
446562306a36Sopenharmony_ci		recv_msg = ipmi_alloc_recv_msg();
446662306a36Sopenharmony_ci		if (!recv_msg) {
446762306a36Sopenharmony_ci			/*
446862306a36Sopenharmony_ci			 * We couldn't allocate memory for the
446962306a36Sopenharmony_ci			 * message, so requeue it for handling
447062306a36Sopenharmony_ci			 * later.
447162306a36Sopenharmony_ci			 */
447262306a36Sopenharmony_ci			rv = 1;
447362306a36Sopenharmony_ci			goto out;
447462306a36Sopenharmony_ci		}
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci		copy_event_into_recv_msg(recv_msg, msg);
447762306a36Sopenharmony_ci		list_add_tail(&recv_msg->link, &intf->waiting_events);
447862306a36Sopenharmony_ci		intf->waiting_events_count++;
447962306a36Sopenharmony_ci	} else if (!intf->event_msg_printed) {
448062306a36Sopenharmony_ci		/*
448162306a36Sopenharmony_ci		 * There's too many things in the queue, discard this
448262306a36Sopenharmony_ci		 * message.
448362306a36Sopenharmony_ci		 */
448462306a36Sopenharmony_ci		dev_warn(intf->si_dev,
448562306a36Sopenharmony_ci			 "Event queue full, discarding incoming events\n");
448662306a36Sopenharmony_ci		intf->event_msg_printed = 1;
448762306a36Sopenharmony_ci	}
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci out:
449062306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->events_lock, flags);
449162306a36Sopenharmony_ci
449262306a36Sopenharmony_ci	return rv;
449362306a36Sopenharmony_ci}
449462306a36Sopenharmony_ci
449562306a36Sopenharmony_cistatic int handle_bmc_rsp(struct ipmi_smi *intf,
449662306a36Sopenharmony_ci			  struct ipmi_smi_msg *msg)
449762306a36Sopenharmony_ci{
449862306a36Sopenharmony_ci	struct ipmi_recv_msg *recv_msg;
449962306a36Sopenharmony_ci	struct ipmi_system_interface_addr *smi_addr;
450062306a36Sopenharmony_ci
450162306a36Sopenharmony_ci	recv_msg = msg->user_data;
450262306a36Sopenharmony_ci	if (recv_msg == NULL) {
450362306a36Sopenharmony_ci		dev_warn(intf->si_dev,
450462306a36Sopenharmony_ci			 "IPMI SMI message received with no owner. This could be because of a malformed message, or because of a hardware error.  Contact your hardware vendor for assistance.\n");
450562306a36Sopenharmony_ci		return 0;
450662306a36Sopenharmony_ci	}
450762306a36Sopenharmony_ci
450862306a36Sopenharmony_ci	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
450962306a36Sopenharmony_ci	recv_msg->msgid = msg->msgid;
451062306a36Sopenharmony_ci	smi_addr = ((struct ipmi_system_interface_addr *)
451162306a36Sopenharmony_ci		    &recv_msg->addr);
451262306a36Sopenharmony_ci	smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
451362306a36Sopenharmony_ci	smi_addr->channel = IPMI_BMC_CHANNEL;
451462306a36Sopenharmony_ci	smi_addr->lun = msg->rsp[0] & 3;
451562306a36Sopenharmony_ci	recv_msg->msg.netfn = msg->rsp[0] >> 2;
451662306a36Sopenharmony_ci	recv_msg->msg.cmd = msg->rsp[1];
451762306a36Sopenharmony_ci	memcpy(recv_msg->msg_data, &msg->rsp[2], msg->rsp_size - 2);
451862306a36Sopenharmony_ci	recv_msg->msg.data = recv_msg->msg_data;
451962306a36Sopenharmony_ci	recv_msg->msg.data_len = msg->rsp_size - 2;
452062306a36Sopenharmony_ci	deliver_local_response(intf, recv_msg);
452162306a36Sopenharmony_ci
452262306a36Sopenharmony_ci	return 0;
452362306a36Sopenharmony_ci}
452462306a36Sopenharmony_ci
452562306a36Sopenharmony_ci/*
452662306a36Sopenharmony_ci * Handle a received message.  Return 1 if the message should be requeued,
452762306a36Sopenharmony_ci * 0 if the message should be freed, or -1 if the message should not
452862306a36Sopenharmony_ci * be freed or requeued.
452962306a36Sopenharmony_ci */
453062306a36Sopenharmony_cistatic int handle_one_recv_msg(struct ipmi_smi *intf,
453162306a36Sopenharmony_ci			       struct ipmi_smi_msg *msg)
453262306a36Sopenharmony_ci{
453362306a36Sopenharmony_ci	int requeue = 0;
453462306a36Sopenharmony_ci	int chan;
453562306a36Sopenharmony_ci	unsigned char cc;
453662306a36Sopenharmony_ci	bool is_cmd = !((msg->rsp[0] >> 2) & 1);
453762306a36Sopenharmony_ci
453862306a36Sopenharmony_ci	dev_dbg(intf->si_dev, "Recv: %*ph\n", msg->rsp_size, msg->rsp);
453962306a36Sopenharmony_ci
454062306a36Sopenharmony_ci	if (msg->rsp_size < 2) {
454162306a36Sopenharmony_ci		/* Message is too small to be correct. */
454262306a36Sopenharmony_ci		dev_warn(intf->si_dev,
454362306a36Sopenharmony_ci			 "BMC returned too small a message for netfn %x cmd %x, got %d bytes\n",
454462306a36Sopenharmony_ci			 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
454562306a36Sopenharmony_ci
454662306a36Sopenharmony_cireturn_unspecified:
454762306a36Sopenharmony_ci		/* Generate an error response for the message. */
454862306a36Sopenharmony_ci		msg->rsp[0] = msg->data[0] | (1 << 2);
454962306a36Sopenharmony_ci		msg->rsp[1] = msg->data[1];
455062306a36Sopenharmony_ci		msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
455162306a36Sopenharmony_ci		msg->rsp_size = 3;
455262306a36Sopenharmony_ci	} else if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) {
455362306a36Sopenharmony_ci		/* commands must have at least 4 bytes, responses 5. */
455462306a36Sopenharmony_ci		if (is_cmd && (msg->rsp_size < 4)) {
455562306a36Sopenharmony_ci			ipmi_inc_stat(intf, invalid_commands);
455662306a36Sopenharmony_ci			goto out;
455762306a36Sopenharmony_ci		}
455862306a36Sopenharmony_ci		if (!is_cmd && (msg->rsp_size < 5)) {
455962306a36Sopenharmony_ci			ipmi_inc_stat(intf, invalid_ipmb_responses);
456062306a36Sopenharmony_ci			/* Construct a valid error response. */
456162306a36Sopenharmony_ci			msg->rsp[0] = msg->data[0] & 0xfc; /* NetFN */
456262306a36Sopenharmony_ci			msg->rsp[0] |= (1 << 2); /* Make it a response */
456362306a36Sopenharmony_ci			msg->rsp[0] |= msg->data[2] & 3; /* rqLUN */
456462306a36Sopenharmony_ci			msg->rsp[1] = msg->data[1]; /* Addr */
456562306a36Sopenharmony_ci			msg->rsp[2] = msg->data[2] & 0xfc; /* rqSeq */
456662306a36Sopenharmony_ci			msg->rsp[2] |= msg->data[0] & 0x3; /* rsLUN */
456762306a36Sopenharmony_ci			msg->rsp[3] = msg->data[3]; /* Cmd */
456862306a36Sopenharmony_ci			msg->rsp[4] = IPMI_ERR_UNSPECIFIED;
456962306a36Sopenharmony_ci			msg->rsp_size = 5;
457062306a36Sopenharmony_ci		}
457162306a36Sopenharmony_ci	} else if ((msg->data_size >= 2)
457262306a36Sopenharmony_ci	    && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
457362306a36Sopenharmony_ci	    && (msg->data[1] == IPMI_SEND_MSG_CMD)
457462306a36Sopenharmony_ci	    && (msg->user_data == NULL)) {
457562306a36Sopenharmony_ci
457662306a36Sopenharmony_ci		if (intf->in_shutdown)
457762306a36Sopenharmony_ci			goto out;
457862306a36Sopenharmony_ci
457962306a36Sopenharmony_ci		/*
458062306a36Sopenharmony_ci		 * This is the local response to a command send, start
458162306a36Sopenharmony_ci		 * the timer for these.  The user_data will not be
458262306a36Sopenharmony_ci		 * NULL if this is a response send, and we will let
458362306a36Sopenharmony_ci		 * response sends just go through.
458462306a36Sopenharmony_ci		 */
458562306a36Sopenharmony_ci
458662306a36Sopenharmony_ci		/*
458762306a36Sopenharmony_ci		 * Check for errors, if we get certain errors (ones
458862306a36Sopenharmony_ci		 * that mean basically we can try again later), we
458962306a36Sopenharmony_ci		 * ignore them and start the timer.  Otherwise we
459062306a36Sopenharmony_ci		 * report the error immediately.
459162306a36Sopenharmony_ci		 */
459262306a36Sopenharmony_ci		if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
459362306a36Sopenharmony_ci		    && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
459462306a36Sopenharmony_ci		    && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
459562306a36Sopenharmony_ci		    && (msg->rsp[2] != IPMI_BUS_ERR)
459662306a36Sopenharmony_ci		    && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) {
459762306a36Sopenharmony_ci			int ch = msg->rsp[3] & 0xf;
459862306a36Sopenharmony_ci			struct ipmi_channel *chans;
459962306a36Sopenharmony_ci
460062306a36Sopenharmony_ci			/* Got an error sending the message, handle it. */
460162306a36Sopenharmony_ci
460262306a36Sopenharmony_ci			chans = READ_ONCE(intf->channel_list)->c;
460362306a36Sopenharmony_ci			if ((chans[ch].medium == IPMI_CHANNEL_MEDIUM_8023LAN)
460462306a36Sopenharmony_ci			    || (chans[ch].medium == IPMI_CHANNEL_MEDIUM_ASYNC))
460562306a36Sopenharmony_ci				ipmi_inc_stat(intf, sent_lan_command_errs);
460662306a36Sopenharmony_ci			else
460762306a36Sopenharmony_ci				ipmi_inc_stat(intf, sent_ipmb_command_errs);
460862306a36Sopenharmony_ci			intf_err_seq(intf, msg->msgid, msg->rsp[2]);
460962306a36Sopenharmony_ci		} else
461062306a36Sopenharmony_ci			/* The message was sent, start the timer. */
461162306a36Sopenharmony_ci			intf_start_seq_timer(intf, msg->msgid);
461262306a36Sopenharmony_ci		requeue = 0;
461362306a36Sopenharmony_ci		goto out;
461462306a36Sopenharmony_ci	} else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))
461562306a36Sopenharmony_ci		   || (msg->rsp[1] != msg->data[1])) {
461662306a36Sopenharmony_ci		/*
461762306a36Sopenharmony_ci		 * The NetFN and Command in the response is not even
461862306a36Sopenharmony_ci		 * marginally correct.
461962306a36Sopenharmony_ci		 */
462062306a36Sopenharmony_ci		dev_warn(intf->si_dev,
462162306a36Sopenharmony_ci			 "BMC returned incorrect response, expected netfn %x cmd %x, got netfn %x cmd %x\n",
462262306a36Sopenharmony_ci			 (msg->data[0] >> 2) | 1, msg->data[1],
462362306a36Sopenharmony_ci			 msg->rsp[0] >> 2, msg->rsp[1]);
462462306a36Sopenharmony_ci
462562306a36Sopenharmony_ci		goto return_unspecified;
462662306a36Sopenharmony_ci	}
462762306a36Sopenharmony_ci
462862306a36Sopenharmony_ci	if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) {
462962306a36Sopenharmony_ci		if ((msg->data[0] >> 2) & 1) {
463062306a36Sopenharmony_ci			/* It's a response to a sent response. */
463162306a36Sopenharmony_ci			chan = 0;
463262306a36Sopenharmony_ci			cc = msg->rsp[4];
463362306a36Sopenharmony_ci			goto process_response_response;
463462306a36Sopenharmony_ci		}
463562306a36Sopenharmony_ci		if (is_cmd)
463662306a36Sopenharmony_ci			requeue = handle_ipmb_direct_rcv_cmd(intf, msg);
463762306a36Sopenharmony_ci		else
463862306a36Sopenharmony_ci			requeue = handle_ipmb_direct_rcv_rsp(intf, msg);
463962306a36Sopenharmony_ci	} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
464062306a36Sopenharmony_ci		   && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
464162306a36Sopenharmony_ci		   && (msg->user_data != NULL)) {
464262306a36Sopenharmony_ci		/*
464362306a36Sopenharmony_ci		 * It's a response to a response we sent.  For this we
464462306a36Sopenharmony_ci		 * deliver a send message response to the user.
464562306a36Sopenharmony_ci		 */
464662306a36Sopenharmony_ci		struct ipmi_recv_msg *recv_msg;
464762306a36Sopenharmony_ci
464862306a36Sopenharmony_ci		chan = msg->data[2] & 0x0f;
464962306a36Sopenharmony_ci		if (chan >= IPMI_MAX_CHANNELS)
465062306a36Sopenharmony_ci			/* Invalid channel number */
465162306a36Sopenharmony_ci			goto out;
465262306a36Sopenharmony_ci		cc = msg->rsp[2];
465362306a36Sopenharmony_ci
465462306a36Sopenharmony_ciprocess_response_response:
465562306a36Sopenharmony_ci		recv_msg = msg->user_data;
465662306a36Sopenharmony_ci
465762306a36Sopenharmony_ci		requeue = 0;
465862306a36Sopenharmony_ci		if (!recv_msg)
465962306a36Sopenharmony_ci			goto out;
466062306a36Sopenharmony_ci
466162306a36Sopenharmony_ci		recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
466262306a36Sopenharmony_ci		recv_msg->msg.data = recv_msg->msg_data;
466362306a36Sopenharmony_ci		recv_msg->msg_data[0] = cc;
466462306a36Sopenharmony_ci		recv_msg->msg.data_len = 1;
466562306a36Sopenharmony_ci		deliver_local_response(intf, recv_msg);
466662306a36Sopenharmony_ci	} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
466762306a36Sopenharmony_ci		   && (msg->rsp[1] == IPMI_GET_MSG_CMD)) {
466862306a36Sopenharmony_ci		struct ipmi_channel   *chans;
466962306a36Sopenharmony_ci
467062306a36Sopenharmony_ci		/* It's from the receive queue. */
467162306a36Sopenharmony_ci		chan = msg->rsp[3] & 0xf;
467262306a36Sopenharmony_ci		if (chan >= IPMI_MAX_CHANNELS) {
467362306a36Sopenharmony_ci			/* Invalid channel number */
467462306a36Sopenharmony_ci			requeue = 0;
467562306a36Sopenharmony_ci			goto out;
467662306a36Sopenharmony_ci		}
467762306a36Sopenharmony_ci
467862306a36Sopenharmony_ci		/*
467962306a36Sopenharmony_ci		 * We need to make sure the channels have been initialized.
468062306a36Sopenharmony_ci		 * The channel_handler routine will set the "curr_channel"
468162306a36Sopenharmony_ci		 * equal to or greater than IPMI_MAX_CHANNELS when all the
468262306a36Sopenharmony_ci		 * channels for this interface have been initialized.
468362306a36Sopenharmony_ci		 */
468462306a36Sopenharmony_ci		if (!intf->channels_ready) {
468562306a36Sopenharmony_ci			requeue = 0; /* Throw the message away */
468662306a36Sopenharmony_ci			goto out;
468762306a36Sopenharmony_ci		}
468862306a36Sopenharmony_ci
468962306a36Sopenharmony_ci		chans = READ_ONCE(intf->channel_list)->c;
469062306a36Sopenharmony_ci
469162306a36Sopenharmony_ci		switch (chans[chan].medium) {
469262306a36Sopenharmony_ci		case IPMI_CHANNEL_MEDIUM_IPMB:
469362306a36Sopenharmony_ci			if (msg->rsp[4] & 0x04) {
469462306a36Sopenharmony_ci				/*
469562306a36Sopenharmony_ci				 * It's a response, so find the
469662306a36Sopenharmony_ci				 * requesting message and send it up.
469762306a36Sopenharmony_ci				 */
469862306a36Sopenharmony_ci				requeue = handle_ipmb_get_msg_rsp(intf, msg);
469962306a36Sopenharmony_ci			} else {
470062306a36Sopenharmony_ci				/*
470162306a36Sopenharmony_ci				 * It's a command to the SMS from some other
470262306a36Sopenharmony_ci				 * entity.  Handle that.
470362306a36Sopenharmony_ci				 */
470462306a36Sopenharmony_ci				requeue = handle_ipmb_get_msg_cmd(intf, msg);
470562306a36Sopenharmony_ci			}
470662306a36Sopenharmony_ci			break;
470762306a36Sopenharmony_ci
470862306a36Sopenharmony_ci		case IPMI_CHANNEL_MEDIUM_8023LAN:
470962306a36Sopenharmony_ci		case IPMI_CHANNEL_MEDIUM_ASYNC:
471062306a36Sopenharmony_ci			if (msg->rsp[6] & 0x04) {
471162306a36Sopenharmony_ci				/*
471262306a36Sopenharmony_ci				 * It's a response, so find the
471362306a36Sopenharmony_ci				 * requesting message and send it up.
471462306a36Sopenharmony_ci				 */
471562306a36Sopenharmony_ci				requeue = handle_lan_get_msg_rsp(intf, msg);
471662306a36Sopenharmony_ci			} else {
471762306a36Sopenharmony_ci				/*
471862306a36Sopenharmony_ci				 * It's a command to the SMS from some other
471962306a36Sopenharmony_ci				 * entity.  Handle that.
472062306a36Sopenharmony_ci				 */
472162306a36Sopenharmony_ci				requeue = handle_lan_get_msg_cmd(intf, msg);
472262306a36Sopenharmony_ci			}
472362306a36Sopenharmony_ci			break;
472462306a36Sopenharmony_ci
472562306a36Sopenharmony_ci		default:
472662306a36Sopenharmony_ci			/* Check for OEM Channels.  Clients had better
472762306a36Sopenharmony_ci			   register for these commands. */
472862306a36Sopenharmony_ci			if ((chans[chan].medium >= IPMI_CHANNEL_MEDIUM_OEM_MIN)
472962306a36Sopenharmony_ci			    && (chans[chan].medium
473062306a36Sopenharmony_ci				<= IPMI_CHANNEL_MEDIUM_OEM_MAX)) {
473162306a36Sopenharmony_ci				requeue = handle_oem_get_msg_cmd(intf, msg);
473262306a36Sopenharmony_ci			} else {
473362306a36Sopenharmony_ci				/*
473462306a36Sopenharmony_ci				 * We don't handle the channel type, so just
473562306a36Sopenharmony_ci				 * free the message.
473662306a36Sopenharmony_ci				 */
473762306a36Sopenharmony_ci				requeue = 0;
473862306a36Sopenharmony_ci			}
473962306a36Sopenharmony_ci		}
474062306a36Sopenharmony_ci
474162306a36Sopenharmony_ci	} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
474262306a36Sopenharmony_ci		   && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) {
474362306a36Sopenharmony_ci		/* It's an asynchronous event. */
474462306a36Sopenharmony_ci		requeue = handle_read_event_rsp(intf, msg);
474562306a36Sopenharmony_ci	} else {
474662306a36Sopenharmony_ci		/* It's a response from the local BMC. */
474762306a36Sopenharmony_ci		requeue = handle_bmc_rsp(intf, msg);
474862306a36Sopenharmony_ci	}
474962306a36Sopenharmony_ci
475062306a36Sopenharmony_ci out:
475162306a36Sopenharmony_ci	return requeue;
475262306a36Sopenharmony_ci}
475362306a36Sopenharmony_ci
475462306a36Sopenharmony_ci/*
475562306a36Sopenharmony_ci * If there are messages in the queue or pretimeouts, handle them.
475662306a36Sopenharmony_ci */
475762306a36Sopenharmony_cistatic void handle_new_recv_msgs(struct ipmi_smi *intf)
475862306a36Sopenharmony_ci{
475962306a36Sopenharmony_ci	struct ipmi_smi_msg  *smi_msg;
476062306a36Sopenharmony_ci	unsigned long        flags = 0;
476162306a36Sopenharmony_ci	int                  rv;
476262306a36Sopenharmony_ci	int                  run_to_completion = intf->run_to_completion;
476362306a36Sopenharmony_ci
476462306a36Sopenharmony_ci	/* See if any waiting messages need to be processed. */
476562306a36Sopenharmony_ci	if (!run_to_completion)
476662306a36Sopenharmony_ci		spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags);
476762306a36Sopenharmony_ci	while (!list_empty(&intf->waiting_rcv_msgs)) {
476862306a36Sopenharmony_ci		smi_msg = list_entry(intf->waiting_rcv_msgs.next,
476962306a36Sopenharmony_ci				     struct ipmi_smi_msg, link);
477062306a36Sopenharmony_ci		list_del(&smi_msg->link);
477162306a36Sopenharmony_ci		if (!run_to_completion)
477262306a36Sopenharmony_ci			spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock,
477362306a36Sopenharmony_ci					       flags);
477462306a36Sopenharmony_ci		rv = handle_one_recv_msg(intf, smi_msg);
477562306a36Sopenharmony_ci		if (!run_to_completion)
477662306a36Sopenharmony_ci			spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags);
477762306a36Sopenharmony_ci		if (rv > 0) {
477862306a36Sopenharmony_ci			/*
477962306a36Sopenharmony_ci			 * To preserve message order, quit if we
478062306a36Sopenharmony_ci			 * can't handle a message.  Add the message
478162306a36Sopenharmony_ci			 * back at the head, this is safe because this
478262306a36Sopenharmony_ci			 * tasklet is the only thing that pulls the
478362306a36Sopenharmony_ci			 * messages.
478462306a36Sopenharmony_ci			 */
478562306a36Sopenharmony_ci			list_add(&smi_msg->link, &intf->waiting_rcv_msgs);
478662306a36Sopenharmony_ci			break;
478762306a36Sopenharmony_ci		} else {
478862306a36Sopenharmony_ci			if (rv == 0)
478962306a36Sopenharmony_ci				/* Message handled */
479062306a36Sopenharmony_ci				ipmi_free_smi_msg(smi_msg);
479162306a36Sopenharmony_ci			/* If rv < 0, fatal error, del but don't free. */
479262306a36Sopenharmony_ci		}
479362306a36Sopenharmony_ci	}
479462306a36Sopenharmony_ci	if (!run_to_completion)
479562306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock, flags);
479662306a36Sopenharmony_ci
479762306a36Sopenharmony_ci	/*
479862306a36Sopenharmony_ci	 * If the pretimout count is non-zero, decrement one from it and
479962306a36Sopenharmony_ci	 * deliver pretimeouts to all the users.
480062306a36Sopenharmony_ci	 */
480162306a36Sopenharmony_ci	if (atomic_add_unless(&intf->watchdog_pretimeouts_to_deliver, -1, 0)) {
480262306a36Sopenharmony_ci		struct ipmi_user *user;
480362306a36Sopenharmony_ci		int index;
480462306a36Sopenharmony_ci
480562306a36Sopenharmony_ci		index = srcu_read_lock(&intf->users_srcu);
480662306a36Sopenharmony_ci		list_for_each_entry_rcu(user, &intf->users, link) {
480762306a36Sopenharmony_ci			if (user->handler->ipmi_watchdog_pretimeout)
480862306a36Sopenharmony_ci				user->handler->ipmi_watchdog_pretimeout(
480962306a36Sopenharmony_ci					user->handler_data);
481062306a36Sopenharmony_ci		}
481162306a36Sopenharmony_ci		srcu_read_unlock(&intf->users_srcu, index);
481262306a36Sopenharmony_ci	}
481362306a36Sopenharmony_ci}
481462306a36Sopenharmony_ci
481562306a36Sopenharmony_cistatic void smi_recv_tasklet(struct tasklet_struct *t)
481662306a36Sopenharmony_ci{
481762306a36Sopenharmony_ci	unsigned long flags = 0; /* keep us warning-free. */
481862306a36Sopenharmony_ci	struct ipmi_smi *intf = from_tasklet(intf, t, recv_tasklet);
481962306a36Sopenharmony_ci	int run_to_completion = intf->run_to_completion;
482062306a36Sopenharmony_ci	struct ipmi_smi_msg *newmsg = NULL;
482162306a36Sopenharmony_ci
482262306a36Sopenharmony_ci	/*
482362306a36Sopenharmony_ci	 * Start the next message if available.
482462306a36Sopenharmony_ci	 *
482562306a36Sopenharmony_ci	 * Do this here, not in the actual receiver, because we may deadlock
482662306a36Sopenharmony_ci	 * because the lower layer is allowed to hold locks while calling
482762306a36Sopenharmony_ci	 * message delivery.
482862306a36Sopenharmony_ci	 */
482962306a36Sopenharmony_ci
483062306a36Sopenharmony_ci	rcu_read_lock();
483162306a36Sopenharmony_ci
483262306a36Sopenharmony_ci	if (!run_to_completion)
483362306a36Sopenharmony_ci		spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
483462306a36Sopenharmony_ci	if (intf->curr_msg == NULL && !intf->in_shutdown) {
483562306a36Sopenharmony_ci		struct list_head *entry = NULL;
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci		/* Pick the high priority queue first. */
483862306a36Sopenharmony_ci		if (!list_empty(&intf->hp_xmit_msgs))
483962306a36Sopenharmony_ci			entry = intf->hp_xmit_msgs.next;
484062306a36Sopenharmony_ci		else if (!list_empty(&intf->xmit_msgs))
484162306a36Sopenharmony_ci			entry = intf->xmit_msgs.next;
484262306a36Sopenharmony_ci
484362306a36Sopenharmony_ci		if (entry) {
484462306a36Sopenharmony_ci			list_del(entry);
484562306a36Sopenharmony_ci			newmsg = list_entry(entry, struct ipmi_smi_msg, link);
484662306a36Sopenharmony_ci			intf->curr_msg = newmsg;
484762306a36Sopenharmony_ci		}
484862306a36Sopenharmony_ci	}
484962306a36Sopenharmony_ci
485062306a36Sopenharmony_ci	if (!run_to_completion)
485162306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
485262306a36Sopenharmony_ci	if (newmsg)
485362306a36Sopenharmony_ci		intf->handlers->sender(intf->send_info, newmsg);
485462306a36Sopenharmony_ci
485562306a36Sopenharmony_ci	rcu_read_unlock();
485662306a36Sopenharmony_ci
485762306a36Sopenharmony_ci	handle_new_recv_msgs(intf);
485862306a36Sopenharmony_ci}
485962306a36Sopenharmony_ci
486062306a36Sopenharmony_ci/* Handle a new message from the lower layer. */
486162306a36Sopenharmony_civoid ipmi_smi_msg_received(struct ipmi_smi *intf,
486262306a36Sopenharmony_ci			   struct ipmi_smi_msg *msg)
486362306a36Sopenharmony_ci{
486462306a36Sopenharmony_ci	unsigned long flags = 0; /* keep us warning-free. */
486562306a36Sopenharmony_ci	int run_to_completion = intf->run_to_completion;
486662306a36Sopenharmony_ci
486762306a36Sopenharmony_ci	/*
486862306a36Sopenharmony_ci	 * To preserve message order, we keep a queue and deliver from
486962306a36Sopenharmony_ci	 * a tasklet.
487062306a36Sopenharmony_ci	 */
487162306a36Sopenharmony_ci	if (!run_to_completion)
487262306a36Sopenharmony_ci		spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags);
487362306a36Sopenharmony_ci	list_add_tail(&msg->link, &intf->waiting_rcv_msgs);
487462306a36Sopenharmony_ci	if (!run_to_completion)
487562306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock,
487662306a36Sopenharmony_ci				       flags);
487762306a36Sopenharmony_ci
487862306a36Sopenharmony_ci	if (!run_to_completion)
487962306a36Sopenharmony_ci		spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
488062306a36Sopenharmony_ci	/*
488162306a36Sopenharmony_ci	 * We can get an asynchronous event or receive message in addition
488262306a36Sopenharmony_ci	 * to commands we send.
488362306a36Sopenharmony_ci	 */
488462306a36Sopenharmony_ci	if (msg == intf->curr_msg)
488562306a36Sopenharmony_ci		intf->curr_msg = NULL;
488662306a36Sopenharmony_ci	if (!run_to_completion)
488762306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
488862306a36Sopenharmony_ci
488962306a36Sopenharmony_ci	if (run_to_completion)
489062306a36Sopenharmony_ci		smi_recv_tasklet(&intf->recv_tasklet);
489162306a36Sopenharmony_ci	else
489262306a36Sopenharmony_ci		tasklet_schedule(&intf->recv_tasklet);
489362306a36Sopenharmony_ci}
489462306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_smi_msg_received);
489562306a36Sopenharmony_ci
489662306a36Sopenharmony_civoid ipmi_smi_watchdog_pretimeout(struct ipmi_smi *intf)
489762306a36Sopenharmony_ci{
489862306a36Sopenharmony_ci	if (intf->in_shutdown)
489962306a36Sopenharmony_ci		return;
490062306a36Sopenharmony_ci
490162306a36Sopenharmony_ci	atomic_set(&intf->watchdog_pretimeouts_to_deliver, 1);
490262306a36Sopenharmony_ci	tasklet_schedule(&intf->recv_tasklet);
490362306a36Sopenharmony_ci}
490462306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
490562306a36Sopenharmony_ci
490662306a36Sopenharmony_cistatic struct ipmi_smi_msg *
490762306a36Sopenharmony_cismi_from_recv_msg(struct ipmi_smi *intf, struct ipmi_recv_msg *recv_msg,
490862306a36Sopenharmony_ci		  unsigned char seq, long seqid)
490962306a36Sopenharmony_ci{
491062306a36Sopenharmony_ci	struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
491162306a36Sopenharmony_ci	if (!smi_msg)
491262306a36Sopenharmony_ci		/*
491362306a36Sopenharmony_ci		 * If we can't allocate the message, then just return, we
491462306a36Sopenharmony_ci		 * get 4 retries, so this should be ok.
491562306a36Sopenharmony_ci		 */
491662306a36Sopenharmony_ci		return NULL;
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci	memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
491962306a36Sopenharmony_ci	smi_msg->data_size = recv_msg->msg.data_len;
492062306a36Sopenharmony_ci	smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
492162306a36Sopenharmony_ci
492262306a36Sopenharmony_ci	dev_dbg(intf->si_dev, "Resend: %*ph\n",
492362306a36Sopenharmony_ci		smi_msg->data_size, smi_msg->data);
492462306a36Sopenharmony_ci
492562306a36Sopenharmony_ci	return smi_msg;
492662306a36Sopenharmony_ci}
492762306a36Sopenharmony_ci
492862306a36Sopenharmony_cistatic void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
492962306a36Sopenharmony_ci			      struct list_head *timeouts,
493062306a36Sopenharmony_ci			      unsigned long timeout_period,
493162306a36Sopenharmony_ci			      int slot, unsigned long *flags,
493262306a36Sopenharmony_ci			      bool *need_timer)
493362306a36Sopenharmony_ci{
493462306a36Sopenharmony_ci	struct ipmi_recv_msg *msg;
493562306a36Sopenharmony_ci
493662306a36Sopenharmony_ci	if (intf->in_shutdown)
493762306a36Sopenharmony_ci		return;
493862306a36Sopenharmony_ci
493962306a36Sopenharmony_ci	if (!ent->inuse)
494062306a36Sopenharmony_ci		return;
494162306a36Sopenharmony_ci
494262306a36Sopenharmony_ci	if (timeout_period < ent->timeout) {
494362306a36Sopenharmony_ci		ent->timeout -= timeout_period;
494462306a36Sopenharmony_ci		*need_timer = true;
494562306a36Sopenharmony_ci		return;
494662306a36Sopenharmony_ci	}
494762306a36Sopenharmony_ci
494862306a36Sopenharmony_ci	if (ent->retries_left == 0) {
494962306a36Sopenharmony_ci		/* The message has used all its retries. */
495062306a36Sopenharmony_ci		ent->inuse = 0;
495162306a36Sopenharmony_ci		smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
495262306a36Sopenharmony_ci		msg = ent->recv_msg;
495362306a36Sopenharmony_ci		list_add_tail(&msg->link, timeouts);
495462306a36Sopenharmony_ci		if (ent->broadcast)
495562306a36Sopenharmony_ci			ipmi_inc_stat(intf, timed_out_ipmb_broadcasts);
495662306a36Sopenharmony_ci		else if (is_lan_addr(&ent->recv_msg->addr))
495762306a36Sopenharmony_ci			ipmi_inc_stat(intf, timed_out_lan_commands);
495862306a36Sopenharmony_ci		else
495962306a36Sopenharmony_ci			ipmi_inc_stat(intf, timed_out_ipmb_commands);
496062306a36Sopenharmony_ci	} else {
496162306a36Sopenharmony_ci		struct ipmi_smi_msg *smi_msg;
496262306a36Sopenharmony_ci		/* More retries, send again. */
496362306a36Sopenharmony_ci
496462306a36Sopenharmony_ci		*need_timer = true;
496562306a36Sopenharmony_ci
496662306a36Sopenharmony_ci		/*
496762306a36Sopenharmony_ci		 * Start with the max timer, set to normal timer after
496862306a36Sopenharmony_ci		 * the message is sent.
496962306a36Sopenharmony_ci		 */
497062306a36Sopenharmony_ci		ent->timeout = MAX_MSG_TIMEOUT;
497162306a36Sopenharmony_ci		ent->retries_left--;
497262306a36Sopenharmony_ci		smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
497362306a36Sopenharmony_ci					    ent->seqid);
497462306a36Sopenharmony_ci		if (!smi_msg) {
497562306a36Sopenharmony_ci			if (is_lan_addr(&ent->recv_msg->addr))
497662306a36Sopenharmony_ci				ipmi_inc_stat(intf,
497762306a36Sopenharmony_ci					      dropped_rexmit_lan_commands);
497862306a36Sopenharmony_ci			else
497962306a36Sopenharmony_ci				ipmi_inc_stat(intf,
498062306a36Sopenharmony_ci					      dropped_rexmit_ipmb_commands);
498162306a36Sopenharmony_ci			return;
498262306a36Sopenharmony_ci		}
498362306a36Sopenharmony_ci
498462306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->seq_lock, *flags);
498562306a36Sopenharmony_ci
498662306a36Sopenharmony_ci		/*
498762306a36Sopenharmony_ci		 * Send the new message.  We send with a zero
498862306a36Sopenharmony_ci		 * priority.  It timed out, I doubt time is that
498962306a36Sopenharmony_ci		 * critical now, and high priority messages are really
499062306a36Sopenharmony_ci		 * only for messages to the local MC, which don't get
499162306a36Sopenharmony_ci		 * resent.
499262306a36Sopenharmony_ci		 */
499362306a36Sopenharmony_ci		if (intf->handlers) {
499462306a36Sopenharmony_ci			if (is_lan_addr(&ent->recv_msg->addr))
499562306a36Sopenharmony_ci				ipmi_inc_stat(intf,
499662306a36Sopenharmony_ci					      retransmitted_lan_commands);
499762306a36Sopenharmony_ci			else
499862306a36Sopenharmony_ci				ipmi_inc_stat(intf,
499962306a36Sopenharmony_ci					      retransmitted_ipmb_commands);
500062306a36Sopenharmony_ci
500162306a36Sopenharmony_ci			smi_send(intf, intf->handlers, smi_msg, 0);
500262306a36Sopenharmony_ci		} else
500362306a36Sopenharmony_ci			ipmi_free_smi_msg(smi_msg);
500462306a36Sopenharmony_ci
500562306a36Sopenharmony_ci		spin_lock_irqsave(&intf->seq_lock, *flags);
500662306a36Sopenharmony_ci	}
500762306a36Sopenharmony_ci}
500862306a36Sopenharmony_ci
500962306a36Sopenharmony_cistatic bool ipmi_timeout_handler(struct ipmi_smi *intf,
501062306a36Sopenharmony_ci				 unsigned long timeout_period)
501162306a36Sopenharmony_ci{
501262306a36Sopenharmony_ci	struct list_head     timeouts;
501362306a36Sopenharmony_ci	struct ipmi_recv_msg *msg, *msg2;
501462306a36Sopenharmony_ci	unsigned long        flags;
501562306a36Sopenharmony_ci	int                  i;
501662306a36Sopenharmony_ci	bool                 need_timer = false;
501762306a36Sopenharmony_ci
501862306a36Sopenharmony_ci	if (!intf->bmc_registered) {
501962306a36Sopenharmony_ci		kref_get(&intf->refcount);
502062306a36Sopenharmony_ci		if (!schedule_work(&intf->bmc_reg_work)) {
502162306a36Sopenharmony_ci			kref_put(&intf->refcount, intf_free);
502262306a36Sopenharmony_ci			need_timer = true;
502362306a36Sopenharmony_ci		}
502462306a36Sopenharmony_ci	}
502562306a36Sopenharmony_ci
502662306a36Sopenharmony_ci	/*
502762306a36Sopenharmony_ci	 * Go through the seq table and find any messages that
502862306a36Sopenharmony_ci	 * have timed out, putting them in the timeouts
502962306a36Sopenharmony_ci	 * list.
503062306a36Sopenharmony_ci	 */
503162306a36Sopenharmony_ci	INIT_LIST_HEAD(&timeouts);
503262306a36Sopenharmony_ci	spin_lock_irqsave(&intf->seq_lock, flags);
503362306a36Sopenharmony_ci	if (intf->ipmb_maintenance_mode_timeout) {
503462306a36Sopenharmony_ci		if (intf->ipmb_maintenance_mode_timeout <= timeout_period)
503562306a36Sopenharmony_ci			intf->ipmb_maintenance_mode_timeout = 0;
503662306a36Sopenharmony_ci		else
503762306a36Sopenharmony_ci			intf->ipmb_maintenance_mode_timeout -= timeout_period;
503862306a36Sopenharmony_ci	}
503962306a36Sopenharmony_ci	for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
504062306a36Sopenharmony_ci		check_msg_timeout(intf, &intf->seq_table[i],
504162306a36Sopenharmony_ci				  &timeouts, timeout_period, i,
504262306a36Sopenharmony_ci				  &flags, &need_timer);
504362306a36Sopenharmony_ci	spin_unlock_irqrestore(&intf->seq_lock, flags);
504462306a36Sopenharmony_ci
504562306a36Sopenharmony_ci	list_for_each_entry_safe(msg, msg2, &timeouts, link)
504662306a36Sopenharmony_ci		deliver_err_response(intf, msg, IPMI_TIMEOUT_COMPLETION_CODE);
504762306a36Sopenharmony_ci
504862306a36Sopenharmony_ci	/*
504962306a36Sopenharmony_ci	 * Maintenance mode handling.  Check the timeout
505062306a36Sopenharmony_ci	 * optimistically before we claim the lock.  It may
505162306a36Sopenharmony_ci	 * mean a timeout gets missed occasionally, but that
505262306a36Sopenharmony_ci	 * only means the timeout gets extended by one period
505362306a36Sopenharmony_ci	 * in that case.  No big deal, and it avoids the lock
505462306a36Sopenharmony_ci	 * most of the time.
505562306a36Sopenharmony_ci	 */
505662306a36Sopenharmony_ci	if (intf->auto_maintenance_timeout > 0) {
505762306a36Sopenharmony_ci		spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
505862306a36Sopenharmony_ci		if (intf->auto_maintenance_timeout > 0) {
505962306a36Sopenharmony_ci			intf->auto_maintenance_timeout
506062306a36Sopenharmony_ci				-= timeout_period;
506162306a36Sopenharmony_ci			if (!intf->maintenance_mode
506262306a36Sopenharmony_ci			    && (intf->auto_maintenance_timeout <= 0)) {
506362306a36Sopenharmony_ci				intf->maintenance_mode_enable = false;
506462306a36Sopenharmony_ci				maintenance_mode_update(intf);
506562306a36Sopenharmony_ci			}
506662306a36Sopenharmony_ci		}
506762306a36Sopenharmony_ci		spin_unlock_irqrestore(&intf->maintenance_mode_lock,
506862306a36Sopenharmony_ci				       flags);
506962306a36Sopenharmony_ci	}
507062306a36Sopenharmony_ci
507162306a36Sopenharmony_ci	tasklet_schedule(&intf->recv_tasklet);
507262306a36Sopenharmony_ci
507362306a36Sopenharmony_ci	return need_timer;
507462306a36Sopenharmony_ci}
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_cistatic void ipmi_request_event(struct ipmi_smi *intf)
507762306a36Sopenharmony_ci{
507862306a36Sopenharmony_ci	/* No event requests when in maintenance mode. */
507962306a36Sopenharmony_ci	if (intf->maintenance_mode_enable)
508062306a36Sopenharmony_ci		return;
508162306a36Sopenharmony_ci
508262306a36Sopenharmony_ci	if (!intf->in_shutdown)
508362306a36Sopenharmony_ci		intf->handlers->request_events(intf->send_info);
508462306a36Sopenharmony_ci}
508562306a36Sopenharmony_ci
508662306a36Sopenharmony_cistatic struct timer_list ipmi_timer;
508762306a36Sopenharmony_ci
508862306a36Sopenharmony_cistatic atomic_t stop_operation;
508962306a36Sopenharmony_ci
509062306a36Sopenharmony_cistatic void ipmi_timeout(struct timer_list *unused)
509162306a36Sopenharmony_ci{
509262306a36Sopenharmony_ci	struct ipmi_smi *intf;
509362306a36Sopenharmony_ci	bool need_timer = false;
509462306a36Sopenharmony_ci	int index;
509562306a36Sopenharmony_ci
509662306a36Sopenharmony_ci	if (atomic_read(&stop_operation))
509762306a36Sopenharmony_ci		return;
509862306a36Sopenharmony_ci
509962306a36Sopenharmony_ci	index = srcu_read_lock(&ipmi_interfaces_srcu);
510062306a36Sopenharmony_ci	list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
510162306a36Sopenharmony_ci		if (atomic_read(&intf->event_waiters)) {
510262306a36Sopenharmony_ci			intf->ticks_to_req_ev--;
510362306a36Sopenharmony_ci			if (intf->ticks_to_req_ev == 0) {
510462306a36Sopenharmony_ci				ipmi_request_event(intf);
510562306a36Sopenharmony_ci				intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
510662306a36Sopenharmony_ci			}
510762306a36Sopenharmony_ci			need_timer = true;
510862306a36Sopenharmony_ci		}
510962306a36Sopenharmony_ci
511062306a36Sopenharmony_ci		need_timer |= ipmi_timeout_handler(intf, IPMI_TIMEOUT_TIME);
511162306a36Sopenharmony_ci	}
511262306a36Sopenharmony_ci	srcu_read_unlock(&ipmi_interfaces_srcu, index);
511362306a36Sopenharmony_ci
511462306a36Sopenharmony_ci	if (need_timer)
511562306a36Sopenharmony_ci		mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
511662306a36Sopenharmony_ci}
511762306a36Sopenharmony_ci
511862306a36Sopenharmony_cistatic void need_waiter(struct ipmi_smi *intf)
511962306a36Sopenharmony_ci{
512062306a36Sopenharmony_ci	/* Racy, but worst case we start the timer twice. */
512162306a36Sopenharmony_ci	if (!timer_pending(&ipmi_timer))
512262306a36Sopenharmony_ci		mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
512362306a36Sopenharmony_ci}
512462306a36Sopenharmony_ci
512562306a36Sopenharmony_cistatic atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
512662306a36Sopenharmony_cistatic atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
512762306a36Sopenharmony_ci
512862306a36Sopenharmony_cistatic void free_smi_msg(struct ipmi_smi_msg *msg)
512962306a36Sopenharmony_ci{
513062306a36Sopenharmony_ci	atomic_dec(&smi_msg_inuse_count);
513162306a36Sopenharmony_ci	/* Try to keep as much stuff out of the panic path as possible. */
513262306a36Sopenharmony_ci	if (!oops_in_progress)
513362306a36Sopenharmony_ci		kfree(msg);
513462306a36Sopenharmony_ci}
513562306a36Sopenharmony_ci
513662306a36Sopenharmony_cistruct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
513762306a36Sopenharmony_ci{
513862306a36Sopenharmony_ci	struct ipmi_smi_msg *rv;
513962306a36Sopenharmony_ci	rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
514062306a36Sopenharmony_ci	if (rv) {
514162306a36Sopenharmony_ci		rv->done = free_smi_msg;
514262306a36Sopenharmony_ci		rv->user_data = NULL;
514362306a36Sopenharmony_ci		rv->type = IPMI_SMI_MSG_TYPE_NORMAL;
514462306a36Sopenharmony_ci		atomic_inc(&smi_msg_inuse_count);
514562306a36Sopenharmony_ci	}
514662306a36Sopenharmony_ci	return rv;
514762306a36Sopenharmony_ci}
514862306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_alloc_smi_msg);
514962306a36Sopenharmony_ci
515062306a36Sopenharmony_cistatic void free_recv_msg(struct ipmi_recv_msg *msg)
515162306a36Sopenharmony_ci{
515262306a36Sopenharmony_ci	atomic_dec(&recv_msg_inuse_count);
515362306a36Sopenharmony_ci	/* Try to keep as much stuff out of the panic path as possible. */
515462306a36Sopenharmony_ci	if (!oops_in_progress)
515562306a36Sopenharmony_ci		kfree(msg);
515662306a36Sopenharmony_ci}
515762306a36Sopenharmony_ci
515862306a36Sopenharmony_cistatic struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
515962306a36Sopenharmony_ci{
516062306a36Sopenharmony_ci	struct ipmi_recv_msg *rv;
516162306a36Sopenharmony_ci
516262306a36Sopenharmony_ci	rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
516362306a36Sopenharmony_ci	if (rv) {
516462306a36Sopenharmony_ci		rv->user = NULL;
516562306a36Sopenharmony_ci		rv->done = free_recv_msg;
516662306a36Sopenharmony_ci		atomic_inc(&recv_msg_inuse_count);
516762306a36Sopenharmony_ci	}
516862306a36Sopenharmony_ci	return rv;
516962306a36Sopenharmony_ci}
517062306a36Sopenharmony_ci
517162306a36Sopenharmony_civoid ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
517262306a36Sopenharmony_ci{
517362306a36Sopenharmony_ci	if (msg->user && !oops_in_progress)
517462306a36Sopenharmony_ci		kref_put(&msg->user->refcount, free_user);
517562306a36Sopenharmony_ci	msg->done(msg);
517662306a36Sopenharmony_ci}
517762306a36Sopenharmony_ciEXPORT_SYMBOL(ipmi_free_recv_msg);
517862306a36Sopenharmony_ci
517962306a36Sopenharmony_cistatic atomic_t panic_done_count = ATOMIC_INIT(0);
518062306a36Sopenharmony_ci
518162306a36Sopenharmony_cistatic void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
518262306a36Sopenharmony_ci{
518362306a36Sopenharmony_ci	atomic_dec(&panic_done_count);
518462306a36Sopenharmony_ci}
518562306a36Sopenharmony_ci
518662306a36Sopenharmony_cistatic void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
518762306a36Sopenharmony_ci{
518862306a36Sopenharmony_ci	atomic_dec(&panic_done_count);
518962306a36Sopenharmony_ci}
519062306a36Sopenharmony_ci
519162306a36Sopenharmony_ci/*
519262306a36Sopenharmony_ci * Inside a panic, send a message and wait for a response.
519362306a36Sopenharmony_ci */
519462306a36Sopenharmony_cistatic void ipmi_panic_request_and_wait(struct ipmi_smi *intf,
519562306a36Sopenharmony_ci					struct ipmi_addr *addr,
519662306a36Sopenharmony_ci					struct kernel_ipmi_msg *msg)
519762306a36Sopenharmony_ci{
519862306a36Sopenharmony_ci	struct ipmi_smi_msg  smi_msg;
519962306a36Sopenharmony_ci	struct ipmi_recv_msg recv_msg;
520062306a36Sopenharmony_ci	int rv;
520162306a36Sopenharmony_ci
520262306a36Sopenharmony_ci	smi_msg.done = dummy_smi_done_handler;
520362306a36Sopenharmony_ci	recv_msg.done = dummy_recv_done_handler;
520462306a36Sopenharmony_ci	atomic_add(2, &panic_done_count);
520562306a36Sopenharmony_ci	rv = i_ipmi_request(NULL,
520662306a36Sopenharmony_ci			    intf,
520762306a36Sopenharmony_ci			    addr,
520862306a36Sopenharmony_ci			    0,
520962306a36Sopenharmony_ci			    msg,
521062306a36Sopenharmony_ci			    intf,
521162306a36Sopenharmony_ci			    &smi_msg,
521262306a36Sopenharmony_ci			    &recv_msg,
521362306a36Sopenharmony_ci			    0,
521462306a36Sopenharmony_ci			    intf->addrinfo[0].address,
521562306a36Sopenharmony_ci			    intf->addrinfo[0].lun,
521662306a36Sopenharmony_ci			    0, 1); /* Don't retry, and don't wait. */
521762306a36Sopenharmony_ci	if (rv)
521862306a36Sopenharmony_ci		atomic_sub(2, &panic_done_count);
521962306a36Sopenharmony_ci	else if (intf->handlers->flush_messages)
522062306a36Sopenharmony_ci		intf->handlers->flush_messages(intf->send_info);
522162306a36Sopenharmony_ci
522262306a36Sopenharmony_ci	while (atomic_read(&panic_done_count) != 0)
522362306a36Sopenharmony_ci		ipmi_poll(intf);
522462306a36Sopenharmony_ci}
522562306a36Sopenharmony_ci
522662306a36Sopenharmony_cistatic void event_receiver_fetcher(struct ipmi_smi *intf,
522762306a36Sopenharmony_ci				   struct ipmi_recv_msg *msg)
522862306a36Sopenharmony_ci{
522962306a36Sopenharmony_ci	if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
523062306a36Sopenharmony_ci	    && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
523162306a36Sopenharmony_ci	    && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
523262306a36Sopenharmony_ci	    && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) {
523362306a36Sopenharmony_ci		/* A get event receiver command, save it. */
523462306a36Sopenharmony_ci		intf->event_receiver = msg->msg.data[1];
523562306a36Sopenharmony_ci		intf->event_receiver_lun = msg->msg.data[2] & 0x3;
523662306a36Sopenharmony_ci	}
523762306a36Sopenharmony_ci}
523862306a36Sopenharmony_ci
523962306a36Sopenharmony_cistatic void device_id_fetcher(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
524062306a36Sopenharmony_ci{
524162306a36Sopenharmony_ci	if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
524262306a36Sopenharmony_ci	    && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
524362306a36Sopenharmony_ci	    && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
524462306a36Sopenharmony_ci	    && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) {
524562306a36Sopenharmony_ci		/*
524662306a36Sopenharmony_ci		 * A get device id command, save if we are an event
524762306a36Sopenharmony_ci		 * receiver or generator.
524862306a36Sopenharmony_ci		 */
524962306a36Sopenharmony_ci		intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
525062306a36Sopenharmony_ci		intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
525162306a36Sopenharmony_ci	}
525262306a36Sopenharmony_ci}
525362306a36Sopenharmony_ci
525462306a36Sopenharmony_cistatic void send_panic_events(struct ipmi_smi *intf, char *str)
525562306a36Sopenharmony_ci{
525662306a36Sopenharmony_ci	struct kernel_ipmi_msg msg;
525762306a36Sopenharmony_ci	unsigned char data[16];
525862306a36Sopenharmony_ci	struct ipmi_system_interface_addr *si;
525962306a36Sopenharmony_ci	struct ipmi_addr addr;
526062306a36Sopenharmony_ci	char *p = str;
526162306a36Sopenharmony_ci	struct ipmi_ipmb_addr *ipmb;
526262306a36Sopenharmony_ci	int j;
526362306a36Sopenharmony_ci
526462306a36Sopenharmony_ci	if (ipmi_send_panic_event == IPMI_SEND_PANIC_EVENT_NONE)
526562306a36Sopenharmony_ci		return;
526662306a36Sopenharmony_ci
526762306a36Sopenharmony_ci	si = (struct ipmi_system_interface_addr *) &addr;
526862306a36Sopenharmony_ci	si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
526962306a36Sopenharmony_ci	si->channel = IPMI_BMC_CHANNEL;
527062306a36Sopenharmony_ci	si->lun = 0;
527162306a36Sopenharmony_ci
527262306a36Sopenharmony_ci	/* Fill in an event telling that we have failed. */
527362306a36Sopenharmony_ci	msg.netfn = 0x04; /* Sensor or Event. */
527462306a36Sopenharmony_ci	msg.cmd = 2; /* Platform event command. */
527562306a36Sopenharmony_ci	msg.data = data;
527662306a36Sopenharmony_ci	msg.data_len = 8;
527762306a36Sopenharmony_ci	data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
527862306a36Sopenharmony_ci	data[1] = 0x03; /* This is for IPMI 1.0. */
527962306a36Sopenharmony_ci	data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
528062306a36Sopenharmony_ci	data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
528162306a36Sopenharmony_ci	data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
528262306a36Sopenharmony_ci
528362306a36Sopenharmony_ci	/*
528462306a36Sopenharmony_ci	 * Put a few breadcrumbs in.  Hopefully later we can add more things
528562306a36Sopenharmony_ci	 * to make the panic events more useful.
528662306a36Sopenharmony_ci	 */
528762306a36Sopenharmony_ci	if (str) {
528862306a36Sopenharmony_ci		data[3] = str[0];
528962306a36Sopenharmony_ci		data[6] = str[1];
529062306a36Sopenharmony_ci		data[7] = str[2];
529162306a36Sopenharmony_ci	}
529262306a36Sopenharmony_ci
529362306a36Sopenharmony_ci	/* Send the event announcing the panic. */
529462306a36Sopenharmony_ci	ipmi_panic_request_and_wait(intf, &addr, &msg);
529562306a36Sopenharmony_ci
529662306a36Sopenharmony_ci	/*
529762306a36Sopenharmony_ci	 * On every interface, dump a bunch of OEM event holding the
529862306a36Sopenharmony_ci	 * string.
529962306a36Sopenharmony_ci	 */
530062306a36Sopenharmony_ci	if (ipmi_send_panic_event != IPMI_SEND_PANIC_EVENT_STRING || !str)
530162306a36Sopenharmony_ci		return;
530262306a36Sopenharmony_ci
530362306a36Sopenharmony_ci	/*
530462306a36Sopenharmony_ci	 * intf_num is used as an marker to tell if the
530562306a36Sopenharmony_ci	 * interface is valid.  Thus we need a read barrier to
530662306a36Sopenharmony_ci	 * make sure data fetched before checking intf_num
530762306a36Sopenharmony_ci	 * won't be used.
530862306a36Sopenharmony_ci	 */
530962306a36Sopenharmony_ci	smp_rmb();
531062306a36Sopenharmony_ci
531162306a36Sopenharmony_ci	/*
531262306a36Sopenharmony_ci	 * First job here is to figure out where to send the
531362306a36Sopenharmony_ci	 * OEM events.  There's no way in IPMI to send OEM
531462306a36Sopenharmony_ci	 * events using an event send command, so we have to
531562306a36Sopenharmony_ci	 * find the SEL to put them in and stick them in
531662306a36Sopenharmony_ci	 * there.
531762306a36Sopenharmony_ci	 */
531862306a36Sopenharmony_ci
531962306a36Sopenharmony_ci	/* Get capabilities from the get device id. */
532062306a36Sopenharmony_ci	intf->local_sel_device = 0;
532162306a36Sopenharmony_ci	intf->local_event_generator = 0;
532262306a36Sopenharmony_ci	intf->event_receiver = 0;
532362306a36Sopenharmony_ci
532462306a36Sopenharmony_ci	/* Request the device info from the local MC. */
532562306a36Sopenharmony_ci	msg.netfn = IPMI_NETFN_APP_REQUEST;
532662306a36Sopenharmony_ci	msg.cmd = IPMI_GET_DEVICE_ID_CMD;
532762306a36Sopenharmony_ci	msg.data = NULL;
532862306a36Sopenharmony_ci	msg.data_len = 0;
532962306a36Sopenharmony_ci	intf->null_user_handler = device_id_fetcher;
533062306a36Sopenharmony_ci	ipmi_panic_request_and_wait(intf, &addr, &msg);
533162306a36Sopenharmony_ci
533262306a36Sopenharmony_ci	if (intf->local_event_generator) {
533362306a36Sopenharmony_ci		/* Request the event receiver from the local MC. */
533462306a36Sopenharmony_ci		msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
533562306a36Sopenharmony_ci		msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
533662306a36Sopenharmony_ci		msg.data = NULL;
533762306a36Sopenharmony_ci		msg.data_len = 0;
533862306a36Sopenharmony_ci		intf->null_user_handler = event_receiver_fetcher;
533962306a36Sopenharmony_ci		ipmi_panic_request_and_wait(intf, &addr, &msg);
534062306a36Sopenharmony_ci	}
534162306a36Sopenharmony_ci	intf->null_user_handler = NULL;
534262306a36Sopenharmony_ci
534362306a36Sopenharmony_ci	/*
534462306a36Sopenharmony_ci	 * Validate the event receiver.  The low bit must not
534562306a36Sopenharmony_ci	 * be 1 (it must be a valid IPMB address), it cannot
534662306a36Sopenharmony_ci	 * be zero, and it must not be my address.
534762306a36Sopenharmony_ci	 */
534862306a36Sopenharmony_ci	if (((intf->event_receiver & 1) == 0)
534962306a36Sopenharmony_ci	    && (intf->event_receiver != 0)
535062306a36Sopenharmony_ci	    && (intf->event_receiver != intf->addrinfo[0].address)) {
535162306a36Sopenharmony_ci		/*
535262306a36Sopenharmony_ci		 * The event receiver is valid, send an IPMB
535362306a36Sopenharmony_ci		 * message.
535462306a36Sopenharmony_ci		 */
535562306a36Sopenharmony_ci		ipmb = (struct ipmi_ipmb_addr *) &addr;
535662306a36Sopenharmony_ci		ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
535762306a36Sopenharmony_ci		ipmb->channel = 0; /* FIXME - is this right? */
535862306a36Sopenharmony_ci		ipmb->lun = intf->event_receiver_lun;
535962306a36Sopenharmony_ci		ipmb->slave_addr = intf->event_receiver;
536062306a36Sopenharmony_ci	} else if (intf->local_sel_device) {
536162306a36Sopenharmony_ci		/*
536262306a36Sopenharmony_ci		 * The event receiver was not valid (or was
536362306a36Sopenharmony_ci		 * me), but I am an SEL device, just dump it
536462306a36Sopenharmony_ci		 * in my SEL.
536562306a36Sopenharmony_ci		 */
536662306a36Sopenharmony_ci		si = (struct ipmi_system_interface_addr *) &addr;
536762306a36Sopenharmony_ci		si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
536862306a36Sopenharmony_ci		si->channel = IPMI_BMC_CHANNEL;
536962306a36Sopenharmony_ci		si->lun = 0;
537062306a36Sopenharmony_ci	} else
537162306a36Sopenharmony_ci		return; /* No where to send the event. */
537262306a36Sopenharmony_ci
537362306a36Sopenharmony_ci	msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
537462306a36Sopenharmony_ci	msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
537562306a36Sopenharmony_ci	msg.data = data;
537662306a36Sopenharmony_ci	msg.data_len = 16;
537762306a36Sopenharmony_ci
537862306a36Sopenharmony_ci	j = 0;
537962306a36Sopenharmony_ci	while (*p) {
538062306a36Sopenharmony_ci		int size = strlen(p);
538162306a36Sopenharmony_ci
538262306a36Sopenharmony_ci		if (size > 11)
538362306a36Sopenharmony_ci			size = 11;
538462306a36Sopenharmony_ci		data[0] = 0;
538562306a36Sopenharmony_ci		data[1] = 0;
538662306a36Sopenharmony_ci		data[2] = 0xf0; /* OEM event without timestamp. */
538762306a36Sopenharmony_ci		data[3] = intf->addrinfo[0].address;
538862306a36Sopenharmony_ci		data[4] = j++; /* sequence # */
538962306a36Sopenharmony_ci		/*
539062306a36Sopenharmony_ci		 * Always give 11 bytes, so strncpy will fill
539162306a36Sopenharmony_ci		 * it with zeroes for me.
539262306a36Sopenharmony_ci		 */
539362306a36Sopenharmony_ci		strncpy(data+5, p, 11);
539462306a36Sopenharmony_ci		p += size;
539562306a36Sopenharmony_ci
539662306a36Sopenharmony_ci		ipmi_panic_request_and_wait(intf, &addr, &msg);
539762306a36Sopenharmony_ci	}
539862306a36Sopenharmony_ci}
539962306a36Sopenharmony_ci
540062306a36Sopenharmony_cistatic int has_panicked;
540162306a36Sopenharmony_ci
540262306a36Sopenharmony_cistatic int panic_event(struct notifier_block *this,
540362306a36Sopenharmony_ci		       unsigned long         event,
540462306a36Sopenharmony_ci		       void                  *ptr)
540562306a36Sopenharmony_ci{
540662306a36Sopenharmony_ci	struct ipmi_smi *intf;
540762306a36Sopenharmony_ci	struct ipmi_user *user;
540862306a36Sopenharmony_ci
540962306a36Sopenharmony_ci	if (has_panicked)
541062306a36Sopenharmony_ci		return NOTIFY_DONE;
541162306a36Sopenharmony_ci	has_panicked = 1;
541262306a36Sopenharmony_ci
541362306a36Sopenharmony_ci	/* For every registered interface, set it to run to completion. */
541462306a36Sopenharmony_ci	list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
541562306a36Sopenharmony_ci		if (!intf->handlers || intf->intf_num == -1)
541662306a36Sopenharmony_ci			/* Interface is not ready. */
541762306a36Sopenharmony_ci			continue;
541862306a36Sopenharmony_ci
541962306a36Sopenharmony_ci		if (!intf->handlers->poll)
542062306a36Sopenharmony_ci			continue;
542162306a36Sopenharmony_ci
542262306a36Sopenharmony_ci		/*
542362306a36Sopenharmony_ci		 * If we were interrupted while locking xmit_msgs_lock or
542462306a36Sopenharmony_ci		 * waiting_rcv_msgs_lock, the corresponding list may be
542562306a36Sopenharmony_ci		 * corrupted.  In this case, drop items on the list for
542662306a36Sopenharmony_ci		 * the safety.
542762306a36Sopenharmony_ci		 */
542862306a36Sopenharmony_ci		if (!spin_trylock(&intf->xmit_msgs_lock)) {
542962306a36Sopenharmony_ci			INIT_LIST_HEAD(&intf->xmit_msgs);
543062306a36Sopenharmony_ci			INIT_LIST_HEAD(&intf->hp_xmit_msgs);
543162306a36Sopenharmony_ci		} else
543262306a36Sopenharmony_ci			spin_unlock(&intf->xmit_msgs_lock);
543362306a36Sopenharmony_ci
543462306a36Sopenharmony_ci		if (!spin_trylock(&intf->waiting_rcv_msgs_lock))
543562306a36Sopenharmony_ci			INIT_LIST_HEAD(&intf->waiting_rcv_msgs);
543662306a36Sopenharmony_ci		else
543762306a36Sopenharmony_ci			spin_unlock(&intf->waiting_rcv_msgs_lock);
543862306a36Sopenharmony_ci
543962306a36Sopenharmony_ci		intf->run_to_completion = 1;
544062306a36Sopenharmony_ci		if (intf->handlers->set_run_to_completion)
544162306a36Sopenharmony_ci			intf->handlers->set_run_to_completion(intf->send_info,
544262306a36Sopenharmony_ci							      1);
544362306a36Sopenharmony_ci
544462306a36Sopenharmony_ci		list_for_each_entry_rcu(user, &intf->users, link) {
544562306a36Sopenharmony_ci			if (user->handler->ipmi_panic_handler)
544662306a36Sopenharmony_ci				user->handler->ipmi_panic_handler(
544762306a36Sopenharmony_ci					user->handler_data);
544862306a36Sopenharmony_ci		}
544962306a36Sopenharmony_ci
545062306a36Sopenharmony_ci		send_panic_events(intf, ptr);
545162306a36Sopenharmony_ci	}
545262306a36Sopenharmony_ci
545362306a36Sopenharmony_ci	return NOTIFY_DONE;
545462306a36Sopenharmony_ci}
545562306a36Sopenharmony_ci
545662306a36Sopenharmony_ci/* Must be called with ipmi_interfaces_mutex held. */
545762306a36Sopenharmony_cistatic int ipmi_register_driver(void)
545862306a36Sopenharmony_ci{
545962306a36Sopenharmony_ci	int rv;
546062306a36Sopenharmony_ci
546162306a36Sopenharmony_ci	if (drvregistered)
546262306a36Sopenharmony_ci		return 0;
546362306a36Sopenharmony_ci
546462306a36Sopenharmony_ci	rv = driver_register(&ipmidriver.driver);
546562306a36Sopenharmony_ci	if (rv)
546662306a36Sopenharmony_ci		pr_err("Could not register IPMI driver\n");
546762306a36Sopenharmony_ci	else
546862306a36Sopenharmony_ci		drvregistered = true;
546962306a36Sopenharmony_ci	return rv;
547062306a36Sopenharmony_ci}
547162306a36Sopenharmony_ci
547262306a36Sopenharmony_cistatic struct notifier_block panic_block = {
547362306a36Sopenharmony_ci	.notifier_call	= panic_event,
547462306a36Sopenharmony_ci	.next		= NULL,
547562306a36Sopenharmony_ci	.priority	= 200	/* priority: INT_MAX >= x >= 0 */
547662306a36Sopenharmony_ci};
547762306a36Sopenharmony_ci
547862306a36Sopenharmony_cistatic int ipmi_init_msghandler(void)
547962306a36Sopenharmony_ci{
548062306a36Sopenharmony_ci	int rv;
548162306a36Sopenharmony_ci
548262306a36Sopenharmony_ci	mutex_lock(&ipmi_interfaces_mutex);
548362306a36Sopenharmony_ci	rv = ipmi_register_driver();
548462306a36Sopenharmony_ci	if (rv)
548562306a36Sopenharmony_ci		goto out;
548662306a36Sopenharmony_ci	if (initialized)
548762306a36Sopenharmony_ci		goto out;
548862306a36Sopenharmony_ci
548962306a36Sopenharmony_ci	rv = init_srcu_struct(&ipmi_interfaces_srcu);
549062306a36Sopenharmony_ci	if (rv)
549162306a36Sopenharmony_ci		goto out;
549262306a36Sopenharmony_ci
549362306a36Sopenharmony_ci	remove_work_wq = create_singlethread_workqueue("ipmi-msghandler-remove-wq");
549462306a36Sopenharmony_ci	if (!remove_work_wq) {
549562306a36Sopenharmony_ci		pr_err("unable to create ipmi-msghandler-remove-wq workqueue");
549662306a36Sopenharmony_ci		rv = -ENOMEM;
549762306a36Sopenharmony_ci		goto out_wq;
549862306a36Sopenharmony_ci	}
549962306a36Sopenharmony_ci
550062306a36Sopenharmony_ci	timer_setup(&ipmi_timer, ipmi_timeout, 0);
550162306a36Sopenharmony_ci	mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
550262306a36Sopenharmony_ci
550362306a36Sopenharmony_ci	atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
550462306a36Sopenharmony_ci
550562306a36Sopenharmony_ci	initialized = true;
550662306a36Sopenharmony_ci
550762306a36Sopenharmony_ciout_wq:
550862306a36Sopenharmony_ci	if (rv)
550962306a36Sopenharmony_ci		cleanup_srcu_struct(&ipmi_interfaces_srcu);
551062306a36Sopenharmony_ciout:
551162306a36Sopenharmony_ci	mutex_unlock(&ipmi_interfaces_mutex);
551262306a36Sopenharmony_ci	return rv;
551362306a36Sopenharmony_ci}
551462306a36Sopenharmony_ci
551562306a36Sopenharmony_cistatic int __init ipmi_init_msghandler_mod(void)
551662306a36Sopenharmony_ci{
551762306a36Sopenharmony_ci	int rv;
551862306a36Sopenharmony_ci
551962306a36Sopenharmony_ci	pr_info("version " IPMI_DRIVER_VERSION "\n");
552062306a36Sopenharmony_ci
552162306a36Sopenharmony_ci	mutex_lock(&ipmi_interfaces_mutex);
552262306a36Sopenharmony_ci	rv = ipmi_register_driver();
552362306a36Sopenharmony_ci	mutex_unlock(&ipmi_interfaces_mutex);
552462306a36Sopenharmony_ci
552562306a36Sopenharmony_ci	return rv;
552662306a36Sopenharmony_ci}
552762306a36Sopenharmony_ci
552862306a36Sopenharmony_cistatic void __exit cleanup_ipmi(void)
552962306a36Sopenharmony_ci{
553062306a36Sopenharmony_ci	int count;
553162306a36Sopenharmony_ci
553262306a36Sopenharmony_ci	if (initialized) {
553362306a36Sopenharmony_ci		destroy_workqueue(remove_work_wq);
553462306a36Sopenharmony_ci
553562306a36Sopenharmony_ci		atomic_notifier_chain_unregister(&panic_notifier_list,
553662306a36Sopenharmony_ci						 &panic_block);
553762306a36Sopenharmony_ci
553862306a36Sopenharmony_ci		/*
553962306a36Sopenharmony_ci		 * This can't be called if any interfaces exist, so no worry
554062306a36Sopenharmony_ci		 * about shutting down the interfaces.
554162306a36Sopenharmony_ci		 */
554262306a36Sopenharmony_ci
554362306a36Sopenharmony_ci		/*
554462306a36Sopenharmony_ci		 * Tell the timer to stop, then wait for it to stop.  This
554562306a36Sopenharmony_ci		 * avoids problems with race conditions removing the timer
554662306a36Sopenharmony_ci		 * here.
554762306a36Sopenharmony_ci		 */
554862306a36Sopenharmony_ci		atomic_set(&stop_operation, 1);
554962306a36Sopenharmony_ci		del_timer_sync(&ipmi_timer);
555062306a36Sopenharmony_ci
555162306a36Sopenharmony_ci		initialized = false;
555262306a36Sopenharmony_ci
555362306a36Sopenharmony_ci		/* Check for buffer leaks. */
555462306a36Sopenharmony_ci		count = atomic_read(&smi_msg_inuse_count);
555562306a36Sopenharmony_ci		if (count != 0)
555662306a36Sopenharmony_ci			pr_warn("SMI message count %d at exit\n", count);
555762306a36Sopenharmony_ci		count = atomic_read(&recv_msg_inuse_count);
555862306a36Sopenharmony_ci		if (count != 0)
555962306a36Sopenharmony_ci			pr_warn("recv message count %d at exit\n", count);
556062306a36Sopenharmony_ci
556162306a36Sopenharmony_ci		cleanup_srcu_struct(&ipmi_interfaces_srcu);
556262306a36Sopenharmony_ci	}
556362306a36Sopenharmony_ci	if (drvregistered)
556462306a36Sopenharmony_ci		driver_unregister(&ipmidriver.driver);
556562306a36Sopenharmony_ci}
556662306a36Sopenharmony_cimodule_exit(cleanup_ipmi);
556762306a36Sopenharmony_ci
556862306a36Sopenharmony_cimodule_init(ipmi_init_msghandler_mod);
556962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
557062306a36Sopenharmony_ciMODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
557162306a36Sopenharmony_ciMODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
557262306a36Sopenharmony_ciMODULE_VERSION(IPMI_DRIVER_VERSION);
557362306a36Sopenharmony_ciMODULE_SOFTDEP("post: ipmi_devintf");
5574