Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Corey Minyard | 19631 | 82.09% | 119 | 56.40% |
Andrew Morton | 2072 | 8.66% | 1 | 0.47% |
Jeremy Kerr | 494 | 2.07% | 2 | 0.95% |
dann frazier | 407 | 1.70% | 1 | 0.47% |
Tony Camuso | 224 | 0.94% | 3 | 1.42% |
Konstantin Baydarov | 155 | 0.65% | 2 | 0.95% |
Hidehiro Kawai | 101 | 0.42% | 3 | 1.42% |
Takashi Iwai | 98 | 0.41% | 1 | 0.47% |
Andy Shevchenko | 89 | 0.37% | 7 | 3.32% |
Arnd Bergmann | 63 | 0.26% | 2 | 0.95% |
Yakui Zhao | 59 | 0.25% | 1 | 0.47% |
Gustavo A. R. Silva | 57 | 0.24% | 1 | 0.47% |
Jeff Garzik | 46 | 0.19% | 1 | 0.47% |
Ioanna Alifieraki | 45 | 0.19% | 1 | 0.47% |
Thadeu Lima de Souza Cascardo | 25 | 0.10% | 2 | 0.95% |
Xianting Tian | 23 | 0.10% | 1 | 0.47% |
Allen Pais | 20 | 0.08% | 1 | 0.47% |
Joe Perches | 20 | 0.08% | 2 | 0.95% |
Khalid Aziz | 20 | 0.08% | 1 | 0.47% |
Jun'ichi Nomura | 19 | 0.08% | 1 | 0.47% |
Linus Torvalds (pre-git) | 18 | 0.08% | 10 | 4.74% |
Zhang Yuchen | 17 | 0.07% | 1 | 0.47% |
Amol Grover | 14 | 0.06% | 1 | 0.47% |
Darrick J. Wong | 14 | 0.06% | 1 | 0.47% |
Alexey Dobriyan | 14 | 0.06% | 1 | 0.47% |
Matthew Garrett | 14 | 0.06% | 1 | 0.47% |
Adrian Bunk | 13 | 0.05% | 2 | 0.95% |
Dan Carpenter | 12 | 0.05% | 2 | 0.95% |
Ye Guojin | 10 | 0.04% | 1 | 0.47% |
Randy Dunlap | 9 | 0.04% | 1 | 0.47% |
Navid Emamdoost | 7 | 0.03% | 1 | 0.47% |
Al Viro | 6 | 0.03% | 1 | 0.47% |
Markus Boehme | 6 | 0.03% | 1 | 0.47% |
Jakub Kiciński | 6 | 0.03% | 1 | 0.47% |
David Barksdale | 6 | 0.03% | 1 | 0.47% |
Feng Tang | 6 | 0.03% | 1 | 0.47% |
Martin Wilck | 5 | 0.02% | 1 | 0.47% |
Kees Cook | 5 | 0.02% | 1 | 0.47% |
Christoph Hellwig | 5 | 0.02% | 1 | 0.47% |
Myron Stowe | 5 | 0.02% | 1 | 0.47% |
Paul E. McKenney | 4 | 0.02% | 1 | 0.47% |
Suzuki K. Poulose | 4 | 0.02% | 1 | 0.47% |
Yang Yingliang | 4 | 0.02% | 1 | 0.47% |
Cheng Renquan | 4 | 0.02% | 1 | 0.47% |
Bo Wu | 3 | 0.01% | 1 | 0.47% |
Lee Revell | 3 | 0.01% | 1 | 0.47% |
Hironobu Ishii | 3 | 0.01% | 1 | 0.47% |
Thomas Gleixner | 3 | 0.01% | 1 | 0.47% |
Yue haibing | 2 | 0.01% | 2 | 0.95% |
Alan Cox | 2 | 0.01% | 1 | 0.47% |
Arvind Yadav | 2 | 0.01% | 1 | 0.47% |
Qinglang Miao | 2 | 0.01% | 1 | 0.47% |
Zaur Kambarov | 2 | 0.01% | 1 | 0.47% |
Alan Stern | 2 | 0.01% | 1 | 0.47% |
Corentin Labbe | 2 | 0.01% | 1 | 0.47% |
Matt Domsch | 1 | 0.00% | 1 | 0.47% |
Xie XiuQi | 1 | 0.00% | 1 | 0.47% |
Jayachandran C | 1 | 0.00% | 1 | 0.47% |
Akinobu Mita | 1 | 0.00% | 1 | 0.47% |
Adam Buchbinder | 1 | 0.00% | 1 | 0.47% |
Bo Liu | 1 | 0.00% | 1 | 0.47% |
Yoann Padioleau | 1 | 0.00% | 1 | 0.47% |
Wen Yang | 1 | 0.00% | 1 | 0.47% |
Linus Torvalds | 1 | 0.00% | 1 | 0.47% |
Hui Wang | 1 | 0.00% | 1 | 0.47% |
Wei Yongjun | 1 | 0.00% | 1 | 0.47% |
Total | 23913 | 211 |
// SPDX-License-Identifier: GPL-2.0+ /* * ipmi_msghandler.c * * Incoming and outgoing message routing for an IPMI interface. * * Author: MontaVista Software, Inc. * Corey Minyard <minyard@mvista.com> * source@mvista.com * * Copyright 2002 MontaVista Software Inc. */ #define pr_fmt(fmt) "IPMI message handler: " fmt #define dev_fmt(fmt) pr_fmt(fmt) #include <linux/module.h> #include <linux/errno.h> #include <linux/panic_notifier.h> #include <linux/poll.h> #include <linux/sched.h> #include <linux/seq_file.h> #include <linux/spinlock.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/ipmi.h> #include <linux/ipmi_smi.h> #include <linux/notifier.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/rcupdate.h> #include <linux/interrupt.h> #include <linux/moduleparam.h> #include <linux/workqueue.h> #include <linux/uuid.h> #include <linux/nospec.h> #include <linux/vmalloc.h> #include <linux/delay.h> #define IPMI_DRIVER_VERSION "39.2" static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); static void smi_recv_tasklet(struct tasklet_struct *t); static void handle_new_recv_msgs(struct ipmi_smi *intf); static void need_waiter(struct ipmi_smi *intf); static int handle_one_recv_msg(struct ipmi_smi *intf, struct ipmi_smi_msg *msg); static bool initialized; static bool drvregistered; /* Numbers in this enumerator should be mapped to ipmi_panic_event_str */ enum ipmi_panic_event_op { IPMI_SEND_PANIC_EVENT_NONE, IPMI_SEND_PANIC_EVENT, IPMI_SEND_PANIC_EVENT_STRING, IPMI_SEND_PANIC_EVENT_MAX }; /* Indices in this array should be mapped to enum ipmi_panic_event_op */ static const char *const ipmi_panic_event_str[] = { "none", "event", "string", NULL }; #ifdef CONFIG_IPMI_PANIC_STRING #define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_STRING #elif defined(CONFIG_IPMI_PANIC_EVENT) #define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT #else #define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_NONE #endif static enum ipmi_panic_event_op ipmi_send_panic_event = IPMI_PANIC_DEFAULT; static int panic_op_write_handler(const char *val, const struct kernel_param *kp) { char valcp[16]; int e; strscpy(valcp, val, sizeof(valcp)); e = match_string(ipmi_panic_event_str, -1, strstrip(valcp)); if (e < 0) return e; ipmi_send_panic_event = e; return 0; } static int panic_op_read_handler(char *buffer, const struct kernel_param *kp) { const char *event_str; if (ipmi_send_panic_event >= IPMI_SEND_PANIC_EVENT_MAX) event_str = "???"; else event_str = ipmi_panic_event_str[ipmi_send_panic_event]; return sprintf(buffer, "%s\n", event_str); } static const struct kernel_param_ops panic_op_ops = { .set = panic_op_write_handler, .get = panic_op_read_handler }; module_param_cb(panic_op, &panic_op_ops, NULL, 0600); MODULE_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."); #define MAX_EVENTS_IN_QUEUE 25 /* Remain in auto-maintenance mode for this amount of time (in ms). */ static unsigned long maintenance_mode_timeout_ms = 30000; module_param(maintenance_mode_timeout_ms, ulong, 0644); MODULE_PARM_DESC(maintenance_mode_timeout_ms, "The time (milliseconds) after the last maintenance message that the connection stays in maintenance mode."); /* * Don't let a message sit in a queue forever, always time it with at lest * the max message timer. This is in milliseconds. */ #define MAX_MSG_TIMEOUT 60000 /* * Timeout times below are in milliseconds, and are done off a 1 * second timer. So setting the value to 1000 would mean anything * between 0 and 1000ms. So really the only reasonable minimum * setting it 2000ms, which is between 1 and 2 seconds. */ /* The default timeout for message retries. */ static unsigned long default_retry_ms = 2000; module_param(default_retry_ms, ulong, 0644); MODULE_PARM_DESC(default_retry_ms, "The time (milliseconds) between retry sends"); /* The default timeout for maintenance mode message retries. */ static unsigned long default_maintenance_retry_ms = 3000; module_param(default_maintenance_retry_ms, ulong, 0644); MODULE_PARM_DESC(default_maintenance_retry_ms, "The time (milliseconds) between retry sends in maintenance mode"); /* The default maximum number of retries */ static unsigned int default_max_retries = 4; module_param(default_max_retries, uint, 0644); MODULE_PARM_DESC(default_max_retries, "The time (milliseconds) between retry sends in maintenance mode"); /* The default maximum number of users that may register. */ static unsigned int max_users = 30; module_param(max_users, uint, 0644); MODULE_PARM_DESC(max_users, "The most users that may use the IPMI stack at one time."); /* The default maximum number of message a user may have outstanding. */ static unsigned int max_msgs_per_user = 100; module_param(max_msgs_per_user, uint, 0644); MODULE_PARM_DESC(max_msgs_per_user, "The most message a user may have outstanding."); /* Call every ~1000 ms. */ #define IPMI_TIMEOUT_TIME 1000 /* How many jiffies does it take to get to the timeout time. */ #define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000) /* * Request events from the queue every second (this is the number of * IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the * future, IPMI will add a way to know immediately if an event is in * the queue and this silliness can go away. */ #define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME)) /* How long should we cache dynamic device IDs? */ #define IPMI_DYN_DEV_ID_EXPIRY (10 * HZ) /* * The main "user" data structure. */ struct ipmi_user { struct list_head link; /* * Set to NULL when the user is destroyed, a pointer to myself * so srcu_dereference can be used on it. */ struct ipmi_user *self; struct srcu_struct release_barrier; struct kref refcount; /* The upper layer that handles receive messages. */ const struct ipmi_user_hndl *handler; void *handler_data; /* The interface this user is bound to. */ struct ipmi_smi *intf; /* Does this interface receive IPMI events? */ bool gets_events; atomic_t nr_msgs; /* Free must run in process context for RCU cleanup. */ struct work_struct remove_work; }; static struct workqueue_struct *remove_work_wq; static struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index) __acquires(user->release_barrier) { struct ipmi_user *ruser; *index = srcu_read_lock(&user->release_barrier); ruser = srcu_dereference(user->self, &user->release_barrier); if (!ruser) srcu_read_unlock(&user->release_barrier, *index); return ruser; } static void release_ipmi_user(struct ipmi_user *user, int index) { srcu_read_unlock(&user->release_barrier, index); } struct cmd_rcvr { struct list_head link; struct ipmi_user *user; unsigned char netfn; unsigned char cmd; unsigned int chans; /* * This is used to form a linked lised during mass deletion. * Since this is in an RCU list, we cannot use the link above * or change any data until the RCU period completes. So we * use this next variable during mass deletion so we can have * a list and don't have to wait and restart the search on * every individual deletion of a command. */ struct cmd_rcvr *next; }; struct seq_table { unsigned int inuse : 1; unsigned int broadcast : 1; unsigned long timeout; unsigned long orig_timeout; unsigned int retries_left; /* * To verify on an incoming send message response that this is * the message that the response is for, we keep a sequence id * and increment it every time we send a message. */ long seqid; /* * This is held so we can properly respond to the message on a * timeout, and it is used to hold the temporary data for * retransmission, too. */ struct ipmi_recv_msg *recv_msg; }; /* * Store the information in a msgid (long) to allow us to find a * sequence table entry from the msgid. */ #define STORE_SEQ_IN_MSGID(seq, seqid) \ ((((seq) & 0x3f) << 26) | ((seqid) & 0x3ffffff)) #define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \ do { \ seq = (((msgid) >> 26) & 0x3f); \ seqid = ((msgid) & 0x3ffffff); \ } while (0) #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3ffffff) #define IPMI_MAX_CHANNELS 16 struct ipmi_channel { unsigned char medium; unsigned char protocol; }; struct ipmi_channel_set { struct ipmi_channel c[IPMI_MAX_CHANNELS]; }; struct ipmi_my_addrinfo { /* * My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, * but may be changed by the user. */ unsigned char address; /* * My LUN. This should generally stay the SMS LUN, but just in * case... */ unsigned char lun; }; /* * Note that the product id, manufacturer id, guid, and device id are * immutable in this structure, so dyn_mutex is not required for * accessing those. If those change on a BMC, a new BMC is allocated. */ struct bmc_device { struct platform_device pdev; struct list_head intfs; /* Interfaces on this BMC. */ struct ipmi_device_id id; struct ipmi_device_id fetch_id; int dyn_id_set; unsigned long dyn_id_expiry; struct mutex dyn_mutex; /* Protects id, intfs, & dyn* */ guid_t guid; guid_t fetch_guid; int dyn_guid_set; struct kref usecount; struct work_struct remove_work; unsigned char cc; /* completion code */ }; #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev) static int bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc, struct ipmi_device_id *id, bool *guid_set, guid_t *guid); /* * Various statistics for IPMI, these index stats[] in the ipmi_smi * structure. */ enum ipmi_stat_indexes { /* Commands we got from the user that were invalid. */ IPMI_STAT_sent_invalid_commands = 0, /* Commands we sent to the MC. */ IPMI_STAT_sent_local_commands, /* Responses from the MC that were delivered to a user. */ IPMI_STAT_handled_local_responses, /* Responses from the MC that were not delivered to a user. */ IPMI_STAT_unhandled_local_responses, /* Commands we sent out to the IPMB bus. */ IPMI_STAT_sent_ipmb_commands, /* Commands sent on the IPMB that had errors on the SEND CMD */ IPMI_STAT_sent_ipmb_command_errs, /* Each retransmit increments this count. */ IPMI_STAT_retransmitted_ipmb_commands, /* * When a message times out (runs out of retransmits) this is * incremented. */ IPMI_STAT_timed_out_ipmb_commands, /* * This is like above, but for broadcasts. Broadcasts are * *not* included in the above count (they are expected to * time out). */ IPMI_STAT_timed_out_ipmb_broadcasts, /* Responses I have sent to the IPMB bus. */ IPMI_STAT_sent_ipmb_responses, /* The response was delivered to the user. */ IPMI_STAT_handled_ipmb_responses, /* The response had invalid data in it. */ IPMI_STAT_invalid_ipmb_responses, /* The response didn't have anyone waiting for it. */ IPMI_STAT_unhandled_ipmb_responses, /* Commands we sent out to the IPMB bus. */ IPMI_STAT_sent_lan_commands, /* Commands sent on the IPMB that had errors on the SEND CMD */ IPMI_STAT_sent_lan_command_errs, /* Each retransmit increments this count. */ IPMI_STAT_retransmitted_lan_commands, /* * When a message times out (runs out of retransmits) this is * incremented. */ IPMI_STAT_timed_out_lan_commands, /* Responses I have sent to the IPMB bus. */ IPMI_STAT_sent_lan_responses, /* The response was delivered to the user. */ IPMI_STAT_handled_lan_responses, /* The response had invalid data in it. */ IPMI_STAT_invalid_lan_responses, /* The response didn't have anyone waiting for it. */ IPMI_STAT_unhandled_lan_responses, /* The command was delivered to the user. */ IPMI_STAT_handled_commands, /* The command had invalid data in it. */ IPMI_STAT_invalid_commands, /* The command didn't have anyone waiting for it. */ IPMI_STAT_unhandled_commands, /* Invalid data in an event. */ IPMI_STAT_invalid_events, /* Events that were received with the proper format. */ IPMI_STAT_events, /* Retransmissions on IPMB that failed. */ IPMI_STAT_dropped_rexmit_ipmb_commands, /* Retransmissions on LAN that failed. */ IPMI_STAT_dropped_rexmit_lan_commands, /* This *must* remain last, add new values above this. */ IPMI_NUM_STATS }; #define IPMI_IPMB_NUM_SEQ 64 struct ipmi_smi { struct module *owner; /* What interface number are we? */ int intf_num; struct kref refcount; /* Set when the interface is being unregistered. */ bool in_shutdown; /* Used for a list of interfaces. */ struct list_head link; /* * The list of upper layers that are using me. seq_lock write * protects this. Read protection is with srcu. */ struct list_head users; struct srcu_struct users_srcu; atomic_t nr_users; struct device_attribute nr_users_devattr; struct device_attribute nr_msgs_devattr; /* Used for wake ups at startup. */ wait_queue_head_t waitq; /* * Prevents the interface from being unregistered when the * interface is used by being looked up through the BMC * structure. */ struct mutex bmc_reg_mutex; struct bmc_device tmp_bmc; struct bmc_device *bmc; bool bmc_registered; struct list_head bmc_link; char *my_dev_name; bool in_bmc_register; /* Handle recursive situations. Yuck. */ struct work_struct bmc_reg_work; const struct ipmi_smi_handlers *handlers; void *send_info; /* Driver-model device for the system interface. */ struct device *si_dev; /* * A table of sequence numbers for this interface. We use the * sequence numbers for IPMB messages that go out of the * interface to match them up with their responses. A routine * is called periodically to time the items in this list. */ spinlock_t seq_lock; struct seq_table seq_table[IPMI_IPMB_NUM_SEQ]; int curr_seq; /* * Messages queued for delivery. If delivery fails (out of memory * for instance), They will stay in here to be processed later in a * periodic timer interrupt. The tasklet is for handling received * messages directly from the handler. */ spinlock_t waiting_rcv_msgs_lock; struct list_head waiting_rcv_msgs; atomic_t watchdog_pretimeouts_to_deliver; struct tasklet_struct recv_tasklet; spinlock_t xmit_msgs_lock; struct list_head xmit_msgs; struct ipmi_smi_msg *curr_msg; struct list_head hp_xmit_msgs; /* * The list of command receivers that are registered for commands * on this interface. */ struct mutex cmd_rcvrs_mutex; struct list_head cmd_rcvrs; /* * Events that were queues because no one was there to receive * them. */ spinlock_t events_lock; /* For dealing with event stuff. */ struct list_head waiting_events; unsigned int waiting_events_count; /* How many events in queue? */ char delivering_events; char event_msg_printed; /* How many users are waiting for events? */ atomic_t event_waiters; unsigned int ticks_to_req_ev; spinlock_t watch_lock; /* For dealing with watch stuff below. */ /* How many users are waiting for commands? */ unsigned int command_waiters; /* How many users are waiting for watchdogs? */ unsigned int watchdog_waiters; /* How many users are waiting for message responses? */ unsigned int response_waiters; /* * Tells what the lower layer has last been asked to watch for, * messages and/or watchdogs. Protected by watch_lock. */ unsigned int last_watch_mask; /* * The event receiver for my BMC, only really used at panic * shutdown as a place to store this. */ unsigned char event_receiver; unsigned char event_receiver_lun; unsigned char local_sel_device; unsigned char local_event_generator; /* For handling of maintenance mode. */ int maintenance_mode; bool maintenance_mode_enable; int auto_maintenance_timeout; spinlock_t maintenance_mode_lock; /* Used in a timer... */ /* * If we are doing maintenance on something on IPMB, extend * the timeout time to avoid timeouts writing firmware and * such. */ int ipmb_maintenance_mode_timeout; /* * A cheap hack, if this is non-null and a message to an * interface comes in with a NULL user, call this routine with * it. Note that the message will still be freed by the * caller. This only works on the system interface. * * Protected by bmc_reg_mutex. */ void (*null_user_handler)(struct ipmi_smi *intf, struct ipmi_recv_msg *msg); /* * When we are scanning the channels for an SMI, this will * tell which channel we are scanning. */ int curr_channel; /* Channel information */ struct ipmi_channel_set *channel_list; unsigned int curr_working_cset; /* First index into the following. */ struct ipmi_channel_set wchannels[2]; struct ipmi_my_addrinfo addrinfo[IPMI_MAX_CHANNELS]; bool channels_ready; atomic_t stats[IPMI_NUM_STATS]; /* * run_to_completion duplicate of smb_info, smi_info * and ipmi_serial_info structures. Used to decrease numbers of * parameters passed by "low" level IPMI code. */ int run_to_completion; }; #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) static void __get_guid(struct ipmi_smi *intf); static void __ipmi_bmc_unregister(struct ipmi_smi *intf); static int __ipmi_bmc_register(struct ipmi_smi *intf, struct ipmi_device_id *id, bool guid_set, guid_t *guid, int intf_num); static int __scan_channels(struct ipmi_smi *intf, struct ipmi_device_id *id); /* * The driver model view of the IPMI messaging driver. */ static struct platform_driver ipmidriver = { .driver = { .name = "ipmi", .bus = &platform_bus_type } }; /* * This mutex keeps us from adding the same BMC twice. */ static DEFINE_MUTEX(ipmidriver_mutex); static LIST_HEAD(ipmi_interfaces); static DEFINE_MUTEX(ipmi_interfaces_mutex); #define ipmi_interfaces_mutex_held() \ lockdep_is_held(&ipmi_interfaces_mutex) static struct srcu_struct ipmi_interfaces_srcu; /* * List of watchers that want to know when smi's are added and deleted. */ static LIST_HEAD(smi_watchers); static DEFINE_MUTEX(smi_watchers_mutex); #define ipmi_inc_stat(intf, stat) \ atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat]) #define ipmi_get_stat(intf, stat) \ ((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat])) static const char * const addr_src_to_str[] = { "invalid", "hotmod", "hardcoded", "SPMI", "ACPI", "SMBIOS", "PCI", "device-tree", "platform" }; const char *ipmi_addr_src_to_str(enum ipmi_addr_src src) { if (src >= SI_LAST) src = 0; /* Invalid */ return addr_src_to_str[src]; } EXPORT_SYMBOL(ipmi_addr_src_to_str); static int is_lan_addr(struct ipmi_addr *addr) { return addr->addr_type == IPMI_LAN_ADDR_TYPE; } static int is_ipmb_addr(struct ipmi_addr *addr) { return addr->addr_type == IPMI_IPMB_ADDR_TYPE; } static int is_ipmb_bcast_addr(struct ipmi_addr *addr) { return addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE; } static int is_ipmb_direct_addr(struct ipmi_addr *addr) { return addr->addr_type == IPMI_IPMB_DIRECT_ADDR_TYPE; } static void free_recv_msg_list(struct list_head *q) { struct ipmi_recv_msg *msg, *msg2; list_for_each_entry_safe(msg, msg2, q, link) { list_del(&msg->link); ipmi_free_recv_msg(msg); } } static void free_smi_msg_list(struct list_head *q) { struct ipmi_smi_msg *msg, *msg2; list_for_each_entry_safe(msg, msg2, q, link) { list_del(&msg->link); ipmi_free_smi_msg(msg); } } static void clean_up_interface_data(struct ipmi_smi *intf) { int i; struct cmd_rcvr *rcvr, *rcvr2; struct list_head list; tasklet_kill(&intf->recv_tasklet); free_smi_msg_list(&intf->waiting_rcv_msgs); free_recv_msg_list(&intf->waiting_events); /* * Wholesale remove all the entries from the list in the * interface and wait for RCU to know that none are in use. */ mutex_lock(&intf->cmd_rcvrs_mutex); INIT_LIST_HEAD(&list); list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu); mutex_unlock(&intf->cmd_rcvrs_mutex); list_for_each_entry_safe(rcvr, rcvr2, &list, link) kfree(rcvr); for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if ((intf->seq_table[i].inuse) && (intf->seq_table[i].recv_msg)) ipmi_free_recv_msg(intf->seq_table[i].recv_msg); } } static void intf_free(struct kref *ref) { struct ipmi_smi *intf = container_of(ref, struct ipmi_smi, refcount); clean_up_interface_data(intf); kfree(intf); } int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) { struct ipmi_smi *intf; int index, rv; /* * Make sure the driver is actually initialized, this handles * problems with initialization order. */ rv = ipmi_init_msghandler(); if (rv) return rv; mutex_lock(&smi_watchers_mutex); list_add(&watcher->link, &smi_watchers); index = srcu_read_lock(&ipmi_interfaces_srcu); list_for_each_entry_rcu(intf, &ipmi_interfaces, link, lockdep_is_held(&smi_watchers_mutex)) { int intf_num = READ_ONCE(intf->intf_num); if (intf_num == -1) continue; watcher->new_smi(intf_num, intf->si_dev); } srcu_read_unlock(&ipmi_interfaces_srcu, index); mutex_unlock(&smi_watchers_mutex); return 0; } EXPORT_SYMBOL(ipmi_smi_watcher_register); int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) { mutex_lock(&smi_watchers_mutex); list_del(&watcher->link); mutex_unlock(&smi_watchers_mutex); return 0; } EXPORT_SYMBOL(ipmi_smi_watcher_unregister); /* * Must be called with smi_watchers_mutex held. */ static void call_smi_watchers(int i, struct device *dev) { struct ipmi_smi_watcher *w; mutex_lock(&smi_watchers_mutex); list_for_each_entry(w, &smi_watchers, link) { if (try_module_get(w->owner)) { w->new_smi(i, dev); module_put(w->owner); } } mutex_unlock(&smi_watchers_mutex); } static int ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2) { if (addr1->addr_type != addr2->addr_type) return 0; if (addr1->channel != addr2->channel) return 0; if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { struct ipmi_system_interface_addr *smi_addr1 = (struct ipmi_system_interface_addr *) addr1; struct ipmi_system_interface_addr *smi_addr2 = (struct ipmi_system_interface_addr *) addr2; return (smi_addr1->lun == smi_addr2->lun); } if (is_ipmb_addr(addr1) || is_ipmb_bcast_addr(addr1)) { struct ipmi_ipmb_addr *ipmb_addr1 = (struct ipmi_ipmb_addr *) addr1; struct ipmi_ipmb_addr *ipmb_addr2 = (struct ipmi_ipmb_addr *) addr2; return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr) && (ipmb_addr1->lun == ipmb_addr2->lun)); } if (is_ipmb_direct_addr(addr1)) { struct ipmi_ipmb_direct_addr *daddr1 = (struct ipmi_ipmb_direct_addr *) addr1; struct ipmi_ipmb_direct_addr *daddr2 = (struct ipmi_ipmb_direct_addr *) addr2; return daddr1->slave_addr == daddr2->slave_addr && daddr1->rq_lun == daddr2->rq_lun && daddr1->rs_lun == daddr2->rs_lun; } if (is_lan_addr(addr1)) { struct ipmi_lan_addr *lan_addr1 = (struct ipmi_lan_addr *) addr1; struct ipmi_lan_addr *lan_addr2 = (struct ipmi_lan_addr *) addr2; return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID) && (lan_addr1->local_SWID == lan_addr2->local_SWID) && (lan_addr1->session_handle == lan_addr2->session_handle) && (lan_addr1->lun == lan_addr2->lun)); } return 1; } int ipmi_validate_addr(struct ipmi_addr *addr, int len) { if (len < sizeof(struct ipmi_system_interface_addr)) return -EINVAL; if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { if (addr->channel != IPMI_BMC_CHANNEL) return -EINVAL; return 0; } if ((addr->channel == IPMI_BMC_CHANNEL) || (addr->channel >= IPMI_MAX_CHANNELS) || (addr->channel < 0)) return -EINVAL; if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) { if (len < sizeof(struct ipmi_ipmb_addr)) return -EINVAL; return 0; } if (is_ipmb_direct_addr(addr)) { struct ipmi_ipmb_direct_addr *daddr = (void *) addr; if (addr->channel != 0) return -EINVAL; if (len < sizeof(struct ipmi_ipmb_direct_addr)) return -EINVAL; if (daddr->slave_addr & 0x01) return -EINVAL; if (daddr->rq_lun >= 4) return -EINVAL; if (daddr->rs_lun >= 4) return -EINVAL; return 0; } if (is_lan_addr(addr)) { if (len < sizeof(struct ipmi_lan_addr)) return -EINVAL; return 0; } return -EINVAL; } EXPORT_SYMBOL(ipmi_validate_addr); unsigned int ipmi_addr_length(int addr_type) { if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) return sizeof(struct ipmi_system_interface_addr); if ((addr_type == IPMI_IPMB_ADDR_TYPE) || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) return sizeof(struct ipmi_ipmb_addr); if (addr_type == IPMI_IPMB_DIRECT_ADDR_TYPE) return sizeof(struct ipmi_ipmb_direct_addr); if (addr_type == IPMI_LAN_ADDR_TYPE) return sizeof(struct ipmi_lan_addr); return 0; } EXPORT_SYMBOL(ipmi_addr_length); static int deliver_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) { int rv = 0; if (!msg->user) { /* Special handling for NULL users. */ if (intf->null_user_handler) { intf->null_user_handler(intf, msg); } else { /* No handler, so give up. */ rv = -EINVAL; } ipmi_free_recv_msg(msg); } else if (oops_in_progress) { /* * If we are running in the panic context, calling the * receive handler doesn't much meaning and has a deadlock * risk. At this moment, simply skip it in that case. */ ipmi_free_recv_msg(msg); atomic_dec(&msg->user->nr_msgs); } else { int index; struct ipmi_user *user = acquire_ipmi_user(msg->user, &index); if (user) { atomic_dec(&user->nr_msgs); user->handler->ipmi_recv_hndl(msg, user->handler_data); release_ipmi_user(user, index); } else { /* User went away, give up. */ ipmi_free_recv_msg(msg); rv = -EINVAL; } } return rv; } static void deliver_local_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) { if (deliver_response(intf, msg)) ipmi_inc_stat(intf, unhandled_local_responses); else ipmi_inc_stat(intf, handled_local_responses); } static void deliver_err_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg, int err) { msg->recv_type = IPMI_RESPONSE_RECV_TYPE; msg->msg_data[0] = err; msg->msg.netfn |= 1; /* Convert to a response. */ msg->msg.data_len = 1; msg->msg.data = msg->msg_data; deliver_local_response(intf, msg); } static void smi_add_watch(struct ipmi_smi *intf, unsigned int flags) { unsigned long iflags; if (!intf->handlers->set_need_watch) return; spin_lock_irqsave(&intf->watch_lock, iflags); if (flags & IPMI_WATCH_MASK_CHECK_MESSAGES) intf->response_waiters++; if (flags & IPMI_WATCH_MASK_CHECK_WATCHDOG) intf->watchdog_waiters++; if (flags & IPMI_WATCH_MASK_CHECK_COMMANDS) intf->command_waiters++; if ((intf->last_watch_mask & flags) != flags) { intf->last_watch_mask |= flags; intf->handlers->set_need_watch(intf->send_info, intf->last_watch_mask); } spin_unlock_irqrestore(&intf->watch_lock, iflags); } static void smi_remove_watch(struct ipmi_smi *intf, unsigned int flags) { unsigned long iflags; if (!intf->handlers->set_need_watch) return; spin_lock_irqsave(&intf->watch_lock, iflags); if (flags & IPMI_WATCH_MASK_CHECK_MESSAGES) intf->response_waiters--; if (flags & IPMI_WATCH_MASK_CHECK_WATCHDOG) intf->watchdog_waiters--; if (flags & IPMI_WATCH_MASK_CHECK_COMMANDS) intf->command_waiters--; flags = 0; if (intf->response_waiters) flags |= IPMI_WATCH_MASK_CHECK_MESSAGES; if (intf->watchdog_waiters) flags |= IPMI_WATCH_MASK_CHECK_WATCHDOG; if (intf->command_waiters) flags |= IPMI_WATCH_MASK_CHECK_COMMANDS; if (intf->last_watch_mask != flags) { intf->last_watch_mask = flags; intf->handlers->set_need_watch(intf->send_info, intf->last_watch_mask); } spin_unlock_irqrestore(&intf->watch_lock, iflags); } /* * Find the next sequence number not being used and add the given * message with the given timeout to the sequence table. This must be * called with the interface's seq_lock held. */ static int intf_next_seq(struct ipmi_smi *intf, struct ipmi_recv_msg *recv_msg, unsigned long timeout, int retries, int broadcast, unsigned char *seq, long *seqid) { int rv = 0; unsigned int i; if (timeout == 0) timeout = default_retry_ms; if (retries < 0) retries = default_max_retries; for (i = intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; i = (i+1)%IPMI_IPMB_NUM_SEQ) { if (!intf->seq_table[i].inuse) break; } if (!intf->seq_table[i].inuse) { intf->seq_table[i].recv_msg = recv_msg; /* * Start with the maximum timeout, when the send response * comes in we will start the real timer. */ intf->seq_table[i].timeout = MAX_MSG_TIMEOUT; intf->seq_table[i].orig_timeout = timeout; intf->seq_table[i].retries_left = retries; intf->seq_table[i].broadcast = broadcast; intf->seq_table[i].inuse = 1; intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid); *seq = i; *seqid = intf->seq_table[i].seqid; intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ; smi_add_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES); need_waiter(intf); } else { rv = -EAGAIN; } return rv; } /* * Return the receive message for the given sequence number and * release the sequence number so it can be reused. Some other data * is passed in to be sure the message matches up correctly (to help * guard against message coming in after their timeout and the * sequence number being reused). */ static int intf_find_seq(struct ipmi_smi *intf, unsigned char seq, short channel, unsigned char cmd, unsigned char netfn, struct ipmi_addr *addr, struct ipmi_recv_msg **recv_msg) { int rv = -ENODEV; unsigned long flags; if (seq >= IPMI_IPMB_NUM_SEQ) return -EINVAL; spin_lock_irqsave(&intf->seq_lock, flags); if (intf->seq_table[seq].inuse) { struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg; if ((msg->addr.channel == channel) && (msg->msg.cmd == cmd) && (msg->msg.netfn == netfn) && (ipmi_addr_equal(addr, &msg->addr))) { *recv_msg = msg; intf->seq_table[seq].inuse = 0; smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES); rv = 0; } } spin_unlock_irqrestore(&intf->seq_lock, flags); return rv; } /* Start the timer for a specific sequence table entry. */ static int intf_start_seq_timer(struct ipmi_smi *intf, long msgid) { int rv = -ENODEV; unsigned long flags; unsigned char seq; unsigned long seqid; GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&intf->seq_lock, flags); /* * We do this verification because the user can be deleted * while a message is outstanding. */ if ((intf->seq_table[seq].inuse) && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &intf->seq_table[seq]; ent->timeout = ent->orig_timeout; rv = 0; } spin_unlock_irqrestore(&intf->seq_lock, flags); return rv; } /* Got an error for the send message for a specific sequence number. */ static int intf_err_seq(struct ipmi_smi *intf, long msgid, unsigned int err) { int rv = -ENODEV; unsigned long flags; unsigned char seq; unsigned long seqid; struct ipmi_recv_msg *msg = NULL; GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&intf->seq_lock, flags); /* * We do this verification because the user can be deleted * while a message is outstanding. */ if ((intf->seq_table[seq].inuse) && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &intf->seq_table[seq]; ent->inuse = 0; smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES); msg = ent->recv_msg; rv = 0; } spin_unlock_irqrestore(&intf->seq_lock, flags); if (msg) deliver_err_response(intf, msg, err); return rv; } static void free_user_work(struct work_struct *work) { struct ipmi_user *user = container_of(work, struct ipmi_user, remove_work); cleanup_srcu_struct(&user->release_barrier); vfree(user); } int ipmi_create_user(unsigned int if_num, const struct ipmi_user_hndl *handler, void *handler_data, struct ipmi_user **user) { unsigned long flags; struct ipmi_user *new_user; int rv, index; struct ipmi_smi *intf; /* * There is no module usecount here, because it's not * required. Since this can only be used by and called from * other modules, they will implicitly use this module, and * thus this can't be removed unless the other modules are * removed. */ if (handler == NULL) return -EINVAL; /* * Make sure the driver is actually initialized, this handles * problems with initialization order. */ rv = ipmi_init_msghandler(); if (rv) return rv; new_user = vzalloc(sizeof(*new_user)); if (!new_user) return -ENOMEM; index = srcu_read_lock(&ipmi_interfaces_srcu); list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { if (intf->intf_num == if_num) goto found; } /* Not found, return an error */ rv = -EINVAL; goto out_kfree; found: if (atomic_add_return(1, &intf->nr_users) > max_users) { rv = -EBUSY; goto out_kfree; } INIT_WORK(&new_user->remove_work, free_user_work); rv = init_srcu_struct(&new_user->release_barrier); if (rv) goto out_kfree; if (!try_module_get(intf->owner)) { rv = -ENODEV; goto out_kfree; } /* Note that each existing user holds a refcount to the interface. */ kref_get(&intf->refcount); atomic_set(&new_user->nr_msgs, 0); kref_init(&new_user->refcount); new_user->handler = handler; new_user->handler_data = handler_data; new_user->intf = intf; new_user->gets_events = false; rcu_assign_pointer(new_user->self, new_user); spin_lock_irqsave(&intf->seq_lock, flags); list_add_rcu(&new_user->link, &intf->users); spin_unlock_irqrestore(&intf->seq_lock, flags); if (handler->ipmi_watchdog_pretimeout) /* User wants pretimeouts, so make sure to watch for them. */ smi_add_watch(intf, IPMI_WATCH_MASK_CHECK_WATCHDOG); srcu_read_unlock(&ipmi_interfaces_srcu, index); *user = new_user; return 0; out_kfree: atomic_dec(&intf->nr_users); srcu_read_unlock(&ipmi_interfaces_srcu, index); vfree(new_user); return rv; } EXPORT_SYMBOL(ipmi_create_user); int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data) { int rv, index; struct ipmi_smi *intf; index = srcu_read_lock(&ipmi_interfaces_srcu); list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { if (intf->intf_num == if_num) goto found; } srcu_read_unlock(&ipmi_interfaces_srcu, index); /* Not found, return an error */ return -EINVAL; found: if (!intf->handlers->get_smi_info) rv = -ENOTTY; else rv = intf->handlers->get_smi_info(intf->send_info, data); srcu_read_unlock(&ipmi_interfaces_srcu, index); return rv; } EXPORT_SYMBOL(ipmi_get_smi_info); static void free_user(struct kref *ref) { struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount); /* SRCU cleanup must happen in task context. */ queue_work(remove_work_wq, &user->remove_work); } static void _ipmi_destroy_user(struct ipmi_user *user) { struct ipmi_smi *intf = user->intf; int i; unsigned long flags; struct cmd_rcvr *rcvr; struct cmd_rcvr *rcvrs = NULL; struct module *owner; if (!acquire_ipmi_user(user, &i)) { /* * The user has already been cleaned up, just make sure * nothing is using it and return. */ synchronize_srcu(&user->release_barrier); return; } rcu_assign_pointer(user->self, NULL); release_ipmi_user(user, i); synchronize_srcu(&user->release_barrier); if (user->handler->shutdown) user->handler->shutdown(user->handler_data); if (user->handler->ipmi_watchdog_pretimeout) smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_WATCHDOG); if (user->gets_events) atomic_dec(&intf->event_waiters); /* Remove the user from the interface's sequence table. */ spin_lock_irqsave(&intf->seq_lock, flags); list_del_rcu(&user->link); atomic_dec(&intf->nr_users); for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if (intf->seq_table[i].inuse && (intf->seq_table[i].recv_msg->user == user)) { intf->seq_table[i].inuse = 0; smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES); ipmi_free_recv_msg(intf->seq_table[i].recv_msg); } } spin_unlock_irqrestore(&intf->seq_lock, flags); /* * Remove the user from the command receiver's table. First * we build a list of everything (not using the standard link, * since other things may be using it till we do * synchronize_srcu()) then free everything in that list. */ mutex_lock(&intf->cmd_rcvrs_mutex); list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link, lockdep_is_held(&intf->cmd_rcvrs_mutex)) { if (rcvr->user == user) { list_del_rcu(&rcvr->link); rcvr->next = rcvrs; rcvrs = rcvr; } } mutex_unlock(&intf->cmd_rcvrs_mutex); synchronize_rcu(); while (rcvrs) { rcvr = rcvrs; rcvrs = rcvr->next; kfree(rcvr); } owner = intf->owner; kref_put(&intf->refcount, intf_free); module_put(owner); } int ipmi_destroy_user(struct ipmi_user *user) { _ipmi_destroy_user(user); kref_put(&user->refcount, free_user); return 0; } EXPORT_SYMBOL(ipmi_destroy_user); int ipmi_get_version(struct ipmi_user *user, unsigned char *major, unsigned char *minor) { struct ipmi_device_id id; int rv, index; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; rv = bmc_get_device_id(user->intf, NULL, &id, NULL, NULL); if (!rv) { *major = ipmi_version_major(&id); *minor = ipmi_version_minor(&id); } release_ipmi_user(user, index); return rv; } EXPORT_SYMBOL(ipmi_get_version); int ipmi_set_my_address(struct ipmi_user *user, unsigned int channel, unsigned char address) { int index, rv = 0; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; if (channel >= IPMI_MAX_CHANNELS) { rv = -EINVAL; } else { channel = array_index_nospec(channel, IPMI_MAX_CHANNELS); user->intf->addrinfo[channel].address = address; } release_ipmi_user(user, index); return rv; } EXPORT_SYMBOL(ipmi_set_my_address); int ipmi_get_my_address(struct ipmi_user *user, unsigned int channel, unsigned char *address) { int index, rv = 0; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; if (channel >= IPMI_MAX_CHANNELS) { rv = -EINVAL; } else { channel = array_index_nospec(channel, IPMI_MAX_CHANNELS); *address = user->intf->addrinfo[channel].address; } release_ipmi_user(user, index); return rv; } EXPORT_SYMBOL(ipmi_get_my_address); int ipmi_set_my_LUN(struct ipmi_user *user, unsigned int channel, unsigned char LUN) { int index, rv = 0; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; if (channel >= IPMI_MAX_CHANNELS) { rv = -EINVAL; } else { channel = array_index_nospec(channel, IPMI_MAX_CHANNELS); user->intf->addrinfo[channel].lun = LUN & 0x3; } release_ipmi_user(user, index); return rv; } EXPORT_SYMBOL(ipmi_set_my_LUN); int ipmi_get_my_LUN(struct ipmi_user *user, unsigned int channel, unsigned char *address) { int index, rv = 0; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; if (channel >= IPMI_MAX_CHANNELS) { rv = -EINVAL; } else { channel = array_index_nospec(channel, IPMI_MAX_CHANNELS); *address = user->intf->addrinfo[channel].lun; } release_ipmi_user(user, index); return rv; } EXPORT_SYMBOL(ipmi_get_my_LUN); int ipmi_get_maintenance_mode(struct ipmi_user *user) { int mode, index; unsigned long flags; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags); mode = user->intf->maintenance_mode; spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags); release_ipmi_user(user, index); return mode; } EXPORT_SYMBOL(ipmi_get_maintenance_mode); static void maintenance_mode_update(struct ipmi_smi *intf) { if (intf->handlers->set_maintenance_mode) intf->handlers->set_maintenance_mode( intf->send_info, intf->maintenance_mode_enable); } int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode) { int rv = 0, index; unsigned long flags; struct ipmi_smi *intf = user->intf; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; spin_lock_irqsave(&intf->maintenance_mode_lock, flags); if (intf->maintenance_mode != mode) { switch (mode) { case IPMI_MAINTENANCE_MODE_AUTO: intf->maintenance_mode_enable = (intf->auto_maintenance_timeout > 0); break; case IPMI_MAINTENANCE_MODE_OFF: intf->maintenance_mode_enable = false; break; case IPMI_MAINTENANCE_MODE_ON: intf->maintenance_mode_enable = true; break; default: rv = -EINVAL; goto out_unlock; } intf->maintenance_mode = mode; maintenance_mode_update(intf); } out_unlock: spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); release_ipmi_user(user, index); return rv; } EXPORT_SYMBOL(ipmi_set_maintenance_mode); int ipmi_set_gets_events(struct ipmi_user *user, bool val) { unsigned long flags; struct ipmi_smi *intf = user->intf; struct ipmi_recv_msg *msg, *msg2; struct list_head msgs; int index; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; INIT_LIST_HEAD(&msgs); spin_lock_irqsave(&intf->events_lock, flags); if (user->gets_events == val) goto out; user->gets_events = val; if (val) { if (atomic_inc_return(&intf->event_waiters) == 1) need_waiter(intf); } else { atomic_dec(&intf->event_waiters); } if (intf->delivering_events) /* * Another thread is delivering events for this, so * let it handle any new events. */ goto out; /* Deliver any queued events. */ while (user->gets_events && !list_empty(&intf->waiting_events)) { list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) list_move_tail(&msg->link, &msgs); intf->waiting_events_count = 0; if (intf->event_msg_printed) { dev_warn(intf->si_dev, "Event queue no longer full\n"); intf->event_msg_printed = 0; } intf->delivering_events = 1; spin_unlock_irqrestore(&intf->events_lock, flags); list_for_each_entry_safe(msg, msg2, &msgs, link) { msg->user = user; kref_get(&user->refcount); deliver_local_response(intf, msg); } spin_lock_irqsave(&intf->events_lock, flags); intf->delivering_events = 0; } out: spin_unlock_irqrestore(&intf->events_lock, flags); release_ipmi_user(user, index); return 0; } EXPORT_SYMBOL(ipmi_set_gets_events); static struct cmd_rcvr *find_cmd_rcvr(struct ipmi_smi *intf, unsigned char netfn, unsigned char cmd, unsigned char chan) { struct cmd_rcvr *rcvr; list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link, lockdep_is_held(&intf->cmd_rcvrs_mutex)) { if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd) && (rcvr->chans & (1 << chan))) return rcvr; } return NULL; } static int is_cmd_rcvr_exclusive(struct ipmi_smi *intf, unsigned char netfn, unsigned char cmd, unsigned int chans) { struct cmd_rcvr *rcvr; list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link, lockdep_is_held(&intf->cmd_rcvrs_mutex)) { if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd) && (rcvr->chans & chans)) return 0; } return 1; } int ipmi_register_for_cmd(struct ipmi_user *user, unsigned char netfn, unsigned char cmd, unsigned int chans) { struct ipmi_smi *intf = user->intf; struct cmd_rcvr *rcvr; int rv = 0, index; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL); if (!rcvr) { rv = -ENOMEM; goto out_release; } rcvr->cmd = cmd; rcvr->netfn = netfn; rcvr->chans = chans; rcvr->user = user; mutex_lock(&intf->cmd_rcvrs_mutex); /* Make sure the command/netfn is not already registered. */ if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) { rv = -EBUSY; goto out_unlock; } smi_add_watch(intf, IPMI_WATCH_MASK_CHECK_COMMANDS); list_add_rcu(&rcvr->link, &intf->cmd_rcvrs); out_unlock: mutex_unlock(&intf->cmd_rcvrs_mutex); if (rv) kfree(rcvr); out_release: release_ipmi_user(user, index); return rv; } EXPORT_SYMBOL(ipmi_register_for_cmd); int ipmi_unregister_for_cmd(struct ipmi_user *user, unsigned char netfn, unsigned char cmd, unsigned int chans) { struct ipmi_smi *intf = user->intf; struct cmd_rcvr *rcvr; struct cmd_rcvr *rcvrs = NULL; int i, rv = -ENOENT, index; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; mutex_lock(&intf->cmd_rcvrs_mutex); for (i = 0; i < IPMI_NUM_CHANNELS; i++) { if (((1 << i) & chans) == 0) continue; rcvr = find_cmd_rcvr(intf, netfn, cmd, i); if (rcvr == NULL) continue; if (rcvr->user == user) { rv = 0; rcvr->chans &= ~chans; if (rcvr->chans == 0) { list_del_rcu(&rcvr->link); rcvr->next = rcvrs; rcvrs = rcvr; } } } mutex_unlock(&intf->cmd_rcvrs_mutex); synchronize_rcu(); release_ipmi_user(user, index); while (rcvrs) { smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_COMMANDS); rcvr = rcvrs; rcvrs = rcvr->next; kfree(rcvr); } return rv; } EXPORT_SYMBOL(ipmi_unregister_for_cmd); unsigned char ipmb_checksum(unsigned char *data, int size) { unsigned char csum = 0; for (; size > 0; size--, data++) csum += *data; return -csum; } EXPORT_SYMBOL(ipmb_checksum); static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg, struct kernel_ipmi_msg *msg, struct ipmi_ipmb_addr *ipmb_addr, long msgid, unsigned char ipmb_seq, int broadcast, unsigned char source_address, unsigned char source_lun) { int i = broadcast; /* Format the IPMB header data. */ smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); smi_msg->data[1] = IPMI_SEND_MSG_CMD; smi_msg->data[2] = ipmb_addr->channel; if (broadcast) smi_msg->data[3] = 0; smi_msg->data[i+3] = ipmb_addr->slave_addr; smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3); smi_msg->data[i+5] = ipmb_checksum(&smi_msg->data[i + 3], 2); smi_msg->data[i+6] = source_address; smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun; smi_msg->data[i+8] = msg->cmd; /* Now tack on the data to the message. */ if (msg->data_len > 0) memcpy(&smi_msg->data[i + 9], msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 9; /* Now calculate the checksum and tack it on. */ smi_msg->data[i+smi_msg->data_size] = ipmb_checksum(&smi_msg->data[i + 6], smi_msg->data_size - 6); /* * Add on the checksum size and the offset from the * broadcast. */ smi_msg->data_size += 1 + i; smi_msg->msgid = msgid; } static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg, struct kernel_ipmi_msg *msg, struct ipmi_lan_addr *lan_addr, long msgid, unsigned char ipmb_seq, unsigned char source_lun) { /* Format the IPMB header data. */ smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); smi_msg->data[1] = IPMI_SEND_MSG_CMD; smi_msg->data[2] = lan_addr->channel; smi_msg->data[3] = lan_addr->session_handle; smi_msg->data[4] = lan_addr->remote_SWID; smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3); smi_msg->data[6] = ipmb_checksum(&smi_msg->data[4], 2); smi_msg->data[7] = lan_addr->local_SWID; smi_msg->data[8] = (ipmb_seq << 2) | source_lun; smi_msg->data[9] = msg->cmd; /* Now tack on the data to the message. */ if (msg->data_len > 0) memcpy(&smi_msg->data[10], msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 10; /* Now calculate the checksum and tack it on. */ smi_msg->data[smi_msg->data_size] = ipmb_checksum(&smi_msg->data[7], smi_msg->data_size - 7); /* * Add on the checksum size and the offset from the * broadcast. */ smi_msg->data_size += 1; smi_msg->msgid = msgid; } static struct ipmi_smi_msg *smi_add_send_msg(struct ipmi_smi *intf, struct ipmi_smi_msg *smi_msg, int priority) { if (intf->curr_msg) { if (priority > 0) list_add_tail(&smi_msg->link, &intf->hp_xmit_msgs); else list_add_tail(&smi_msg->link, &intf->xmit_msgs); smi_msg = NULL; } else { intf->curr_msg = smi_msg; } return smi_msg; } static void smi_send(struct ipmi_smi *intf, const struct ipmi_smi_handlers *handlers, struct ipmi_smi_msg *smi_msg, int priority) { int run_to_completion = intf->run_to_completion; unsigned long flags = 0; if (!run_to_completion) spin_lock_irqsave(&intf->xmit_msgs_lock, flags); smi_msg = smi_add_send_msg(intf, smi_msg, priority); if (!run_to_completion) spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags); if (smi_msg) handlers->sender(intf->send_info, smi_msg); } static bool is_maintenance_mode_cmd(struct kernel_ipmi_msg *msg) { return (((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_COLD_RESET_CMD) || (msg->cmd == IPMI_WARM_RESET_CMD))) || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)); } static int i_ipmi_req_sysintf(struct ipmi_smi *intf, struct ipmi_addr *addr, long msgid, struct kernel_ipmi_msg *msg, struct ipmi_smi_msg *smi_msg, struct ipmi_recv_msg *recv_msg, int retries, unsigned int retry_time_ms) { struct ipmi_system_interface_addr *smi_addr; if (msg->netfn & 1) /* Responses are not allowed to the SMI. */ return -EINVAL; smi_addr = (struct ipmi_system_interface_addr *) addr; if (smi_addr->lun > 3) { ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr)); if ((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_SEND_MSG_CMD) || (msg->cmd == IPMI_GET_MSG_CMD) || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) { /* * We don't let the user do these, since we manage * the sequence numbers. */ ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } if (is_maintenance_mode_cmd(msg)) { unsigned long flags; spin_lock_irqsave(&intf->maintenance_mode_lock, flags); intf->auto_maintenance_timeout = maintenance_mode_timeout_ms; if (!intf->maintenance_mode && !intf->maintenance_mode_enable) { intf->maintenance_mode_enable = true; maintenance_mode_update(intf); } spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); } if (msg->data_len + 2 > IPMI_MAX_MSG_LENGTH) { ipmi_inc_stat(intf, sent_invalid_commands); return -EMSGSIZE; } smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3); smi_msg->data[1] = msg->cmd; smi_msg->msgid = msgid; smi_msg->user_data = recv_msg; if (msg->data_len > 0) memcpy(&smi_msg->data[2], msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 2; ipmi_inc_stat(intf, sent_local_commands); return 0; } static int i_ipmi_req_ipmb(struct ipmi_smi *intf, struct ipmi_addr *addr, long msgid, struct kernel_ipmi_msg *msg, struct ipmi_smi_msg *smi_msg, struct ipmi_recv_msg *recv_msg, unsigned char source_address, unsigned char source_lun, int retries, unsigned int retry_time_ms) { struct ipmi_ipmb_addr *ipmb_addr; unsigned char ipmb_seq; long seqid; int broadcast = 0; struct ipmi_channel *chans; int rv = 0; if (addr->channel >= IPMI_MAX_CHANNELS) { ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } chans = READ_ONCE(intf->channel_list)->c; if (chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_IPMB) { ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) { /* * Broadcasts add a zero at the beginning of the * message, but otherwise is the same as an IPMB * address. */ addr->addr_type = IPMI_IPMB_ADDR_TYPE; broadcast = 1; retries = 0; /* Don't retry broadcasts. */ } /* * 9 for the header and 1 for the checksum, plus * possibly one for the broadcast. */ if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) { ipmi_inc_stat(intf, sent_invalid_commands); return -EMSGSIZE; } ipmb_addr = (struct ipmi_ipmb_addr *) addr; if (ipmb_addr->lun > 3) { ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr)); if (recv_msg->msg.netfn & 0x1) { /* * It's a response, so use the user's sequence * from msgid. */ ipmi_inc_stat(intf, sent_ipmb_responses); format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid, msgid, broadcast, source_address, source_lun); /* * Save the receive message so we can use it * to deliver the response. */ smi_msg->user_data = recv_msg; } else { /* It's a command, so get a sequence for it. */ unsigned long flags; spin_lock_irqsave(&intf->seq_lock, flags); if (is_maintenance_mode_cmd(msg)) intf->ipmb_maintenance_mode_timeout = maintenance_mode_timeout_ms; if (intf->ipmb_maintenance_mode_timeout && retry_time_ms == 0) /* Different default in maintenance mode */ retry_time_ms = default_maintenance_retry_ms; /* * Create a sequence number with a 1 second * timeout and 4 retries. */ rv = intf_next_seq(intf, recv_msg, retry_time_ms, retries, broadcast, &ipmb_seq, &seqid); if (rv) /* * We have used up all the sequence numbers, * probably, so abort. */ goto out_err; ipmi_inc_stat(intf, sent_ipmb_commands); /* * Store the sequence number in the message, * so that when the send message response * comes back we can start the timer. */ format_ipmb_msg(smi_msg, msg, ipmb_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, broadcast, source_address, source_lun); /* * Copy the message into the recv message data, so we * can retransmit it later if necessary. */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; /* * We don't unlock until here, because we need * to copy the completed message into the * recv_msg before we release the lock. * Otherwise, race conditions may bite us. I * know that's pretty paranoid, but I prefer * to be correct. */ out_err: spin_unlock_irqrestore(&intf->seq_lock, flags); } return rv; } static int i_ipmi_req_ipmb_direct(struct ipmi_smi *intf, struct ipmi_addr *addr, long msgid, struct kernel_ipmi_msg *msg, struct ipmi_smi_msg *smi_msg, struct ipmi_recv_msg *recv_msg, unsigned char source_lun) { struct ipmi_ipmb_direct_addr *daddr; bool is_cmd = !(recv_msg->msg.netfn & 0x1); if (!(intf->handlers->flags & IPMI_SMI_CAN_HANDLE_IPMB_DIRECT)) return -EAFNOSUPPORT; /* Responses must have a completion code. */ if (!is_cmd && msg->data_len < 1) { ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } if ((msg->data_len + 4) > IPMI_MAX_MSG_LENGTH) { ipmi_inc_stat(intf, sent_invalid_commands); return -EMSGSIZE; } daddr = (struct ipmi_ipmb_direct_addr *) addr; if (daddr->rq_lun > 3 || daddr->rs_lun > 3) { ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } smi_msg->type = IPMI_SMI_MSG_TYPE_IPMB_DIRECT; smi_msg->msgid = msgid; if (is_cmd) { smi_msg->data[0] = msg->netfn << 2 | daddr->rs_lun; smi_msg->data[2] = recv_msg->msgid << 2 | daddr->rq_lun; } else { smi_msg->data[0] = msg->netfn << 2 | daddr->rq_lun; smi_msg->data[2] = recv_msg->msgid << 2 | daddr->rs_lun; } smi_msg->data[1] = daddr->slave_addr; smi_msg->data[3] = msg->cmd; memcpy(smi_msg->data + 4, msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 4; smi_msg->user_data = recv_msg; return 0; } static int i_ipmi_req_lan(struct ipmi_smi *intf, struct ipmi_addr *addr, long msgid, struct kernel_ipmi_msg *msg, struct ipmi_smi_msg *smi_msg, struct ipmi_recv_msg *recv_msg, unsigned char source_lun, int retries, unsigned int retry_time_ms) { struct ipmi_lan_addr *lan_addr; unsigned char ipmb_seq; long seqid; struct ipmi_channel *chans; int rv = 0; if (addr->channel >= IPMI_MAX_CHANNELS) { ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } chans = READ_ONCE(intf->channel_list)->c; if ((chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_8023LAN) && (chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_ASYNC)) { ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } /* 11 for the header and 1 for the checksum. */ if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) { ipmi_inc_stat(intf, sent_invalid_commands); return -EMSGSIZE; } lan_addr = (struct ipmi_lan_addr *) addr; if (lan_addr->lun > 3) { ipmi_inc_stat(intf, sent_invalid_commands); return -EINVAL; } memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr)); if (recv_msg->msg.netfn & 0x1) { /* * It's a response, so use the user's sequence * from msgid. */ ipmi_inc_stat(intf, sent_lan_responses); format_lan_msg(smi_msg, msg, lan_addr, msgid, msgid, source_lun); /* * Save the receive message so we can use it * to deliver the response. */ smi_msg->user_data = recv_msg; } else { /* It's a command, so get a sequence for it. */ unsigned long flags; spin_lock_irqsave(&intf->seq_lock, flags); /* * Create a sequence number with a 1 second * timeout and 4 retries. */ rv = intf_next_seq(intf, recv_msg, retry_time_ms, retries, 0, &ipmb_seq, &seqid); if (rv) /* * We have used up all the sequence numbers, * probably, so abort. */ goto out_err; ipmi_inc_stat(intf, sent_lan_commands); /* * Store the sequence number in the message, * so that when the send message response * comes back we can start the timer. */ format_lan_msg(smi_msg, msg, lan_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, source_lun); /* * Copy the message into the recv message data, so we * can retransmit it later if necessary. */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; /* * We don't unlock until here, because we need * to copy the completed message into the * recv_msg before we release the lock. * Otherwise, race conditions may bite us. I * know that's pretty paranoid, but I prefer * to be correct. */ out_err: spin_unlock_irqrestore(&intf->seq_lock, flags); } return rv; } /* * Separate from ipmi_request so that the user does not have to be * supplied in certain circumstances (mainly at panic time). If * messages are supplied, they will be freed, even if an error * occurs. */ static int i_ipmi_request(struct ipmi_user *user, struct ipmi_smi *intf, struct ipmi_addr *addr, long msgid, struct kernel_ipmi_msg *msg, void *user_msg_data, void *supplied_smi, struct ipmi_recv_msg *supplied_recv, int priority, unsigned char source_address, unsigned char source_lun, int retries, unsigned int retry_time_ms) { struct ipmi_smi_msg *smi_msg; struct ipmi_recv_msg *recv_msg; int rv = 0; if (user) { if (atomic_add_return(1, &user->nr_msgs) > max_msgs_per_user) { /* Decrement will happen at the end of the routine. */ rv = -EBUSY; goto out; } } if (supplied_recv) recv_msg = supplied_recv; else { recv_msg = ipmi_alloc_recv_msg(); if (recv_msg == NULL) { rv = -ENOMEM; goto out; } } recv_msg->user_msg_data = user_msg_data; if (supplied_smi) smi_msg = supplied_smi; else { smi_msg = ipmi_alloc_smi_msg(); if (smi_msg == NULL) { if (!supplied_recv) ipmi_free_recv_msg(recv_msg); rv = -ENOMEM; goto out; } } rcu_read_lock(); if (intf->in_shutdown) { rv = -ENODEV; goto out_err; } recv_msg->user = user; if (user) /* The put happens when the message is freed. */ kref_get(&user->refcount); recv_msg->msgid = msgid; /* * Store the message to send in the receive message so timeout * responses can get the proper response data. */ recv_msg->msg = *msg; if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { rv = i_ipmi_req_sysintf(intf, addr, msgid, msg, smi_msg, recv_msg, retries, retry_time_ms); } else if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) { rv = i_ipmi_req_ipmb(intf, addr, msgid, msg, smi_msg, recv_msg, source_address, source_lun, retries, retry_time_ms); } else if (is_ipmb_direct_addr(addr)) { rv = i_ipmi_req_ipmb_direct(intf, addr, msgid, msg, smi_msg, recv_msg, source_lun); } else if (is_lan_addr(addr)) { rv = i_ipmi_req_lan(intf, addr, msgid, msg, smi_msg, recv_msg, source_lun, retries, retry_time_ms); } else { /* Unknown address type. */ ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; } if (rv) { out_err: ipmi_free_smi_msg(smi_msg); ipmi_free_recv_msg(recv_msg); } else { dev_dbg(intf->si_dev, "Send: %*ph\n", smi_msg->data_size, smi_msg->data); smi_send(intf, intf->handlers, smi_msg, priority); } rcu_read_unlock(); out: if (rv && user) atomic_dec(&user->nr_msgs); return rv; } static int check_addr(struct ipmi_smi *intf, struct ipmi_addr *addr, unsigned char *saddr, unsigned char *lun) { if (addr->channel >= IPMI_MAX_CHANNELS) return -EINVAL; addr->channel = array_index_nospec(addr->channel, IPMI_MAX_CHANNELS); *lun = intf->addrinfo[addr->channel].lun; *saddr = intf->addrinfo[addr->channel].address; return 0; } int ipmi_request_settime(struct ipmi_user *user, struct ipmi_addr *addr, long msgid, struct kernel_ipmi_msg *msg, void *user_msg_data, int priority, int retries, unsigned int retry_time_ms) { unsigned char saddr = 0, lun = 0; int rv, index; if (!user) return -EINVAL; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; rv = check_addr(user->intf, addr, &saddr, &lun); if (!rv) rv = i_ipmi_request(user, user->intf, addr, msgid, msg, user_msg_data, NULL, NULL, priority, saddr, lun, retries, retry_time_ms); release_ipmi_user(user, index); return rv; } EXPORT_SYMBOL(ipmi_request_settime); int ipmi_request_supply_msgs(struct ipmi_user *user, struct ipmi_addr *addr, long msgid, struct kernel_ipmi_msg *msg, void *user_msg_data, void *supplied_smi, struct ipmi_recv_msg *supplied_recv, int priority) { unsigned char saddr = 0, lun = 0; int rv, index; if (!user) return -EINVAL; user = acquire_ipmi_user(user, &index); if (!user) return -ENODEV; rv = check_addr(user->intf, addr, &saddr, &lun); if (!rv) rv = i_ipmi_request(user, user->intf, addr, msgid, msg, user_msg_data, supplied_smi, supplied_recv, priority, saddr, lun, -1, 0); release_ipmi_user(user, index); return rv; } EXPORT_SYMBOL(ipmi_request_supply_msgs); static void bmc_device_id_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) { int rv; if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE) || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE) || (msg->msg.cmd != IPMI_GET_DEVICE_ID_CMD)) { dev_warn(intf->si_dev, "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n", msg->addr.addr_type, msg->msg.netfn, msg->msg.cmd); return; } if (msg->msg.data[0]) { dev_warn(intf->si_dev, "device id fetch failed: 0x%2.2x\n", msg->msg.data[0]); intf->bmc->dyn_id_set = 0; goto out; } rv = ipmi_demangle_device_id(msg->msg.netfn, msg->msg.cmd, msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id); if (rv) { dev_warn(intf->si_dev, "device id demangle failed: %d\n", rv); /* record completion code when error */ intf->bmc->cc = msg->msg.data[0]; intf->bmc->dyn_id_set = 0; } else { /* * Make sure the id data is available before setting * dyn_id_set. */ smp_wmb(); intf->bmc->dyn_id_set = 1; } out: wake_up(&intf->waitq); } static int send_get_device_id_cmd(struct ipmi_smi *intf) { struct ipmi_system_interface_addr si; struct kernel_ipmi_msg msg; si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si.channel = IPMI_BMC_CHANNEL; si.lun = 0; msg.netfn = IPMI_NETFN_APP_REQUEST; msg.cmd = IPMI_GET_DEVICE_ID_CMD; msg.data = NULL; msg.data_len = 0; return i_ipmi_request(NULL, intf, (struct ipmi_addr *) &si, 0, &msg, intf, NULL, NULL, 0, intf->addrinfo[0].address, intf->addrinfo[0].lun, -1, 0); } static int __get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc) { int rv; unsigned int retry_count = 0; intf->null_user_handler = bmc_device_id_handler; retry: bmc->cc = 0; bmc->dyn_id_set = 2; rv = send_get_device_id_cmd(intf); if (rv) goto out_reset_handler; wait_event(intf->waitq, bmc->dyn_id_set != 2); if (!bmc->dyn_id_set) { if (bmc->cc != IPMI_CC_NO_ERROR && ++retry_count <= GET_DEVICE_ID_MAX_RETRY) { msleep(500); dev_warn(intf->si_dev, "BMC returned 0x%2.2x, retry get bmc device id\n", bmc->cc); goto retry; } rv = -EIO; /* Something went wrong in the fetch. */ } /* dyn_id_set makes the id data available. */ smp_rmb(); out_reset_handler: intf->null_user_handler = NULL; return rv; } /* * Fetch the device id for the bmc/interface. You must pass in either * bmc or intf, this code will get the other one. If the data has * been recently fetched, this will just use the cached data. Otherwise * it will run a new fetch. * * Except for the first time this is called (in ipmi_add_smi()), * this will always return good data; */ static int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc, struct ipmi_device_id *id, bool *guid_set, guid_t *guid, int intf_num) { int rv = 0; int prev_dyn_id_set, prev_guid_set; bool intf_set = intf != NULL; if (!intf) { mutex_lock(&bmc->dyn_mutex); retry_bmc_lock: if (list_empty(&bmc->intfs)) { mutex_unlock(&bmc->dyn_mutex); return -ENOENT; } intf = list_first_entry(&bmc->intfs, struct ipmi_smi, bmc_link); kref_get(&intf->refcount); mutex_unlock(&bmc->dyn_mutex); mutex_lock(&intf->bmc_reg_mutex); mutex_lock(&bmc->dyn_mutex); if (intf != list_first_entry(&bmc->intfs, struct ipmi_smi, bmc_link)) { mutex_unlock(&intf->bmc_reg_mutex); kref_put(&intf->refcount, intf_free); goto retry_bmc_lock; } } else { mutex_lock(&intf->bmc_reg_mutex); bmc = intf->bmc; mutex_lock(&bmc->dyn_mutex); kref_get(&intf->refcount); } /* If we have a valid and current ID, just return that. */ if (intf->in_bmc_register || (bmc->dyn_id_set && time_is_after_jiffies(bmc->dyn_id_expiry))) goto out_noprocessing; prev_guid_set = bmc->dyn_guid_set; __get_guid(intf); prev_dyn_id_set = bmc->dyn_id_set; rv = __get_device_id(intf, bmc); if (rv) goto out; /* * The guid, device id, manufacturer id, and product id should * not change on a BMC. If it does we have to do some dancing. */ if (!intf->bmc_registered || (!prev_guid_set && bmc->dyn_guid_set) || (!prev_dyn_id_set && bmc->dyn_id_set) || (prev_guid_set && bmc->dyn_guid_set && !guid_equal(&bmc->guid, &bmc->fetch_guid)) || bmc->id.device_id != bmc->fetch_id.device_id || bmc->id.manufacturer_id != bmc->fetch_id.manufacturer_id || bmc->id.product_id != bmc->fetch_id.product_id) { struct ipmi_device_id id = bmc->fetch_id; int guid_set = bmc->dyn_guid_set; guid_t guid; guid = bmc->fetch_guid; mutex_unlock(&bmc->dyn_mutex); __ipmi_bmc_unregister(intf); /* Fill in the temporary BMC for good measure. */ intf->bmc->id = id; intf->bmc->dyn_guid_set = guid_set; intf->bmc->guid = guid; if (__ipmi_bmc_register(intf, &id, guid_set, &guid, intf_num)) need_waiter(intf); /* Retry later on an error. */ else __scan_channels(intf, &id); if (!intf_set) { /* * We weren't given the interface on the * command line, so restart the operation on * the next interface for the BMC. */ mutex_unlock(&intf->bmc_reg_mutex); mutex_lock(&bmc->dyn_mutex); goto retry_bmc_lock; } /* We have a new BMC, set it up. */ bmc = intf->bmc; mutex_lock(&bmc->dyn_mutex); goto out_noprocessing; } else if (memcmp(&bmc->fetch_id, &bmc->id, sizeof(bmc->id))) /* Version info changes, scan the channels again. */ __scan_channels(intf, &bmc->fetch_id); bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY; out: if (rv && prev_dyn_id_set) { rv = 0; /* Ignore failures if we have previous data. */ bmc->dyn_id_set = prev_dyn_id_set; } if (!rv) { bmc->id = bmc->fetch_id; if (bmc->dyn_guid_set) bmc->guid = bmc->fetch_guid; else if (prev_guid_set) /* * The guid used to be valid and it failed to fetch, * just use the cached value. */ bmc->dyn_guid_set = prev_guid_set; } out_noprocessing: if (!rv) { if (id) *id = bmc->id; if (guid_set) *guid_set = bmc->dyn_guid_set; if (guid && bmc->dyn_guid_set) *guid = bmc->guid; } mutex_unlock(&bmc->dyn_mutex); mutex_unlock(&intf->bmc_reg_mutex); kref_put(&intf->refcount, intf_free); return rv; } static int bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc, struct ipmi_device_id *id, bool *guid_set, guid_t *guid) { return __bmc_get_device_id(intf, bmc, id, guid_set, guid, -1); } static ssize_t device_id_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); struct ipmi_device_id id; int rv; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; return sysfs_emit(buf, "%u\n", id.device_id); } static DEVICE_ATTR_RO(device_id); static ssize_t provides_device_sdrs_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); struct ipmi_device_id id; int rv; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; return sysfs_emit(buf, "%u\n", (id.device_revision & 0x80) >> 7); } static DEVICE_ATTR_RO(provides_device_sdrs); static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); struct ipmi_device_id id; int rv; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; return sysfs_emit(buf, "%u\n", id.device_revision & 0x0F); } static DEVICE_ATTR_RO(revision); static ssize_t firmware_revision_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); struct ipmi_device_id id; int rv; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; return sysfs_emit(buf, "%u.%x\n", id.firmware_revision_1, id.firmware_revision_2); } static DEVICE_ATTR_RO(firmware_revision); static ssize_t ipmi_version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); struct ipmi_device_id id; int rv; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; return sysfs_emit(buf, "%u.%u\n", ipmi_version_major(&id), ipmi_version_minor(&id)); } static DEVICE_ATTR_RO(ipmi_version); static ssize_t add_dev_support_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); struct ipmi_device_id id; int rv; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; return sysfs_emit(buf, "0x%02x\n", id.additional_device_support); } static DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show, NULL); static ssize_t manufacturer_id_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); struct ipmi_device_id id; int rv; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; return sysfs_emit(buf, "0x%6.6x\n", id.manufacturer_id); } static DEVICE_ATTR_RO(manufacturer_id); static ssize_t product_id_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); struct ipmi_device_id id; int rv; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; return sysfs_emit(buf, "0x%4.4x\n", id.product_id); } static DEVICE_ATTR_RO(product_id); static ssize_t aux_firmware_rev_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); struct ipmi_device_id id; int rv; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); if (rv) return rv; return sysfs_emit(buf, "0x%02x 0x%02x 0x%02x 0x%02x\n", id.aux_firmware_revision[3], id.aux_firmware_revision[2], id.aux_firmware_revision[1], id.aux_firmware_revision[0]); } static DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL); static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bmc_device *bmc = to_bmc_device(dev); bool guid_set; guid_t guid; int rv; rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, &guid); if (rv) return rv; if (!guid_set) return -ENOENT; return sysfs_emit(buf, "%pUl\n", &guid); } static DEVICE_ATTR_RO(guid); static struct attribute *bmc_dev_attrs[] = { &dev_attr_device_id.attr, &dev_attr_provides_device_sdrs.attr, &dev_attr_revision.attr, &dev_attr_firmware_revision.attr, &dev_attr_ipmi_version.attr, &dev_attr_additional_device_support.attr, &dev_attr_manufacturer_id.attr, &dev_attr_product_id.attr, &dev_attr_aux_firmware_revision.attr, &dev_attr_guid.attr, NULL }; static umode_t bmc_dev_attr_is_visible(struct kobject *kobj, struct attribute *attr, int idx) { struct device *dev = kobj_to_dev(kobj); struct bmc_device *bmc = to_bmc_device(dev); umode_t mode = attr->mode; int rv; if (attr == &dev_attr_aux_firmware_revision.attr) { struct ipmi_device_id id; rv = bmc_get_device_id(NULL, bmc, &id, NULL, NULL); return (!rv && id.aux_firmware_revision_set) ? mode : 0; } if (attr == &dev_attr_guid.attr) { bool guid_set; rv = bmc_get_device_id(NULL, bmc, NULL, &guid_set, NULL); return (!rv && guid_set) ? mode : 0; } return mode; } static const struct attribute_group bmc_dev_attr_group = { .attrs = bmc_dev_attrs, .is_visible = bmc_dev_attr_is_visible, }; static const struct attribute_group *bmc_dev_attr_groups[] = { &bmc_dev_attr_group, NULL }; static const struct device_type bmc_device_type = { .groups = bmc_dev_attr_groups, }; static int __find_bmc_guid(struct device *dev, const void *data) { const guid_t *guid = data; struct bmc_device *bmc; int rv; if (dev->type != &bmc_device_type) return 0; bmc = to_bmc_device(dev); rv = bmc->dyn_guid_set && guid_equal(&bmc->guid, guid); if (rv) rv = kref_get_unless_zero(&bmc->usecount); return rv; } /* * Returns with the bmc's usecount incremented, if it is non-NULL. */ static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv, guid_t *guid) { struct device *dev; struct bmc_device *bmc = NULL; dev = driver_find_device(drv, NULL, guid, __find_bmc_guid); if (dev) { bmc = to_bmc_device(dev); put_device(dev); } return bmc; } struct prod_dev_id { unsigned int product_id; unsigned char device_id; }; static int __find_bmc_prod_dev_id(struct device *dev, const void *data) { const struct prod_dev_id *cid = data; struct bmc_device *bmc; int rv; if (dev->type != &bmc_device_type) return 0; bmc = to_bmc_device(dev); rv = (bmc->id.product_id == cid->product_id && bmc->id.device_id == cid->device_id); if (rv) rv = kref_get_unless_zero(&bmc->usecount); return rv; } /* * Returns with the bmc's usecount incremented, if it is non-NULL. */ static struct bmc_device *ipmi_find_bmc_prod_dev_id( struct device_driver *drv, unsigned int product_id, unsigned char device_id) { struct prod_dev_id id = { .product_id = product_id, .device_id = device_id, }; struct device *dev; struct bmc_device *bmc = NULL; dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id); if (dev) { bmc = to_bmc_device(dev); put_device(dev); } return bmc; } static DEFINE_IDA(ipmi_bmc_ida); static void release_bmc_device(struct device *dev) { kfree(to_bmc_device(dev)); } static void cleanup_bmc_work(struct work_struct *work) { struct bmc_device *bmc = container_of(work, struct bmc_device, remove_work); int id = bmc->pdev.id; /* Unregister overwrites id */ platform_device_unregister(&bmc->pdev); ida_simple_remove(&ipmi_bmc_ida, id); } static void cleanup_bmc_device(struct kref *ref) { struct bmc_device *bmc = container_of(ref, struct bmc_device, usecount); /* * Remove the platform device in a work queue to avoid issues * with removing the device attributes while reading a device * attribute. */ queue_work(remove_work_wq, &bmc->remove_work); } /* * Must be called with intf->bmc_reg_mutex held. */ static void __ipmi_bmc_unregister(struct ipmi_smi *intf) { struct bmc_device *bmc = intf->bmc; if (!intf->bmc_registered) return; sysfs_remove_link(&intf->si_dev->kobj, "bmc"); sysfs_remove_link(&bmc->pdev.dev.kobj, intf->my_dev_name); kfree(intf->my_dev_name); intf->my_dev_name = NULL; mutex_lock(&bmc->dyn_mutex); list_del(&intf->bmc_link); mutex_unlock(&bmc->dyn_mutex); intf->bmc = &intf->tmp_bmc; kref_put(&bmc->usecount, cleanup_bmc_device); intf->bmc_registered = false; } static void ipmi_bmc_unregister(struct ipmi_smi *intf) { mutex_lock(&intf->bmc_reg_mutex); __ipmi_bmc_unregister(intf); mutex_unlock(&intf->bmc_reg_mutex); } /* * Must be called with intf->bmc_reg_mutex held. */ static int __ipmi_bmc_register(struct ipmi_smi *intf, struct ipmi_device_id *id, bool guid_set, guid_t *guid, int intf_num) { int rv; struct bmc_device *bmc; struct bmc_device *old_bmc; /* * platform_device_register() can cause bmc_reg_mutex to * be claimed because of the is_visible functions of * the attributes. Eliminate possible recursion and * release the lock. */ intf->in_bmc_register = true; mutex_unlock(&intf->bmc_reg_mutex); /* * Try to find if there is an bmc_device struct * representing the interfaced BMC already */ mutex_lock(&ipmidriver_mutex); if (guid_set) old_bmc = ipmi_find_bmc_guid(&ipmidriver.driver, guid); else old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver.driver, id->product_id, id->device_id); /* * If there is already an bmc_device, free the new one, * otherwise register the new BMC device */ if (old_bmc) { bmc = old_bmc; /* * Note: old_bmc already has usecount incremented by * the BMC find functions. */ intf->bmc = old_bmc; mutex_lock(&bmc->dyn_mutex); list_add_tail(&intf->bmc_link, &bmc->intfs); mutex_unlock(&bmc->dyn_mutex); dev_info(intf->si_dev, "interfacing existing BMC (man_id: 0x%6.6x, prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", bmc->id.manufacturer_id, bmc->id.product_id, bmc->id.device_id); } else { bmc = kzalloc(sizeof(*bmc), GFP_KERNEL); if (!bmc) { rv = -ENOMEM; goto out; } INIT_LIST_HEAD(&bmc->intfs); mutex_init(&bmc->dyn_mutex); INIT_WORK(&bmc->remove_work, cleanup_bmc_work); bmc->id = *id; bmc->dyn_id_set = 1; bmc->dyn_guid_set = guid_set; bmc->guid = *guid; bmc->dyn_id_expiry = jiffies + IPMI_DYN_DEV_ID_EXPIRY; bmc->pdev.name = "ipmi_bmc"; rv = ida_simple_get(&ipmi_bmc_ida, 0, 0, GFP_KERNEL); if (rv < 0) { kfree(bmc); goto out; } bmc->pdev.dev.driver = &ipmidriver.driver; bmc->pdev.id = rv; bmc->pdev.dev.release = release_bmc_device; bmc->pdev.dev.type = &bmc_device_type; kref_init(&bmc->usecount); intf->bmc = bmc; mutex_lock(&bmc->dyn_mutex); list_add_tail(&intf->bmc_link, &bmc->intfs); mutex_unlock(&bmc->dyn_mutex); rv = platform_device_register(&bmc->pdev); if (rv) { dev_err(intf->si_dev, "Unable to register bmc device: %d\n", rv); goto out_list_del; } dev_info(intf->si_dev, "Found new BMC (man_id: 0x%6.6x, prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", bmc->id.manufacturer_id, bmc->id.product_id, bmc->id.device_id); } /* * create symlink from system interface device to bmc device * and back. */ rv = sysfs_create_link(&intf->si_dev->kobj, &bmc->pdev.dev.kobj, "bmc"); if (rv) { dev_err(intf->si_dev, "Unable to create bmc symlink: %d\n", rv); goto out_put_bmc; } if (intf_num == -1) intf_num = intf->intf_num; intf->my_dev_name = kasprintf(GFP_KERNEL, "ipmi%d", intf_num); if (!intf->my_dev_name) { rv = -ENOMEM; dev_err(intf->si_dev, "Unable to allocate link from BMC: %d\n", rv); goto out_unlink1; } rv = sysfs_create_link(&bmc->pdev.dev.kobj, &intf->si_dev->kobj, intf->my_dev_name); if (rv) { dev_err(intf->si_dev, "Unable to create symlink to bmc: %d\n", rv); goto out_free_my_dev_name; } intf->bmc_registered = true; out: mutex_unlock(&ipmidriver_mutex); mutex_lock(&intf->bmc_reg_mutex); intf->in_bmc_register = false; return rv; out_free_my_dev_name: kfree(intf->my_dev_name); intf->my_dev_name = NULL; out_unlink1: sysfs_remove_link(&intf->si_dev->kobj, "bmc"); out_put_bmc: mutex_lock(&bmc->dyn_mutex); list_del(&intf->bmc_link); mutex_unlock(&bmc->dyn_mutex); intf->bmc = &intf->tmp_bmc; kref_put(&bmc->usecount, cleanup_bmc_device); goto out; out_list_del: mutex_lock(&bmc->dyn_mutex); list_del(&intf->bmc_link); mutex_unlock(&bmc->dyn_mutex); intf->bmc = &intf->tmp_bmc; put_device(&bmc->pdev.dev); goto out; } static int send_guid_cmd(struct ipmi_smi *intf, int chan) { struct kernel_ipmi_msg msg; struct ipmi_system_interface_addr si; si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si.channel = IPMI_BMC_CHANNEL; si.lun = 0; msg.netfn = IPMI_NETFN_APP_REQUEST; msg.cmd = IPMI_GET_DEVICE_GUID_CMD; msg.data = NULL; msg.data_len = 0; return i_ipmi_request(NULL, intf, (struct ipmi_addr *) &si, 0, &msg, intf, NULL, NULL, 0, intf->addrinfo[0].address, intf->addrinfo[0].lun, -1, 0); } static void guid_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) { struct bmc_device *bmc = intf->bmc; if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE) || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE) || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD)) /* Not for me */ return; if (msg->msg.data[0] != 0) { /* Error from getting the GUID, the BMC doesn't have one. */ bmc->dyn_guid_set = 0; goto out; } if (msg->msg.data_len < UUID_SIZE + 1) { bmc->dyn_guid_set = 0; dev_warn(intf->si_dev, "The GUID response from the BMC was too short, it was %d but should have been %d. Assuming GUID is not available.\n", msg->msg.data_len, UUID_SIZE + 1); goto out; } import_guid(&bmc->fetch_guid, msg->msg.data + 1); /* * Make sure the guid data is available before setting * dyn_guid_set. */ smp_wmb(); bmc->dyn_guid_set = 1; out: wake_up(&intf->waitq); } static void __get_guid(struct ipmi_smi *intf) { int rv; struct bmc_device *bmc = intf->bmc; bmc->dyn_guid_set = 2; intf->null_user_handler = guid_handler; rv = send_guid_cmd(intf, 0); if (rv) /* Send failed, no GUID available. */ bmc->dyn_guid_set = 0; else wait_event(intf->waitq, bmc->dyn_guid_set != 2); /* dyn_guid_set makes the guid data available. */ smp_rmb(); intf->null_user_handler = NULL; } static int send_channel_info_cmd(struct ipmi_smi *intf, int chan) { struct kernel_ipmi_msg msg; unsigned char data[1]; struct ipmi_system_interface_addr si; si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si.channel = IPMI_BMC_CHANNEL; si.lun = 0; msg.netfn = IPMI_NETFN_APP_REQUEST; msg.cmd = IPMI_GET_CHANNEL_INFO_CMD; msg.data = data; msg.data_len = 1; data[0] = chan; return i_ipmi_request(NULL, intf, (struct ipmi_addr *) &si, 0, &msg, intf, NULL, NULL, 0, intf->addrinfo[0].address, intf->addrinfo[0].lun, -1, 0); } static void channel_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) { int rv = 0; int ch; unsigned int set = intf->curr_working_cset; struct ipmi_channel *chans; if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) { /* It's the one we want */ if (msg->msg.data[0] != 0) { /* Got an error from the channel, just go on. */ if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) { /* * If the MC does not support this * command, that is legal. We just * assume it has one IPMB at channel * zero. */ intf->wchannels[set].c[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; intf->wchannels[set].c[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; intf->channel_list = intf->wchannels + set; intf->channels_ready = true; wake_up(&intf->waitq); goto out; } goto next_channel; } if (msg->msg.data_len < 4) { /* Message not big enough, just go on. */ goto next_channel; } ch = intf->curr_channel; chans = intf->wchannels[set].c; chans[ch].medium = msg->msg.data[2] & 0x7f; chans[ch].protocol = msg->msg.data[3] & 0x1f; next_channel: intf->curr_channel++; if (intf->curr_channel >= IPMI_MAX_CHANNELS) { intf->channel_list = intf->wchannels + set; intf->channels_ready = true; wake_up(&intf->waitq); } else { intf->channel_list = intf->wchannels + set; intf->channels_ready = true; rv = send_channel_info_cmd(intf, intf->curr_channel); } if (rv) { /* Got an error somehow, just give up. */ dev_warn(intf->si_dev, "Error sending channel information for channel %d: %d\n", intf->curr_channel, rv); intf->channel_list = intf->wchannels + set; intf->channels_ready = true; wake_up(&intf->waitq); } } out: return; } /* * Must be holding intf->bmc_reg_mutex to call this. */ static int __scan_channels(struct ipmi_smi *intf, struct ipmi_device_id *id) { int rv; if (ipmi_version_major(id) > 1 || (ipmi_version_major(id) == 1 && ipmi_version_minor(id) >= 5)) { unsigned int set; /* * Start scanning the channels to see what is * available. */ set = !intf->curr_working_cset; intf->curr_working_cset = set; memset(&intf->wchannels[set], 0, sizeof(struct ipmi_channel_set)); intf->null_user_handler = channel_handler; intf->curr_channel = 0; rv = send_channel_info_cmd(intf, 0); if (rv) { dev_warn(intf->si_dev, "Error sending channel information for channel 0, %d\n", rv); intf->null_user_handler = NULL; return -EIO; } /* Wait for the channel info to be read. */ wait_event(intf->waitq, intf->channels_ready); intf->null_user_handler = NULL; } else { unsigned int set = intf->curr_working_cset; /* Assume a single IPMB channel at zero. */ intf->wchannels[set].c[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; intf->wchannels[set].c[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; intf->channel_list = intf->wchannels + set; intf->channels_ready = true; } return 0; } static void ipmi_poll(struct ipmi_smi *intf) { if (intf->handlers->poll) intf->handlers->poll(intf->send_info); /* In case something came in */ handle_new_recv_msgs(intf); } void ipmi_poll_interface(struct ipmi_user *user) { ipmi_poll(user->intf); } EXPORT_SYMBOL(ipmi_poll_interface); static ssize_t nr_users_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ipmi_smi *intf = container_of(attr, struct ipmi_smi, nr_users_devattr); return sysfs_emit(buf, "%d\n", atomic_read(&intf->nr_users)); } static DEVICE_ATTR_RO(nr_users); static ssize_t nr_msgs_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ipmi_smi *intf = container_of(attr, struct ipmi_smi, nr_msgs_devattr); struct ipmi_user *user; int index; unsigned int count = 0; index = srcu_read_lock(&intf->users_srcu); list_for_each_entry_rcu(user, &intf->users, link) count += atomic_read(&user->nr_msgs); srcu_read_unlock(&intf->users_srcu, index); return sysfs_emit(buf, "%u\n", count); } static DEVICE_ATTR_RO(nr_msgs); static void redo_bmc_reg(struct work_struct *work) { struct ipmi_smi *intf = container_of(work, struct ipmi_smi, bmc_reg_work); if (!intf->in_shutdown) bmc_get_device_id(intf, NULL, NULL, NULL, NULL); kref_put(&intf->refcount, intf_free); } int ipmi_add_smi(struct module *owner, const struct ipmi_smi_handlers *handlers, void *send_info, struct device *si_dev, unsigned char slave_addr) { int i, j; int rv; struct ipmi_smi *intf, *tintf; struct list_head *link; struct ipmi_device_id id; /* * Make sure the driver is actually initialized, this handles * problems with initialization order. */ rv = ipmi_init_msghandler(); if (rv) return rv; intf = kzalloc(sizeof(*intf), GFP_KERNEL); if (!intf) return -ENOMEM; rv = init_srcu_struct(&intf->users_srcu); if (rv) { kfree(intf); return rv; } intf->owner = owner; intf->bmc = &intf->tmp_bmc; INIT_LIST_HEAD(&intf->bmc->intfs); mutex_init(&intf->bmc->dyn_mutex); INIT_LIST_HEAD(&intf->bmc_link); mutex_init(&intf->bmc_reg_mutex); intf->intf_num = -1; /* Mark it invalid for now. */ kref_init(&intf->refcount); INIT_WORK(&intf->bmc_reg_work, redo_bmc_reg); intf->si_dev = si_dev; for (j = 0; j < IPMI_MAX_CHANNELS; j++) { intf->addrinfo[j].address = IPMI_BMC_SLAVE_ADDR; intf->addrinfo[j].lun = 2; } if (slave_addr != 0) intf->addrinfo[0].address = slave_addr; INIT_LIST_HEAD(&intf->users); atomic_set(&intf->nr_users, 0); intf->handlers = handlers; intf->send_info = send_info; spin_lock_init(&intf->seq_lock); for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) { intf->seq_table[j].inuse = 0; intf->seq_table[j].seqid = 0; } intf->curr_seq = 0; spin_lock_init(&intf->waiting_rcv_msgs_lock); INIT_LIST_HEAD(&intf->waiting_rcv_msgs); tasklet_setup(&intf->recv_tasklet, smi_recv_tasklet); atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0); spin_lock_init(&intf->xmit_msgs_lock); INIT_LIST_HEAD(&intf->xmit_msgs); INIT_LIST_HEAD(&intf->hp_xmit_msgs); spin_lock_init(&intf->events_lock); spin_lock_init(&intf->watch_lock); atomic_set(&intf->event_waiters, 0); intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME; INIT_LIST_HEAD(&intf->waiting_events); intf->waiting_events_count = 0; mutex_init(&intf->cmd_rcvrs_mutex); spin_lock_init(&intf->maintenance_mode_lock); INIT_LIST_HEAD(&intf->cmd_rcvrs); init_waitqueue_head(&intf->waitq); for (i = 0; i < IPMI_NUM_STATS; i++) atomic_set(&intf->stats[i], 0); mutex_lock(&ipmi_interfaces_mutex); /* Look for a hole in the numbers. */ i = 0; link = &ipmi_interfaces; list_for_each_entry_rcu(tintf, &ipmi_interfaces, link, ipmi_interfaces_mutex_held()) { if (tintf->intf_num != i) { link = &tintf->link; break; } i++; } /* Add the new interface in numeric order. */ if (i == 0) list_add_rcu(&intf->link, &ipmi_interfaces); else list_add_tail_rcu(&intf->link, link); rv = handlers->start_processing(send_info, intf); if (rv) goto out_err; rv = __bmc_get_device_id(intf, NULL, &id, NULL, NULL, i); if (rv) { dev_err(si_dev, "Unable to get the device id: %d\n", rv); goto out_err_started; } mutex_lock(&intf->bmc_reg_mutex); rv = __scan_channels(intf, &id); mutex_unlock(&intf->bmc_reg_mutex); if (rv) goto out_err_bmc_reg; intf->nr_users_devattr = dev_attr_nr_users; sysfs_attr_init(&intf->nr_users_devattr.attr); rv = device_create_file(intf->si_dev, &intf->nr_users_devattr); if (rv) goto out_err_bmc_reg; intf->nr_msgs_devattr = dev_attr_nr_msgs; sysfs_attr_init(&intf->nr_msgs_devattr.attr); rv = device_create_file(intf->si_dev, &intf->nr_msgs_devattr); if (rv) { device_remove_file(intf->si_dev, &intf->nr_users_devattr); goto out_err_bmc_reg; } /* * Keep memory order straight for RCU readers. Make * sure everything else is committed to memory before * setting intf_num to mark the interface valid. */ smp_wmb(); intf->intf_num = i; mutex_unlock(&ipmi_interfaces_mutex); /* After this point the interface is legal to use. */ call_smi_watchers(i, intf->si_dev); return 0; out_err_bmc_reg: ipmi_bmc_unregister(intf); out_err_started: if (intf->handlers->shutdown) intf->handlers->shutdown(intf->send_info); out_err: list_del_rcu(&intf->link); mutex_unlock(&ipmi_interfaces_mutex); synchronize_srcu(&ipmi_interfaces_srcu); cleanup_srcu_struct(&intf->users_srcu); kref_put(&intf->refcount, intf_free); return rv; } EXPORT_SYMBOL(ipmi_add_smi); static void deliver_smi_err_response(struct ipmi_smi *intf, struct ipmi_smi_msg *msg, unsigned char err) { int rv; msg->rsp[0] = msg->data[0] | 4; msg->rsp[1] = msg->data[1]; msg->rsp[2] = err; msg->rsp_size = 3; /* This will never requeue, but it may ask us to free the message. */ rv = handle_one_recv_msg(intf, msg); if (rv == 0) ipmi_free_smi_msg(msg); } static void cleanup_smi_msgs(struct ipmi_smi *intf) { int i; struct seq_table *ent; struct ipmi_smi_msg *msg; struct list_head *entry; struct list_head tmplist; /* Clear out our transmit queues and hold the messages. */ INIT_LIST_HEAD(&tmplist); list_splice_tail(&intf->hp_xmit_msgs, &tmplist); list_splice_tail(&intf->xmit_msgs, &tmplist); /* Current message first, to preserve order */ while (intf->curr_msg && !list_empty(&intf->waiting_rcv_msgs)) { /* Wait for the message to clear out. */ schedule_timeout(1); } /* No need for locks, the interface is down. */ /* * Return errors for all pending messages in queue and in the * tables waiting for remote responses. */ while (!list_empty(&tmplist)) { entry = tmplist.next; list_del(entry); msg = list_entry(entry, struct ipmi_smi_msg, link); deliver_smi_err_response(intf, msg, IPMI_ERR_UNSPECIFIED); } for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { ent = &intf->seq_table[i]; if (!ent->inuse) continue; deliver_err_response(intf, ent->recv_msg, IPMI_ERR_UNSPECIFIED); } } void ipmi_unregister_smi(struct ipmi_smi *intf) { struct ipmi_smi_watcher *w; int intf_num, index; if (!intf) return; intf_num = intf->intf_num; mutex_lock(&ipmi_interfaces_mutex); intf->intf_num = -1; intf->in_shutdown = true; list_del_rcu(&intf->link); mutex_unlock(&ipmi_interfaces_mutex); synchronize_srcu(&ipmi_interfaces_srcu); /* At this point no users can be added to the interface. */ device_remove_file(intf->si_dev, &intf->nr_msgs_devattr); device_remove_file(intf->si_dev, &intf->nr_users_devattr); /* * Call all the watcher interfaces to tell them that * an interface is going away. */ mutex_lock(&smi_watchers_mutex); list_for_each_entry(w, &smi_watchers, link) w->smi_gone(intf_num); mutex_unlock(&smi_watchers_mutex); index = srcu_read_lock(&intf->users_srcu); while (!list_empty(&intf->users)) { struct ipmi_user *user = container_of(list_next_rcu(&intf->users), struct ipmi_user, link); _ipmi_destroy_user(user); } srcu_read_unlock(&intf->users_srcu, index); if (intf->handlers->shutdown) intf->handlers->shutdown(intf->send_info); cleanup_smi_msgs(intf); ipmi_bmc_unregister(intf); cleanup_srcu_struct(&intf->users_srcu); kref_put(&intf->refcount, intf_free); } EXPORT_SYMBOL(ipmi_unregister_smi); static int handle_ipmb_get_msg_rsp(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { struct ipmi_ipmb_addr ipmb_addr; struct ipmi_recv_msg *recv_msg; /* * This is 11, not 10, because the response must contain a * completion code. */ if (msg->rsp_size < 11) { /* Message not big enough, just ignore it. */ ipmi_inc_stat(intf, invalid_ipmb_responses); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE; ipmb_addr.slave_addr = msg->rsp[6]; ipmb_addr.channel = msg->rsp[3] & 0x0f; ipmb_addr.lun = msg->rsp[7] & 3; /* * It's a response from a remote entity. Look up the sequence * number and handle the response. */ if (intf_find_seq(intf, msg->rsp[7] >> 2, msg->rsp[3] & 0x0f, msg->rsp[8], (msg->rsp[4] >> 2) & (~1), (struct ipmi_addr *) &ipmb_addr, &recv_msg)) { /* * We were unable to find the sequence number, * so just nuke the message. */ ipmi_inc_stat(intf, unhandled_ipmb_responses); return 0; } memcpy(recv_msg->msg_data, &msg->rsp[9], msg->rsp_size - 9); /* * The other fields matched, so no need to set them, except * for netfn, which needs to be the response that was * returned, not the request value. */ recv_msg->msg.netfn = msg->rsp[4] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 10; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; if (deliver_response(intf, recv_msg)) ipmi_inc_stat(intf, unhandled_ipmb_responses); else ipmi_inc_stat(intf, handled_ipmb_responses); return 0; } static int handle_ipmb_get_msg_cmd(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { struct cmd_rcvr *rcvr; int rv = 0; unsigned char netfn; unsigned char cmd; unsigned char chan; struct ipmi_user *user = NULL; struct ipmi_ipmb_addr *ipmb_addr; struct ipmi_recv_msg *recv_msg; if (msg->rsp_size < 10) { /* Message not big enough, just ignore it. */ ipmi_inc_stat(intf, invalid_commands); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } netfn = msg->rsp[4] >> 2; cmd = msg->rsp[8]; chan = msg->rsp[3] & 0xf; rcu_read_lock(); rcvr = find_cmd_rcvr(intf, netfn, cmd, chan); if (rcvr) { user = rcvr->user; kref_get(&user->refcount); } else user = NULL; rcu_read_unlock(); if (user == NULL) { /* We didn't find a user, deliver an error response. */ ipmi_inc_stat(intf, unhandled_commands); msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); msg->data[1] = IPMI_SEND_MSG_CMD; msg->data[2] = msg->rsp[3]; msg->data[3] = msg->rsp[6]; msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); msg->data[5] = ipmb_checksum(&msg->data[3], 2); msg->data[6] = intf->addrinfo[msg->rsp[3] & 0xf].address; /* rqseq/lun */ msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); msg->data[8] = msg->rsp[8]; /* cmd */ msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE; msg->data[10] = ipmb_checksum(&msg->data[6], 4); msg->data_size = 11; dev_dbg(intf->si_dev, "Invalid command: %*ph\n", msg->data_size, msg->data); rcu_read_lock(); if (!intf->in_shutdown) { smi_send(intf, intf->handlers, msg, 0); /* * We used the message, so return the value * that causes it to not be freed or * queued. */ rv = -1; } rcu_read_unlock(); } else { recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { /* * We couldn't allocate memory for the * message, so requeue it for handling * later. */ rv = 1; kref_put(&user->refcount, free_user); } else { /* Extract the source address from the data. */ ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr; ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE; ipmb_addr->slave_addr = msg->rsp[6]; ipmb_addr->lun = msg->rsp[7] & 3; ipmb_addr->channel = msg->rsp[3] & 0xf; /* * Extract the rest of the message information * from the IPMB header. */ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[7] >> 2; recv_msg->msg.netfn = msg->rsp[4] >> 2; recv_msg->msg.cmd = msg->rsp[8]; recv_msg->msg.data = recv_msg->msg_data; /* * We chop off 10, not 9 bytes because the checksum * at the end also needs to be removed. */ recv_msg->msg.data_len = msg->rsp_size - 10; memcpy(recv_msg->msg_data, &msg->rsp[9], msg->rsp_size - 10); if (deliver_response(intf, recv_msg)) ipmi_inc_stat(intf, unhandled_commands); else ipmi_inc_stat(intf, handled_commands); } } return rv; } static int handle_ipmb_direct_rcv_cmd(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { struct cmd_rcvr *rcvr; int rv = 0; struct ipmi_user *user = NULL; struct ipmi_ipmb_direct_addr *daddr; struct ipmi_recv_msg *recv_msg; unsigned char netfn = msg->rsp[0] >> 2; unsigned char cmd = msg->rsp[3]; rcu_read_lock(); /* We always use channel 0 for direct messages. */ rcvr = find_cmd_rcvr(intf, netfn, cmd, 0); if (rcvr) { user = rcvr->user; kref_get(&user->refcount); } else user = NULL; rcu_read_unlock(); if (user == NULL) { /* We didn't find a user, deliver an error response. */ ipmi_inc_stat(intf, unhandled_commands); msg->data[0] = (netfn + 1) << 2; msg->data[0] |= msg->rsp[2] & 0x3; /* rqLUN */ msg->data[1] = msg->rsp[1]; /* Addr */ msg->data[2] = msg->rsp[2] & ~0x3; /* rqSeq */ msg->data[2] |= msg->rsp[0] & 0x3; /* rsLUN */ msg->data[3] = cmd; msg->data[4] = IPMI_INVALID_CMD_COMPLETION_CODE; msg->data_size = 5; rcu_read_lock(); if (!intf->in_shutdown) { smi_send(intf, intf->handlers, msg, 0); /* * We used the message, so return the value * that causes it to not be freed or * queued. */ rv = -1; } rcu_read_unlock(); } else { recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { /* * We couldn't allocate memory for the * message, so requeue it for handling * later. */ rv = 1; kref_put(&user->refcount, free_user); } else { /* Extract the source address from the data. */ daddr = (struct ipmi_ipmb_direct_addr *)&recv_msg->addr; daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE; daddr->channel = 0; daddr->slave_addr = msg->rsp[1]; daddr->rs_lun = msg->rsp[0] & 3; daddr->rq_lun = msg->rsp[2] & 3; /* * Extract the rest of the message information * from the IPMB header. */ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = (msg->rsp[2] >> 2); recv_msg->msg.netfn = msg->rsp[0] >> 2; recv_msg->msg.cmd = msg->rsp[3]; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 4; memcpy(recv_msg->msg_data, msg->rsp + 4, msg->rsp_size - 4); if (deliver_response(intf, recv_msg)) ipmi_inc_stat(intf, unhandled_commands); else ipmi_inc_stat(intf, handled_commands); } } return rv; } static int handle_ipmb_direct_rcv_rsp(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { struct ipmi_recv_msg *recv_msg; struct ipmi_ipmb_direct_addr *daddr; recv_msg = msg->user_data; if (recv_msg == NULL) { dev_warn(intf->si_dev, "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"); return 0; } recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; recv_msg->msgid = msg->msgid; daddr = (struct ipmi_ipmb_direct_addr *) &recv_msg->addr; daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE; daddr->channel = 0; daddr->slave_addr = msg->rsp[1]; daddr->rq_lun = msg->rsp[0] & 3; daddr->rs_lun = msg->rsp[2] & 3; recv_msg->msg.netfn = msg->rsp[0] >> 2; recv_msg->msg.cmd = msg->rsp[3]; memcpy(recv_msg->msg_data, &msg->rsp[4], msg->rsp_size - 4); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 4; deliver_local_response(intf, recv_msg); return 0; } static int handle_lan_get_msg_rsp(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { struct ipmi_lan_addr lan_addr; struct ipmi_recv_msg *recv_msg; /* * This is 13, not 12, because the response must contain a * completion code. */ if (msg->rsp_size < 13) { /* Message not big enough, just ignore it. */ ipmi_inc_stat(intf, invalid_lan_responses); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } lan_addr.addr_type = IPMI_LAN_ADDR_TYPE; lan_addr.session_handle = msg->rsp[4]; lan_addr.remote_SWID = msg->rsp[8]; lan_addr.local_SWID = msg->rsp[5]; lan_addr.channel = msg->rsp[3] & 0x0f; lan_addr.privilege = msg->rsp[3] >> 4; lan_addr.lun = msg->rsp[9] & 3; /* * It's a response from a remote entity. Look up the sequence * number and handle the response. */ if (intf_find_seq(intf, msg->rsp[9] >> 2, msg->rsp[3] & 0x0f, msg->rsp[10], (msg->rsp[6] >> 2) & (~1), (struct ipmi_addr *) &lan_addr, &recv_msg)) { /* * We were unable to find the sequence number, * so just nuke the message. */ ipmi_inc_stat(intf, unhandled_lan_responses); return 0; } memcpy(recv_msg->msg_data, &msg->rsp[11], msg->rsp_size - 11); /* * The other fields matched, so no need to set them, except * for netfn, which needs to be the response that was * returned, not the request value. */ recv_msg->msg.netfn = msg->rsp[6] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 12; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; if (deliver_response(intf, recv_msg)) ipmi_inc_stat(intf, unhandled_lan_responses); else ipmi_inc_stat(intf, handled_lan_responses); return 0; } static int handle_lan_get_msg_cmd(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { struct cmd_rcvr *rcvr; int rv = 0; unsigned char netfn; unsigned char cmd; unsigned char chan; struct ipmi_user *user = NULL; struct ipmi_lan_addr *lan_addr; struct ipmi_recv_msg *recv_msg; if (msg->rsp_size < 12) { /* Message not big enough, just ignore it. */ ipmi_inc_stat(intf, invalid_commands); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } netfn = msg->rsp[6] >> 2; cmd = msg->rsp[10]; chan = msg->rsp[3] & 0xf; rcu_read_lock(); rcvr = find_cmd_rcvr(intf, netfn, cmd, chan); if (rcvr) { user = rcvr->user; kref_get(&user->refcount); } else user = NULL; rcu_read_unlock(); if (user == NULL) { /* We didn't find a user, just give up. */ ipmi_inc_stat(intf, unhandled_commands); /* * Don't do anything with these messages, just allow * them to be freed. */ rv = 0; } else { recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { /* * We couldn't allocate memory for the * message, so requeue it for handling later. */ rv = 1; kref_put(&user->refcount, free_user); } else { /* Extract the source address from the data. */ lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr; lan_addr->addr_type = IPMI_LAN_ADDR_TYPE; lan_addr->session_handle = msg->rsp[4]; lan_addr->remote_SWID = msg->rsp[8]; lan_addr->local_SWID = msg->rsp[5]; lan_addr->lun = msg->rsp[9] & 3; lan_addr->channel = msg->rsp[3] & 0xf; lan_addr->privilege = msg->rsp[3] >> 4; /* * Extract the rest of the message information * from the IPMB header. */ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[9] >> 2; recv_msg->msg.netfn = msg->rsp[6] >> 2; recv_msg->msg.cmd = msg->rsp[10]; recv_msg->msg.data = recv_msg->msg_data; /* * We chop off 12, not 11 bytes because the checksum * at the end also needs to be removed. */ recv_msg->msg.data_len = msg->rsp_size - 12; memcpy(recv_msg->msg_data, &msg->rsp[11], msg->rsp_size - 12); if (deliver_response(intf, recv_msg)) ipmi_inc_stat(intf, unhandled_commands); else ipmi_inc_stat(intf, handled_commands); } } return rv; } /* * This routine will handle "Get Message" command responses with * channels that use an OEM Medium. The message format belongs to * the OEM. See IPMI 2.0 specification, Chapter 6 and * Chapter 22, sections 22.6 and 22.24 for more details. */ static int handle_oem_get_msg_cmd(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { struct cmd_rcvr *rcvr; int rv = 0; unsigned char netfn; unsigned char cmd; unsigned char chan; struct ipmi_user *user = NULL; struct ipmi_system_interface_addr *smi_addr; struct ipmi_recv_msg *recv_msg; /* * We expect the OEM SW to perform error checking * so we just do some basic sanity checks */ if (msg->rsp_size < 4) { /* Message not big enough, just ignore it. */ ipmi_inc_stat(intf, invalid_commands); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } /* * This is an OEM Message so the OEM needs to know how * handle the message. We do no interpretation. */ netfn = msg->rsp[0] >> 2; cmd = msg->rsp[1]; chan = msg->rsp[3] & 0xf; rcu_read_lock(); rcvr = find_cmd_rcvr(intf, netfn, cmd, chan); if (rcvr) { user = rcvr->user; kref_get(&user->refcount); } else user = NULL; rcu_read_unlock(); if (user == NULL) { /* We didn't find a user, just give up. */ ipmi_inc_stat(intf, unhandled_commands); /* * Don't do anything with these messages, just allow * them to be freed. */ rv = 0; } else { recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { /* * We couldn't allocate memory for the * message, so requeue it for handling * later. */ rv = 1; kref_put(&user->refcount, free_user); } else { /* * OEM Messages are expected to be delivered via * the system interface to SMS software. We might * need to visit this again depending on OEM * requirements */ smi_addr = ((struct ipmi_system_interface_addr *) &recv_msg->addr); smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; smi_addr->channel = IPMI_BMC_CHANNEL; smi_addr->lun = msg->rsp[0] & 3; recv_msg->user = user; recv_msg->user_msg_data = NULL; recv_msg->recv_type = IPMI_OEM_RECV_TYPE; recv_msg->msg.netfn = msg->rsp[0] >> 2; recv_msg->msg.cmd = msg->rsp[1]; recv_msg->msg.data = recv_msg->msg_data; /* * The message starts at byte 4 which follows the * Channel Byte in the "GET MESSAGE" command */ recv_msg->msg.data_len = msg->rsp_size - 4; memcpy(recv_msg->msg_data, &msg->rsp[4], msg->rsp_size - 4); if (deliver_response(intf, recv_msg)) ipmi_inc_stat(intf, unhandled_commands); else ipmi_inc_stat(intf, handled_commands); } } return rv; } static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg, struct ipmi_smi_msg *msg) { struct ipmi_system_interface_addr *smi_addr; recv_msg->msgid = 0; smi_addr = (struct ipmi_system_interface_addr *) &recv_msg->addr; smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; smi_addr->channel = IPMI_BMC_CHANNEL; smi_addr->lun = msg->rsp[0] & 3; recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE; recv_msg->msg.netfn = msg->rsp[0] >> 2; recv_msg->msg.cmd = msg->rsp[1]; memcpy(recv_msg->msg_data, &msg->rsp[3], msg->rsp_size - 3); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 3; } static int handle_read_event_rsp(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { struct ipmi_recv_msg *recv_msg, *recv_msg2; struct list_head msgs; struct ipmi_user *user; int rv = 0, deliver_count = 0, index; unsigned long flags; if (msg->rsp_size < 19) { /* Message is too small to be an IPMB event. */ ipmi_inc_stat(intf, invalid_events); return 0; } if (msg->rsp[2] != 0) { /* An error getting the event, just ignore it. */ return 0; } INIT_LIST_HEAD(&msgs); spin_lock_irqsave(&intf->events_lock, flags); ipmi_inc_stat(intf, events); /* * Allocate and fill in one message for every user that is * getting events. */ index = srcu_read_lock(&intf->users_srcu); list_for_each_entry_rcu(user, &intf->users, link) { if (!user->gets_events) continue; recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { rcu_read_unlock(); list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) { list_del(&recv_msg->link); ipmi_free_recv_msg(recv_msg); } /* * We couldn't allocate memory for the * message, so requeue it for handling * later. */ rv = 1; goto out; } deliver_count++; copy_event_into_recv_msg(recv_msg, msg); recv_msg->user = user; kref_get(&user->refcount); list_add_tail(&recv_msg->link, &msgs); } srcu_read_unlock(&intf->users_srcu, index); if (deliver_count) { /* Now deliver all the messages. */ list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) { list_del(&recv_msg->link); deliver_local_response(intf, recv_msg); } } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) { /* * No one to receive the message, put it in queue if there's * not already too many things in the queue. */ recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { /* * We couldn't allocate memory for the * message, so requeue it for handling * later. */ rv = 1; goto out; } copy_event_into_recv_msg(recv_msg, msg); list_add_tail(&recv_msg->link, &intf->waiting_events); intf->waiting_events_count++; } else if (!intf->event_msg_printed) { /* * There's too many things in the queue, discard this * message. */ dev_warn(intf->si_dev, "Event queue full, discarding incoming events\n"); intf->event_msg_printed = 1; } out: spin_unlock_irqrestore(&intf->events_lock, flags); return rv; } static int handle_bmc_rsp(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { struct ipmi_recv_msg *recv_msg; struct ipmi_system_interface_addr *smi_addr; recv_msg = msg->user_data; if (recv_msg == NULL) { dev_warn(intf->si_dev, "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"); return 0; } recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; recv_msg->msgid = msg->msgid; smi_addr = ((struct ipmi_system_interface_addr *) &recv_msg->addr); smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; smi_addr->channel = IPMI_BMC_CHANNEL; smi_addr->lun = msg->rsp[0] & 3; recv_msg->msg.netfn = msg->rsp[0] >> 2; recv_msg->msg.cmd = msg->rsp[1]; memcpy(recv_msg->msg_data, &msg->rsp[2], msg->rsp_size - 2); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 2; deliver_local_response(intf, recv_msg); return 0; } /* * Handle a received message. Return 1 if the message should be requeued, * 0 if the message should be freed, or -1 if the message should not * be freed or requeued. */ static int handle_one_recv_msg(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { int requeue = 0; int chan; unsigned char cc; bool is_cmd = !((msg->rsp[0] >> 2) & 1); dev_dbg(intf->si_dev, "Recv: %*ph\n", msg->rsp_size, msg->rsp); if (msg->rsp_size < 2) { /* Message is too small to be correct. */ dev_warn(intf->si_dev, "BMC returned too small a message for netfn %x cmd %x, got %d bytes\n", (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size); return_unspecified: /* Generate an error response for the message. */ msg->rsp[0] = msg->data[0] | (1 << 2); msg->rsp[1] = msg->data[1]; msg->rsp[2] = IPMI_ERR_UNSPECIFIED; msg->rsp_size = 3; } else if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) { /* commands must have at least 4 bytes, responses 5. */ if (is_cmd && (msg->rsp_size < 4)) { ipmi_inc_stat(intf, invalid_commands); goto out; } if (!is_cmd && (msg->rsp_size < 5)) { ipmi_inc_stat(intf, invalid_ipmb_responses); /* Construct a valid error response. */ msg->rsp[0] = msg->data[0] & 0xfc; /* NetFN */ msg->rsp[0] |= (1 << 2); /* Make it a response */ msg->rsp[0] |= msg->data[2] & 3; /* rqLUN */ msg->rsp[1] = msg->data[1]; /* Addr */ msg->rsp[2] = msg->data[2] & 0xfc; /* rqSeq */ msg->rsp[2] |= msg->data[0] & 0x3; /* rsLUN */ msg->rsp[3] = msg->data[3]; /* Cmd */ msg->rsp[4] = IPMI_ERR_UNSPECIFIED; msg->rsp_size = 5; } } else if ((msg->data_size >= 2) && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2)) && (msg->data[1] == IPMI_SEND_MSG_CMD) && (msg->user_data == NULL)) { if (intf->in_shutdown) goto out; /* * This is the local response to a command send, start * the timer for these. The user_data will not be * NULL if this is a response send, and we will let * response sends just go through. */ /* * Check for errors, if we get certain errors (ones * that mean basically we can try again later), we * ignore them and start the timer. Otherwise we * report the error immediately. */ if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) && (msg->rsp[2] != IPMI_BUS_ERR) && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { int ch = msg->rsp[3] & 0xf; struct ipmi_channel *chans; /* Got an error sending the message, handle it. */ chans = READ_ONCE(intf->channel_list)->c; if ((chans[ch].medium == IPMI_CHANNEL_MEDIUM_8023LAN) || (chans[ch].medium == IPMI_CHANNEL_MEDIUM_ASYNC)) ipmi_inc_stat(intf, sent_lan_command_errs); else ipmi_inc_stat(intf, sent_ipmb_command_errs); intf_err_seq(intf, msg->msgid, msg->rsp[2]); } else /* The message was sent, start the timer. */ intf_start_seq_timer(intf, msg->msgid); requeue = 0; goto out; } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1)) || (msg->rsp[1] != msg->data[1])) { /* * The NetFN and Command in the response is not even * marginally correct. */ dev_warn(intf->si_dev, "BMC returned incorrect response, expected netfn %x cmd %x, got netfn %x cmd %x\n", (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp[0] >> 2, msg->rsp[1]); goto return_unspecified; } if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) { if ((msg->data[0] >> 2) & 1) { /* It's a response to a sent response. */ chan = 0; cc = msg->rsp[4]; goto process_response_response; } if (is_cmd) requeue = handle_ipmb_direct_rcv_cmd(intf, msg); else requeue = handle_ipmb_direct_rcv_rsp(intf, msg); } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) && (msg->rsp[1] == IPMI_SEND_MSG_CMD) && (msg->user_data != NULL)) { /* * It's a response to a response we sent. For this we * deliver a send message response to the user. */ struct ipmi_recv_msg *recv_msg; chan = msg->data[2] & 0x0f; if (chan >= IPMI_MAX_CHANNELS) /* Invalid channel number */ goto out; cc = msg->rsp[2]; process_response_response: recv_msg = msg->user_data; requeue = 0; if (!recv_msg) goto out; recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg_data[0] = cc; recv_msg->msg.data_len = 1; deliver_local_response(intf, recv_msg); } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) && (msg->rsp[1] == IPMI_GET_MSG_CMD)) { struct ipmi_channel *chans; /* It's from the receive queue. */ chan = msg->rsp[3] & 0xf; if (chan >= IPMI_MAX_CHANNELS) { /* Invalid channel number */ requeue = 0; goto out; } /* * We need to make sure the channels have been initialized. * The channel_handler routine will set the "curr_channel" * equal to or greater than IPMI_MAX_CHANNELS when all the * channels for this interface have been initialized. */ if (!intf->channels_ready) { requeue = 0; /* Throw the message away */ goto out; } chans = READ_ONCE(intf->channel_list)->c; switch (chans[chan].medium) { case IPMI_CHANNEL_MEDIUM_IPMB: if (msg->rsp[4] & 0x04) { /* * It's a response, so find the * requesting message and send it up. */ requeue = handle_ipmb_get_msg_rsp(intf, msg); } else { /* * It's a command to the SMS from some other * entity. Handle that. */ requeue = handle_ipmb_get_msg_cmd(intf, msg); } break; case IPMI_CHANNEL_MEDIUM_8023LAN: case IPMI_CHANNEL_MEDIUM_ASYNC: if (msg->rsp[6] & 0x04) { /* * It's a response, so find the * requesting message and send it up. */ requeue = handle_lan_get_msg_rsp(intf, msg); } else { /* * It's a command to the SMS from some other * entity. Handle that. */ requeue = handle_lan_get_msg_cmd(intf, msg); } break; default: /* Check for OEM Channels. Clients had better register for these commands. */ if ((chans[chan].medium >= IPMI_CHANNEL_MEDIUM_OEM_MIN) && (chans[chan].medium <= IPMI_CHANNEL_MEDIUM_OEM_MAX)) { requeue = handle_oem_get_msg_cmd(intf, msg); } else { /* * We don't handle the channel type, so just * free the message. */ requeue = 0; } } } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) { /* It's an asynchronous event. */ requeue = handle_read_event_rsp(intf, msg); } else { /* It's a response from the local BMC. */ requeue = handle_bmc_rsp(intf, msg); } out: return requeue; } /* * If there are messages in the queue or pretimeouts, handle them. */ static void handle_new_recv_msgs(struct ipmi_smi *intf) { struct ipmi_smi_msg *smi_msg; unsigned long flags = 0; int rv; int run_to_completion = intf->run_to_completion; /* See if any waiting messages need to be processed. */ if (!run_to_completion) spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags); while (!list_empty(&intf->waiting_rcv_msgs)) { smi_msg = list_entry(intf->waiting_rcv_msgs.next, struct ipmi_smi_msg, link); list_del(&smi_msg->link); if (!run_to_completion) spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock, flags); rv = handle_one_recv_msg(intf, smi_msg); if (!run_to_completion) spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags); if (rv > 0) { /* * To preserve message order, quit if we * can't handle a message. Add the message * back at the head, this is safe because this * tasklet is the only thing that pulls the * messages. */ list_add(&smi_msg->link, &intf->waiting_rcv_msgs); break; } else { if (rv == 0) /* Message handled */ ipmi_free_smi_msg(smi_msg); /* If rv < 0, fatal error, del but don't free. */ } } if (!run_to_completion) spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock, flags); /* * If the pretimout count is non-zero, decrement one from it and * deliver pretimeouts to all the users. */ if (atomic_add_unless(&intf->watchdog_pretimeouts_to_deliver, -1, 0)) { struct ipmi_user *user; int index; index = srcu_read_lock(&intf->users_srcu); list_for_each_entry_rcu(user, &intf->users, link) { if (user->handler->ipmi_watchdog_pretimeout) user->handler->ipmi_watchdog_pretimeout( user->handler_data); } srcu_read_unlock(&intf->users_srcu, index); } } static void smi_recv_tasklet(struct tasklet_struct *t) { unsigned long flags = 0; /* keep us warning-free. */ struct ipmi_smi *intf = from_tasklet(intf, t, recv_tasklet); int run_to_completion = intf->run_to_completion; struct ipmi_smi_msg *newmsg = NULL; /* * Start the next message if available. * * Do this here, not in the actual receiver, because we may deadlock * because the lower layer is allowed to hold locks while calling * message delivery. */ rcu_read_lock(); if (!run_to_completion) spin_lock_irqsave(&intf->xmit_msgs_lock, flags); if (intf->curr_msg == NULL && !intf->in_shutdown) { struct list_head *entry = NULL; /* Pick the high priority queue first. */ if (!list_empty(&intf->hp_xmit_msgs)) entry = intf->hp_xmit_msgs.next; else if (!list_empty(&intf->xmit_msgs)) entry = intf->xmit_msgs.next; if (entry) { list_del(entry); newmsg = list_entry(entry, struct ipmi_smi_msg, link); intf->curr_msg = newmsg; } } if (!run_to_completion) spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags); if (newmsg) intf->handlers->sender(intf->send_info, newmsg); rcu_read_unlock(); handle_new_recv_msgs(intf); } /* Handle a new message from the lower layer. */ void ipmi_smi_msg_received(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { unsigned long flags = 0; /* keep us warning-free. */ int run_to_completion = intf->run_to_completion; /* * To preserve message order, we keep a queue and deliver from * a tasklet. */ if (!run_to_completion) spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags); list_add_tail(&msg->link, &intf->waiting_rcv_msgs); if (!run_to_completion) spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock, flags); if (!run_to_completion) spin_lock_irqsave(&intf->xmit_msgs_lock, flags); /* * We can get an asynchronous event or receive message in addition * to commands we send. */ if (msg == intf->curr_msg) intf->curr_msg = NULL; if (!run_to_completion) spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags); if (run_to_completion) smi_recv_tasklet(&intf->recv_tasklet); else tasklet_schedule(&intf->recv_tasklet); } EXPORT_SYMBOL(ipmi_smi_msg_received); void ipmi_smi_watchdog_pretimeout(struct ipmi_smi *intf) { if (intf->in_shutdown) return; atomic_set(&intf->watchdog_pretimeouts_to_deliver, 1); tasklet_schedule(&intf->recv_tasklet); } EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout); static struct ipmi_smi_msg * smi_from_recv_msg(struct ipmi_smi *intf, struct ipmi_recv_msg *recv_msg, unsigned char seq, long seqid) { struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg(); if (!smi_msg) /* * If we can't allocate the message, then just return, we * get 4 retries, so this should be ok. */ return NULL; memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len); smi_msg->data_size = recv_msg->msg.data_len; smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid); dev_dbg(intf->si_dev, "Resend: %*ph\n", smi_msg->data_size, smi_msg->data); return smi_msg; } static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent, struct list_head *timeouts, unsigned long timeout_period, int slot, unsigned long *flags, bool *need_timer) { struct ipmi_recv_msg *msg; if (intf->in_shutdown) return; if (!ent->inuse) return; if (timeout_period < ent->timeout) { ent->timeout -= timeout_period; *need_timer = true; return; } if (ent->retries_left == 0) { /* The message has used all its retries. */ ent->inuse = 0; smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES); msg = ent->recv_msg; list_add_tail(&msg->link, timeouts); if (ent->broadcast) ipmi_inc_stat(intf, timed_out_ipmb_broadcasts); else if (is_lan_addr(&ent->recv_msg->addr)) ipmi_inc_stat(intf, timed_out_lan_commands); else ipmi_inc_stat(intf, timed_out_ipmb_commands); } else { struct ipmi_smi_msg *smi_msg; /* More retries, send again. */ *need_timer = true; /* * Start with the max timer, set to normal timer after * the message is sent. */ ent->timeout = MAX_MSG_TIMEOUT; ent->retries_left--; smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot, ent->seqid); if (!smi_msg) { if (is_lan_addr(&ent->recv_msg->addr)) ipmi_inc_stat(intf, dropped_rexmit_lan_commands); else ipmi_inc_stat(intf, dropped_rexmit_ipmb_commands); return; } spin_unlock_irqrestore(&intf->seq_lock, *flags); /* * Send the new message. We send with a zero * priority. It timed out, I doubt time is that * critical now, and high priority messages are really * only for messages to the local MC, which don't get * resent. */ if (intf->handlers) { if (is_lan_addr(&ent->recv_msg->addr)) ipmi_inc_stat(intf, retransmitted_lan_commands); else ipmi_inc_stat(intf, retransmitted_ipmb_commands); smi_send(intf, intf->handlers, smi_msg, 0); } else ipmi_free_smi_msg(smi_msg); spin_lock_irqsave(&intf->seq_lock, *flags); } } static bool ipmi_timeout_handler(struct ipmi_smi *intf, unsigned long timeout_period) { struct list_head timeouts; struct ipmi_recv_msg *msg, *msg2; unsigned long flags; int i; bool need_timer = false; if (!intf->bmc_registered) { kref_get(&intf->refcount); if (!schedule_work(&intf->bmc_reg_work)) { kref_put(&intf->refcount, intf_free); need_timer = true; } } /* * Go through the seq table and find any messages that * have timed out, putting them in the timeouts * list. */ INIT_LIST_HEAD(&timeouts); spin_lock_irqsave(&intf->seq_lock, flags); if (intf->ipmb_maintenance_mode_timeout) { if (intf->ipmb_maintenance_mode_timeout <= timeout_period) intf->ipmb_maintenance_mode_timeout = 0; else intf->ipmb_maintenance_mode_timeout -= timeout_period; } for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) check_msg_timeout(intf, &intf->seq_table[i], &timeouts, timeout_period, i, &flags, &need_timer); spin_unlock_irqrestore(&intf->seq_lock, flags); list_for_each_entry_safe(msg, msg2, &timeouts, link) deliver_err_response(intf, msg, IPMI_TIMEOUT_COMPLETION_CODE); /* * Maintenance mode handling. Check the timeout * optimistically before we claim the lock. It may * mean a timeout gets missed occasionally, but that * only means the timeout gets extended by one period * in that case. No big deal, and it avoids the lock * most of the time. */ if (intf->auto_maintenance_timeout > 0) { spin_lock_irqsave(&intf->maintenance_mode_lock, flags); if (intf->auto_maintenance_timeout > 0) { intf->auto_maintenance_timeout -= timeout_period; if (!intf->maintenance_mode && (intf->auto_maintenance_timeout <= 0)) { intf->maintenance_mode_enable = false; maintenance_mode_update(intf); } } spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); } tasklet_schedule(&intf->recv_tasklet); return need_timer; } static void ipmi_request_event(struct ipmi_smi *intf) { /* No event requests when in maintenance mode. */ if (intf->maintenance_mode_enable) return; if (!intf->in_shutdown) intf->handlers->request_events(intf->send_info); } static struct timer_list ipmi_timer; static atomic_t stop_operation; static void ipmi_timeout(struct timer_list *unused) { struct ipmi_smi *intf; bool need_timer = false; int index; if (atomic_read(&stop_operation)) return; index = srcu_read_lock(&ipmi_interfaces_srcu); list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { if (atomic_read(&intf->event_waiters)) { intf->ticks_to_req_ev--; if (intf->ticks_to_req_ev == 0) { ipmi_request_event(intf); intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME; } need_timer = true; } need_timer |= ipmi_timeout_handler(intf, IPMI_TIMEOUT_TIME); } srcu_read_unlock(&ipmi_interfaces_srcu, index); if (need_timer) mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); } static void need_waiter(struct ipmi_smi *intf) { /* Racy, but worst case we start the timer twice. */ if (!timer_pending(&ipmi_timer)) mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); } static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0); static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0); static void free_smi_msg(struct ipmi_smi_msg *msg) { atomic_dec(&smi_msg_inuse_count); /* Try to keep as much stuff out of the panic path as possible. */ if (!oops_in_progress) kfree(msg); } struct ipmi_smi_msg *ipmi_alloc_smi_msg(void) { struct ipmi_smi_msg *rv; rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC); if (rv) { rv->done = free_smi_msg; rv->user_data = NULL; rv->type = IPMI_SMI_MSG_TYPE_NORMAL; atomic_inc(&smi_msg_inuse_count); } return rv; } EXPORT_SYMBOL(ipmi_alloc_smi_msg); static void free_recv_msg(struct ipmi_recv_msg *msg) { atomic_dec(&recv_msg_inuse_count); /* Try to keep as much stuff out of the panic path as possible. */ if (!oops_in_progress) kfree(msg); } static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) { struct ipmi_recv_msg *rv; rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC); if (rv) { rv->user = NULL; rv->done = free_recv_msg; atomic_inc(&recv_msg_inuse_count); } return rv; } void ipmi_free_recv_msg(struct ipmi_recv_msg *msg) { if (msg->user && !oops_in_progress) kref_put(&msg->user->refcount, free_user); msg->done(msg); } EXPORT_SYMBOL(ipmi_free_recv_msg); static atomic_t panic_done_count = ATOMIC_INIT(0); static void dummy_smi_done_handler(struct ipmi_smi_msg *msg) { atomic_dec(&panic_done_count); } static void dummy_recv_done_handler(struct ipmi_recv_msg *msg) { atomic_dec(&panic_done_count); } /* * Inside a panic, send a message and wait for a response. */ static void ipmi_panic_request_and_wait(struct ipmi_smi *intf, struct ipmi_addr *addr, struct kernel_ipmi_msg *msg) { struct ipmi_smi_msg smi_msg; struct ipmi_recv_msg recv_msg; int rv; smi_msg.done = dummy_smi_done_handler; recv_msg.done = dummy_recv_done_handler; atomic_add(2, &panic_done_count); rv = i_ipmi_request(NULL, intf, addr, 0, msg, intf, &smi_msg, &recv_msg, 0, intf->addrinfo[0].address, intf->addrinfo[0].lun, 0, 1); /* Don't retry, and don't wait. */ if (rv) atomic_sub(2, &panic_done_count); else if (intf->handlers->flush_messages) intf->handlers->flush_messages(intf->send_info); while (atomic_read(&panic_done_count) != 0) ipmi_poll(intf); } static void event_receiver_fetcher(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) { if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE) && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD) && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { /* A get event receiver command, save it. */ intf->event_receiver = msg->msg.data[1]; intf->event_receiver_lun = msg->msg.data[2] & 0x3; } } static void device_id_fetcher(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) { if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD) && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { /* * A get device id command, save if we are an event * receiver or generator. */ intf->local_sel_device = (msg->msg.data[6] >> 2) & 1; intf->local_event_generator = (msg->msg.data[6] >> 5) & 1; } } static void send_panic_events(struct ipmi_smi *intf, char *str) { struct kernel_ipmi_msg msg; unsigned char data[16]; struct ipmi_system_interface_addr *si; struct ipmi_addr addr; char *p = str; struct ipmi_ipmb_addr *ipmb; int j; if (ipmi_send_panic_event == IPMI_SEND_PANIC_EVENT_NONE) return; si = (struct ipmi_system_interface_addr *) &addr; si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si->channel = IPMI_BMC_CHANNEL; si->lun = 0; /* Fill in an event telling that we have failed. */ msg.netfn = 0x04; /* Sensor or Event. */ msg.cmd = 2; /* Platform event command. */ msg.data = data; msg.data_len = 8; data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */ data[1] = 0x03; /* This is for IPMI 1.0. */ data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */ data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */ data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */ /* * Put a few breadcrumbs in. Hopefully later we can add more things * to make the panic events more useful. */ if (str) { data[3] = str[0]; data[6] = str[1]; data[7] = str[2]; } /* Send the event announcing the panic. */ ipmi_panic_request_and_wait(intf, &addr, &msg); /* * On every interface, dump a bunch of OEM event holding the * string. */ if (ipmi_send_panic_event != IPMI_SEND_PANIC_EVENT_STRING || !str) return; /* * intf_num is used as an marker to tell if the * interface is valid. Thus we need a read barrier to * make sure data fetched before checking intf_num * won't be used. */ smp_rmb(); /* * First job here is to figure out where to send the * OEM events. There's no way in IPMI to send OEM * events using an event send command, so we have to * find the SEL to put them in and stick them in * there. */ /* Get capabilities from the get device id. */ intf->local_sel_device = 0; intf->local_event_generator = 0; intf->event_receiver = 0; /* Request the device info from the local MC. */ msg.netfn = IPMI_NETFN_APP_REQUEST; msg.cmd = IPMI_GET_DEVICE_ID_CMD; msg.data = NULL; msg.data_len = 0; intf->null_user_handler = device_id_fetcher; ipmi_panic_request_and_wait(intf, &addr, &msg); if (intf->local_event_generator) { /* Request the event receiver from the local MC. */ msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST; msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD; msg.data = NULL; msg.data_len = 0; intf->null_user_handler = event_receiver_fetcher; ipmi_panic_request_and_wait(intf, &addr, &msg); } intf->null_user_handler = NULL; /* * Validate the event receiver. The low bit must not * be 1 (it must be a valid IPMB address), it cannot * be zero, and it must not be my address. */ if (((intf->event_receiver & 1) == 0) && (intf->event_receiver != 0) && (intf->event_receiver != intf->addrinfo[0].address)) { /* * The event receiver is valid, send an IPMB * message. */ ipmb = (struct ipmi_ipmb_addr *) &addr; ipmb->addr_type = IPMI_IPMB_ADDR_TYPE; ipmb->channel = 0; /* FIXME - is this right? */ ipmb->lun = intf->event_receiver_lun; ipmb->slave_addr = intf->event_receiver; } else if (intf->local_sel_device) { /* * The event receiver was not valid (or was * me), but I am an SEL device, just dump it * in my SEL. */ si = (struct ipmi_system_interface_addr *) &addr; si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si->channel = IPMI_BMC_CHANNEL; si->lun = 0; } else return; /* No where to send the event. */ msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */ msg.cmd = IPMI_ADD_SEL_ENTRY_CMD; msg.data = data; msg.data_len = 16; j = 0; while (*p) { int size = strlen(p); if (size > 11) size = 11; data[0] = 0; data[1] = 0; data[2] = 0xf0; /* OEM event without timestamp. */ data[3] = intf->addrinfo[0].address; data[4] = j++; /* sequence # */ /* * Always give 11 bytes, so strncpy will fill * it with zeroes for me. */ strncpy(data+5, p, 11); p += size; ipmi_panic_request_and_wait(intf, &addr, &msg); } } static int has_panicked; static int panic_event(struct notifier_block *this, unsigned long event, void *ptr) { struct ipmi_smi *intf; struct ipmi_user *user; if (has_panicked) return NOTIFY_DONE; has_panicked = 1; /* For every registered interface, set it to run to completion. */ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { if (!intf->handlers || intf->intf_num == -1) /* Interface is not ready. */ continue; if (!intf->handlers->poll) continue; /* * If we were interrupted while locking xmit_msgs_lock or * waiting_rcv_msgs_lock, the corresponding list may be * corrupted. In this case, drop items on the list for * the safety. */ if (!spin_trylock(&intf->xmit_msgs_lock)) { INIT_LIST_HEAD(&intf->xmit_msgs); INIT_LIST_HEAD(&intf->hp_xmit_msgs); } else spin_unlock(&intf->xmit_msgs_lock); if (!spin_trylock(&intf->waiting_rcv_msgs_lock)) INIT_LIST_HEAD(&intf->waiting_rcv_msgs); else spin_unlock(&intf->waiting_rcv_msgs_lock); intf->run_to_completion = 1; if (intf->handlers->set_run_to_completion) intf->handlers->set_run_to_completion(intf->send_info, 1); list_for_each_entry_rcu(user, &intf->users, link) { if (user->handler->ipmi_panic_handler) user->handler->ipmi_panic_handler( user->handler_data); } send_panic_events(intf, ptr); } return NOTIFY_DONE; } /* Must be called with ipmi_interfaces_mutex held. */ static int ipmi_register_driver(void) { int rv; if (drvregistered) return 0; rv = driver_register(&ipmidriver.driver); if (rv) pr_err("Could not register IPMI driver\n"); else drvregistered = true; return rv; } static struct notifier_block panic_block = { .notifier_call = panic_event, .next = NULL, .priority = 200 /* priority: INT_MAX >= x >= 0 */ }; static int ipmi_init_msghandler(void) { int rv; mutex_lock(&ipmi_interfaces_mutex); rv = ipmi_register_driver(); if (rv) goto out; if (initialized) goto out; rv = init_srcu_struct(&ipmi_interfaces_srcu); if (rv) goto out; remove_work_wq = create_singlethread_workqueue("ipmi-msghandler-remove-wq"); if (!remove_work_wq) { pr_err("unable to create ipmi-msghandler-remove-wq workqueue"); rv = -ENOMEM; goto out_wq; } timer_setup(&ipmi_timer, ipmi_timeout, 0); mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); atomic_notifier_chain_register(&panic_notifier_list, &panic_block); initialized = true; out_wq: if (rv) cleanup_srcu_struct(&ipmi_interfaces_srcu); out: mutex_unlock(&ipmi_interfaces_mutex); return rv; } static int __init ipmi_init_msghandler_mod(void) { int rv; pr_info("version " IPMI_DRIVER_VERSION "\n"); mutex_lock(&ipmi_interfaces_mutex); rv = ipmi_register_driver(); mutex_unlock(&ipmi_interfaces_mutex); return rv; } static void __exit cleanup_ipmi(void) { int count; if (initialized) { destroy_workqueue(remove_work_wq); atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block); /* * This can't be called if any interfaces exist, so no worry * about shutting down the interfaces. */ /* * Tell the timer to stop, then wait for it to stop. This * avoids problems with race conditions removing the timer * here. */ atomic_set(&stop_operation, 1); del_timer_sync(&ipmi_timer); initialized = false; /* Check for buffer leaks. */ count = atomic_read(&smi_msg_inuse_count); if (count != 0) pr_warn("SMI message count %d at exit\n", count); count = atomic_read(&recv_msg_inuse_count); if (count != 0) pr_warn("recv message count %d at exit\n", count); cleanup_srcu_struct(&ipmi_interfaces_srcu); } if (drvregistered) driver_unregister(&ipmidriver.driver); } module_exit(cleanup_ipmi); module_init(ipmi_init_msghandler_mod); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface."); MODULE_VERSION(IPMI_DRIVER_VERSION); MODULE_SOFTDEP("post: ipmi_devintf");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1