blob: ea6ba35b3d7e5a363a094caaaa2428cb32ba0b6e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ipmi_msghandler.c
3 *
4 * Incoming and outgoing message routing for an IPMI interface.
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2002 MontaVista Software Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/module.h>
35#include <linux/errno.h>
36#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/poll.h>
38#include <linux/spinlock.h>
Corey Minyardd6dfd132006-03-31 02:30:41 -080039#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/slab.h>
41#include <linux/ipmi.h>
42#include <linux/ipmi_smi.h>
43#include <linux/notifier.h>
44#include <linux/init.h>
45#include <linux/proc_fs.h>
Corey Minyard393d2cc2005-11-07 00:59:54 -080046#include <linux/rcupdate.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#define PFX "IPMI message handler: "
Corey Minyard1fdd75b2005-09-06 15:18:42 -070049
Corey Minyardf7caa1b2008-04-29 01:01:04 -070050#define IPMI_DRIVER_VERSION "39.2"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
53static int ipmi_init_msghandler(void);
54
Randy Dunlap0c8204b2006-12-10 02:19:06 -080055static int initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Corey Minyard3b625942005-06-23 22:01:42 -070057#ifdef CONFIG_PROC_FS
Randy Dunlap0c8204b2006-12-10 02:19:06 -080058static struct proc_dir_entry *proc_ipmi_root;
Corey Minyard3b625942005-06-23 22:01:42 -070059#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Corey Minyardb9675132006-12-06 20:41:02 -080061/* Remain in auto-maintenance mode for this amount of time (in ms). */
62#define IPMI_MAINTENANCE_MODE_TIMEOUT 30000
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#define MAX_EVENTS_IN_QUEUE 25
65
66/* Don't let a message sit in a queue forever, always time it with at lest
67 the max message timer. This is in milliseconds. */
68#define MAX_MSG_TIMEOUT 60000
69
Corey Minyard393d2cc2005-11-07 00:59:54 -080070/*
71 * The main "user" data structure.
72 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070073struct ipmi_user
74{
75 struct list_head link;
76
Corey Minyard393d2cc2005-11-07 00:59:54 -080077 /* Set to "0" when the user is destroyed. */
78 int valid;
79
80 struct kref refcount;
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 /* The upper layer that handles receive messages. */
83 struct ipmi_user_hndl *handler;
84 void *handler_data;
85
86 /* The interface this user is bound to. */
87 ipmi_smi_t intf;
88
89 /* Does this interface receive IPMI events? */
90 int gets_events;
91};
92
93struct cmd_rcvr
94{
95 struct list_head link;
96
97 ipmi_user_t user;
98 unsigned char netfn;
99 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -0700100 unsigned int chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800101
102 /*
103 * This is used to form a linked lised during mass deletion.
104 * Since this is in an RCU list, we cannot use the link above
105 * or change any data until the RCU period completes. So we
106 * use this next variable during mass deletion so we can have
107 * a list and don't have to wait and restart the search on
108 * every individual deletion of a command. */
109 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110};
111
112struct seq_table
113{
114 unsigned int inuse : 1;
115 unsigned int broadcast : 1;
116
117 unsigned long timeout;
118 unsigned long orig_timeout;
119 unsigned int retries_left;
120
121 /* To verify on an incoming send message response that this is
122 the message that the response is for, we keep a sequence id
123 and increment it every time we send a message. */
124 long seqid;
125
126 /* This is held so we can properly respond to the message on a
127 timeout, and it is used to hold the temporary data for
128 retransmission, too. */
129 struct ipmi_recv_msg *recv_msg;
130};
131
132/* Store the information in a msgid (long) to allow us to find a
133 sequence table entry from the msgid. */
134#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
135
136#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
137 do { \
138 seq = ((msgid >> 26) & 0x3f); \
139 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700140 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
143
144struct ipmi_channel
145{
146 unsigned char medium;
147 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700148
149 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
150 but may be changed by the user. */
151 unsigned char address;
152
153 /* My LUN. This should generally stay the SMS LUN, but just in
154 case... */
155 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156};
157
Corey Minyard3b625942005-06-23 22:01:42 -0700158#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159struct ipmi_proc_entry
160{
161 char *name;
162 struct ipmi_proc_entry *next;
163};
Corey Minyard3b625942005-06-23 22:01:42 -0700164#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
Corey Minyard50c812b2006-03-26 01:37:21 -0800166struct bmc_device
167{
168 struct platform_device *dev;
169 struct ipmi_device_id id;
170 unsigned char guid[16];
171 int guid_set;
172
173 struct kref refcount;
174
175 /* bmc device attributes */
176 struct device_attribute device_id_attr;
177 struct device_attribute provides_dev_sdrs_attr;
178 struct device_attribute revision_attr;
179 struct device_attribute firmware_rev_attr;
180 struct device_attribute version_attr;
181 struct device_attribute add_dev_support_attr;
182 struct device_attribute manufacturer_id_attr;
183 struct device_attribute product_id_attr;
184 struct device_attribute guid_attr;
185 struct device_attribute aux_firmware_rev_attr;
186};
187
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700188/*
189 * Various statistics for IPMI, these index stats[] in the ipmi_smi
190 * structure.
191 */
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700192enum ipmi_stat_indexes {
193 /* Commands we got from the user that were invalid. */
194 IPMI_STAT_sent_invalid_commands = 0,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700195
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700196 /* Commands we sent to the MC. */
197 IPMI_STAT_sent_local_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700198
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700199 /* Responses from the MC that were delivered to a user. */
200 IPMI_STAT_handled_local_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700201
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700202 /* Responses from the MC that were not delivered to a user. */
203 IPMI_STAT_unhandled_local_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700204
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700205 /* Commands we sent out to the IPMB bus. */
206 IPMI_STAT_sent_ipmb_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700207
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700208 /* Commands sent on the IPMB that had errors on the SEND CMD */
209 IPMI_STAT_sent_ipmb_command_errs,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700210
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700211 /* Each retransmit increments this count. */
212 IPMI_STAT_retransmitted_ipmb_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700213
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700214 /*
215 * When a message times out (runs out of retransmits) this is
216 * incremented.
217 */
218 IPMI_STAT_timed_out_ipmb_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700219
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700220 /*
221 * This is like above, but for broadcasts. Broadcasts are
222 * *not* included in the above count (they are expected to
223 * time out).
224 */
225 IPMI_STAT_timed_out_ipmb_broadcasts,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700226
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700227 /* Responses I have sent to the IPMB bus. */
228 IPMI_STAT_sent_ipmb_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700229
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700230 /* The response was delivered to the user. */
231 IPMI_STAT_handled_ipmb_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700232
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700233 /* The response had invalid data in it. */
234 IPMI_STAT_invalid_ipmb_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700235
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700236 /* The response didn't have anyone waiting for it. */
237 IPMI_STAT_unhandled_ipmb_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700238
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700239 /* Commands we sent out to the IPMB bus. */
240 IPMI_STAT_sent_lan_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700241
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700242 /* Commands sent on the IPMB that had errors on the SEND CMD */
243 IPMI_STAT_sent_lan_command_errs,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700244
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700245 /* Each retransmit increments this count. */
246 IPMI_STAT_retransmitted_lan_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700247
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700248 /*
249 * When a message times out (runs out of retransmits) this is
250 * incremented.
251 */
252 IPMI_STAT_timed_out_lan_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700253
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700254 /* Responses I have sent to the IPMB bus. */
255 IPMI_STAT_sent_lan_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700256
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700257 /* The response was delivered to the user. */
258 IPMI_STAT_handled_lan_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700259
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700260 /* The response had invalid data in it. */
261 IPMI_STAT_invalid_lan_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700262
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700263 /* The response didn't have anyone waiting for it. */
264 IPMI_STAT_unhandled_lan_responses,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700265
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700266 /* The command was delivered to the user. */
267 IPMI_STAT_handled_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700268
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700269 /* The command had invalid data in it. */
270 IPMI_STAT_invalid_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700271
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700272 /* The command didn't have anyone waiting for it. */
273 IPMI_STAT_unhandled_commands,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700274
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700275 /* Invalid data in an event. */
276 IPMI_STAT_invalid_events,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700277
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700278 /* Events that were received with the proper format. */
279 IPMI_STAT_events,
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700280
Corey Minyard73f2bdb2008-04-29 01:01:06 -0700281
282 /* This *must* remain last, add new values above this. */
283 IPMI_NUM_STATS
284};
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700285
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700288#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289struct ipmi_smi
290{
291 /* What interface number are we? */
292 int intf_num;
293
Corey Minyard393d2cc2005-11-07 00:59:54 -0800294 struct kref refcount;
295
Corey Minyardbca03242006-12-06 20:40:57 -0800296 /* Used for a list of interfaces. */
297 struct list_head link;
298
Corey Minyard393d2cc2005-11-07 00:59:54 -0800299 /* The list of upper layers that are using me. seq_lock
300 * protects this. */
301 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Corey Minyardb2c03942006-12-06 20:41:00 -0800303 /* Information to supply to users. */
304 unsigned char ipmi_version_major;
305 unsigned char ipmi_version_minor;
306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 /* Used for wake ups at startup. */
308 wait_queue_head_t waitq;
309
Corey Minyard50c812b2006-03-26 01:37:21 -0800310 struct bmc_device *bmc;
311 char *my_dev_name;
Corey Minyard759643b2006-12-06 20:40:59 -0800312 char *sysfs_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Corey Minyardb2c03942006-12-06 20:41:00 -0800314 /* This is the lower-layer's sender routine. Note that you
315 * must either be holding the ipmi_interfaces_mutex or be in
316 * an umpreemptible region to use this. You must fetch the
317 * value into a local variable and make sure it is not NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 struct ipmi_smi_handlers *handlers;
319 void *send_info;
320
Corey Minyard3b625942005-06-23 22:01:42 -0700321#ifdef CONFIG_PROC_FS
Corey Minyardac019152007-10-18 03:07:11 -0700322 /* A list of proc entries for this interface. */
323 struct mutex proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700325#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Corey Minyard50c812b2006-03-26 01:37:21 -0800327 /* Driver-model device for the system interface. */
328 struct device *si_dev;
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 /* A table of sequence numbers for this interface. We use the
331 sequence numbers for IPMB messages that go out of the
332 interface to match them up with their responses. A routine
333 is called periodically to time the items in this list. */
334 spinlock_t seq_lock;
335 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
336 int curr_seq;
337
338 /* Messages that were delayed for some reason (out of memory,
339 for instance), will go in here to be processed later in a
340 periodic timer interrupt. */
341 spinlock_t waiting_msgs_lock;
342 struct list_head waiting_msgs;
343
344 /* The list of command receivers that are registered for commands
345 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800346 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 struct list_head cmd_rcvrs;
348
349 /* Events that were queues because no one was there to receive
350 them. */
351 spinlock_t events_lock; /* For dealing with event stuff. */
352 struct list_head waiting_events;
353 unsigned int waiting_events_count; /* How many events in queue? */
Corey Minyard87ebd062008-04-29 01:01:04 -0700354 char delivering_events;
355 char event_msg_printed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 /* The event receiver for my BMC, only really used at panic
358 shutdown as a place to store this. */
359 unsigned char event_receiver;
360 unsigned char event_receiver_lun;
361 unsigned char local_sel_device;
362 unsigned char local_event_generator;
363
Corey Minyardb9675132006-12-06 20:41:02 -0800364 /* For handling of maintenance mode. */
365 int maintenance_mode;
366 int maintenance_mode_enable;
367 int auto_maintenance_timeout;
368 spinlock_t maintenance_mode_lock; /* Used in a timer... */
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 /* A cheap hack, if this is non-null and a message to an
371 interface comes in with a NULL user, call this routine with
372 it. Note that the message will still be freed by the
373 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700374 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 /* When we are scanning the channels for an SMI, this will
377 tell which channel we are scanning. */
378 int curr_channel;
379
380 /* Channel information */
381 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
382
383 /* Proc FS stuff. */
384 struct proc_dir_entry *proc_dir;
385 char proc_dir_name[10];
386
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700387 atomic_t stats[IPMI_NUM_STATS];
Konstantin Baydarov5956dce2008-04-29 01:01:03 -0700388
389 /*
390 * run_to_completion duplicate of smb_info, smi_info
391 * and ipmi_serial_info structures. Used to decrease numbers of
392 * parameters passed by "low" level IPMI code.
393 */
394 int run_to_completion;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395};
Corey Minyard50c812b2006-03-26 01:37:21 -0800396#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Corey Minyard50c812b2006-03-26 01:37:21 -0800398/**
399 * The driver model view of the IPMI messaging driver.
400 */
401static struct device_driver ipmidriver = {
402 .name = "ipmi",
403 .bus = &platform_bus_type
404};
405static DEFINE_MUTEX(ipmidriver_mutex);
406
Denis Chengbed97592008-02-06 01:37:35 -0800407static LIST_HEAD(ipmi_interfaces);
Corey Minyardbca03242006-12-06 20:40:57 -0800408static DEFINE_MUTEX(ipmi_interfaces_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
410/* List of watchers that want to know when smi's are added and
411 deleted. */
Denis Chengbed97592008-02-06 01:37:35 -0800412static LIST_HEAD(smi_watchers);
Corey Minyardb2c03942006-12-06 20:41:00 -0800413static DEFINE_MUTEX(smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700416#define ipmi_inc_stat(intf, stat) \
417 atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat])
418#define ipmi_get_stat(intf, stat) \
419 ((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat]))
420
421
Corey Minyard393d2cc2005-11-07 00:59:54 -0800422static void free_recv_msg_list(struct list_head *q)
423{
424 struct ipmi_recv_msg *msg, *msg2;
425
426 list_for_each_entry_safe(msg, msg2, q, link) {
427 list_del(&msg->link);
428 ipmi_free_recv_msg(msg);
429 }
430}
431
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800432static void free_smi_msg_list(struct list_head *q)
433{
434 struct ipmi_smi_msg *msg, *msg2;
435
436 list_for_each_entry_safe(msg, msg2, q, link) {
437 list_del(&msg->link);
438 ipmi_free_smi_msg(msg);
439 }
440}
441
Corey Minyard393d2cc2005-11-07 00:59:54 -0800442static void clean_up_interface_data(ipmi_smi_t intf)
443{
444 int i;
445 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800446 struct list_head list;
447
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800448 free_smi_msg_list(&intf->waiting_msgs);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800449 free_recv_msg_list(&intf->waiting_events);
450
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800451 /*
452 * Wholesale remove all the entries from the list in the
453 * interface and wait for RCU to know that none are in use.
454 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800455 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800456 INIT_LIST_HEAD(&list);
457 list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800458 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800459
460 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
461 kfree(rcvr);
462
463 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
464 if ((intf->seq_table[i].inuse)
465 && (intf->seq_table[i].recv_msg))
466 {
467 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 }
469 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800470}
471
472static void intf_free(struct kref *ref)
473{
474 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
475
476 clean_up_interface_data(intf);
477 kfree(intf);
478}
479
Corey Minyardbca03242006-12-06 20:40:57 -0800480struct watcher_entry {
Corey Minyardb2c03942006-12-06 20:41:00 -0800481 int intf_num;
482 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800483 struct list_head link;
Corey Minyardbca03242006-12-06 20:40:57 -0800484};
485
Corey Minyard393d2cc2005-11-07 00:59:54 -0800486int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
487{
Corey Minyardbca03242006-12-06 20:40:57 -0800488 ipmi_smi_t intf;
Denis Chenge381d1c2008-02-06 01:37:39 -0800489 LIST_HEAD(to_deliver);
Corey Minyardbca03242006-12-06 20:40:57 -0800490 struct watcher_entry *e, *e2;
491
Corey Minyardb2c03942006-12-06 20:41:00 -0800492 mutex_lock(&smi_watchers_mutex);
493
Corey Minyardbca03242006-12-06 20:40:57 -0800494 mutex_lock(&ipmi_interfaces_mutex);
495
Corey Minyardb2c03942006-12-06 20:41:00 -0800496 /* Build a list of things to deliver. */
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800497 list_for_each_entry(intf, &ipmi_interfaces, link) {
Corey Minyardbca03242006-12-06 20:40:57 -0800498 if (intf->intf_num == -1)
499 continue;
500 e = kmalloc(sizeof(*e), GFP_KERNEL);
501 if (!e)
502 goto out_err;
Corey Minyardb2c03942006-12-06 20:41:00 -0800503 kref_get(&intf->refcount);
504 e->intf = intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800505 e->intf_num = intf->intf_num;
506 list_add_tail(&e->link, &to_deliver);
507 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800508
Corey Minyardb2c03942006-12-06 20:41:00 -0800509 /* We will succeed, so add it to the list. */
510 list_add(&watcher->link, &smi_watchers);
Corey Minyardbca03242006-12-06 20:40:57 -0800511
512 mutex_unlock(&ipmi_interfaces_mutex);
513
514 list_for_each_entry_safe(e, e2, &to_deliver, link) {
515 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800516 watcher->new_smi(e->intf_num, e->intf->si_dev);
517 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800518 kfree(e);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800519 }
Corey Minyardbca03242006-12-06 20:40:57 -0800520
Corey Minyardb2c03942006-12-06 20:41:00 -0800521 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 return 0;
Corey Minyardbca03242006-12-06 20:40:57 -0800524
525 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -0800526 mutex_unlock(&ipmi_interfaces_mutex);
527 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800528 list_for_each_entry_safe(e, e2, &to_deliver, link) {
529 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800530 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800531 kfree(e);
532 }
533 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534}
535
536int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
537{
Corey Minyardb2c03942006-12-06 20:41:00 -0800538 mutex_lock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 list_del(&(watcher->link));
Corey Minyardb2c03942006-12-06 20:41:00 -0800540 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 return 0;
542}
543
Corey Minyardb2c03942006-12-06 20:41:00 -0800544/*
545 * Must be called with smi_watchers_mutex held.
546 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800548call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
550 struct ipmi_smi_watcher *w;
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 list_for_each_entry(w, &smi_watchers, link) {
553 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800554 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 module_put(w->owner);
556 }
557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
560static int
561ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
562{
563 if (addr1->addr_type != addr2->addr_type)
564 return 0;
565
566 if (addr1->channel != addr2->channel)
567 return 0;
568
569 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
570 struct ipmi_system_interface_addr *smi_addr1
571 = (struct ipmi_system_interface_addr *) addr1;
572 struct ipmi_system_interface_addr *smi_addr2
573 = (struct ipmi_system_interface_addr *) addr2;
574 return (smi_addr1->lun == smi_addr2->lun);
575 }
576
577 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
578 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
579 {
580 struct ipmi_ipmb_addr *ipmb_addr1
581 = (struct ipmi_ipmb_addr *) addr1;
582 struct ipmi_ipmb_addr *ipmb_addr2
583 = (struct ipmi_ipmb_addr *) addr2;
584
585 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
586 && (ipmb_addr1->lun == ipmb_addr2->lun));
587 }
588
589 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
590 struct ipmi_lan_addr *lan_addr1
591 = (struct ipmi_lan_addr *) addr1;
592 struct ipmi_lan_addr *lan_addr2
593 = (struct ipmi_lan_addr *) addr2;
594
595 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
596 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
597 && (lan_addr1->session_handle
598 == lan_addr2->session_handle)
599 && (lan_addr1->lun == lan_addr2->lun));
600 }
601
602 return 1;
603}
604
605int ipmi_validate_addr(struct ipmi_addr *addr, int len)
606{
607 if (len < sizeof(struct ipmi_system_interface_addr)) {
608 return -EINVAL;
609 }
610
611 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
612 if (addr->channel != IPMI_BMC_CHANNEL)
613 return -EINVAL;
614 return 0;
615 }
616
617 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800618 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 || (addr->channel < 0))
620 return -EINVAL;
621
622 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
623 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
624 {
625 if (len < sizeof(struct ipmi_ipmb_addr)) {
626 return -EINVAL;
627 }
628 return 0;
629 }
630
631 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
632 if (len < sizeof(struct ipmi_lan_addr)) {
633 return -EINVAL;
634 }
635 return 0;
636 }
637
638 return -EINVAL;
639}
640
641unsigned int ipmi_addr_length(int addr_type)
642{
643 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
644 return sizeof(struct ipmi_system_interface_addr);
645
646 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
647 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
648 {
649 return sizeof(struct ipmi_ipmb_addr);
650 }
651
652 if (addr_type == IPMI_LAN_ADDR_TYPE)
653 return sizeof(struct ipmi_lan_addr);
654
655 return 0;
656}
657
658static void deliver_response(struct ipmi_recv_msg *msg)
659{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800660 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700661 ipmi_smi_t intf = msg->user_msg_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -0700662
663 /* Special handling for NULL users. */
664 if (intf->null_user_handler) {
665 intf->null_user_handler(intf, msg);
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700666 ipmi_inc_stat(intf, handled_local_responses);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700667 } else {
668 /* No handler, so give up. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -0700669 ipmi_inc_stat(intf, unhandled_local_responses);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700670 }
671 ipmi_free_recv_msg(msg);
672 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800673 ipmi_user_t user = msg->user;
674 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676}
677
Corey Minyardb2c03942006-12-06 20:41:00 -0800678static void
679deliver_err_response(struct ipmi_recv_msg *msg, int err)
680{
681 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
682 msg->msg_data[0] = err;
683 msg->msg.netfn |= 1; /* Convert to a response. */
684 msg->msg.data_len = 1;
685 msg->msg.data = msg->msg_data;
686 deliver_response(msg);
687}
688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689/* Find the next sequence number not being used and add the given
690 message with the given timeout to the sequence table. This must be
691 called with the interface's seq_lock held. */
692static int intf_next_seq(ipmi_smi_t intf,
693 struct ipmi_recv_msg *recv_msg,
694 unsigned long timeout,
695 int retries,
696 int broadcast,
697 unsigned char *seq,
698 long *seqid)
699{
700 int rv = 0;
701 unsigned int i;
702
Corey Minyarde8b33612005-09-06 15:18:45 -0700703 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700705 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800707 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 break;
709 }
710
Corey Minyard8a3628d2006-03-31 02:30:40 -0800711 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 intf->seq_table[i].recv_msg = recv_msg;
713
714 /* Start with the maximum timeout, when the send response
715 comes in we will start the real timer. */
716 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
717 intf->seq_table[i].orig_timeout = timeout;
718 intf->seq_table[i].retries_left = retries;
719 intf->seq_table[i].broadcast = broadcast;
720 intf->seq_table[i].inuse = 1;
721 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
722 *seq = i;
723 *seqid = intf->seq_table[i].seqid;
724 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
725 } else {
726 rv = -EAGAIN;
727 }
728
729 return rv;
730}
731
732/* Return the receive message for the given sequence number and
733 release the sequence number so it can be reused. Some other data
734 is passed in to be sure the message matches up correctly (to help
735 guard against message coming in after their timeout and the
736 sequence number being reused). */
737static int intf_find_seq(ipmi_smi_t intf,
738 unsigned char seq,
739 short channel,
740 unsigned char cmd,
741 unsigned char netfn,
742 struct ipmi_addr *addr,
743 struct ipmi_recv_msg **recv_msg)
744{
745 int rv = -ENODEV;
746 unsigned long flags;
747
748 if (seq >= IPMI_IPMB_NUM_SEQ)
749 return -EINVAL;
750
751 spin_lock_irqsave(&(intf->seq_lock), flags);
752 if (intf->seq_table[seq].inuse) {
753 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
754
755 if ((msg->addr.channel == channel)
756 && (msg->msg.cmd == cmd)
757 && (msg->msg.netfn == netfn)
758 && (ipmi_addr_equal(addr, &(msg->addr))))
759 {
760 *recv_msg = msg;
761 intf->seq_table[seq].inuse = 0;
762 rv = 0;
763 }
764 }
765 spin_unlock_irqrestore(&(intf->seq_lock), flags);
766
767 return rv;
768}
769
770
771/* Start the timer for a specific sequence table entry. */
772static int intf_start_seq_timer(ipmi_smi_t intf,
773 long msgid)
774{
775 int rv = -ENODEV;
776 unsigned long flags;
777 unsigned char seq;
778 unsigned long seqid;
779
780
781 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
782
783 spin_lock_irqsave(&(intf->seq_lock), flags);
784 /* We do this verification because the user can be deleted
785 while a message is outstanding. */
786 if ((intf->seq_table[seq].inuse)
787 && (intf->seq_table[seq].seqid == seqid))
788 {
789 struct seq_table *ent = &(intf->seq_table[seq]);
790 ent->timeout = ent->orig_timeout;
791 rv = 0;
792 }
793 spin_unlock_irqrestore(&(intf->seq_lock), flags);
794
795 return rv;
796}
797
798/* Got an error for the send message for a specific sequence number. */
799static int intf_err_seq(ipmi_smi_t intf,
800 long msgid,
801 unsigned int err)
802{
803 int rv = -ENODEV;
804 unsigned long flags;
805 unsigned char seq;
806 unsigned long seqid;
807 struct ipmi_recv_msg *msg = NULL;
808
809
810 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
811
812 spin_lock_irqsave(&(intf->seq_lock), flags);
813 /* We do this verification because the user can be deleted
814 while a message is outstanding. */
815 if ((intf->seq_table[seq].inuse)
816 && (intf->seq_table[seq].seqid == seqid))
817 {
818 struct seq_table *ent = &(intf->seq_table[seq]);
819
820 ent->inuse = 0;
821 msg = ent->recv_msg;
822 rv = 0;
823 }
824 spin_unlock_irqrestore(&(intf->seq_lock), flags);
825
Corey Minyardb2c03942006-12-06 20:41:00 -0800826 if (msg)
827 deliver_err_response(msg, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829 return rv;
830}
831
832
833int ipmi_create_user(unsigned int if_num,
834 struct ipmi_user_hndl *handler,
835 void *handler_data,
836 ipmi_user_t *user)
837{
838 unsigned long flags;
839 ipmi_user_t new_user;
840 int rv = 0;
841 ipmi_smi_t intf;
842
843 /* There is no module usecount here, because it's not
844 required. Since this can only be used by and called from
845 other modules, they will implicitly use this module, and
846 thus this can't be removed unless the other modules are
847 removed. */
848
849 if (handler == NULL)
850 return -EINVAL;
851
852 /* Make sure the driver is actually initialized, this handles
853 problems with initialization order. */
854 if (!initialized) {
855 rv = ipmi_init_msghandler();
856 if (rv)
857 return rv;
858
859 /* The init code doesn't return an error if it was turned
860 off, but it won't initialize. Check that. */
861 if (!initialized)
862 return -ENODEV;
863 }
864
865 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800866 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 return -ENOMEM;
868
Corey Minyardb2c03942006-12-06 20:41:00 -0800869 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800870 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
871 if (intf->intf_num == if_num)
872 goto found;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 }
Corey Minyardb2c03942006-12-06 20:41:00 -0800874 /* Not found, return an error */
Corey Minyardbca03242006-12-06 20:40:57 -0800875 rv = -EINVAL;
876 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Corey Minyardbca03242006-12-06 20:40:57 -0800878 found:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800879 /* Note that each existing user holds a refcount to the interface. */
880 kref_get(&intf->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Corey Minyard393d2cc2005-11-07 00:59:54 -0800882 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 new_user->handler = handler;
884 new_user->handler_data = handler_data;
885 new_user->intf = intf;
886 new_user->gets_events = 0;
887
888 if (!try_module_get(intf->handlers->owner)) {
889 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800890 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 }
892
893 if (intf->handlers->inc_usecount) {
894 rv = intf->handlers->inc_usecount(intf->send_info);
895 if (rv) {
896 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800897 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
899 }
900
Corey Minyardb2c03942006-12-06 20:41:00 -0800901 /* Hold the lock so intf->handlers is guaranteed to be good
902 * until now */
903 mutex_unlock(&ipmi_interfaces_mutex);
904
Corey Minyard393d2cc2005-11-07 00:59:54 -0800905 new_user->valid = 1;
906 spin_lock_irqsave(&intf->seq_lock, flags);
907 list_add_rcu(&new_user->link, &intf->users);
908 spin_unlock_irqrestore(&intf->seq_lock, flags);
909 *user = new_user;
910 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
Adrian Bunk5c98d292006-03-25 03:07:52 -0800912out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800913 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800914out_kfree:
Corey Minyardb2c03942006-12-06 20:41:00 -0800915 mutex_unlock(&ipmi_interfaces_mutex);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800916 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 return rv;
918}
919
Corey Minyard393d2cc2005-11-07 00:59:54 -0800920static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800922 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924}
925
926int ipmi_destroy_user(ipmi_user_t user)
927{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800928 ipmi_smi_t intf = user->intf;
929 int i;
930 unsigned long flags;
931 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800932 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
Corey Minyard8a3628d2006-03-31 02:30:40 -0800934 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800935
936 /* Remove the user from the interface's sequence table. */
937 spin_lock_irqsave(&intf->seq_lock, flags);
938 list_del_rcu(&user->link);
939
940 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
941 if (intf->seq_table[i].inuse
942 && (intf->seq_table[i].recv_msg->user == user))
943 {
944 intf->seq_table[i].inuse = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -0800945 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800948 spin_unlock_irqrestore(&intf->seq_lock, flags);
949
950 /*
951 * Remove the user from the command receiver's table. First
952 * we build a list of everything (not using the standard link,
953 * since other things may be using it till we do
954 * synchronize_rcu()) then free everything in that list.
955 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800956 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800957 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800958 if (rcvr->user == user) {
959 list_del_rcu(&rcvr->link);
960 rcvr->next = rcvrs;
961 rcvrs = rcvr;
962 }
963 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800964 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800965 synchronize_rcu();
966 while (rcvrs) {
967 rcvr = rcvrs;
968 rcvrs = rcvr->next;
969 kfree(rcvr);
970 }
971
Corey Minyardb2c03942006-12-06 20:41:00 -0800972 mutex_lock(&ipmi_interfaces_mutex);
973 if (intf->handlers) {
974 module_put(intf->handlers->owner);
975 if (intf->handlers->dec_usecount)
976 intf->handlers->dec_usecount(intf->send_info);
977 }
978 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800979
980 kref_put(&intf->refcount, intf_free);
981
982 kref_put(&user->refcount, free_user);
983
Corey Minyard8a3628d2006-03-31 02:30:40 -0800984 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985}
986
987void ipmi_get_version(ipmi_user_t user,
988 unsigned char *major,
989 unsigned char *minor)
990{
Corey Minyardb2c03942006-12-06 20:41:00 -0800991 *major = user->intf->ipmi_version_major;
992 *minor = user->intf->ipmi_version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993}
994
Corey Minyardc14979b2005-09-06 15:18:38 -0700995int ipmi_set_my_address(ipmi_user_t user,
996 unsigned int channel,
997 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
Corey Minyardc14979b2005-09-06 15:18:38 -0700999 if (channel >= IPMI_MAX_CHANNELS)
1000 return -EINVAL;
1001 user->intf->channels[channel].address = address;
1002 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003}
1004
Corey Minyardc14979b2005-09-06 15:18:38 -07001005int ipmi_get_my_address(ipmi_user_t user,
1006 unsigned int channel,
1007 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
Corey Minyardc14979b2005-09-06 15:18:38 -07001009 if (channel >= IPMI_MAX_CHANNELS)
1010 return -EINVAL;
1011 *address = user->intf->channels[channel].address;
1012 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013}
1014
Corey Minyardc14979b2005-09-06 15:18:38 -07001015int ipmi_set_my_LUN(ipmi_user_t user,
1016 unsigned int channel,
1017 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
Corey Minyardc14979b2005-09-06 15:18:38 -07001019 if (channel >= IPMI_MAX_CHANNELS)
1020 return -EINVAL;
1021 user->intf->channels[channel].lun = LUN & 0x3;
1022 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023}
1024
Corey Minyardc14979b2005-09-06 15:18:38 -07001025int ipmi_get_my_LUN(ipmi_user_t user,
1026 unsigned int channel,
1027 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028{
Corey Minyardc14979b2005-09-06 15:18:38 -07001029 if (channel >= IPMI_MAX_CHANNELS)
1030 return -EINVAL;
1031 *address = user->intf->channels[channel].lun;
1032 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
Corey Minyardb9675132006-12-06 20:41:02 -08001035int ipmi_get_maintenance_mode(ipmi_user_t user)
1036{
1037 int mode;
1038 unsigned long flags;
1039
1040 spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
1041 mode = user->intf->maintenance_mode;
1042 spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
1043
1044 return mode;
1045}
1046EXPORT_SYMBOL(ipmi_get_maintenance_mode);
1047
1048static void maintenance_mode_update(ipmi_smi_t intf)
1049{
1050 if (intf->handlers->set_maintenance_mode)
1051 intf->handlers->set_maintenance_mode(
1052 intf->send_info, intf->maintenance_mode_enable);
1053}
1054
1055int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)
1056{
1057 int rv = 0;
1058 unsigned long flags;
1059 ipmi_smi_t intf = user->intf;
1060
1061 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1062 if (intf->maintenance_mode != mode) {
1063 switch (mode) {
1064 case IPMI_MAINTENANCE_MODE_AUTO:
1065 intf->maintenance_mode = mode;
1066 intf->maintenance_mode_enable
1067 = (intf->auto_maintenance_timeout > 0);
1068 break;
1069
1070 case IPMI_MAINTENANCE_MODE_OFF:
1071 intf->maintenance_mode = mode;
1072 intf->maintenance_mode_enable = 0;
1073 break;
1074
1075 case IPMI_MAINTENANCE_MODE_ON:
1076 intf->maintenance_mode = mode;
1077 intf->maintenance_mode_enable = 1;
1078 break;
1079
1080 default:
1081 rv = -EINVAL;
1082 goto out_unlock;
1083 }
1084
1085 maintenance_mode_update(intf);
1086 }
1087 out_unlock:
1088 spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
1089
1090 return rv;
1091}
1092EXPORT_SYMBOL(ipmi_set_maintenance_mode);
1093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094int ipmi_set_gets_events(ipmi_user_t user, int val)
1095{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001096 unsigned long flags;
1097 ipmi_smi_t intf = user->intf;
1098 struct ipmi_recv_msg *msg, *msg2;
1099 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Corey Minyard393d2cc2005-11-07 00:59:54 -08001101 INIT_LIST_HEAD(&msgs);
1102
1103 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 user->gets_events = val;
1105
Corey Minyardb2c03942006-12-06 20:41:00 -08001106 if (intf->delivering_events)
1107 /*
1108 * Another thread is delivering events for this, so
1109 * let it handle any new events.
1110 */
1111 goto out;
1112
1113 /* Deliver any queued events. */
1114 while (user->gets_events && !list_empty(&intf->waiting_events)) {
Akinobu Mita179e0912006-06-26 00:24:41 -07001115 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
1116 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -07001117 intf->waiting_events_count = 0;
Corey Minyard87ebd062008-04-29 01:01:04 -07001118 if (intf->event_msg_printed) {
1119 printk(KERN_WARNING PFX "Event queue no longer"
1120 " full\n");
1121 intf->event_msg_printed = 0;
1122 }
Corey Minyardb2c03942006-12-06 20:41:00 -08001123
1124 intf->delivering_events = 1;
1125 spin_unlock_irqrestore(&intf->events_lock, flags);
1126
1127 list_for_each_entry_safe(msg, msg2, &msgs, link) {
1128 msg->user = user;
1129 kref_get(&user->refcount);
1130 deliver_response(msg);
1131 }
1132
1133 spin_lock_irqsave(&intf->events_lock, flags);
1134 intf->delivering_events = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001136
Corey Minyardb2c03942006-12-06 20:41:00 -08001137 out:
Corey Minyard393d2cc2005-11-07 00:59:54 -08001138 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
1140 return 0;
1141}
1142
Corey Minyard393d2cc2005-11-07 00:59:54 -08001143static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
1144 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001145 unsigned char cmd,
1146 unsigned char chan)
Corey Minyard393d2cc2005-11-07 00:59:54 -08001147{
1148 struct cmd_rcvr *rcvr;
1149
1150 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyardc69c3122006-09-30 23:27:56 -07001151 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1152 && (rcvr->chans & (1 << chan)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08001153 return rcvr;
1154 }
1155 return NULL;
1156}
1157
Corey Minyardc69c3122006-09-30 23:27:56 -07001158static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
1159 unsigned char netfn,
1160 unsigned char cmd,
1161 unsigned int chans)
1162{
1163 struct cmd_rcvr *rcvr;
1164
1165 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1166 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1167 && (rcvr->chans & chans))
1168 return 0;
1169 }
1170 return 1;
1171}
1172
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173int ipmi_register_for_cmd(ipmi_user_t user,
1174 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001175 unsigned char cmd,
1176 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001178 ipmi_smi_t intf = user->intf;
1179 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001180 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182
1183 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001184 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001186 rcvr->cmd = cmd;
1187 rcvr->netfn = netfn;
Corey Minyardc69c3122006-09-30 23:27:56 -07001188 rcvr->chans = chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001189 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
Corey Minyardd6dfd132006-03-31 02:30:41 -08001191 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 /* Make sure the command/netfn is not already registered. */
Corey Minyardc69c3122006-09-30 23:27:56 -07001193 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001194 rv = -EBUSY;
1195 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 }
1197
Corey Minyard393d2cc2005-11-07 00:59:54 -08001198 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -07001199
Corey Minyard393d2cc2005-11-07 00:59:54 -08001200 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -08001201 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 if (rv)
1203 kfree(rcvr);
1204
1205 return rv;
1206}
1207
1208int ipmi_unregister_for_cmd(ipmi_user_t user,
1209 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001210 unsigned char cmd,
1211 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001213 ipmi_smi_t intf = user->intf;
1214 struct cmd_rcvr *rcvr;
Corey Minyardc69c3122006-09-30 23:27:56 -07001215 struct cmd_rcvr *rcvrs = NULL;
1216 int i, rv = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Corey Minyardd6dfd132006-03-31 02:30:41 -08001218 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyardc69c3122006-09-30 23:27:56 -07001219 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1220 if (((1 << i) & chans) == 0)
1221 continue;
1222 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1223 if (rcvr == NULL)
1224 continue;
1225 if (rcvr->user == user) {
1226 rv = 0;
1227 rcvr->chans &= ~chans;
1228 if (rcvr->chans == 0) {
1229 list_del_rcu(&rcvr->link);
1230 rcvr->next = rcvrs;
1231 rcvrs = rcvr;
1232 }
1233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
Corey Minyardc69c3122006-09-30 23:27:56 -07001235 mutex_unlock(&intf->cmd_rcvrs_mutex);
1236 synchronize_rcu();
1237 while (rcvrs) {
1238 rcvr = rcvrs;
1239 rcvrs = rcvr->next;
1240 kfree(rcvr);
1241 }
1242 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243}
1244
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245static unsigned char
1246ipmb_checksum(unsigned char *data, int size)
1247{
1248 unsigned char csum = 0;
1249
1250 for (; size > 0; size--, data++)
1251 csum += *data;
1252
1253 return -csum;
1254}
1255
1256static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1257 struct kernel_ipmi_msg *msg,
1258 struct ipmi_ipmb_addr *ipmb_addr,
1259 long msgid,
1260 unsigned char ipmb_seq,
1261 int broadcast,
1262 unsigned char source_address,
1263 unsigned char source_lun)
1264{
1265 int i = broadcast;
1266
1267 /* Format the IPMB header data. */
1268 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1269 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1270 smi_msg->data[2] = ipmb_addr->channel;
1271 if (broadcast)
1272 smi_msg->data[3] = 0;
1273 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1274 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1275 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1276 smi_msg->data[i+6] = source_address;
1277 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1278 smi_msg->data[i+8] = msg->cmd;
1279
1280 /* Now tack on the data to the message. */
1281 if (msg->data_len > 0)
1282 memcpy(&(smi_msg->data[i+9]), msg->data,
1283 msg->data_len);
1284 smi_msg->data_size = msg->data_len + 9;
1285
1286 /* Now calculate the checksum and tack it on. */
1287 smi_msg->data[i+smi_msg->data_size]
1288 = ipmb_checksum(&(smi_msg->data[i+6]),
1289 smi_msg->data_size-6);
1290
1291 /* Add on the checksum size and the offset from the
1292 broadcast. */
1293 smi_msg->data_size += 1 + i;
1294
1295 smi_msg->msgid = msgid;
1296}
1297
1298static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1299 struct kernel_ipmi_msg *msg,
1300 struct ipmi_lan_addr *lan_addr,
1301 long msgid,
1302 unsigned char ipmb_seq,
1303 unsigned char source_lun)
1304{
1305 /* Format the IPMB header data. */
1306 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1307 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1308 smi_msg->data[2] = lan_addr->channel;
1309 smi_msg->data[3] = lan_addr->session_handle;
1310 smi_msg->data[4] = lan_addr->remote_SWID;
1311 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1312 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1313 smi_msg->data[7] = lan_addr->local_SWID;
1314 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1315 smi_msg->data[9] = msg->cmd;
1316
1317 /* Now tack on the data to the message. */
1318 if (msg->data_len > 0)
1319 memcpy(&(smi_msg->data[10]), msg->data,
1320 msg->data_len);
1321 smi_msg->data_size = msg->data_len + 10;
1322
1323 /* Now calculate the checksum and tack it on. */
1324 smi_msg->data[smi_msg->data_size]
1325 = ipmb_checksum(&(smi_msg->data[7]),
1326 smi_msg->data_size-7);
1327
1328 /* Add on the checksum size and the offset from the
1329 broadcast. */
1330 smi_msg->data_size += 1;
1331
1332 smi_msg->msgid = msgid;
1333}
1334
1335/* Separate from ipmi_request so that the user does not have to be
1336 supplied in certain circumstances (mainly at panic time). If
1337 messages are supplied, they will be freed, even if an error
1338 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001339static int i_ipmi_request(ipmi_user_t user,
1340 ipmi_smi_t intf,
1341 struct ipmi_addr *addr,
1342 long msgid,
1343 struct kernel_ipmi_msg *msg,
1344 void *user_msg_data,
1345 void *supplied_smi,
1346 struct ipmi_recv_msg *supplied_recv,
1347 int priority,
1348 unsigned char source_address,
1349 unsigned char source_lun,
1350 int retries,
1351 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352{
Corey Minyardb2c03942006-12-06 20:41:00 -08001353 int rv = 0;
1354 struct ipmi_smi_msg *smi_msg;
1355 struct ipmi_recv_msg *recv_msg;
1356 unsigned long flags;
1357 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
1359
1360 if (supplied_recv) {
1361 recv_msg = supplied_recv;
1362 } else {
1363 recv_msg = ipmi_alloc_recv_msg();
1364 if (recv_msg == NULL) {
1365 return -ENOMEM;
1366 }
1367 }
1368 recv_msg->user_msg_data = user_msg_data;
1369
1370 if (supplied_smi) {
1371 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1372 } else {
1373 smi_msg = ipmi_alloc_smi_msg();
1374 if (smi_msg == NULL) {
1375 ipmi_free_recv_msg(recv_msg);
1376 return -ENOMEM;
1377 }
1378 }
1379
Corey Minyardb2c03942006-12-06 20:41:00 -08001380 rcu_read_lock();
1381 handlers = intf->handlers;
1382 if (!handlers) {
1383 rv = -ENODEV;
1384 goto out_err;
1385 }
1386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001388 if (user)
1389 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 recv_msg->msgid = msgid;
1391 /* Store the message to send in the receive message so timeout
1392 responses can get the proper response data. */
1393 recv_msg->msg = *msg;
1394
1395 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1396 struct ipmi_system_interface_addr *smi_addr;
1397
1398 if (msg->netfn & 1) {
1399 /* Responses are not allowed to the SMI. */
1400 rv = -EINVAL;
1401 goto out_err;
1402 }
1403
1404 smi_addr = (struct ipmi_system_interface_addr *) addr;
1405 if (smi_addr->lun > 3) {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001406 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 rv = -EINVAL;
1408 goto out_err;
1409 }
1410
1411 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1412
1413 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1414 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1415 || (msg->cmd == IPMI_GET_MSG_CMD)
1416 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1417 {
1418 /* We don't let the user do these, since we manage
1419 the sequence numbers. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001420 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 rv = -EINVAL;
1422 goto out_err;
1423 }
1424
Corey Minyardb9675132006-12-06 20:41:02 -08001425 if (((msg->netfn == IPMI_NETFN_APP_REQUEST)
1426 && ((msg->cmd == IPMI_COLD_RESET_CMD)
1427 || (msg->cmd == IPMI_WARM_RESET_CMD)))
1428 || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))
1429 {
1430 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1431 intf->auto_maintenance_timeout
1432 = IPMI_MAINTENANCE_MODE_TIMEOUT;
1433 if (!intf->maintenance_mode
1434 && !intf->maintenance_mode_enable)
1435 {
1436 intf->maintenance_mode_enable = 1;
1437 maintenance_mode_update(intf);
1438 }
1439 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
1440 flags);
1441 }
1442
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001444 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 rv = -EMSGSIZE;
1446 goto out_err;
1447 }
1448
1449 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1450 smi_msg->data[1] = msg->cmd;
1451 smi_msg->msgid = msgid;
1452 smi_msg->user_data = recv_msg;
1453 if (msg->data_len > 0)
1454 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1455 smi_msg->data_size = msg->data_len + 2;
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001456 ipmi_inc_stat(intf, sent_local_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1458 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1459 {
1460 struct ipmi_ipmb_addr *ipmb_addr;
1461 unsigned char ipmb_seq;
1462 long seqid;
1463 int broadcast = 0;
1464
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001465 if (addr->channel >= IPMI_MAX_CHANNELS) {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001466 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 rv = -EINVAL;
1468 goto out_err;
1469 }
1470
1471 if (intf->channels[addr->channel].medium
1472 != IPMI_CHANNEL_MEDIUM_IPMB)
1473 {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001474 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 rv = -EINVAL;
1476 goto out_err;
1477 }
1478
1479 if (retries < 0) {
1480 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1481 retries = 0; /* Don't retry broadcasts. */
1482 else
1483 retries = 4;
1484 }
1485 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1486 /* Broadcasts add a zero at the beginning of the
1487 message, but otherwise is the same as an IPMB
1488 address. */
1489 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1490 broadcast = 1;
1491 }
1492
1493
1494 /* Default to 1 second retries. */
1495 if (retry_time_ms == 0)
1496 retry_time_ms = 1000;
1497
1498 /* 9 for the header and 1 for the checksum, plus
1499 possibly one for the broadcast. */
1500 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001501 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 rv = -EMSGSIZE;
1503 goto out_err;
1504 }
1505
1506 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1507 if (ipmb_addr->lun > 3) {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001508 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 rv = -EINVAL;
1510 goto out_err;
1511 }
1512
1513 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1514
1515 if (recv_msg->msg.netfn & 0x1) {
1516 /* It's a response, so use the user's sequence
1517 from msgid. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001518 ipmi_inc_stat(intf, sent_ipmb_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1520 msgid, broadcast,
1521 source_address, source_lun);
1522
1523 /* Save the receive message so we can use it
1524 to deliver the response. */
1525 smi_msg->user_data = recv_msg;
1526 } else {
1527 /* It's a command, so get a sequence for it. */
1528
1529 spin_lock_irqsave(&(intf->seq_lock), flags);
1530
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001531 ipmi_inc_stat(intf, sent_ipmb_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532
1533 /* Create a sequence number with a 1 second
1534 timeout and 4 retries. */
1535 rv = intf_next_seq(intf,
1536 recv_msg,
1537 retry_time_ms,
1538 retries,
1539 broadcast,
1540 &ipmb_seq,
1541 &seqid);
1542 if (rv) {
1543 /* We have used up all the sequence numbers,
1544 probably, so abort. */
1545 spin_unlock_irqrestore(&(intf->seq_lock),
1546 flags);
1547 goto out_err;
1548 }
1549
1550 /* Store the sequence number in the message,
1551 so that when the send message response
1552 comes back we can start the timer. */
1553 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1554 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1555 ipmb_seq, broadcast,
1556 source_address, source_lun);
1557
1558 /* Copy the message into the recv message data, so we
1559 can retransmit it later if necessary. */
1560 memcpy(recv_msg->msg_data, smi_msg->data,
1561 smi_msg->data_size);
1562 recv_msg->msg.data = recv_msg->msg_data;
1563 recv_msg->msg.data_len = smi_msg->data_size;
1564
1565 /* We don't unlock until here, because we need
1566 to copy the completed message into the
1567 recv_msg before we release the lock.
1568 Otherwise, race conditions may bite us. I
1569 know that's pretty paranoid, but I prefer
1570 to be correct. */
1571 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1572 }
1573 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1574 struct ipmi_lan_addr *lan_addr;
1575 unsigned char ipmb_seq;
1576 long seqid;
1577
Jayachandran C12fc1d72006-02-03 03:04:51 -08001578 if (addr->channel >= IPMI_MAX_CHANNELS) {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001579 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 rv = -EINVAL;
1581 goto out_err;
1582 }
1583
1584 if ((intf->channels[addr->channel].medium
1585 != IPMI_CHANNEL_MEDIUM_8023LAN)
1586 && (intf->channels[addr->channel].medium
1587 != IPMI_CHANNEL_MEDIUM_ASYNC))
1588 {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001589 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 rv = -EINVAL;
1591 goto out_err;
1592 }
1593
1594 retries = 4;
1595
1596 /* Default to 1 second retries. */
1597 if (retry_time_ms == 0)
1598 retry_time_ms = 1000;
1599
1600 /* 11 for the header and 1 for the checksum. */
1601 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001602 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 rv = -EMSGSIZE;
1604 goto out_err;
1605 }
1606
1607 lan_addr = (struct ipmi_lan_addr *) addr;
1608 if (lan_addr->lun > 3) {
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001609 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 rv = -EINVAL;
1611 goto out_err;
1612 }
1613
1614 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1615
1616 if (recv_msg->msg.netfn & 0x1) {
1617 /* It's a response, so use the user's sequence
1618 from msgid. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001619 ipmi_inc_stat(intf, sent_lan_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1621 msgid, source_lun);
1622
1623 /* Save the receive message so we can use it
1624 to deliver the response. */
1625 smi_msg->user_data = recv_msg;
1626 } else {
1627 /* It's a command, so get a sequence for it. */
1628
1629 spin_lock_irqsave(&(intf->seq_lock), flags);
1630
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001631 ipmi_inc_stat(intf, sent_lan_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633 /* Create a sequence number with a 1 second
1634 timeout and 4 retries. */
1635 rv = intf_next_seq(intf,
1636 recv_msg,
1637 retry_time_ms,
1638 retries,
1639 0,
1640 &ipmb_seq,
1641 &seqid);
1642 if (rv) {
1643 /* We have used up all the sequence numbers,
1644 probably, so abort. */
1645 spin_unlock_irqrestore(&(intf->seq_lock),
1646 flags);
1647 goto out_err;
1648 }
1649
1650 /* Store the sequence number in the message,
1651 so that when the send message response
1652 comes back we can start the timer. */
1653 format_lan_msg(smi_msg, msg, lan_addr,
1654 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1655 ipmb_seq, source_lun);
1656
1657 /* Copy the message into the recv message data, so we
1658 can retransmit it later if necessary. */
1659 memcpy(recv_msg->msg_data, smi_msg->data,
1660 smi_msg->data_size);
1661 recv_msg->msg.data = recv_msg->msg_data;
1662 recv_msg->msg.data_len = smi_msg->data_size;
1663
1664 /* We don't unlock until here, because we need
1665 to copy the completed message into the
1666 recv_msg before we release the lock.
1667 Otherwise, race conditions may bite us. I
1668 know that's pretty paranoid, but I prefer
1669 to be correct. */
1670 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1671 }
1672 } else {
1673 /* Unknown address type. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001674 ipmi_inc_stat(intf, sent_invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 rv = -EINVAL;
1676 goto out_err;
1677 }
1678
1679#ifdef DEBUG_MSGING
1680 {
1681 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001682 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 printk(" %2.2x", smi_msg->data[m]);
1684 printk("\n");
1685 }
1686#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08001687
1688 handlers->sender(intf->send_info, smi_msg, priority);
1689 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691 return 0;
1692
1693 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -08001694 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 ipmi_free_smi_msg(smi_msg);
1696 ipmi_free_recv_msg(recv_msg);
1697 return rv;
1698}
1699
Corey Minyardc14979b2005-09-06 15:18:38 -07001700static int check_addr(ipmi_smi_t intf,
1701 struct ipmi_addr *addr,
1702 unsigned char *saddr,
1703 unsigned char *lun)
1704{
1705 if (addr->channel >= IPMI_MAX_CHANNELS)
1706 return -EINVAL;
1707 *lun = intf->channels[addr->channel].lun;
1708 *saddr = intf->channels[addr->channel].address;
1709 return 0;
1710}
1711
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712int ipmi_request_settime(ipmi_user_t user,
1713 struct ipmi_addr *addr,
1714 long msgid,
1715 struct kernel_ipmi_msg *msg,
1716 void *user_msg_data,
1717 int priority,
1718 int retries,
1719 unsigned int retry_time_ms)
1720{
Corey Minyardc14979b2005-09-06 15:18:38 -07001721 unsigned char saddr, lun;
1722 int rv;
1723
Corey Minyard8a3628d2006-03-31 02:30:40 -08001724 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001725 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001726 rv = check_addr(user->intf, addr, &saddr, &lun);
1727 if (rv)
1728 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 return i_ipmi_request(user,
1730 user->intf,
1731 addr,
1732 msgid,
1733 msg,
1734 user_msg_data,
1735 NULL, NULL,
1736 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001737 saddr,
1738 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 retries,
1740 retry_time_ms);
1741}
1742
1743int ipmi_request_supply_msgs(ipmi_user_t user,
1744 struct ipmi_addr *addr,
1745 long msgid,
1746 struct kernel_ipmi_msg *msg,
1747 void *user_msg_data,
1748 void *supplied_smi,
1749 struct ipmi_recv_msg *supplied_recv,
1750 int priority)
1751{
Corey Minyardc14979b2005-09-06 15:18:38 -07001752 unsigned char saddr, lun;
1753 int rv;
1754
Corey Minyard8a3628d2006-03-31 02:30:40 -08001755 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001756 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001757 rv = check_addr(user->intf, addr, &saddr, &lun);
1758 if (rv)
1759 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 return i_ipmi_request(user,
1761 user->intf,
1762 addr,
1763 msgid,
1764 msg,
1765 user_msg_data,
1766 supplied_smi,
1767 supplied_recv,
1768 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001769 saddr,
1770 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 -1, 0);
1772}
1773
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001774#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775static int ipmb_file_read_proc(char *page, char **start, off_t off,
1776 int count, int *eof, void *data)
1777{
1778 char *out = (char *) page;
1779 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001780 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001781 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
Corey Minyarde8b33612005-09-06 15:18:45 -07001783 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001784 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1785 out[rv-1] = '\n'; /* Replace the final space with a newline */
1786 out[rv] = '\0';
1787 rv++;
1788 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789}
1790
1791static int version_file_read_proc(char *page, char **start, off_t off,
1792 int count, int *eof, void *data)
1793{
1794 char *out = (char *) page;
1795 ipmi_smi_t intf = data;
1796
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001797 return sprintf(out, "%u.%u\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001798 ipmi_version_major(&intf->bmc->id),
1799 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800}
1801
1802static int stat_file_read_proc(char *page, char **start, off_t off,
1803 int count, int *eof, void *data)
1804{
1805 char *out = (char *) page;
1806 ipmi_smi_t intf = data;
1807
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07001808 out += sprintf(out, "sent_invalid_commands: %u\n",
1809 ipmi_get_stat(intf, sent_invalid_commands));
1810 out += sprintf(out, "sent_local_commands: %u\n",
1811 ipmi_get_stat(intf, sent_local_commands));
1812 out += sprintf(out, "handled_local_responses: %u\n",
1813 ipmi_get_stat(intf, handled_local_responses));
1814 out += sprintf(out, "unhandled_local_responses: %u\n",
1815 ipmi_get_stat(intf, unhandled_local_responses));
1816 out += sprintf(out, "sent_ipmb_commands: %u\n",
1817 ipmi_get_stat(intf, sent_ipmb_commands));
1818 out += sprintf(out, "sent_ipmb_command_errs: %u\n",
1819 ipmi_get_stat(intf, sent_ipmb_command_errs));
1820 out += sprintf(out, "retransmitted_ipmb_commands: %u\n",
1821 ipmi_get_stat(intf, retransmitted_ipmb_commands));
1822 out += sprintf(out, "timed_out_ipmb_commands: %u\n",
1823 ipmi_get_stat(intf, timed_out_ipmb_commands));
1824 out += sprintf(out, "timed_out_ipmb_broadcasts: %u\n",
1825 ipmi_get_stat(intf, timed_out_ipmb_broadcasts));
1826 out += sprintf(out, "sent_ipmb_responses: %u\n",
1827 ipmi_get_stat(intf, sent_ipmb_responses));
1828 out += sprintf(out, "handled_ipmb_responses: %u\n",
1829 ipmi_get_stat(intf, handled_ipmb_responses));
1830 out += sprintf(out, "invalid_ipmb_responses: %u\n",
1831 ipmi_get_stat(intf, invalid_ipmb_responses));
1832 out += sprintf(out, "unhandled_ipmb_responses: %u\n",
1833 ipmi_get_stat(intf, unhandled_ipmb_responses));
1834 out += sprintf(out, "sent_lan_commands: %u\n",
1835 ipmi_get_stat(intf, sent_lan_commands));
1836 out += sprintf(out, "sent_lan_command_errs: %u\n",
1837 ipmi_get_stat(intf, sent_lan_command_errs));
1838 out += sprintf(out, "retransmitted_lan_commands: %u\n",
1839 ipmi_get_stat(intf, retransmitted_lan_commands));
1840 out += sprintf(out, "timed_out_lan_commands: %u\n",
1841 ipmi_get_stat(intf, timed_out_lan_commands));
1842 out += sprintf(out, "sent_lan_responses: %u\n",
1843 ipmi_get_stat(intf, sent_lan_responses));
1844 out += sprintf(out, "handled_lan_responses: %u\n",
1845 ipmi_get_stat(intf, handled_lan_responses));
1846 out += sprintf(out, "invalid_lan_responses: %u\n",
1847 ipmi_get_stat(intf, invalid_lan_responses));
1848 out += sprintf(out, "unhandled_lan_responses: %u\n",
1849 ipmi_get_stat(intf, unhandled_lan_responses));
1850 out += sprintf(out, "handled_commands: %u\n",
1851 ipmi_get_stat(intf, handled_commands));
1852 out += sprintf(out, "invalid_commands: %u\n",
1853 ipmi_get_stat(intf, invalid_commands));
1854 out += sprintf(out, "unhandled_commands: %u\n",
1855 ipmi_get_stat(intf, unhandled_commands));
1856 out += sprintf(out, "invalid_events: %u\n",
1857 ipmi_get_stat(intf, invalid_events));
1858 out += sprintf(out, "events: %u\n",
1859 ipmi_get_stat(intf, events));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
1861 return (out - ((char *) page));
1862}
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001863#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1866 read_proc_t *read_proc, write_proc_t *write_proc,
1867 void *data, struct module *owner)
1868{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001870#ifdef CONFIG_PROC_FS
1871 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 struct ipmi_proc_entry *entry;
1873
1874 /* Create a list element. */
1875 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1876 if (!entry)
1877 return -ENOMEM;
1878 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1879 if (!entry->name) {
1880 kfree(entry);
1881 return -ENOMEM;
1882 }
1883 strcpy(entry->name, name);
1884
1885 file = create_proc_entry(name, 0, smi->proc_dir);
1886 if (!file) {
1887 kfree(entry->name);
1888 kfree(entry);
1889 rv = -ENOMEM;
1890 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 file->data = data;
1892 file->read_proc = read_proc;
1893 file->write_proc = write_proc;
1894 file->owner = owner;
1895
Corey Minyardac019152007-10-18 03:07:11 -07001896 mutex_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 /* Stick it on the list. */
1898 entry->next = smi->proc_entries;
1899 smi->proc_entries = entry;
Corey Minyardac019152007-10-18 03:07:11 -07001900 mutex_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 }
Corey Minyard3b625942005-06-23 22:01:42 -07001902#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
1904 return rv;
1905}
1906
1907static int add_proc_entries(ipmi_smi_t smi, int num)
1908{
1909 int rv = 0;
1910
Corey Minyard3b625942005-06-23 22:01:42 -07001911#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 sprintf(smi->proc_dir_name, "%d", num);
1913 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1914 if (!smi->proc_dir)
1915 rv = -ENOMEM;
1916 else {
1917 smi->proc_dir->owner = THIS_MODULE;
1918 }
1919
1920 if (rv == 0)
1921 rv = ipmi_smi_add_proc_entry(smi, "stats",
1922 stat_file_read_proc, NULL,
1923 smi, THIS_MODULE);
1924
1925 if (rv == 0)
1926 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1927 ipmb_file_read_proc, NULL,
1928 smi, THIS_MODULE);
1929
1930 if (rv == 0)
1931 rv = ipmi_smi_add_proc_entry(smi, "version",
1932 version_file_read_proc, NULL,
1933 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001934#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
1936 return rv;
1937}
1938
1939static void remove_proc_entries(ipmi_smi_t smi)
1940{
Corey Minyard3b625942005-06-23 22:01:42 -07001941#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 struct ipmi_proc_entry *entry;
1943
Corey Minyardac019152007-10-18 03:07:11 -07001944 mutex_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 while (smi->proc_entries) {
1946 entry = smi->proc_entries;
1947 smi->proc_entries = entry->next;
1948
1949 remove_proc_entry(entry->name, smi->proc_dir);
1950 kfree(entry->name);
1951 kfree(entry);
1952 }
Corey Minyardac019152007-10-18 03:07:11 -07001953 mutex_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001955#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956}
1957
Corey Minyard50c812b2006-03-26 01:37:21 -08001958static int __find_bmc_guid(struct device *dev, void *data)
1959{
1960 unsigned char *id = data;
1961 struct bmc_device *bmc = dev_get_drvdata(dev);
1962 return memcmp(bmc->guid, id, 16) == 0;
1963}
1964
1965static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1966 unsigned char *guid)
1967{
1968 struct device *dev;
1969
1970 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1971 if (dev)
1972 return dev_get_drvdata(dev);
1973 else
1974 return NULL;
1975}
1976
1977struct prod_dev_id {
1978 unsigned int product_id;
1979 unsigned char device_id;
1980};
1981
1982static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1983{
1984 struct prod_dev_id *id = data;
1985 struct bmc_device *bmc = dev_get_drvdata(dev);
1986
1987 return (bmc->id.product_id == id->product_id
Corey Minyard50c812b2006-03-26 01:37:21 -08001988 && bmc->id.device_id == id->device_id);
1989}
1990
1991static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1992 struct device_driver *drv,
Corey Minyardf0b55da2006-12-06 20:40:54 -08001993 unsigned int product_id, unsigned char device_id)
Corey Minyard50c812b2006-03-26 01:37:21 -08001994{
1995 struct prod_dev_id id = {
1996 .product_id = product_id,
1997 .device_id = device_id,
1998 };
1999 struct device *dev;
2000
2001 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
2002 if (dev)
2003 return dev_get_drvdata(dev);
2004 else
2005 return NULL;
2006}
2007
2008static ssize_t device_id_show(struct device *dev,
2009 struct device_attribute *attr,
2010 char *buf)
2011{
2012 struct bmc_device *bmc = dev_get_drvdata(dev);
2013
2014 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
2015}
2016
2017static ssize_t provides_dev_sdrs_show(struct device *dev,
2018 struct device_attribute *attr,
2019 char *buf)
2020{
2021 struct bmc_device *bmc = dev_get_drvdata(dev);
2022
2023 return snprintf(buf, 10, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002024 (bmc->id.device_revision & 0x80) >> 7);
Corey Minyard50c812b2006-03-26 01:37:21 -08002025}
2026
2027static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
2028 char *buf)
2029{
2030 struct bmc_device *bmc = dev_get_drvdata(dev);
2031
2032 return snprintf(buf, 20, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002033 bmc->id.device_revision & 0x0F);
Corey Minyard50c812b2006-03-26 01:37:21 -08002034}
2035
2036static ssize_t firmware_rev_show(struct device *dev,
2037 struct device_attribute *attr,
2038 char *buf)
2039{
2040 struct bmc_device *bmc = dev_get_drvdata(dev);
2041
2042 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
2043 bmc->id.firmware_revision_2);
2044}
2045
2046static ssize_t ipmi_version_show(struct device *dev,
2047 struct device_attribute *attr,
2048 char *buf)
2049{
2050 struct bmc_device *bmc = dev_get_drvdata(dev);
2051
2052 return snprintf(buf, 20, "%u.%u\n",
2053 ipmi_version_major(&bmc->id),
2054 ipmi_version_minor(&bmc->id));
2055}
2056
2057static ssize_t add_dev_support_show(struct device *dev,
2058 struct device_attribute *attr,
2059 char *buf)
2060{
2061 struct bmc_device *bmc = dev_get_drvdata(dev);
2062
2063 return snprintf(buf, 10, "0x%02x\n",
2064 bmc->id.additional_device_support);
2065}
2066
2067static ssize_t manufacturer_id_show(struct device *dev,
2068 struct device_attribute *attr,
2069 char *buf)
2070{
2071 struct bmc_device *bmc = dev_get_drvdata(dev);
2072
2073 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
2074}
2075
2076static ssize_t product_id_show(struct device *dev,
2077 struct device_attribute *attr,
2078 char *buf)
2079{
2080 struct bmc_device *bmc = dev_get_drvdata(dev);
2081
2082 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
2083}
2084
2085static ssize_t aux_firmware_rev_show(struct device *dev,
2086 struct device_attribute *attr,
2087 char *buf)
2088{
2089 struct bmc_device *bmc = dev_get_drvdata(dev);
2090
2091 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
2092 bmc->id.aux_firmware_revision[3],
2093 bmc->id.aux_firmware_revision[2],
2094 bmc->id.aux_firmware_revision[1],
2095 bmc->id.aux_firmware_revision[0]);
2096}
2097
2098static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
2099 char *buf)
2100{
2101 struct bmc_device *bmc = dev_get_drvdata(dev);
2102
2103 return snprintf(buf, 100, "%Lx%Lx\n",
2104 (long long) bmc->guid[0],
2105 (long long) bmc->guid[8]);
2106}
2107
Jeff Garzik5e593932006-10-11 01:22:21 -07002108static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08002109{
Corey Minyardf0b55da2006-12-06 20:40:54 -08002110 if (!bmc->dev)
2111 return;
2112
Corey Minyard50c812b2006-03-26 01:37:21 -08002113 device_remove_file(&bmc->dev->dev,
2114 &bmc->device_id_attr);
2115 device_remove_file(&bmc->dev->dev,
2116 &bmc->provides_dev_sdrs_attr);
2117 device_remove_file(&bmc->dev->dev,
2118 &bmc->revision_attr);
2119 device_remove_file(&bmc->dev->dev,
2120 &bmc->firmware_rev_attr);
2121 device_remove_file(&bmc->dev->dev,
2122 &bmc->version_attr);
2123 device_remove_file(&bmc->dev->dev,
2124 &bmc->add_dev_support_attr);
2125 device_remove_file(&bmc->dev->dev,
2126 &bmc->manufacturer_id_attr);
2127 device_remove_file(&bmc->dev->dev,
2128 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002129
Corey Minyard50c812b2006-03-26 01:37:21 -08002130 if (bmc->id.aux_firmware_revision_set)
2131 device_remove_file(&bmc->dev->dev,
2132 &bmc->aux_firmware_rev_attr);
2133 if (bmc->guid_set)
2134 device_remove_file(&bmc->dev->dev,
2135 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002136}
2137
2138static void
2139cleanup_bmc_device(struct kref *ref)
2140{
2141 struct bmc_device *bmc;
2142
2143 bmc = container_of(ref, struct bmc_device, refcount);
2144
2145 remove_files(bmc);
Corey Minyard1d5636c2006-12-10 02:19:08 -08002146 platform_device_unregister(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002147 kfree(bmc);
2148}
2149
2150static void ipmi_bmc_unregister(ipmi_smi_t intf)
2151{
2152 struct bmc_device *bmc = intf->bmc;
2153
Corey Minyard759643b2006-12-06 20:40:59 -08002154 if (intf->sysfs_name) {
2155 sysfs_remove_link(&intf->si_dev->kobj, intf->sysfs_name);
2156 kfree(intf->sysfs_name);
2157 intf->sysfs_name = NULL;
2158 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002159 if (intf->my_dev_name) {
2160 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
2161 kfree(intf->my_dev_name);
2162 intf->my_dev_name = NULL;
2163 }
2164
2165 mutex_lock(&ipmidriver_mutex);
2166 kref_put(&bmc->refcount, cleanup_bmc_device);
Corey Minyardf0b55da2006-12-06 20:40:54 -08002167 intf->bmc = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002168 mutex_unlock(&ipmidriver_mutex);
2169}
2170
Jeff Garzik5e593932006-10-11 01:22:21 -07002171static int create_files(struct bmc_device *bmc)
2172{
2173 int err;
2174
Corey Minyardf0b55da2006-12-06 20:40:54 -08002175 bmc->device_id_attr.attr.name = "device_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002176 bmc->device_id_attr.attr.mode = S_IRUGO;
2177 bmc->device_id_attr.show = device_id_show;
2178
2179 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002180 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2181 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2182
2183 bmc->revision_attr.attr.name = "revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002184 bmc->revision_attr.attr.mode = S_IRUGO;
2185 bmc->revision_attr.show = revision_show;
2186
2187 bmc->firmware_rev_attr.attr.name = "firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002188 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2189 bmc->firmware_rev_attr.show = firmware_rev_show;
2190
2191 bmc->version_attr.attr.name = "ipmi_version";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002192 bmc->version_attr.attr.mode = S_IRUGO;
2193 bmc->version_attr.show = ipmi_version_show;
2194
2195 bmc->add_dev_support_attr.attr.name = "additional_device_support";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002196 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2197 bmc->add_dev_support_attr.show = add_dev_support_show;
2198
2199 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002200 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2201 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2202
2203 bmc->product_id_attr.attr.name = "product_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002204 bmc->product_id_attr.attr.mode = S_IRUGO;
2205 bmc->product_id_attr.show = product_id_show;
2206
2207 bmc->guid_attr.attr.name = "guid";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002208 bmc->guid_attr.attr.mode = S_IRUGO;
2209 bmc->guid_attr.show = guid_show;
2210
2211 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002212 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2213 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2214
Jeff Garzik5e593932006-10-11 01:22:21 -07002215 err = device_create_file(&bmc->dev->dev,
2216 &bmc->device_id_attr);
2217 if (err) goto out;
2218 err = device_create_file(&bmc->dev->dev,
2219 &bmc->provides_dev_sdrs_attr);
2220 if (err) goto out_devid;
2221 err = device_create_file(&bmc->dev->dev,
2222 &bmc->revision_attr);
2223 if (err) goto out_sdrs;
2224 err = device_create_file(&bmc->dev->dev,
2225 &bmc->firmware_rev_attr);
2226 if (err) goto out_rev;
2227 err = device_create_file(&bmc->dev->dev,
2228 &bmc->version_attr);
2229 if (err) goto out_firm;
2230 err = device_create_file(&bmc->dev->dev,
2231 &bmc->add_dev_support_attr);
2232 if (err) goto out_version;
2233 err = device_create_file(&bmc->dev->dev,
2234 &bmc->manufacturer_id_attr);
2235 if (err) goto out_add_dev;
2236 err = device_create_file(&bmc->dev->dev,
2237 &bmc->product_id_attr);
2238 if (err) goto out_manu;
2239 if (bmc->id.aux_firmware_revision_set) {
2240 err = device_create_file(&bmc->dev->dev,
2241 &bmc->aux_firmware_rev_attr);
2242 if (err) goto out_prod_id;
2243 }
2244 if (bmc->guid_set) {
2245 err = device_create_file(&bmc->dev->dev,
2246 &bmc->guid_attr);
2247 if (err) goto out_aux_firm;
2248 }
2249
2250 return 0;
2251
2252out_aux_firm:
2253 if (bmc->id.aux_firmware_revision_set)
2254 device_remove_file(&bmc->dev->dev,
2255 &bmc->aux_firmware_rev_attr);
2256out_prod_id:
2257 device_remove_file(&bmc->dev->dev,
2258 &bmc->product_id_attr);
2259out_manu:
2260 device_remove_file(&bmc->dev->dev,
2261 &bmc->manufacturer_id_attr);
2262out_add_dev:
2263 device_remove_file(&bmc->dev->dev,
2264 &bmc->add_dev_support_attr);
2265out_version:
2266 device_remove_file(&bmc->dev->dev,
2267 &bmc->version_attr);
2268out_firm:
2269 device_remove_file(&bmc->dev->dev,
2270 &bmc->firmware_rev_attr);
2271out_rev:
2272 device_remove_file(&bmc->dev->dev,
2273 &bmc->revision_attr);
2274out_sdrs:
2275 device_remove_file(&bmc->dev->dev,
2276 &bmc->provides_dev_sdrs_attr);
2277out_devid:
2278 device_remove_file(&bmc->dev->dev,
2279 &bmc->device_id_attr);
2280out:
2281 return err;
2282}
2283
Corey Minyard759643b2006-12-06 20:40:59 -08002284static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
2285 const char *sysfs_name)
Corey Minyard50c812b2006-03-26 01:37:21 -08002286{
2287 int rv;
2288 struct bmc_device *bmc = intf->bmc;
2289 struct bmc_device *old_bmc;
2290 int size;
2291 char dummy[1];
2292
2293 mutex_lock(&ipmidriver_mutex);
2294
2295 /*
2296 * Try to find if there is an bmc_device struct
2297 * representing the interfaced BMC already
2298 */
2299 if (bmc->guid_set)
2300 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2301 else
2302 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2303 bmc->id.product_id,
2304 bmc->id.device_id);
2305
2306 /*
2307 * If there is already an bmc_device, free the new one,
2308 * otherwise register the new BMC device
2309 */
2310 if (old_bmc) {
2311 kfree(bmc);
2312 intf->bmc = old_bmc;
2313 bmc = old_bmc;
2314
2315 kref_get(&bmc->refcount);
2316 mutex_unlock(&ipmidriver_mutex);
2317
2318 printk(KERN_INFO
2319 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2320 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2321 bmc->id.manufacturer_id,
2322 bmc->id.product_id,
2323 bmc->id.device_id);
2324 } else {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002325 char name[14];
2326 unsigned char orig_dev_id = bmc->id.device_id;
2327 int warn_printed = 0;
2328
2329 snprintf(name, sizeof(name),
2330 "ipmi_bmc.%4.4x", bmc->id.product_id);
2331
2332 while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
2333 bmc->id.product_id,
Corey Minyard1d5636c2006-12-10 02:19:08 -08002334 bmc->id.device_id)) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002335 if (!warn_printed) {
2336 printk(KERN_WARNING PFX
2337 "This machine has two different BMCs"
2338 " with the same product id and device"
2339 " id. This is an error in the"
2340 " firmware, but incrementing the"
2341 " device id to work around the problem."
2342 " Prod ID = 0x%x, Dev ID = 0x%x\n",
2343 bmc->id.product_id, bmc->id.device_id);
2344 warn_printed = 1;
2345 }
2346 bmc->id.device_id++; /* Wraps at 255 */
2347 if (bmc->id.device_id == orig_dev_id) {
2348 printk(KERN_ERR PFX
2349 "Out of device ids!\n");
2350 break;
2351 }
2352 }
2353
2354 bmc->dev = platform_device_alloc(name, bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002355 if (!bmc->dev) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002356 mutex_unlock(&ipmidriver_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002357 printk(KERN_ERR
2358 "ipmi_msghandler:"
2359 " Unable to allocate platform device\n");
2360 return -ENOMEM;
2361 }
2362 bmc->dev->dev.driver = &ipmidriver;
2363 dev_set_drvdata(&bmc->dev->dev, bmc);
2364 kref_init(&bmc->refcount);
2365
Zhang, Yanminb48f5452006-11-16 01:19:08 -08002366 rv = platform_device_add(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002367 mutex_unlock(&ipmidriver_mutex);
2368 if (rv) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002369 platform_device_put(bmc->dev);
2370 bmc->dev = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002371 printk(KERN_ERR
2372 "ipmi_msghandler:"
2373 " Unable to register bmc device: %d\n",
2374 rv);
2375 /* Don't go to out_err, you can only do that if
2376 the device is registered already. */
2377 return rv;
2378 }
2379
Jeff Garzik5e593932006-10-11 01:22:21 -07002380 rv = create_files(bmc);
2381 if (rv) {
2382 mutex_lock(&ipmidriver_mutex);
2383 platform_device_unregister(bmc->dev);
2384 mutex_unlock(&ipmidriver_mutex);
2385
2386 return rv;
2387 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002388
2389 printk(KERN_INFO
2390 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2391 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2392 bmc->id.manufacturer_id,
2393 bmc->id.product_id,
2394 bmc->id.device_id);
2395 }
2396
2397 /*
2398 * create symlink from system interface device to bmc device
2399 * and back.
2400 */
Corey Minyard759643b2006-12-06 20:40:59 -08002401 intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL);
2402 if (!intf->sysfs_name) {
2403 rv = -ENOMEM;
2404 printk(KERN_ERR
2405 "ipmi_msghandler: allocate link to BMC: %d\n",
2406 rv);
2407 goto out_err;
2408 }
2409
Corey Minyard50c812b2006-03-26 01:37:21 -08002410 rv = sysfs_create_link(&intf->si_dev->kobj,
Corey Minyard759643b2006-12-06 20:40:59 -08002411 &bmc->dev->dev.kobj, intf->sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002412 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002413 kfree(intf->sysfs_name);
2414 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002415 printk(KERN_ERR
2416 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2417 rv);
2418 goto out_err;
2419 }
2420
Corey Minyard759643b2006-12-06 20:40:59 -08002421 size = snprintf(dummy, 0, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002422 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2423 if (!intf->my_dev_name) {
Corey Minyard759643b2006-12-06 20:40:59 -08002424 kfree(intf->sysfs_name);
2425 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002426 rv = -ENOMEM;
2427 printk(KERN_ERR
2428 "ipmi_msghandler: allocate link from BMC: %d\n",
2429 rv);
2430 goto out_err;
2431 }
Corey Minyard759643b2006-12-06 20:40:59 -08002432 snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002433
2434 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2435 intf->my_dev_name);
2436 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002437 kfree(intf->sysfs_name);
2438 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002439 kfree(intf->my_dev_name);
2440 intf->my_dev_name = NULL;
2441 printk(KERN_ERR
2442 "ipmi_msghandler:"
2443 " Unable to create symlink to bmc: %d\n",
2444 rv);
2445 goto out_err;
2446 }
2447
2448 return 0;
2449
2450out_err:
2451 ipmi_bmc_unregister(intf);
2452 return rv;
2453}
2454
2455static int
2456send_guid_cmd(ipmi_smi_t intf, int chan)
2457{
2458 struct kernel_ipmi_msg msg;
2459 struct ipmi_system_interface_addr si;
2460
2461 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2462 si.channel = IPMI_BMC_CHANNEL;
2463 si.lun = 0;
2464
2465 msg.netfn = IPMI_NETFN_APP_REQUEST;
2466 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2467 msg.data = NULL;
2468 msg.data_len = 0;
2469 return i_ipmi_request(NULL,
2470 intf,
2471 (struct ipmi_addr *) &si,
2472 0,
2473 &msg,
2474 intf,
2475 NULL,
2476 NULL,
2477 0,
2478 intf->channels[0].address,
2479 intf->channels[0].lun,
2480 -1, 0);
2481}
2482
2483static void
2484guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2485{
2486 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2487 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2488 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2489 /* Not for me */
2490 return;
2491
2492 if (msg->msg.data[0] != 0) {
2493 /* Error from getting the GUID, the BMC doesn't have one. */
2494 intf->bmc->guid_set = 0;
2495 goto out;
2496 }
2497
2498 if (msg->msg.data_len < 17) {
2499 intf->bmc->guid_set = 0;
2500 printk(KERN_WARNING PFX
2501 "guid_handler: The GUID response from the BMC was too"
2502 " short, it was %d but should have been 17. Assuming"
2503 " GUID is not available.\n",
2504 msg->msg.data_len);
2505 goto out;
2506 }
2507
2508 memcpy(intf->bmc->guid, msg->msg.data, 16);
2509 intf->bmc->guid_set = 1;
2510 out:
2511 wake_up(&intf->waitq);
2512}
2513
2514static void
2515get_guid(ipmi_smi_t intf)
2516{
2517 int rv;
2518
2519 intf->bmc->guid_set = 0x2;
2520 intf->null_user_handler = guid_handler;
2521 rv = send_guid_cmd(intf, 0);
2522 if (rv)
2523 /* Send failed, no GUID available. */
2524 intf->bmc->guid_set = 0;
2525 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2526 intf->null_user_handler = NULL;
2527}
2528
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529static int
2530send_channel_info_cmd(ipmi_smi_t intf, int chan)
2531{
2532 struct kernel_ipmi_msg msg;
2533 unsigned char data[1];
2534 struct ipmi_system_interface_addr si;
2535
2536 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2537 si.channel = IPMI_BMC_CHANNEL;
2538 si.lun = 0;
2539
2540 msg.netfn = IPMI_NETFN_APP_REQUEST;
2541 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2542 msg.data = data;
2543 msg.data_len = 1;
2544 data[0] = chan;
2545 return i_ipmi_request(NULL,
2546 intf,
2547 (struct ipmi_addr *) &si,
2548 0,
2549 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002550 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 NULL,
2552 NULL,
2553 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002554 intf->channels[0].address,
2555 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 -1, 0);
2557}
2558
2559static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002560channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561{
2562 int rv = 0;
2563 int chan;
2564
Corey Minyard56a55ec2005-09-06 15:18:42 -07002565 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2566 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2567 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 {
2569 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002570 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 /* Got an error from the channel, just go on. */
2572
Corey Minyard56a55ec2005-09-06 15:18:42 -07002573 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 /* If the MC does not support this
2575 command, that is legal. We just
2576 assume it has one IPMB at channel
2577 zero. */
2578 intf->channels[0].medium
2579 = IPMI_CHANNEL_MEDIUM_IPMB;
2580 intf->channels[0].protocol
2581 = IPMI_CHANNEL_PROTOCOL_IPMB;
2582 rv = -ENOSYS;
2583
2584 intf->curr_channel = IPMI_MAX_CHANNELS;
2585 wake_up(&intf->waitq);
2586 goto out;
2587 }
2588 goto next_channel;
2589 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002590 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 /* Message not big enough, just go on. */
2592 goto next_channel;
2593 }
2594 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002595 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2596 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597
2598 next_channel:
2599 intf->curr_channel++;
2600 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2601 wake_up(&intf->waitq);
2602 else
2603 rv = send_channel_info_cmd(intf, intf->curr_channel);
2604
2605 if (rv) {
2606 /* Got an error somehow, just give up. */
2607 intf->curr_channel = IPMI_MAX_CHANNELS;
2608 wake_up(&intf->waitq);
2609
2610 printk(KERN_WARNING PFX
2611 "Error sending channel information: %d\n",
2612 rv);
2613 }
2614 }
2615 out:
2616 return;
2617}
2618
Corey Minyardfcfa4722007-10-18 03:07:09 -07002619void ipmi_poll_interface(ipmi_user_t user)
2620{
2621 ipmi_smi_t intf = user->intf;
2622
2623 if (intf->handlers->poll)
2624 intf->handlers->poll(intf->send_info);
2625}
2626
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2628 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002629 struct ipmi_device_id *device_id,
2630 struct device *si_dev,
Corey Minyard759643b2006-12-06 20:40:59 -08002631 const char *sysfs_name,
Corey Minyard453823b2006-03-31 02:30:39 -08002632 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633{
2634 int i, j;
2635 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002636 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -08002637 ipmi_smi_t tintf;
Corey Minyardbca03242006-12-06 20:40:57 -08002638 struct list_head *link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 /* Make sure the driver is actually initialized, this handles
2641 problems with initialization order. */
2642 if (!initialized) {
2643 rv = ipmi_init_msghandler();
2644 if (rv)
2645 return rv;
2646 /* The init code doesn't return an error if it was turned
2647 off, but it won't initialize. Check that. */
2648 if (!initialized)
2649 return -ENODEV;
2650 }
2651
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07002652 intf = kzalloc(sizeof(*intf), GFP_KERNEL);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002653 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 return -ENOMEM;
Corey Minyardb2c03942006-12-06 20:41:00 -08002655
2656 intf->ipmi_version_major = ipmi_version_major(device_id);
2657 intf->ipmi_version_minor = ipmi_version_minor(device_id);
2658
Corey Minyard50c812b2006-03-26 01:37:21 -08002659 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2660 if (!intf->bmc) {
2661 kfree(intf);
2662 return -ENOMEM;
2663 }
Corey Minyardbca03242006-12-06 20:40:57 -08002664 intf->intf_num = -1; /* Mark it invalid for now. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002665 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002666 intf->bmc->id = *device_id;
2667 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002668 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2669 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2670 intf->channels[j].lun = 2;
2671 }
2672 if (slave_addr != 0)
2673 intf->channels[0].address = slave_addr;
2674 INIT_LIST_HEAD(&intf->users);
2675 intf->handlers = handlers;
2676 intf->send_info = send_info;
2677 spin_lock_init(&intf->seq_lock);
2678 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2679 intf->seq_table[j].inuse = 0;
2680 intf->seq_table[j].seqid = 0;
2681 }
2682 intf->curr_seq = 0;
2683#ifdef CONFIG_PROC_FS
Corey Minyardac019152007-10-18 03:07:11 -07002684 mutex_init(&intf->proc_entry_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002685#endif
2686 spin_lock_init(&intf->waiting_msgs_lock);
2687 INIT_LIST_HEAD(&intf->waiting_msgs);
2688 spin_lock_init(&intf->events_lock);
2689 INIT_LIST_HEAD(&intf->waiting_events);
2690 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002691 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyardb9675132006-12-06 20:41:02 -08002692 spin_lock_init(&intf->maintenance_mode_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002693 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2694 init_waitqueue_head(&intf->waitq);
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07002695 for (i = 0; i < IPMI_NUM_STATS; i++)
2696 atomic_set(&intf->stats[i], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Corey Minyard393d2cc2005-11-07 00:59:54 -08002698 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
Corey Minyardb2c03942006-12-06 20:41:00 -08002700 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002701 mutex_lock(&ipmi_interfaces_mutex);
2702 /* Look for a hole in the numbers. */
2703 i = 0;
2704 link = &ipmi_interfaces;
2705 list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
2706 if (tintf->intf_num != i) {
2707 link = &tintf->link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 break;
2709 }
Corey Minyardbca03242006-12-06 20:40:57 -08002710 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 }
Corey Minyardbca03242006-12-06 20:40:57 -08002712 /* Add the new interface in numeric order. */
2713 if (i == 0)
2714 list_add_rcu(&intf->link, &ipmi_interfaces);
2715 else
2716 list_add_tail_rcu(&intf->link, link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
Corey Minyard453823b2006-03-31 02:30:39 -08002718 rv = handlers->start_processing(send_info, intf);
2719 if (rv)
2720 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002721
Corey Minyard50c812b2006-03-26 01:37:21 -08002722 get_guid(intf);
2723
Corey Minyardb2c03942006-12-06 20:41:00 -08002724 if ((intf->ipmi_version_major > 1)
2725 || ((intf->ipmi_version_major == 1)
2726 && (intf->ipmi_version_minor >= 5)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08002727 {
2728 /* Start scanning the channels to see what is
2729 available. */
2730 intf->null_user_handler = channel_handler;
2731 intf->curr_channel = 0;
2732 rv = send_channel_info_cmd(intf, 0);
2733 if (rv)
2734 goto out;
2735
2736 /* Wait for the channel info to be read. */
2737 wait_event(intf->waitq,
2738 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002739 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002740 } else {
2741 /* Assume a single IPMB channel at zero. */
2742 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2743 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
2746 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002747 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
Corey Minyard759643b2006-12-06 20:40:59 -08002749 rv = ipmi_bmc_register(intf, i, sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002750
Corey Minyard393d2cc2005-11-07 00:59:54 -08002751 out:
2752 if (rv) {
2753 if (intf->proc_dir)
2754 remove_proc_entries(intf);
Corey Minyardb2c03942006-12-06 20:41:00 -08002755 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002756 list_del_rcu(&intf->link);
2757 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002758 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002759 synchronize_rcu();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002760 kref_put(&intf->refcount, intf_free);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002761 } else {
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002762 /*
2763 * Keep memory order straight for RCU readers. Make
2764 * sure everything else is committed to memory before
2765 * setting intf_num to mark the interface valid.
2766 */
2767 smp_wmb();
Corey Minyardbca03242006-12-06 20:40:57 -08002768 intf->intf_num = i;
2769 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002770 /* After this point the interface is legal to use. */
Corey Minyard50c812b2006-03-26 01:37:21 -08002771 call_smi_watchers(i, intf->si_dev);
Corey Minyardb2c03942006-12-06 20:41:00 -08002772 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 }
2774
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 return rv;
2776}
2777
Corey Minyardb2c03942006-12-06 20:41:00 -08002778static void cleanup_smi_msgs(ipmi_smi_t intf)
2779{
2780 int i;
2781 struct seq_table *ent;
2782
2783 /* No need for locks, the interface is down. */
2784 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
2785 ent = &(intf->seq_table[i]);
2786 if (!ent->inuse)
2787 continue;
2788 deliver_err_response(ent->recv_msg, IPMI_ERR_UNSPECIFIED);
2789 }
2790}
2791
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792int ipmi_unregister_smi(ipmi_smi_t intf)
2793{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 struct ipmi_smi_watcher *w;
Corey Minyardb2c03942006-12-06 20:41:00 -08002795 int intf_num = intf->intf_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
Corey Minyard50c812b2006-03-26 01:37:21 -08002797 ipmi_bmc_unregister(intf);
2798
Corey Minyardb2c03942006-12-06 20:41:00 -08002799 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002800 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002801 intf->intf_num = -1;
2802 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002803 list_del_rcu(&intf->link);
2804 mutex_unlock(&ipmi_interfaces_mutex);
2805 synchronize_rcu();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806
Corey Minyardb2c03942006-12-06 20:41:00 -08002807 cleanup_smi_msgs(intf);
2808
Corey Minyard393d2cc2005-11-07 00:59:54 -08002809 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810
2811 /* Call all the watcher interfaces to tell them that
2812 an interface is gone. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002813 list_for_each_entry(w, &smi_watchers, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08002814 w->smi_gone(intf_num);
2815 mutex_unlock(&smi_watchers_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002816
Corey Minyard393d2cc2005-11-07 00:59:54 -08002817 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 return 0;
2819}
2820
2821static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2822 struct ipmi_smi_msg *msg)
2823{
2824 struct ipmi_ipmb_addr ipmb_addr;
2825 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826
2827
2828 /* This is 11, not 10, because the response must contain a
2829 * completion code. */
2830 if (msg->rsp_size < 11) {
2831 /* Message not big enough, just ignore it. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07002832 ipmi_inc_stat(intf, invalid_ipmb_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 return 0;
2834 }
2835
2836 if (msg->rsp[2] != 0) {
2837 /* An error getting the response, just ignore it. */
2838 return 0;
2839 }
2840
2841 ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
2842 ipmb_addr.slave_addr = msg->rsp[6];
2843 ipmb_addr.channel = msg->rsp[3] & 0x0f;
2844 ipmb_addr.lun = msg->rsp[7] & 3;
2845
2846 /* It's a response from a remote entity. Look up the sequence
2847 number and handle the response. */
2848 if (intf_find_seq(intf,
2849 msg->rsp[7] >> 2,
2850 msg->rsp[3] & 0x0f,
2851 msg->rsp[8],
2852 (msg->rsp[4] >> 2) & (~1),
2853 (struct ipmi_addr *) &(ipmb_addr),
2854 &recv_msg))
2855 {
2856 /* We were unable to find the sequence number,
2857 so just nuke the message. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07002858 ipmi_inc_stat(intf, unhandled_ipmb_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 return 0;
2860 }
2861
2862 memcpy(recv_msg->msg_data,
2863 &(msg->rsp[9]),
2864 msg->rsp_size - 9);
2865 /* THe other fields matched, so no need to set them, except
2866 for netfn, which needs to be the response that was
2867 returned, not the request value. */
2868 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2869 recv_msg->msg.data = recv_msg->msg_data;
2870 recv_msg->msg.data_len = msg->rsp_size - 10;
2871 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07002872 ipmi_inc_stat(intf, handled_ipmb_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 deliver_response(recv_msg);
2874
2875 return 0;
2876}
2877
2878static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2879 struct ipmi_smi_msg *msg)
2880{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002881 struct cmd_rcvr *rcvr;
2882 int rv = 0;
2883 unsigned char netfn;
2884 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002885 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002886 ipmi_user_t user = NULL;
2887 struct ipmi_ipmb_addr *ipmb_addr;
2888 struct ipmi_recv_msg *recv_msg;
Corey Minyardb2c03942006-12-06 20:41:00 -08002889 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890
2891 if (msg->rsp_size < 10) {
2892 /* Message not big enough, just ignore it. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07002893 ipmi_inc_stat(intf, invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 return 0;
2895 }
2896
2897 if (msg->rsp[2] != 0) {
2898 /* An error getting the response, just ignore it. */
2899 return 0;
2900 }
2901
2902 netfn = msg->rsp[4] >> 2;
2903 cmd = msg->rsp[8];
Corey Minyardc69c3122006-09-30 23:27:56 -07002904 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002906 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002907 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002908 if (rcvr) {
2909 user = rcvr->user;
2910 kref_get(&user->refcount);
2911 } else
2912 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002913 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
2915 if (user == NULL) {
2916 /* We didn't find a user, deliver an error response. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07002917 ipmi_inc_stat(intf, unhandled_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918
2919 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2920 msg->data[1] = IPMI_SEND_MSG_CMD;
2921 msg->data[2] = msg->rsp[3];
2922 msg->data[3] = msg->rsp[6];
2923 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2924 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002925 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 /* rqseq/lun */
2927 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2928 msg->data[8] = msg->rsp[8]; /* cmd */
2929 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2930 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2931 msg->data_size = 11;
2932
2933#ifdef DEBUG_MSGING
2934 {
2935 int m;
2936 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002937 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 printk(" %2.2x", msg->data[m]);
2939 printk("\n");
2940 }
2941#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08002942 rcu_read_lock();
2943 handlers = intf->handlers;
2944 if (handlers) {
2945 handlers->sender(intf->send_info, msg, 0);
2946 /* We used the message, so return the value
2947 that causes it to not be freed or
2948 queued. */
2949 rv = -1;
2950 }
2951 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 } else {
2953 /* Deliver the message to the user. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07002954 ipmi_inc_stat(intf, handled_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955
2956 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002957 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 /* We couldn't allocate memory for the
2959 message, so requeue it for handling
2960 later. */
2961 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002962 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 } else {
2964 /* Extract the source address from the data. */
2965 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2966 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2967 ipmb_addr->slave_addr = msg->rsp[6];
2968 ipmb_addr->lun = msg->rsp[7] & 3;
2969 ipmb_addr->channel = msg->rsp[3] & 0xf;
2970
2971 /* Extract the rest of the message information
2972 from the IPMB header.*/
2973 recv_msg->user = user;
2974 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2975 recv_msg->msgid = msg->rsp[7] >> 2;
2976 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2977 recv_msg->msg.cmd = msg->rsp[8];
2978 recv_msg->msg.data = recv_msg->msg_data;
2979
2980 /* We chop off 10, not 9 bytes because the checksum
2981 at the end also needs to be removed. */
2982 recv_msg->msg.data_len = msg->rsp_size - 10;
2983 memcpy(recv_msg->msg_data,
2984 &(msg->rsp[9]),
2985 msg->rsp_size - 10);
2986 deliver_response(recv_msg);
2987 }
2988 }
2989
2990 return rv;
2991}
2992
2993static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
2994 struct ipmi_smi_msg *msg)
2995{
2996 struct ipmi_lan_addr lan_addr;
2997 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998
2999
3000 /* This is 13, not 12, because the response must contain a
3001 * completion code. */
3002 if (msg->rsp_size < 13) {
3003 /* Message not big enough, just ignore it. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003004 ipmi_inc_stat(intf, invalid_lan_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 return 0;
3006 }
3007
3008 if (msg->rsp[2] != 0) {
3009 /* An error getting the response, just ignore it. */
3010 return 0;
3011 }
3012
3013 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
3014 lan_addr.session_handle = msg->rsp[4];
3015 lan_addr.remote_SWID = msg->rsp[8];
3016 lan_addr.local_SWID = msg->rsp[5];
3017 lan_addr.channel = msg->rsp[3] & 0x0f;
3018 lan_addr.privilege = msg->rsp[3] >> 4;
3019 lan_addr.lun = msg->rsp[9] & 3;
3020
3021 /* It's a response from a remote entity. Look up the sequence
3022 number and handle the response. */
3023 if (intf_find_seq(intf,
3024 msg->rsp[9] >> 2,
3025 msg->rsp[3] & 0x0f,
3026 msg->rsp[10],
3027 (msg->rsp[6] >> 2) & (~1),
3028 (struct ipmi_addr *) &(lan_addr),
3029 &recv_msg))
3030 {
3031 /* We were unable to find the sequence number,
3032 so just nuke the message. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003033 ipmi_inc_stat(intf, unhandled_lan_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 return 0;
3035 }
3036
3037 memcpy(recv_msg->msg_data,
3038 &(msg->rsp[11]),
3039 msg->rsp_size - 11);
3040 /* The other fields matched, so no need to set them, except
3041 for netfn, which needs to be the response that was
3042 returned, not the request value. */
3043 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3044 recv_msg->msg.data = recv_msg->msg_data;
3045 recv_msg->msg.data_len = msg->rsp_size - 12;
3046 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003047 ipmi_inc_stat(intf, handled_lan_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 deliver_response(recv_msg);
3049
3050 return 0;
3051}
3052
3053static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
3054 struct ipmi_smi_msg *msg)
3055{
Corey Minyard393d2cc2005-11-07 00:59:54 -08003056 struct cmd_rcvr *rcvr;
3057 int rv = 0;
3058 unsigned char netfn;
3059 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07003060 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003061 ipmi_user_t user = NULL;
3062 struct ipmi_lan_addr *lan_addr;
3063 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
3065 if (msg->rsp_size < 12) {
3066 /* Message not big enough, just ignore it. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003067 ipmi_inc_stat(intf, invalid_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 return 0;
3069 }
3070
3071 if (msg->rsp[2] != 0) {
3072 /* An error getting the response, just ignore it. */
3073 return 0;
3074 }
3075
3076 netfn = msg->rsp[6] >> 2;
3077 cmd = msg->rsp[10];
Corey Minyardc69c3122006-09-30 23:27:56 -07003078 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003080 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07003081 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003082 if (rcvr) {
3083 user = rcvr->user;
3084 kref_get(&user->refcount);
3085 } else
3086 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003087 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088
3089 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003090 /* We didn't find a user, just give up. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003091 ipmi_inc_stat(intf, unhandled_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
3093 rv = 0; /* Don't do anything with these messages, just
3094 allow them to be freed. */
3095 } else {
3096 /* Deliver the message to the user. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003097 ipmi_inc_stat(intf, handled_commands);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
3099 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003100 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 /* We couldn't allocate memory for the
3102 message, so requeue it for handling
3103 later. */
3104 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003105 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 } else {
3107 /* Extract the source address from the data. */
3108 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
3109 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
3110 lan_addr->session_handle = msg->rsp[4];
3111 lan_addr->remote_SWID = msg->rsp[8];
3112 lan_addr->local_SWID = msg->rsp[5];
3113 lan_addr->lun = msg->rsp[9] & 3;
3114 lan_addr->channel = msg->rsp[3] & 0xf;
3115 lan_addr->privilege = msg->rsp[3] >> 4;
3116
3117 /* Extract the rest of the message information
3118 from the IPMB header.*/
3119 recv_msg->user = user;
3120 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
3121 recv_msg->msgid = msg->rsp[9] >> 2;
3122 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3123 recv_msg->msg.cmd = msg->rsp[10];
3124 recv_msg->msg.data = recv_msg->msg_data;
3125
3126 /* We chop off 12, not 11 bytes because the checksum
3127 at the end also needs to be removed. */
3128 recv_msg->msg.data_len = msg->rsp_size - 12;
3129 memcpy(recv_msg->msg_data,
3130 &(msg->rsp[11]),
3131 msg->rsp_size - 12);
3132 deliver_response(recv_msg);
3133 }
3134 }
3135
3136 return rv;
3137}
3138
3139static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
3140 struct ipmi_smi_msg *msg)
3141{
3142 struct ipmi_system_interface_addr *smi_addr;
3143
3144 recv_msg->msgid = 0;
3145 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
3146 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3147 smi_addr->channel = IPMI_BMC_CHANNEL;
3148 smi_addr->lun = msg->rsp[0] & 3;
3149 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
3150 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3151 recv_msg->msg.cmd = msg->rsp[1];
3152 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
3153 recv_msg->msg.data = recv_msg->msg_data;
3154 recv_msg->msg.data_len = msg->rsp_size - 3;
3155}
3156
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157static int handle_read_event_rsp(ipmi_smi_t intf,
3158 struct ipmi_smi_msg *msg)
3159{
3160 struct ipmi_recv_msg *recv_msg, *recv_msg2;
3161 struct list_head msgs;
3162 ipmi_user_t user;
3163 int rv = 0;
3164 int deliver_count = 0;
3165 unsigned long flags;
3166
3167 if (msg->rsp_size < 19) {
3168 /* Message is too small to be an IPMB event. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003169 ipmi_inc_stat(intf, invalid_events);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 return 0;
3171 }
3172
3173 if (msg->rsp[2] != 0) {
3174 /* An error getting the event, just ignore it. */
3175 return 0;
3176 }
3177
3178 INIT_LIST_HEAD(&msgs);
3179
Corey Minyard393d2cc2005-11-07 00:59:54 -08003180 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003182 ipmi_inc_stat(intf, events);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
3184 /* Allocate and fill in one message for every user that is getting
3185 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003186 rcu_read_lock();
3187 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003188 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 continue;
3190
3191 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003192 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003193 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003194 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
3195 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 list_del(&recv_msg->link);
3197 ipmi_free_recv_msg(recv_msg);
3198 }
3199 /* We couldn't allocate memory for the
3200 message, so requeue it for handling
3201 later. */
3202 rv = 1;
3203 goto out;
3204 }
3205
3206 deliver_count++;
3207
3208 copy_event_into_recv_msg(recv_msg, msg);
3209 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003210 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 list_add_tail(&(recv_msg->link), &msgs);
3212 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003213 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214
3215 if (deliver_count) {
3216 /* Now deliver all the messages. */
3217 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
3218 list_del(&recv_msg->link);
3219 deliver_response(recv_msg);
3220 }
3221 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
3222 /* No one to receive the message, put it in queue if there's
3223 not already too many things in the queue. */
3224 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003225 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 /* We couldn't allocate memory for the
3227 message, so requeue it for handling
3228 later. */
3229 rv = 1;
3230 goto out;
3231 }
3232
3233 copy_event_into_recv_msg(recv_msg, msg);
3234 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07003235 intf->waiting_events_count++;
Corey Minyard87ebd062008-04-29 01:01:04 -07003236 } else if (!intf->event_msg_printed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 /* There's too many things in the queue, discard this
3238 message. */
Corey Minyard87ebd062008-04-29 01:01:04 -07003239 printk(KERN_WARNING PFX "Event queue full, discarding"
3240 " incoming events\n");
3241 intf->event_msg_printed = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 }
3243
3244 out:
3245 spin_unlock_irqrestore(&(intf->events_lock), flags);
3246
3247 return rv;
3248}
3249
3250static int handle_bmc_rsp(ipmi_smi_t intf,
3251 struct ipmi_smi_msg *msg)
3252{
3253 struct ipmi_recv_msg *recv_msg;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003254 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255
3256 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003257 if (recv_msg == NULL)
3258 {
3259 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3260 "could be because of a malformed message, or\n"
3261 "because of a hardware error. Contact your\n"
3262 "hardware vender for assistance\n");
3263 return 0;
3264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
Corey Minyard393d2cc2005-11-07 00:59:54 -08003266 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003268 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003269 /* The user for the message went away, so give up. */
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003270 ipmi_inc_stat(intf, unhandled_local_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 ipmi_free_recv_msg(recv_msg);
3272 } else {
3273 struct ipmi_system_interface_addr *smi_addr;
3274
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003275 ipmi_inc_stat(intf, handled_local_responses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3277 recv_msg->msgid = msg->msgid;
3278 smi_addr = ((struct ipmi_system_interface_addr *)
3279 &(recv_msg->addr));
3280 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3281 smi_addr->channel = IPMI_BMC_CHANNEL;
3282 smi_addr->lun = msg->rsp[0] & 3;
3283 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3284 recv_msg->msg.cmd = msg->rsp[1];
3285 memcpy(recv_msg->msg_data,
3286 &(msg->rsp[2]),
3287 msg->rsp_size - 2);
3288 recv_msg->msg.data = recv_msg->msg_data;
3289 recv_msg->msg.data_len = msg->rsp_size - 2;
3290 deliver_response(recv_msg);
3291 }
3292
3293 return 0;
3294}
3295
3296/* Handle a new message. Return 1 if the message should be requeued,
3297 0 if the message should be freed, or -1 if the message should not
3298 be freed or requeued. */
3299static int handle_new_recv_msg(ipmi_smi_t intf,
3300 struct ipmi_smi_msg *msg)
3301{
3302 int requeue;
3303 int chan;
3304
3305#ifdef DEBUG_MSGING
3306 int m;
3307 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003308 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 printk(" %2.2x", msg->rsp[m]);
3310 printk("\n");
3311#endif
3312 if (msg->rsp_size < 2) {
3313 /* Message is too small to be correct. */
3314 printk(KERN_WARNING PFX "BMC returned to small a message"
3315 " for netfn %x cmd %x, got %d bytes\n",
3316 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3317
3318 /* Generate an error response for the message. */
3319 msg->rsp[0] = msg->data[0] | (1 << 2);
3320 msg->rsp[1] = msg->data[1];
3321 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3322 msg->rsp_size = 3;
3323 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3324 || (msg->rsp[1] != msg->data[1])) /* Command */
3325 {
3326 /* The response is not even marginally correct. */
3327 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3328 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3329 (msg->data[0] >> 2) | 1, msg->data[1],
3330 msg->rsp[0] >> 2, msg->rsp[1]);
3331
3332 /* Generate an error response for the message. */
3333 msg->rsp[0] = msg->data[0] | (1 << 2);
3334 msg->rsp[1] = msg->data[1];
3335 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3336 msg->rsp_size = 3;
3337 }
3338
3339 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3340 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3341 && (msg->user_data != NULL))
3342 {
3343 /* It's a response to a response we sent. For this we
3344 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003345 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
3347 requeue = 0;
3348 if (msg->rsp_size < 2)
3349 /* Message is too small to be correct. */
3350 goto out;
3351
3352 chan = msg->data[2] & 0x0f;
3353 if (chan >= IPMI_MAX_CHANNELS)
3354 /* Invalid channel number */
3355 goto out;
3356
Corey Minyard393d2cc2005-11-07 00:59:54 -08003357 if (!recv_msg)
3358 goto out;
3359
3360 /* Make sure the user still exists. */
3361 if (!recv_msg->user || !recv_msg->user->valid)
3362 goto out;
3363
3364 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3365 recv_msg->msg.data = recv_msg->msg_data;
3366 recv_msg->msg.data_len = 1;
3367 recv_msg->msg_data[0] = msg->rsp[2];
3368 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3370 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3371 {
3372 /* It's from the receive queue. */
3373 chan = msg->rsp[3] & 0xf;
3374 if (chan >= IPMI_MAX_CHANNELS) {
3375 /* Invalid channel number */
3376 requeue = 0;
3377 goto out;
3378 }
3379
3380 switch (intf->channels[chan].medium) {
3381 case IPMI_CHANNEL_MEDIUM_IPMB:
3382 if (msg->rsp[4] & 0x04) {
3383 /* It's a response, so find the
3384 requesting message and send it up. */
3385 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3386 } else {
3387 /* It's a command to the SMS from some other
3388 entity. Handle that. */
3389 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3390 }
3391 break;
3392
3393 case IPMI_CHANNEL_MEDIUM_8023LAN:
3394 case IPMI_CHANNEL_MEDIUM_ASYNC:
3395 if (msg->rsp[6] & 0x04) {
3396 /* It's a response, so find the
3397 requesting message and send it up. */
3398 requeue = handle_lan_get_msg_rsp(intf, msg);
3399 } else {
3400 /* It's a command to the SMS from some other
3401 entity. Handle that. */
3402 requeue = handle_lan_get_msg_cmd(intf, msg);
3403 }
3404 break;
3405
3406 default:
3407 /* We don't handle the channel type, so just
3408 * free the message. */
3409 requeue = 0;
3410 }
3411
3412 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3413 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3414 {
3415 /* It's an asyncronous event. */
3416 requeue = handle_read_event_rsp(intf, msg);
3417 } else {
3418 /* It's a response from the local BMC. */
3419 requeue = handle_bmc_rsp(intf, msg);
3420 }
3421
3422 out:
3423 return requeue;
3424}
3425
3426/* Handle a new message from the lower layer. */
3427void ipmi_smi_msg_received(ipmi_smi_t intf,
3428 struct ipmi_smi_msg *msg)
3429{
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003430 unsigned long flags = 0; /* keep us warning-free. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 int rv;
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003432 int run_to_completion;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433
3434
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 if ((msg->data_size >= 2)
3436 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3437 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003438 && (msg->user_data == NULL))
3439 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 /* This is the local response to a command send, start
3441 the timer for these. The user_data will not be
3442 NULL if this is a response send, and we will let
3443 response sends just go through. */
3444
3445 /* Check for errors, if we get certain errors (ones
3446 that mean basically we can try again later), we
3447 ignore them and start the timer. Otherwise we
3448 report the error immediately. */
3449 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3450 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
Corey Minyard46d52b02006-11-08 17:44:55 -08003451 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
3452 && (msg->rsp[2] != IPMI_BUS_ERR)
3453 && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 {
3455 int chan = msg->rsp[3] & 0xf;
3456
3457 /* Got an error sending the message, handle it. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 if (chan >= IPMI_MAX_CHANNELS)
3459 ; /* This shouldn't happen */
3460 else if ((intf->channels[chan].medium
3461 == IPMI_CHANNEL_MEDIUM_8023LAN)
3462 || (intf->channels[chan].medium
3463 == IPMI_CHANNEL_MEDIUM_ASYNC))
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003464 ipmi_inc_stat(intf, sent_lan_command_errs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 else
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003466 ipmi_inc_stat(intf, sent_ipmb_command_errs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3468 } else {
3469 /* The message was sent, start the timer. */
3470 intf_start_seq_timer(intf, msg->msgid);
3471 }
3472
3473 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003474 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 }
3476
3477 /* To preserve message order, if the list is not empty, we
3478 tack this message onto the end of the list. */
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003479 run_to_completion = intf->run_to_completion;
3480 if (!run_to_completion)
3481 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003482 if (!list_empty(&intf->waiting_msgs)) {
3483 list_add_tail(&msg->link, &intf->waiting_msgs);
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003484 if (!run_to_completion)
3485 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003486 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 }
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003488 if (!run_to_completion)
3489 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
3491 rv = handle_new_recv_msg(intf, msg);
3492 if (rv > 0) {
3493 /* Could not handle the message now, just add it to a
3494 list to handle later. */
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003495 run_to_completion = intf->run_to_completion;
3496 if (!run_to_completion)
3497 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003498 list_add_tail(&msg->link, &intf->waiting_msgs);
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003499 if (!run_to_completion)
3500 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 } else if (rv == 0) {
3502 ipmi_free_smi_msg(msg);
3503 }
3504
Corey Minyard393d2cc2005-11-07 00:59:54 -08003505 out:
3506 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507}
3508
3509void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3510{
3511 ipmi_user_t user;
3512
Corey Minyard393d2cc2005-11-07 00:59:54 -08003513 rcu_read_lock();
3514 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003515 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 continue;
3517
3518 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3519 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003520 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521}
3522
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523
Corey Minyard882fe012005-05-01 08:59:12 -07003524static struct ipmi_smi_msg *
3525smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3526 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527{
Corey Minyard882fe012005-05-01 08:59:12 -07003528 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 if (!smi_msg)
3530 /* If we can't allocate the message, then just return, we
3531 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003532 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
3534 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3535 smi_msg->data_size = recv_msg->msg.data_len;
3536 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3537
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538#ifdef DEBUG_MSGING
3539 {
3540 int m;
3541 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003542 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 printk(" %2.2x", smi_msg->data[m]);
3544 printk("\n");
3545 }
3546#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003547 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548}
3549
Corey Minyard393d2cc2005-11-07 00:59:54 -08003550static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3551 struct list_head *timeouts, long timeout_period,
3552 int slot, unsigned long *flags)
3553{
Corey Minyardb2c03942006-12-06 20:41:00 -08003554 struct ipmi_recv_msg *msg;
3555 struct ipmi_smi_handlers *handlers;
3556
3557 if (intf->intf_num == -1)
3558 return;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003559
3560 if (!ent->inuse)
3561 return;
3562
3563 ent->timeout -= timeout_period;
3564 if (ent->timeout > 0)
3565 return;
3566
3567 if (ent->retries_left == 0) {
3568 /* The message has used all its retries. */
3569 ent->inuse = 0;
3570 msg = ent->recv_msg;
3571 list_add_tail(&msg->link, timeouts);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003572 if (ent->broadcast)
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003573 ipmi_inc_stat(intf, timed_out_ipmb_broadcasts);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003574 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003575 ipmi_inc_stat(intf, timed_out_lan_commands);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003576 else
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003577 ipmi_inc_stat(intf, timed_out_ipmb_commands);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003578 } else {
3579 struct ipmi_smi_msg *smi_msg;
3580 /* More retries, send again. */
3581
3582 /* Start with the max timer, set to normal
3583 timer after the message is sent. */
3584 ent->timeout = MAX_MSG_TIMEOUT;
3585 ent->retries_left--;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003586 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003587 ipmi_inc_stat(intf, retransmitted_lan_commands);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003588 else
Konstantin Baydarovb2655f22008-04-29 01:01:05 -07003589 ipmi_inc_stat(intf, retransmitted_ipmb_commands);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003590
3591 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3592 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003593 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003594 return;
3595
3596 spin_unlock_irqrestore(&intf->seq_lock, *flags);
Corey Minyardb2c03942006-12-06 20:41:00 -08003597
Corey Minyard393d2cc2005-11-07 00:59:54 -08003598 /* Send the new message. We send with a zero
3599 * priority. It timed out, I doubt time is
3600 * that critical now, and high priority
3601 * messages are really only for messages to the
3602 * local MC, which don't get resent. */
Corey Minyardb2c03942006-12-06 20:41:00 -08003603 handlers = intf->handlers;
3604 if (handlers)
3605 intf->handlers->sender(intf->send_info,
3606 smi_msg, 0);
3607 else
3608 ipmi_free_smi_msg(smi_msg);
3609
Corey Minyard393d2cc2005-11-07 00:59:54 -08003610 spin_lock_irqsave(&intf->seq_lock, *flags);
3611 }
3612}
3613
3614static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615{
3616 ipmi_smi_t intf;
3617 struct list_head timeouts;
3618 struct ipmi_recv_msg *msg, *msg2;
3619 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3620 unsigned long flags;
Corey Minyardbca03242006-12-06 20:40:57 -08003621 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622
Corey Minyardbca03242006-12-06 20:40:57 -08003623 rcu_read_lock();
3624 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003626 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003627 list_for_each_entry_safe(smi_msg, smi_msg2,
3628 &intf->waiting_msgs, link) {
3629 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 list_del(&smi_msg->link);
3631 ipmi_free_smi_msg(smi_msg);
3632 } else {
3633 /* To preserve message order, quit if we
3634 can't handle a message. */
3635 break;
3636 }
3637 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003638 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639
3640 /* Go through the seq table and find any messages that
3641 have timed out, putting them in the timeouts
3642 list. */
David Barksdale41c57a82007-01-30 14:36:25 -08003643 INIT_LIST_HEAD(&timeouts);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003644 spin_lock_irqsave(&intf->seq_lock, flags);
Corey Minyardbca03242006-12-06 20:40:57 -08003645 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
3646 check_msg_timeout(intf, &(intf->seq_table[i]),
3647 &timeouts, timeout_period, i,
Corey Minyard393d2cc2005-11-07 00:59:54 -08003648 &flags);
3649 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650
Corey Minyard393d2cc2005-11-07 00:59:54 -08003651 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08003652 deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
Corey Minyardb9675132006-12-06 20:41:02 -08003653
3654 /*
3655 * Maintenance mode handling. Check the timeout
3656 * optimistically before we claim the lock. It may
3657 * mean a timeout gets missed occasionally, but that
3658 * only means the timeout gets extended by one period
3659 * in that case. No big deal, and it avoids the lock
3660 * most of the time.
3661 */
3662 if (intf->auto_maintenance_timeout > 0) {
3663 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
3664 if (intf->auto_maintenance_timeout > 0) {
3665 intf->auto_maintenance_timeout
3666 -= timeout_period;
3667 if (!intf->maintenance_mode
3668 && (intf->auto_maintenance_timeout <= 0))
3669 {
3670 intf->maintenance_mode_enable = 0;
3671 maintenance_mode_update(intf);
3672 }
3673 }
3674 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
3675 flags);
3676 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 }
Corey Minyardbca03242006-12-06 20:40:57 -08003678 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679}
3680
3681static void ipmi_request_event(void)
3682{
Corey Minyardb2c03942006-12-06 20:41:00 -08003683 ipmi_smi_t intf;
3684 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685
Corey Minyardbca03242006-12-06 20:40:57 -08003686 rcu_read_lock();
Corey Minyardb2c03942006-12-06 20:41:00 -08003687 /* Called from the timer, no need to check if handlers is
3688 * valid. */
3689 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb9675132006-12-06 20:41:02 -08003690 /* No event requests when in maintenance mode. */
3691 if (intf->maintenance_mode_enable)
3692 continue;
3693
Corey Minyardb2c03942006-12-06 20:41:00 -08003694 handlers = intf->handlers;
3695 if (handlers)
3696 handlers->request_events(intf->send_info);
3697 }
Corey Minyardbca03242006-12-06 20:40:57 -08003698 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699}
3700
3701static struct timer_list ipmi_timer;
3702
3703/* Call every ~100 ms. */
3704#define IPMI_TIMEOUT_TIME 100
3705
3706/* How many jiffies does it take to get to the timeout time. */
3707#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3708
3709/* Request events from the queue every second (this is the number of
3710 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3711 future, IPMI will add a way to know immediately if an event is in
3712 the queue and this silliness can go away. */
3713#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3714
Corey Minyard8f43f842005-06-23 22:01:40 -07003715static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3717
3718static void ipmi_timeout(unsigned long data)
3719{
Corey Minyard8f43f842005-06-23 22:01:40 -07003720 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722
3723 ticks_to_req_ev--;
3724 if (ticks_to_req_ev == 0) {
3725 ipmi_request_event();
3726 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3727 }
3728
3729 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3730
Corey Minyard8f43f842005-06-23 22:01:40 -07003731 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732}
3733
3734
3735static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3736static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3737
3738/* FIXME - convert these to slabs. */
3739static void free_smi_msg(struct ipmi_smi_msg *msg)
3740{
3741 atomic_dec(&smi_msg_inuse_count);
3742 kfree(msg);
3743}
3744
3745struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3746{
3747 struct ipmi_smi_msg *rv;
3748 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3749 if (rv) {
3750 rv->done = free_smi_msg;
3751 rv->user_data = NULL;
3752 atomic_inc(&smi_msg_inuse_count);
3753 }
3754 return rv;
3755}
3756
3757static void free_recv_msg(struct ipmi_recv_msg *msg)
3758{
3759 atomic_dec(&recv_msg_inuse_count);
3760 kfree(msg);
3761}
3762
3763struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3764{
3765 struct ipmi_recv_msg *rv;
3766
3767 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3768 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003769 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 rv->done = free_recv_msg;
3771 atomic_inc(&recv_msg_inuse_count);
3772 }
3773 return rv;
3774}
3775
Corey Minyard393d2cc2005-11-07 00:59:54 -08003776void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3777{
3778 if (msg->user)
3779 kref_put(&msg->user->refcount, free_user);
3780 msg->done(msg);
3781}
3782
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783#ifdef CONFIG_IPMI_PANIC_EVENT
3784
3785static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3786{
3787}
3788
3789static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3790{
3791}
3792
3793#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003794static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003796 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3797 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3798 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3799 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 {
3801 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003802 intf->event_receiver = msg->msg.data[1];
3803 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 }
3805}
3806
Corey Minyard56a55ec2005-09-06 15:18:42 -07003807static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003809 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3810 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3811 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3812 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 {
3814 /* A get device id command, save if we are an event
3815 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003816 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3817 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 }
3819}
3820#endif
3821
3822static void send_panic_events(char *str)
3823{
3824 struct kernel_ipmi_msg msg;
3825 ipmi_smi_t intf;
3826 unsigned char data[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 struct ipmi_system_interface_addr *si;
3828 struct ipmi_addr addr;
3829 struct ipmi_smi_msg smi_msg;
3830 struct ipmi_recv_msg recv_msg;
3831
3832 si = (struct ipmi_system_interface_addr *) &addr;
3833 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3834 si->channel = IPMI_BMC_CHANNEL;
3835 si->lun = 0;
3836
3837 /* Fill in an event telling that we have failed. */
3838 msg.netfn = 0x04; /* Sensor or Event. */
3839 msg.cmd = 2; /* Platform event command. */
3840 msg.data = data;
3841 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003842 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 data[1] = 0x03; /* This is for IPMI 1.0. */
3844 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3845 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3846 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3847
3848 /* Put a few breadcrumbs in. Hopefully later we can add more things
3849 to make the panic events more useful. */
3850 if (str) {
3851 data[3] = str[0];
3852 data[6] = str[1];
3853 data[7] = str[2];
3854 }
3855
3856 smi_msg.done = dummy_smi_done_handler;
3857 recv_msg.done = dummy_recv_done_handler;
3858
3859 /* For every registered interface, send the event. */
Corey Minyardbca03242006-12-06 20:40:57 -08003860 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08003861 if (!intf->handlers)
3862 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 continue;
3864
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07003865 intf->run_to_completion = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 /* Send the event announcing the panic. */
3867 intf->handlers->set_run_to_completion(intf->send_info, 1);
3868 i_ipmi_request(NULL,
3869 intf,
3870 &addr,
3871 0,
3872 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003873 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 &smi_msg,
3875 &recv_msg,
3876 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003877 intf->channels[0].address,
3878 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 0, 1); /* Don't retry, and don't wait. */
3880 }
3881
3882#ifdef CONFIG_IPMI_PANIC_STRING
3883 /* On every interface, dump a bunch of OEM event holding the
3884 string. */
3885 if (!str)
3886 return;
3887
Corey Minyardbca03242006-12-06 20:40:57 -08003888 /* For every registered interface, send the event. */
3889 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 char *p = str;
3891 struct ipmi_ipmb_addr *ipmb;
3892 int j;
3893
Corey Minyardbca03242006-12-06 20:40:57 -08003894 if (intf->intf_num == -1)
3895 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 continue;
3897
Corey Minyard78ba2fa2007-02-10 01:45:45 -08003898 /*
3899 * intf_num is used as an marker to tell if the
3900 * interface is valid. Thus we need a read barrier to
3901 * make sure data fetched before checking intf_num
3902 * won't be used.
3903 */
3904 smp_rmb();
3905
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 /* First job here is to figure out where to send the
3907 OEM events. There's no way in IPMI to send OEM
3908 events using an event send command, so we have to
3909 find the SEL to put them in and stick them in
3910 there. */
3911
3912 /* Get capabilities from the get device id. */
3913 intf->local_sel_device = 0;
3914 intf->local_event_generator = 0;
3915 intf->event_receiver = 0;
3916
3917 /* Request the device info from the local MC. */
3918 msg.netfn = IPMI_NETFN_APP_REQUEST;
3919 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3920 msg.data = NULL;
3921 msg.data_len = 0;
3922 intf->null_user_handler = device_id_fetcher;
3923 i_ipmi_request(NULL,
3924 intf,
3925 &addr,
3926 0,
3927 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003928 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 &smi_msg,
3930 &recv_msg,
3931 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003932 intf->channels[0].address,
3933 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 0, 1); /* Don't retry, and don't wait. */
3935
3936 if (intf->local_event_generator) {
3937 /* Request the event receiver from the local MC. */
3938 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3939 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3940 msg.data = NULL;
3941 msg.data_len = 0;
3942 intf->null_user_handler = event_receiver_fetcher;
3943 i_ipmi_request(NULL,
3944 intf,
3945 &addr,
3946 0,
3947 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003948 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 &smi_msg,
3950 &recv_msg,
3951 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003952 intf->channels[0].address,
3953 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 0, 1); /* no retry, and no wait. */
3955 }
3956 intf->null_user_handler = NULL;
3957
3958 /* Validate the event receiver. The low bit must not
3959 be 1 (it must be a valid IPMB address), it cannot
3960 be zero, and it must not be my address. */
3961 if (((intf->event_receiver & 1) == 0)
3962 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003963 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 {
3965 /* The event receiver is valid, send an IPMB
3966 message. */
3967 ipmb = (struct ipmi_ipmb_addr *) &addr;
3968 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3969 ipmb->channel = 0; /* FIXME - is this right? */
3970 ipmb->lun = intf->event_receiver_lun;
3971 ipmb->slave_addr = intf->event_receiver;
3972 } else if (intf->local_sel_device) {
3973 /* The event receiver was not valid (or was
3974 me), but I am an SEL device, just dump it
3975 in my SEL. */
3976 si = (struct ipmi_system_interface_addr *) &addr;
3977 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3978 si->channel = IPMI_BMC_CHANNEL;
3979 si->lun = 0;
3980 } else
3981 continue; /* No where to send the event. */
3982
3983
3984 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
3985 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
3986 msg.data = data;
3987 msg.data_len = 16;
3988
3989 j = 0;
3990 while (*p) {
3991 int size = strlen(p);
3992
3993 if (size > 11)
3994 size = 11;
3995 data[0] = 0;
3996 data[1] = 0;
3997 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07003998 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 data[4] = j++; /* sequence # */
4000 /* Always give 11 bytes, so strncpy will fill
4001 it with zeroes for me. */
4002 strncpy(data+5, p, 11);
4003 p += size;
4004
4005 i_ipmi_request(NULL,
4006 intf,
4007 &addr,
4008 0,
4009 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07004010 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 &smi_msg,
4012 &recv_msg,
4013 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07004014 intf->channels[0].address,
4015 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 0, 1); /* no retry, and no wait. */
4017 }
4018 }
4019#endif /* CONFIG_IPMI_PANIC_STRING */
4020}
4021#endif /* CONFIG_IPMI_PANIC_EVENT */
4022
Randy Dunlap0c8204b2006-12-10 02:19:06 -08004023static int has_panicked;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024
4025static int panic_event(struct notifier_block *this,
4026 unsigned long event,
4027 void *ptr)
4028{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 ipmi_smi_t intf;
4030
Lee Revellf18190b2006-06-26 18:30:00 +02004031 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02004033 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034
4035 /* For every registered interface, set it to run to completion. */
Corey Minyardbca03242006-12-06 20:40:57 -08004036 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08004037 if (!intf->handlers)
4038 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 continue;
4040
Konstantin Baydarov5956dce2008-04-29 01:01:03 -07004041 intf->run_to_completion = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 intf->handlers->set_run_to_completion(intf->send_info, 1);
4043 }
4044
4045#ifdef CONFIG_IPMI_PANIC_EVENT
4046 send_panic_events(ptr);
4047#endif
4048
4049 return NOTIFY_DONE;
4050}
4051
4052static struct notifier_block panic_block = {
4053 .notifier_call = panic_event,
4054 .next = NULL,
4055 .priority = 200 /* priority: INT_MAX >= x >= 0 */
4056};
4057
4058static int ipmi_init_msghandler(void)
4059{
Corey Minyard50c812b2006-03-26 01:37:21 -08004060 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061
4062 if (initialized)
4063 return 0;
4064
Corey Minyard50c812b2006-03-26 01:37:21 -08004065 rv = driver_register(&ipmidriver);
4066 if (rv) {
4067 printk(KERN_ERR PFX "Could not register IPMI driver\n");
4068 return rv;
4069 }
4070
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004072 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073
Corey Minyard3b625942005-06-23 22:01:42 -07004074#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 proc_ipmi_root = proc_mkdir("ipmi", NULL);
4076 if (!proc_ipmi_root) {
4077 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
4078 return -ENOMEM;
4079 }
4080
4081 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07004082#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083
Corey Minyard409035e2006-06-28 04:26:53 -07004084 setup_timer(&ipmi_timer, ipmi_timeout, 0);
4085 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086
Alan Sterne041c682006-03-27 01:16:30 -08004087 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088
4089 initialized = 1;
4090
4091 return 0;
4092}
4093
4094static __init int ipmi_init_msghandler_mod(void)
4095{
4096 ipmi_init_msghandler();
4097 return 0;
4098}
4099
4100static __exit void cleanup_ipmi(void)
4101{
4102 int count;
4103
4104 if (!initialized)
4105 return;
4106
Alan Sterne041c682006-03-27 01:16:30 -08004107 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108
4109 /* This can't be called if any interfaces exist, so no worry about
4110 shutting down the interfaces. */
4111
4112 /* Tell the timer to stop, then wait for it to stop. This avoids
4113 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07004114 atomic_inc(&stop_operation);
4115 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116
Corey Minyard3b625942005-06-23 22:01:42 -07004117#ifdef CONFIG_PROC_FS
Alexey Dobriyan3542ae42007-10-16 23:26:50 -07004118 remove_proc_entry(proc_ipmi_root->name, NULL);
Corey Minyard3b625942005-06-23 22:01:42 -07004119#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120
Corey Minyard50c812b2006-03-26 01:37:21 -08004121 driver_unregister(&ipmidriver);
4122
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 initialized = 0;
4124
4125 /* Check for buffer leaks. */
4126 count = atomic_read(&smi_msg_inuse_count);
4127 if (count != 0)
4128 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
4129 count);
4130 count = atomic_read(&recv_msg_inuse_count);
4131 if (count != 0)
4132 printk(KERN_WARNING PFX "recv message count %d at exit\n",
4133 count);
4134}
4135module_exit(cleanup_ipmi);
4136
4137module_init(ipmi_init_msghandler_mod);
4138MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004139MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
4140MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
4141MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
4143EXPORT_SYMBOL(ipmi_create_user);
4144EXPORT_SYMBOL(ipmi_destroy_user);
4145EXPORT_SYMBOL(ipmi_get_version);
4146EXPORT_SYMBOL(ipmi_request_settime);
4147EXPORT_SYMBOL(ipmi_request_supply_msgs);
Corey Minyardfcfa4722007-10-18 03:07:09 -07004148EXPORT_SYMBOL(ipmi_poll_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149EXPORT_SYMBOL(ipmi_register_smi);
4150EXPORT_SYMBOL(ipmi_unregister_smi);
4151EXPORT_SYMBOL(ipmi_register_for_cmd);
4152EXPORT_SYMBOL(ipmi_unregister_for_cmd);
4153EXPORT_SYMBOL(ipmi_smi_msg_received);
4154EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
4155EXPORT_SYMBOL(ipmi_alloc_smi_msg);
4156EXPORT_SYMBOL(ipmi_addr_length);
4157EXPORT_SYMBOL(ipmi_validate_addr);
4158EXPORT_SYMBOL(ipmi_set_gets_events);
4159EXPORT_SYMBOL(ipmi_smi_watcher_register);
4160EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
4161EXPORT_SYMBOL(ipmi_set_my_address);
4162EXPORT_SYMBOL(ipmi_get_my_address);
4163EXPORT_SYMBOL(ipmi_set_my_LUN);
4164EXPORT_SYMBOL(ipmi_get_my_LUN);
4165EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Corey Minyard393d2cc2005-11-07 00:59:54 -08004166EXPORT_SYMBOL(ipmi_free_recv_msg);