blob: 46d14ac162123b387337a8b015f334195a21fe37 [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 Minyardb9675132006-12-06 20:41:02 -080050#define IPMI_DRIVER_VERSION "39.1"
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/*
72 * The main "user" data structure.
73 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070074struct ipmi_user
75{
76 struct list_head link;
77
Corey Minyard393d2cc2005-11-07 00:59:54 -080078 /* Set to "0" when the user is destroyed. */
79 int valid;
80
81 struct kref refcount;
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 /* The upper layer that handles receive messages. */
84 struct ipmi_user_hndl *handler;
85 void *handler_data;
86
87 /* The interface this user is bound to. */
88 ipmi_smi_t intf;
89
90 /* Does this interface receive IPMI events? */
91 int gets_events;
92};
93
94struct cmd_rcvr
95{
96 struct list_head link;
97
98 ipmi_user_t user;
99 unsigned char netfn;
100 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -0700101 unsigned int chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800102
103 /*
104 * This is used to form a linked lised during mass deletion.
105 * Since this is in an RCU list, we cannot use the link above
106 * or change any data until the RCU period completes. So we
107 * use this next variable during mass deletion so we can have
108 * a list and don't have to wait and restart the search on
109 * every individual deletion of a command. */
110 struct cmd_rcvr *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
112
113struct seq_table
114{
115 unsigned int inuse : 1;
116 unsigned int broadcast : 1;
117
118 unsigned long timeout;
119 unsigned long orig_timeout;
120 unsigned int retries_left;
121
122 /* To verify on an incoming send message response that this is
123 the message that the response is for, we keep a sequence id
124 and increment it every time we send a message. */
125 long seqid;
126
127 /* This is held so we can properly respond to the message on a
128 timeout, and it is used to hold the temporary data for
129 retransmission, too. */
130 struct ipmi_recv_msg *recv_msg;
131};
132
133/* Store the information in a msgid (long) to allow us to find a
134 sequence table entry from the msgid. */
135#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
136
137#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
138 do { \
139 seq = ((msgid >> 26) & 0x3f); \
140 seqid = (msgid & 0x3fffff); \
Corey Minyarde8b33612005-09-06 15:18:45 -0700141 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
144
145struct ipmi_channel
146{
147 unsigned char medium;
148 unsigned char protocol;
Corey Minyardc14979b2005-09-06 15:18:38 -0700149
150 /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
151 but may be changed by the user. */
152 unsigned char address;
153
154 /* My LUN. This should generally stay the SMS LUN, but just in
155 case... */
156 unsigned char lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157};
158
Corey Minyard3b625942005-06-23 22:01:42 -0700159#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160struct ipmi_proc_entry
161{
162 char *name;
163 struct ipmi_proc_entry *next;
164};
Corey Minyard3b625942005-06-23 22:01:42 -0700165#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
Corey Minyard50c812b2006-03-26 01:37:21 -0800167struct bmc_device
168{
169 struct platform_device *dev;
170 struct ipmi_device_id id;
171 unsigned char guid[16];
172 int guid_set;
173
174 struct kref refcount;
175
176 /* bmc device attributes */
177 struct device_attribute device_id_attr;
178 struct device_attribute provides_dev_sdrs_attr;
179 struct device_attribute revision_attr;
180 struct device_attribute firmware_rev_attr;
181 struct device_attribute version_attr;
182 struct device_attribute add_dev_support_attr;
183 struct device_attribute manufacturer_id_attr;
184 struct device_attribute product_id_attr;
185 struct device_attribute guid_attr;
186 struct device_attribute aux_firmware_rev_attr;
187};
188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189#define IPMI_IPMB_NUM_SEQ 64
Corey Minyardc14979b2005-09-06 15:18:38 -0700190#define IPMI_MAX_CHANNELS 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191struct ipmi_smi
192{
193 /* What interface number are we? */
194 int intf_num;
195
Corey Minyard393d2cc2005-11-07 00:59:54 -0800196 struct kref refcount;
197
Corey Minyardbca03242006-12-06 20:40:57 -0800198 /* Used for a list of interfaces. */
199 struct list_head link;
200
Corey Minyard393d2cc2005-11-07 00:59:54 -0800201 /* The list of upper layers that are using me. seq_lock
202 * protects this. */
203 struct list_head users;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Corey Minyardb2c03942006-12-06 20:41:00 -0800205 /* Information to supply to users. */
206 unsigned char ipmi_version_major;
207 unsigned char ipmi_version_minor;
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 /* Used for wake ups at startup. */
210 wait_queue_head_t waitq;
211
Corey Minyard50c812b2006-03-26 01:37:21 -0800212 struct bmc_device *bmc;
213 char *my_dev_name;
Corey Minyard759643b2006-12-06 20:40:59 -0800214 char *sysfs_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Corey Minyardb2c03942006-12-06 20:41:00 -0800216 /* This is the lower-layer's sender routine. Note that you
217 * must either be holding the ipmi_interfaces_mutex or be in
218 * an umpreemptible region to use this. You must fetch the
219 * value into a local variable and make sure it is not NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 struct ipmi_smi_handlers *handlers;
221 void *send_info;
222
Corey Minyard3b625942005-06-23 22:01:42 -0700223#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 /* A list of proc entries for this interface. This does not
225 need a lock, only one thread creates it and only one thread
226 destroys it. */
Corey Minyard3b625942005-06-23 22:01:42 -0700227 spinlock_t proc_entry_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 struct ipmi_proc_entry *proc_entries;
Corey Minyard3b625942005-06-23 22:01:42 -0700229#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
Corey Minyard50c812b2006-03-26 01:37:21 -0800231 /* Driver-model device for the system interface. */
232 struct device *si_dev;
233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 /* A table of sequence numbers for this interface. We use the
235 sequence numbers for IPMB messages that go out of the
236 interface to match them up with their responses. A routine
237 is called periodically to time the items in this list. */
238 spinlock_t seq_lock;
239 struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
240 int curr_seq;
241
242 /* Messages that were delayed for some reason (out of memory,
243 for instance), will go in here to be processed later in a
244 periodic timer interrupt. */
245 spinlock_t waiting_msgs_lock;
246 struct list_head waiting_msgs;
247
248 /* The list of command receivers that are registered for commands
249 on this interface. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800250 struct mutex cmd_rcvrs_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 struct list_head cmd_rcvrs;
252
253 /* Events that were queues because no one was there to receive
254 them. */
255 spinlock_t events_lock; /* For dealing with event stuff. */
256 struct list_head waiting_events;
257 unsigned int waiting_events_count; /* How many events in queue? */
Corey Minyardb2c03942006-12-06 20:41:00 -0800258 int delivering_events;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 /* The event receiver for my BMC, only really used at panic
261 shutdown as a place to store this. */
262 unsigned char event_receiver;
263 unsigned char event_receiver_lun;
264 unsigned char local_sel_device;
265 unsigned char local_event_generator;
266
Corey Minyardb9675132006-12-06 20:41:02 -0800267 /* For handling of maintenance mode. */
268 int maintenance_mode;
269 int maintenance_mode_enable;
270 int auto_maintenance_timeout;
271 spinlock_t maintenance_mode_lock; /* Used in a timer... */
272
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 /* A cheap hack, if this is non-null and a message to an
274 interface comes in with a NULL user, call this routine with
275 it. Note that the message will still be freed by the
276 caller. This only works on the system interface. */
Corey Minyard56a55ec2005-09-06 15:18:42 -0700277 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279 /* When we are scanning the channels for an SMI, this will
280 tell which channel we are scanning. */
281 int curr_channel;
282
283 /* Channel information */
284 struct ipmi_channel channels[IPMI_MAX_CHANNELS];
285
286 /* Proc FS stuff. */
287 struct proc_dir_entry *proc_dir;
288 char proc_dir_name[10];
289
290 spinlock_t counter_lock; /* For making counters atomic. */
291
292 /* Commands we got that were invalid. */
293 unsigned int sent_invalid_commands;
294
295 /* Commands we sent to the MC. */
296 unsigned int sent_local_commands;
297 /* Responses from the MC that were delivered to a user. */
298 unsigned int handled_local_responses;
299 /* Responses from the MC that were not delivered to a user. */
300 unsigned int unhandled_local_responses;
301
302 /* Commands we sent out to the IPMB bus. */
303 unsigned int sent_ipmb_commands;
304 /* Commands sent on the IPMB that had errors on the SEND CMD */
305 unsigned int sent_ipmb_command_errs;
306 /* Each retransmit increments this count. */
307 unsigned int retransmitted_ipmb_commands;
308 /* When a message times out (runs out of retransmits) this is
309 incremented. */
310 unsigned int timed_out_ipmb_commands;
311
312 /* This is like above, but for broadcasts. Broadcasts are
313 *not* included in the above count (they are expected to
314 time out). */
315 unsigned int timed_out_ipmb_broadcasts;
316
317 /* Responses I have sent to the IPMB bus. */
318 unsigned int sent_ipmb_responses;
319
320 /* The response was delivered to the user. */
321 unsigned int handled_ipmb_responses;
322 /* The response had invalid data in it. */
323 unsigned int invalid_ipmb_responses;
324 /* The response didn't have anyone waiting for it. */
325 unsigned int unhandled_ipmb_responses;
326
327 /* Commands we sent out to the IPMB bus. */
328 unsigned int sent_lan_commands;
329 /* Commands sent on the IPMB that had errors on the SEND CMD */
330 unsigned int sent_lan_command_errs;
331 /* Each retransmit increments this count. */
332 unsigned int retransmitted_lan_commands;
333 /* When a message times out (runs out of retransmits) this is
334 incremented. */
335 unsigned int timed_out_lan_commands;
336
337 /* Responses I have sent to the IPMB bus. */
338 unsigned int sent_lan_responses;
339
340 /* The response was delivered to the user. */
341 unsigned int handled_lan_responses;
342 /* The response had invalid data in it. */
343 unsigned int invalid_lan_responses;
344 /* The response didn't have anyone waiting for it. */
345 unsigned int unhandled_lan_responses;
346
347 /* The command was delivered to the user. */
348 unsigned int handled_commands;
349 /* The command had invalid data in it. */
350 unsigned int invalid_commands;
351 /* The command didn't have anyone waiting for it. */
352 unsigned int unhandled_commands;
353
354 /* Invalid data in an event. */
355 unsigned int invalid_events;
356 /* Events that were received with the proper format. */
357 unsigned int events;
358};
Corey Minyard50c812b2006-03-26 01:37:21 -0800359#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Corey Minyard50c812b2006-03-26 01:37:21 -0800361/**
362 * The driver model view of the IPMI messaging driver.
363 */
364static struct device_driver ipmidriver = {
365 .name = "ipmi",
366 .bus = &platform_bus_type
367};
368static DEFINE_MUTEX(ipmidriver_mutex);
369
Corey Minyardbca03242006-12-06 20:40:57 -0800370static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
371static DEFINE_MUTEX(ipmi_interfaces_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373/* List of watchers that want to know when smi's are added and
374 deleted. */
375static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
Corey Minyardb2c03942006-12-06 20:41:00 -0800376static DEFINE_MUTEX(smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Corey Minyard393d2cc2005-11-07 00:59:54 -0800379static void free_recv_msg_list(struct list_head *q)
380{
381 struct ipmi_recv_msg *msg, *msg2;
382
383 list_for_each_entry_safe(msg, msg2, q, link) {
384 list_del(&msg->link);
385 ipmi_free_recv_msg(msg);
386 }
387}
388
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800389static void free_smi_msg_list(struct list_head *q)
390{
391 struct ipmi_smi_msg *msg, *msg2;
392
393 list_for_each_entry_safe(msg, msg2, q, link) {
394 list_del(&msg->link);
395 ipmi_free_smi_msg(msg);
396 }
397}
398
Corey Minyard393d2cc2005-11-07 00:59:54 -0800399static void clean_up_interface_data(ipmi_smi_t intf)
400{
401 int i;
402 struct cmd_rcvr *rcvr, *rcvr2;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800403 struct list_head list;
404
Corey Minyardf3ce6a02006-11-08 17:44:52 -0800405 free_smi_msg_list(&intf->waiting_msgs);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800406 free_recv_msg_list(&intf->waiting_events);
407
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800408 /*
409 * Wholesale remove all the entries from the list in the
410 * interface and wait for RCU to know that none are in use.
411 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800412 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800413 INIT_LIST_HEAD(&list);
414 list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800415 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800416
417 list_for_each_entry_safe(rcvr, rcvr2, &list, link)
418 kfree(rcvr);
419
420 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
421 if ((intf->seq_table[i].inuse)
422 && (intf->seq_table[i].recv_msg))
423 {
424 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 }
426 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800427}
428
429static void intf_free(struct kref *ref)
430{
431 ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);
432
433 clean_up_interface_data(intf);
434 kfree(intf);
435}
436
Corey Minyardbca03242006-12-06 20:40:57 -0800437struct watcher_entry {
Corey Minyardb2c03942006-12-06 20:41:00 -0800438 int intf_num;
439 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800440 struct list_head link;
Corey Minyardbca03242006-12-06 20:40:57 -0800441};
442
Corey Minyard393d2cc2005-11-07 00:59:54 -0800443int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
444{
Corey Minyardbca03242006-12-06 20:40:57 -0800445 ipmi_smi_t intf;
446 struct list_head to_deliver = LIST_HEAD_INIT(to_deliver);
447 struct watcher_entry *e, *e2;
448
Corey Minyardb2c03942006-12-06 20:41:00 -0800449 mutex_lock(&smi_watchers_mutex);
450
Corey Minyardbca03242006-12-06 20:40:57 -0800451 mutex_lock(&ipmi_interfaces_mutex);
452
Corey Minyardb2c03942006-12-06 20:41:00 -0800453 /* Build a list of things to deliver. */
Corey Minyard78ba2fa2007-02-10 01:45:45 -0800454 list_for_each_entry(intf, &ipmi_interfaces, link) {
Corey Minyardbca03242006-12-06 20:40:57 -0800455 if (intf->intf_num == -1)
456 continue;
457 e = kmalloc(sizeof(*e), GFP_KERNEL);
458 if (!e)
459 goto out_err;
Corey Minyardb2c03942006-12-06 20:41:00 -0800460 kref_get(&intf->refcount);
461 e->intf = intf;
Corey Minyardbca03242006-12-06 20:40:57 -0800462 e->intf_num = intf->intf_num;
463 list_add_tail(&e->link, &to_deliver);
464 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800465
Corey Minyardb2c03942006-12-06 20:41:00 -0800466 /* We will succeed, so add it to the list. */
467 list_add(&watcher->link, &smi_watchers);
Corey Minyardbca03242006-12-06 20:40:57 -0800468
469 mutex_unlock(&ipmi_interfaces_mutex);
470
471 list_for_each_entry_safe(e, e2, &to_deliver, link) {
472 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800473 watcher->new_smi(e->intf_num, e->intf->si_dev);
474 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800475 kfree(e);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800476 }
Corey Minyardbca03242006-12-06 20:40:57 -0800477
Corey Minyardb2c03942006-12-06 20:41:00 -0800478 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 return 0;
Corey Minyardbca03242006-12-06 20:40:57 -0800481
482 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -0800483 mutex_unlock(&ipmi_interfaces_mutex);
484 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800485 list_for_each_entry_safe(e, e2, &to_deliver, link) {
486 list_del(&e->link);
Corey Minyardb2c03942006-12-06 20:41:00 -0800487 kref_put(&e->intf->refcount, intf_free);
Corey Minyardbca03242006-12-06 20:40:57 -0800488 kfree(e);
489 }
490 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
493int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
494{
Corey Minyardb2c03942006-12-06 20:41:00 -0800495 mutex_lock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 list_del(&(watcher->link));
Corey Minyardb2c03942006-12-06 20:41:00 -0800497 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return 0;
499}
500
Corey Minyardb2c03942006-12-06 20:41:00 -0800501/*
502 * Must be called with smi_watchers_mutex held.
503 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504static void
Corey Minyard50c812b2006-03-26 01:37:21 -0800505call_smi_watchers(int i, struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
507 struct ipmi_smi_watcher *w;
508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 list_for_each_entry(w, &smi_watchers, link) {
510 if (try_module_get(w->owner)) {
Corey Minyard50c812b2006-03-26 01:37:21 -0800511 w->new_smi(i, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 module_put(w->owner);
513 }
514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515}
516
517static int
518ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
519{
520 if (addr1->addr_type != addr2->addr_type)
521 return 0;
522
523 if (addr1->channel != addr2->channel)
524 return 0;
525
526 if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
527 struct ipmi_system_interface_addr *smi_addr1
528 = (struct ipmi_system_interface_addr *) addr1;
529 struct ipmi_system_interface_addr *smi_addr2
530 = (struct ipmi_system_interface_addr *) addr2;
531 return (smi_addr1->lun == smi_addr2->lun);
532 }
533
534 if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
535 || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
536 {
537 struct ipmi_ipmb_addr *ipmb_addr1
538 = (struct ipmi_ipmb_addr *) addr1;
539 struct ipmi_ipmb_addr *ipmb_addr2
540 = (struct ipmi_ipmb_addr *) addr2;
541
542 return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
543 && (ipmb_addr1->lun == ipmb_addr2->lun));
544 }
545
546 if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
547 struct ipmi_lan_addr *lan_addr1
548 = (struct ipmi_lan_addr *) addr1;
549 struct ipmi_lan_addr *lan_addr2
550 = (struct ipmi_lan_addr *) addr2;
551
552 return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
553 && (lan_addr1->local_SWID == lan_addr2->local_SWID)
554 && (lan_addr1->session_handle
555 == lan_addr2->session_handle)
556 && (lan_addr1->lun == lan_addr2->lun));
557 }
558
559 return 1;
560}
561
562int ipmi_validate_addr(struct ipmi_addr *addr, int len)
563{
564 if (len < sizeof(struct ipmi_system_interface_addr)) {
565 return -EINVAL;
566 }
567
568 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
569 if (addr->channel != IPMI_BMC_CHANNEL)
570 return -EINVAL;
571 return 0;
572 }
573
574 if ((addr->channel == IPMI_BMC_CHANNEL)
Jayachandran C12fc1d72006-02-03 03:04:51 -0800575 || (addr->channel >= IPMI_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 || (addr->channel < 0))
577 return -EINVAL;
578
579 if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
580 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
581 {
582 if (len < sizeof(struct ipmi_ipmb_addr)) {
583 return -EINVAL;
584 }
585 return 0;
586 }
587
588 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
589 if (len < sizeof(struct ipmi_lan_addr)) {
590 return -EINVAL;
591 }
592 return 0;
593 }
594
595 return -EINVAL;
596}
597
598unsigned int ipmi_addr_length(int addr_type)
599{
600 if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
601 return sizeof(struct ipmi_system_interface_addr);
602
603 if ((addr_type == IPMI_IPMB_ADDR_TYPE)
604 || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
605 {
606 return sizeof(struct ipmi_ipmb_addr);
607 }
608
609 if (addr_type == IPMI_LAN_ADDR_TYPE)
610 return sizeof(struct ipmi_lan_addr);
611
612 return 0;
613}
614
615static void deliver_response(struct ipmi_recv_msg *msg)
616{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800617 if (!msg->user) {
Corey Minyard56a55ec2005-09-06 15:18:42 -0700618 ipmi_smi_t intf = msg->user_msg_data;
619 unsigned long flags;
620
621 /* Special handling for NULL users. */
622 if (intf->null_user_handler) {
623 intf->null_user_handler(intf, msg);
624 spin_lock_irqsave(&intf->counter_lock, flags);
625 intf->handled_local_responses++;
626 spin_unlock_irqrestore(&intf->counter_lock, flags);
627 } else {
628 /* No handler, so give up. */
629 spin_lock_irqsave(&intf->counter_lock, flags);
630 intf->unhandled_local_responses++;
631 spin_unlock_irqrestore(&intf->counter_lock, flags);
632 }
633 ipmi_free_recv_msg(msg);
634 } else {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800635 ipmi_user_t user = msg->user;
636 user->handler->ipmi_recv_hndl(msg, user->handler_data);
Corey Minyard56a55ec2005-09-06 15:18:42 -0700637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638}
639
Corey Minyardb2c03942006-12-06 20:41:00 -0800640static void
641deliver_err_response(struct ipmi_recv_msg *msg, int err)
642{
643 msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
644 msg->msg_data[0] = err;
645 msg->msg.netfn |= 1; /* Convert to a response. */
646 msg->msg.data_len = 1;
647 msg->msg.data = msg->msg_data;
648 deliver_response(msg);
649}
650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651/* Find the next sequence number not being used and add the given
652 message with the given timeout to the sequence table. This must be
653 called with the interface's seq_lock held. */
654static int intf_next_seq(ipmi_smi_t intf,
655 struct ipmi_recv_msg *recv_msg,
656 unsigned long timeout,
657 int retries,
658 int broadcast,
659 unsigned char *seq,
660 long *seqid)
661{
662 int rv = 0;
663 unsigned int i;
664
Corey Minyarde8b33612005-09-06 15:18:45 -0700665 for (i = intf->curr_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
Corey Minyarde8b33612005-09-06 15:18:45 -0700667 i = (i+1)%IPMI_IPMB_NUM_SEQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800669 if (!intf->seq_table[i].inuse)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 break;
671 }
672
Corey Minyard8a3628d2006-03-31 02:30:40 -0800673 if (!intf->seq_table[i].inuse) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 intf->seq_table[i].recv_msg = recv_msg;
675
676 /* Start with the maximum timeout, when the send response
677 comes in we will start the real timer. */
678 intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
679 intf->seq_table[i].orig_timeout = timeout;
680 intf->seq_table[i].retries_left = retries;
681 intf->seq_table[i].broadcast = broadcast;
682 intf->seq_table[i].inuse = 1;
683 intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
684 *seq = i;
685 *seqid = intf->seq_table[i].seqid;
686 intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
687 } else {
688 rv = -EAGAIN;
689 }
690
691 return rv;
692}
693
694/* Return the receive message for the given sequence number and
695 release the sequence number so it can be reused. Some other data
696 is passed in to be sure the message matches up correctly (to help
697 guard against message coming in after their timeout and the
698 sequence number being reused). */
699static int intf_find_seq(ipmi_smi_t intf,
700 unsigned char seq,
701 short channel,
702 unsigned char cmd,
703 unsigned char netfn,
704 struct ipmi_addr *addr,
705 struct ipmi_recv_msg **recv_msg)
706{
707 int rv = -ENODEV;
708 unsigned long flags;
709
710 if (seq >= IPMI_IPMB_NUM_SEQ)
711 return -EINVAL;
712
713 spin_lock_irqsave(&(intf->seq_lock), flags);
714 if (intf->seq_table[seq].inuse) {
715 struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
716
717 if ((msg->addr.channel == channel)
718 && (msg->msg.cmd == cmd)
719 && (msg->msg.netfn == netfn)
720 && (ipmi_addr_equal(addr, &(msg->addr))))
721 {
722 *recv_msg = msg;
723 intf->seq_table[seq].inuse = 0;
724 rv = 0;
725 }
726 }
727 spin_unlock_irqrestore(&(intf->seq_lock), flags);
728
729 return rv;
730}
731
732
733/* Start the timer for a specific sequence table entry. */
734static int intf_start_seq_timer(ipmi_smi_t intf,
735 long msgid)
736{
737 int rv = -ENODEV;
738 unsigned long flags;
739 unsigned char seq;
740 unsigned long seqid;
741
742
743 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
744
745 spin_lock_irqsave(&(intf->seq_lock), flags);
746 /* We do this verification because the user can be deleted
747 while a message is outstanding. */
748 if ((intf->seq_table[seq].inuse)
749 && (intf->seq_table[seq].seqid == seqid))
750 {
751 struct seq_table *ent = &(intf->seq_table[seq]);
752 ent->timeout = ent->orig_timeout;
753 rv = 0;
754 }
755 spin_unlock_irqrestore(&(intf->seq_lock), flags);
756
757 return rv;
758}
759
760/* Got an error for the send message for a specific sequence number. */
761static int intf_err_seq(ipmi_smi_t intf,
762 long msgid,
763 unsigned int err)
764{
765 int rv = -ENODEV;
766 unsigned long flags;
767 unsigned char seq;
768 unsigned long seqid;
769 struct ipmi_recv_msg *msg = NULL;
770
771
772 GET_SEQ_FROM_MSGID(msgid, seq, seqid);
773
774 spin_lock_irqsave(&(intf->seq_lock), flags);
775 /* We do this verification because the user can be deleted
776 while a message is outstanding. */
777 if ((intf->seq_table[seq].inuse)
778 && (intf->seq_table[seq].seqid == seqid))
779 {
780 struct seq_table *ent = &(intf->seq_table[seq]);
781
782 ent->inuse = 0;
783 msg = ent->recv_msg;
784 rv = 0;
785 }
786 spin_unlock_irqrestore(&(intf->seq_lock), flags);
787
Corey Minyardb2c03942006-12-06 20:41:00 -0800788 if (msg)
789 deliver_err_response(msg, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 return rv;
792}
793
794
795int ipmi_create_user(unsigned int if_num,
796 struct ipmi_user_hndl *handler,
797 void *handler_data,
798 ipmi_user_t *user)
799{
800 unsigned long flags;
801 ipmi_user_t new_user;
802 int rv = 0;
803 ipmi_smi_t intf;
804
805 /* There is no module usecount here, because it's not
806 required. Since this can only be used by and called from
807 other modules, they will implicitly use this module, and
808 thus this can't be removed unless the other modules are
809 removed. */
810
811 if (handler == NULL)
812 return -EINVAL;
813
814 /* Make sure the driver is actually initialized, this handles
815 problems with initialization order. */
816 if (!initialized) {
817 rv = ipmi_init_msghandler();
818 if (rv)
819 return rv;
820
821 /* The init code doesn't return an error if it was turned
822 off, but it won't initialize. Check that. */
823 if (!initialized)
824 return -ENODEV;
825 }
826
827 new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -0800828 if (!new_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 return -ENOMEM;
830
Corey Minyardb2c03942006-12-06 20:41:00 -0800831 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -0800832 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
833 if (intf->intf_num == if_num)
834 goto found;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 }
Corey Minyardb2c03942006-12-06 20:41:00 -0800836 /* Not found, return an error */
Corey Minyardbca03242006-12-06 20:40:57 -0800837 rv = -EINVAL;
838 goto out_kfree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Corey Minyardbca03242006-12-06 20:40:57 -0800840 found:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800841 /* Note that each existing user holds a refcount to the interface. */
842 kref_get(&intf->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Corey Minyard393d2cc2005-11-07 00:59:54 -0800844 kref_init(&new_user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 new_user->handler = handler;
846 new_user->handler_data = handler_data;
847 new_user->intf = intf;
848 new_user->gets_events = 0;
849
850 if (!try_module_get(intf->handlers->owner)) {
851 rv = -ENODEV;
Adrian Bunk5c98d292006-03-25 03:07:52 -0800852 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
854
855 if (intf->handlers->inc_usecount) {
856 rv = intf->handlers->inc_usecount(intf->send_info);
857 if (rv) {
858 module_put(intf->handlers->owner);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800859 goto out_kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 }
861 }
862
Corey Minyardb2c03942006-12-06 20:41:00 -0800863 /* Hold the lock so intf->handlers is guaranteed to be good
864 * until now */
865 mutex_unlock(&ipmi_interfaces_mutex);
866
Corey Minyard393d2cc2005-11-07 00:59:54 -0800867 new_user->valid = 1;
868 spin_lock_irqsave(&intf->seq_lock, flags);
869 list_add_rcu(&new_user->link, &intf->users);
870 spin_unlock_irqrestore(&intf->seq_lock, flags);
871 *user = new_user;
872 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Adrian Bunk5c98d292006-03-25 03:07:52 -0800874out_kref:
Corey Minyard393d2cc2005-11-07 00:59:54 -0800875 kref_put(&intf->refcount, intf_free);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800876out_kfree:
Corey Minyardb2c03942006-12-06 20:41:00 -0800877 mutex_unlock(&ipmi_interfaces_mutex);
Adrian Bunk5c98d292006-03-25 03:07:52 -0800878 kfree(new_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return rv;
880}
881
Corey Minyard393d2cc2005-11-07 00:59:54 -0800882static void free_user(struct kref *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800884 ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886}
887
888int ipmi_destroy_user(ipmi_user_t user)
889{
Corey Minyard393d2cc2005-11-07 00:59:54 -0800890 ipmi_smi_t intf = user->intf;
891 int i;
892 unsigned long flags;
893 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800894 struct cmd_rcvr *rcvrs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
Corey Minyard8a3628d2006-03-31 02:30:40 -0800896 user->valid = 0;
Corey Minyard393d2cc2005-11-07 00:59:54 -0800897
898 /* Remove the user from the interface's sequence table. */
899 spin_lock_irqsave(&intf->seq_lock, flags);
900 list_del_rcu(&user->link);
901
902 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
903 if (intf->seq_table[i].inuse
904 && (intf->seq_table[i].recv_msg->user == user))
905 {
906 intf->seq_table[i].inuse = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -0800907 ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800908 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 }
Corey Minyard393d2cc2005-11-07 00:59:54 -0800910 spin_unlock_irqrestore(&intf->seq_lock, flags);
911
912 /*
913 * Remove the user from the command receiver's table. First
914 * we build a list of everything (not using the standard link,
915 * since other things may be using it till we do
916 * synchronize_rcu()) then free everything in that list.
917 */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800918 mutex_lock(&intf->cmd_rcvrs_mutex);
Paul E. McKenney066bb8d2006-01-06 00:19:53 -0800919 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyard393d2cc2005-11-07 00:59:54 -0800920 if (rcvr->user == user) {
921 list_del_rcu(&rcvr->link);
922 rcvr->next = rcvrs;
923 rcvrs = rcvr;
924 }
925 }
Corey Minyardd6dfd132006-03-31 02:30:41 -0800926 mutex_unlock(&intf->cmd_rcvrs_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800927 synchronize_rcu();
928 while (rcvrs) {
929 rcvr = rcvrs;
930 rcvrs = rcvr->next;
931 kfree(rcvr);
932 }
933
Corey Minyardb2c03942006-12-06 20:41:00 -0800934 mutex_lock(&ipmi_interfaces_mutex);
935 if (intf->handlers) {
936 module_put(intf->handlers->owner);
937 if (intf->handlers->dec_usecount)
938 intf->handlers->dec_usecount(intf->send_info);
939 }
940 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -0800941
942 kref_put(&intf->refcount, intf_free);
943
944 kref_put(&user->refcount, free_user);
945
Corey Minyard8a3628d2006-03-31 02:30:40 -0800946 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947}
948
949void ipmi_get_version(ipmi_user_t user,
950 unsigned char *major,
951 unsigned char *minor)
952{
Corey Minyardb2c03942006-12-06 20:41:00 -0800953 *major = user->intf->ipmi_version_major;
954 *minor = user->intf->ipmi_version_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955}
956
Corey Minyardc14979b2005-09-06 15:18:38 -0700957int ipmi_set_my_address(ipmi_user_t user,
958 unsigned int channel,
959 unsigned char address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960{
Corey Minyardc14979b2005-09-06 15:18:38 -0700961 if (channel >= IPMI_MAX_CHANNELS)
962 return -EINVAL;
963 user->intf->channels[channel].address = address;
964 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965}
966
Corey Minyardc14979b2005-09-06 15:18:38 -0700967int ipmi_get_my_address(ipmi_user_t user,
968 unsigned int channel,
969 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
Corey Minyardc14979b2005-09-06 15:18:38 -0700971 if (channel >= IPMI_MAX_CHANNELS)
972 return -EINVAL;
973 *address = user->intf->channels[channel].address;
974 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975}
976
Corey Minyardc14979b2005-09-06 15:18:38 -0700977int ipmi_set_my_LUN(ipmi_user_t user,
978 unsigned int channel,
979 unsigned char LUN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980{
Corey Minyardc14979b2005-09-06 15:18:38 -0700981 if (channel >= IPMI_MAX_CHANNELS)
982 return -EINVAL;
983 user->intf->channels[channel].lun = LUN & 0x3;
984 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985}
986
Corey Minyardc14979b2005-09-06 15:18:38 -0700987int ipmi_get_my_LUN(ipmi_user_t user,
988 unsigned int channel,
989 unsigned char *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
Corey Minyardc14979b2005-09-06 15:18:38 -0700991 if (channel >= IPMI_MAX_CHANNELS)
992 return -EINVAL;
993 *address = user->intf->channels[channel].lun;
994 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995}
996
Corey Minyardb9675132006-12-06 20:41:02 -0800997int ipmi_get_maintenance_mode(ipmi_user_t user)
998{
999 int mode;
1000 unsigned long flags;
1001
1002 spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
1003 mode = user->intf->maintenance_mode;
1004 spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
1005
1006 return mode;
1007}
1008EXPORT_SYMBOL(ipmi_get_maintenance_mode);
1009
1010static void maintenance_mode_update(ipmi_smi_t intf)
1011{
1012 if (intf->handlers->set_maintenance_mode)
1013 intf->handlers->set_maintenance_mode(
1014 intf->send_info, intf->maintenance_mode_enable);
1015}
1016
1017int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)
1018{
1019 int rv = 0;
1020 unsigned long flags;
1021 ipmi_smi_t intf = user->intf;
1022
1023 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1024 if (intf->maintenance_mode != mode) {
1025 switch (mode) {
1026 case IPMI_MAINTENANCE_MODE_AUTO:
1027 intf->maintenance_mode = mode;
1028 intf->maintenance_mode_enable
1029 = (intf->auto_maintenance_timeout > 0);
1030 break;
1031
1032 case IPMI_MAINTENANCE_MODE_OFF:
1033 intf->maintenance_mode = mode;
1034 intf->maintenance_mode_enable = 0;
1035 break;
1036
1037 case IPMI_MAINTENANCE_MODE_ON:
1038 intf->maintenance_mode = mode;
1039 intf->maintenance_mode_enable = 1;
1040 break;
1041
1042 default:
1043 rv = -EINVAL;
1044 goto out_unlock;
1045 }
1046
1047 maintenance_mode_update(intf);
1048 }
1049 out_unlock:
1050 spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
1051
1052 return rv;
1053}
1054EXPORT_SYMBOL(ipmi_set_maintenance_mode);
1055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056int ipmi_set_gets_events(ipmi_user_t user, int val)
1057{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001058 unsigned long flags;
1059 ipmi_smi_t intf = user->intf;
1060 struct ipmi_recv_msg *msg, *msg2;
1061 struct list_head msgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Corey Minyard393d2cc2005-11-07 00:59:54 -08001063 INIT_LIST_HEAD(&msgs);
1064
1065 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 user->gets_events = val;
1067
Corey Minyardb2c03942006-12-06 20:41:00 -08001068 if (intf->delivering_events)
1069 /*
1070 * Another thread is delivering events for this, so
1071 * let it handle any new events.
1072 */
1073 goto out;
1074
1075 /* Deliver any queued events. */
1076 while (user->gets_events && !list_empty(&intf->waiting_events)) {
Akinobu Mita179e0912006-06-26 00:24:41 -07001077 list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
1078 list_move_tail(&msg->link, &msgs);
Corey Minyard4791c032006-04-10 22:54:31 -07001079 intf->waiting_events_count = 0;
Corey Minyardb2c03942006-12-06 20:41:00 -08001080
1081 intf->delivering_events = 1;
1082 spin_unlock_irqrestore(&intf->events_lock, flags);
1083
1084 list_for_each_entry_safe(msg, msg2, &msgs, link) {
1085 msg->user = user;
1086 kref_get(&user->refcount);
1087 deliver_response(msg);
1088 }
1089
1090 spin_lock_irqsave(&intf->events_lock, flags);
1091 intf->delivering_events = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08001093
Corey Minyardb2c03942006-12-06 20:41:00 -08001094 out:
Corey Minyard393d2cc2005-11-07 00:59:54 -08001095 spin_unlock_irqrestore(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
1097 return 0;
1098}
1099
Corey Minyard393d2cc2005-11-07 00:59:54 -08001100static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
1101 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001102 unsigned char cmd,
1103 unsigned char chan)
Corey Minyard393d2cc2005-11-07 00:59:54 -08001104{
1105 struct cmd_rcvr *rcvr;
1106
1107 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
Corey Minyardc69c3122006-09-30 23:27:56 -07001108 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1109 && (rcvr->chans & (1 << chan)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08001110 return rcvr;
1111 }
1112 return NULL;
1113}
1114
Corey Minyardc69c3122006-09-30 23:27:56 -07001115static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
1116 unsigned char netfn,
1117 unsigned char cmd,
1118 unsigned int chans)
1119{
1120 struct cmd_rcvr *rcvr;
1121
1122 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1123 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
1124 && (rcvr->chans & chans))
1125 return 0;
1126 }
1127 return 1;
1128}
1129
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130int ipmi_register_for_cmd(ipmi_user_t user,
1131 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001132 unsigned char cmd,
1133 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001135 ipmi_smi_t intf = user->intf;
1136 struct cmd_rcvr *rcvr;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001137 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
1139
1140 rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
Corey Minyard8a3628d2006-03-31 02:30:40 -08001141 if (!rcvr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 return -ENOMEM;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001143 rcvr->cmd = cmd;
1144 rcvr->netfn = netfn;
Corey Minyardc69c3122006-09-30 23:27:56 -07001145 rcvr->chans = chans;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001146 rcvr->user = user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Corey Minyardd6dfd132006-03-31 02:30:41 -08001148 mutex_lock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 /* Make sure the command/netfn is not already registered. */
Corey Minyardc69c3122006-09-30 23:27:56 -07001150 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08001151 rv = -EBUSY;
1152 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 }
1154
Corey Minyard393d2cc2005-11-07 00:59:54 -08001155 list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
Corey Minyard877197e2005-09-06 15:18:45 -07001156
Corey Minyard393d2cc2005-11-07 00:59:54 -08001157 out_unlock:
Corey Minyardd6dfd132006-03-31 02:30:41 -08001158 mutex_unlock(&intf->cmd_rcvrs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 if (rv)
1160 kfree(rcvr);
1161
1162 return rv;
1163}
1164
1165int ipmi_unregister_for_cmd(ipmi_user_t user,
1166 unsigned char netfn,
Corey Minyardc69c3122006-09-30 23:27:56 -07001167 unsigned char cmd,
1168 unsigned int chans)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001170 ipmi_smi_t intf = user->intf;
1171 struct cmd_rcvr *rcvr;
Corey Minyardc69c3122006-09-30 23:27:56 -07001172 struct cmd_rcvr *rcvrs = NULL;
1173 int i, rv = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
Corey Minyardd6dfd132006-03-31 02:30:41 -08001175 mutex_lock(&intf->cmd_rcvrs_mutex);
Corey Minyardc69c3122006-09-30 23:27:56 -07001176 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1177 if (((1 << i) & chans) == 0)
1178 continue;
1179 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1180 if (rcvr == NULL)
1181 continue;
1182 if (rcvr->user == user) {
1183 rv = 0;
1184 rcvr->chans &= ~chans;
1185 if (rcvr->chans == 0) {
1186 list_del_rcu(&rcvr->link);
1187 rcvr->next = rcvrs;
1188 rcvrs = rcvr;
1189 }
1190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 }
Corey Minyardc69c3122006-09-30 23:27:56 -07001192 mutex_unlock(&intf->cmd_rcvrs_mutex);
1193 synchronize_rcu();
1194 while (rcvrs) {
1195 rcvr = rcvrs;
1196 rcvrs = rcvr->next;
1197 kfree(rcvr);
1198 }
1199 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200}
1201
1202void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
1203{
Corey Minyard393d2cc2005-11-07 00:59:54 -08001204 ipmi_smi_t intf = user->intf;
Corey Minyardb2c03942006-12-06 20:41:00 -08001205 if (intf->handlers)
1206 intf->handlers->set_run_to_completion(intf->send_info, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207}
1208
1209static unsigned char
1210ipmb_checksum(unsigned char *data, int size)
1211{
1212 unsigned char csum = 0;
1213
1214 for (; size > 0; size--, data++)
1215 csum += *data;
1216
1217 return -csum;
1218}
1219
1220static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
1221 struct kernel_ipmi_msg *msg,
1222 struct ipmi_ipmb_addr *ipmb_addr,
1223 long msgid,
1224 unsigned char ipmb_seq,
1225 int broadcast,
1226 unsigned char source_address,
1227 unsigned char source_lun)
1228{
1229 int i = broadcast;
1230
1231 /* Format the IPMB header data. */
1232 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1233 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1234 smi_msg->data[2] = ipmb_addr->channel;
1235 if (broadcast)
1236 smi_msg->data[3] = 0;
1237 smi_msg->data[i+3] = ipmb_addr->slave_addr;
1238 smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
1239 smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
1240 smi_msg->data[i+6] = source_address;
1241 smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
1242 smi_msg->data[i+8] = msg->cmd;
1243
1244 /* Now tack on the data to the message. */
1245 if (msg->data_len > 0)
1246 memcpy(&(smi_msg->data[i+9]), msg->data,
1247 msg->data_len);
1248 smi_msg->data_size = msg->data_len + 9;
1249
1250 /* Now calculate the checksum and tack it on. */
1251 smi_msg->data[i+smi_msg->data_size]
1252 = ipmb_checksum(&(smi_msg->data[i+6]),
1253 smi_msg->data_size-6);
1254
1255 /* Add on the checksum size and the offset from the
1256 broadcast. */
1257 smi_msg->data_size += 1 + i;
1258
1259 smi_msg->msgid = msgid;
1260}
1261
1262static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
1263 struct kernel_ipmi_msg *msg,
1264 struct ipmi_lan_addr *lan_addr,
1265 long msgid,
1266 unsigned char ipmb_seq,
1267 unsigned char source_lun)
1268{
1269 /* Format the IPMB header data. */
1270 smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
1271 smi_msg->data[1] = IPMI_SEND_MSG_CMD;
1272 smi_msg->data[2] = lan_addr->channel;
1273 smi_msg->data[3] = lan_addr->session_handle;
1274 smi_msg->data[4] = lan_addr->remote_SWID;
1275 smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
1276 smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
1277 smi_msg->data[7] = lan_addr->local_SWID;
1278 smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
1279 smi_msg->data[9] = msg->cmd;
1280
1281 /* Now tack on the data to the message. */
1282 if (msg->data_len > 0)
1283 memcpy(&(smi_msg->data[10]), msg->data,
1284 msg->data_len);
1285 smi_msg->data_size = msg->data_len + 10;
1286
1287 /* Now calculate the checksum and tack it on. */
1288 smi_msg->data[smi_msg->data_size]
1289 = ipmb_checksum(&(smi_msg->data[7]),
1290 smi_msg->data_size-7);
1291
1292 /* Add on the checksum size and the offset from the
1293 broadcast. */
1294 smi_msg->data_size += 1;
1295
1296 smi_msg->msgid = msgid;
1297}
1298
1299/* Separate from ipmi_request so that the user does not have to be
1300 supplied in certain circumstances (mainly at panic time). If
1301 messages are supplied, they will be freed, even if an error
1302 occurs. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08001303static int i_ipmi_request(ipmi_user_t user,
1304 ipmi_smi_t intf,
1305 struct ipmi_addr *addr,
1306 long msgid,
1307 struct kernel_ipmi_msg *msg,
1308 void *user_msg_data,
1309 void *supplied_smi,
1310 struct ipmi_recv_msg *supplied_recv,
1311 int priority,
1312 unsigned char source_address,
1313 unsigned char source_lun,
1314 int retries,
1315 unsigned int retry_time_ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316{
Corey Minyardb2c03942006-12-06 20:41:00 -08001317 int rv = 0;
1318 struct ipmi_smi_msg *smi_msg;
1319 struct ipmi_recv_msg *recv_msg;
1320 unsigned long flags;
1321 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
1323
1324 if (supplied_recv) {
1325 recv_msg = supplied_recv;
1326 } else {
1327 recv_msg = ipmi_alloc_recv_msg();
1328 if (recv_msg == NULL) {
1329 return -ENOMEM;
1330 }
1331 }
1332 recv_msg->user_msg_data = user_msg_data;
1333
1334 if (supplied_smi) {
1335 smi_msg = (struct ipmi_smi_msg *) supplied_smi;
1336 } else {
1337 smi_msg = ipmi_alloc_smi_msg();
1338 if (smi_msg == NULL) {
1339 ipmi_free_recv_msg(recv_msg);
1340 return -ENOMEM;
1341 }
1342 }
1343
Corey Minyardb2c03942006-12-06 20:41:00 -08001344 rcu_read_lock();
1345 handlers = intf->handlers;
1346 if (!handlers) {
1347 rv = -ENODEV;
1348 goto out_err;
1349 }
1350
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08001352 if (user)
1353 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 recv_msg->msgid = msgid;
1355 /* Store the message to send in the receive message so timeout
1356 responses can get the proper response data. */
1357 recv_msg->msg = *msg;
1358
1359 if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1360 struct ipmi_system_interface_addr *smi_addr;
1361
1362 if (msg->netfn & 1) {
1363 /* Responses are not allowed to the SMI. */
1364 rv = -EINVAL;
1365 goto out_err;
1366 }
1367
1368 smi_addr = (struct ipmi_system_interface_addr *) addr;
1369 if (smi_addr->lun > 3) {
1370 spin_lock_irqsave(&intf->counter_lock, flags);
1371 intf->sent_invalid_commands++;
1372 spin_unlock_irqrestore(&intf->counter_lock, flags);
1373 rv = -EINVAL;
1374 goto out_err;
1375 }
1376
1377 memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
1378
1379 if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
1380 && ((msg->cmd == IPMI_SEND_MSG_CMD)
1381 || (msg->cmd == IPMI_GET_MSG_CMD)
1382 || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
1383 {
1384 /* We don't let the user do these, since we manage
1385 the sequence numbers. */
1386 spin_lock_irqsave(&intf->counter_lock, flags);
1387 intf->sent_invalid_commands++;
1388 spin_unlock_irqrestore(&intf->counter_lock, flags);
1389 rv = -EINVAL;
1390 goto out_err;
1391 }
1392
Corey Minyardb9675132006-12-06 20:41:02 -08001393 if (((msg->netfn == IPMI_NETFN_APP_REQUEST)
1394 && ((msg->cmd == IPMI_COLD_RESET_CMD)
1395 || (msg->cmd == IPMI_WARM_RESET_CMD)))
1396 || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))
1397 {
1398 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1399 intf->auto_maintenance_timeout
1400 = IPMI_MAINTENANCE_MODE_TIMEOUT;
1401 if (!intf->maintenance_mode
1402 && !intf->maintenance_mode_enable)
1403 {
1404 intf->maintenance_mode_enable = 1;
1405 maintenance_mode_update(intf);
1406 }
1407 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
1408 flags);
1409 }
1410
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1412 spin_lock_irqsave(&intf->counter_lock, flags);
1413 intf->sent_invalid_commands++;
1414 spin_unlock_irqrestore(&intf->counter_lock, flags);
1415 rv = -EMSGSIZE;
1416 goto out_err;
1417 }
1418
1419 smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
1420 smi_msg->data[1] = msg->cmd;
1421 smi_msg->msgid = msgid;
1422 smi_msg->user_data = recv_msg;
1423 if (msg->data_len > 0)
1424 memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
1425 smi_msg->data_size = msg->data_len + 2;
1426 spin_lock_irqsave(&intf->counter_lock, flags);
1427 intf->sent_local_commands++;
1428 spin_unlock_irqrestore(&intf->counter_lock, flags);
1429 } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
1430 || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
1431 {
1432 struct ipmi_ipmb_addr *ipmb_addr;
1433 unsigned char ipmb_seq;
1434 long seqid;
1435 int broadcast = 0;
1436
KAMBAROV, ZAUR9c101fd2005-06-28 20:45:08 -07001437 if (addr->channel >= IPMI_MAX_CHANNELS) {
1438 spin_lock_irqsave(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 intf->sent_invalid_commands++;
1440 spin_unlock_irqrestore(&intf->counter_lock, flags);
1441 rv = -EINVAL;
1442 goto out_err;
1443 }
1444
1445 if (intf->channels[addr->channel].medium
1446 != IPMI_CHANNEL_MEDIUM_IPMB)
1447 {
1448 spin_lock_irqsave(&intf->counter_lock, flags);
1449 intf->sent_invalid_commands++;
1450 spin_unlock_irqrestore(&intf->counter_lock, flags);
1451 rv = -EINVAL;
1452 goto out_err;
1453 }
1454
1455 if (retries < 0) {
1456 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
1457 retries = 0; /* Don't retry broadcasts. */
1458 else
1459 retries = 4;
1460 }
1461 if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
1462 /* Broadcasts add a zero at the beginning of the
1463 message, but otherwise is the same as an IPMB
1464 address. */
1465 addr->addr_type = IPMI_IPMB_ADDR_TYPE;
1466 broadcast = 1;
1467 }
1468
1469
1470 /* Default to 1 second retries. */
1471 if (retry_time_ms == 0)
1472 retry_time_ms = 1000;
1473
1474 /* 9 for the header and 1 for the checksum, plus
1475 possibly one for the broadcast. */
1476 if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
1477 spin_lock_irqsave(&intf->counter_lock, flags);
1478 intf->sent_invalid_commands++;
1479 spin_unlock_irqrestore(&intf->counter_lock, flags);
1480 rv = -EMSGSIZE;
1481 goto out_err;
1482 }
1483
1484 ipmb_addr = (struct ipmi_ipmb_addr *) addr;
1485 if (ipmb_addr->lun > 3) {
1486 spin_lock_irqsave(&intf->counter_lock, flags);
1487 intf->sent_invalid_commands++;
1488 spin_unlock_irqrestore(&intf->counter_lock, flags);
1489 rv = -EINVAL;
1490 goto out_err;
1491 }
1492
1493 memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
1494
1495 if (recv_msg->msg.netfn & 0x1) {
1496 /* It's a response, so use the user's sequence
1497 from msgid. */
1498 spin_lock_irqsave(&intf->counter_lock, flags);
1499 intf->sent_ipmb_responses++;
1500 spin_unlock_irqrestore(&intf->counter_lock, flags);
1501 format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
1502 msgid, broadcast,
1503 source_address, source_lun);
1504
1505 /* Save the receive message so we can use it
1506 to deliver the response. */
1507 smi_msg->user_data = recv_msg;
1508 } else {
1509 /* It's a command, so get a sequence for it. */
1510
1511 spin_lock_irqsave(&(intf->seq_lock), flags);
1512
1513 spin_lock(&intf->counter_lock);
1514 intf->sent_ipmb_commands++;
1515 spin_unlock(&intf->counter_lock);
1516
1517 /* Create a sequence number with a 1 second
1518 timeout and 4 retries. */
1519 rv = intf_next_seq(intf,
1520 recv_msg,
1521 retry_time_ms,
1522 retries,
1523 broadcast,
1524 &ipmb_seq,
1525 &seqid);
1526 if (rv) {
1527 /* We have used up all the sequence numbers,
1528 probably, so abort. */
1529 spin_unlock_irqrestore(&(intf->seq_lock),
1530 flags);
1531 goto out_err;
1532 }
1533
1534 /* Store the sequence number in the message,
1535 so that when the send message response
1536 comes back we can start the timer. */
1537 format_ipmb_msg(smi_msg, msg, ipmb_addr,
1538 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1539 ipmb_seq, broadcast,
1540 source_address, source_lun);
1541
1542 /* Copy the message into the recv message data, so we
1543 can retransmit it later if necessary. */
1544 memcpy(recv_msg->msg_data, smi_msg->data,
1545 smi_msg->data_size);
1546 recv_msg->msg.data = recv_msg->msg_data;
1547 recv_msg->msg.data_len = smi_msg->data_size;
1548
1549 /* We don't unlock until here, because we need
1550 to copy the completed message into the
1551 recv_msg before we release the lock.
1552 Otherwise, race conditions may bite us. I
1553 know that's pretty paranoid, but I prefer
1554 to be correct. */
1555 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1556 }
1557 } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
1558 struct ipmi_lan_addr *lan_addr;
1559 unsigned char ipmb_seq;
1560 long seqid;
1561
Jayachandran C12fc1d72006-02-03 03:04:51 -08001562 if (addr->channel >= IPMI_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 spin_lock_irqsave(&intf->counter_lock, flags);
1564 intf->sent_invalid_commands++;
1565 spin_unlock_irqrestore(&intf->counter_lock, flags);
1566 rv = -EINVAL;
1567 goto out_err;
1568 }
1569
1570 if ((intf->channels[addr->channel].medium
1571 != IPMI_CHANNEL_MEDIUM_8023LAN)
1572 && (intf->channels[addr->channel].medium
1573 != IPMI_CHANNEL_MEDIUM_ASYNC))
1574 {
1575 spin_lock_irqsave(&intf->counter_lock, flags);
1576 intf->sent_invalid_commands++;
1577 spin_unlock_irqrestore(&intf->counter_lock, flags);
1578 rv = -EINVAL;
1579 goto out_err;
1580 }
1581
1582 retries = 4;
1583
1584 /* Default to 1 second retries. */
1585 if (retry_time_ms == 0)
1586 retry_time_ms = 1000;
1587
1588 /* 11 for the header and 1 for the checksum. */
1589 if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
1590 spin_lock_irqsave(&intf->counter_lock, flags);
1591 intf->sent_invalid_commands++;
1592 spin_unlock_irqrestore(&intf->counter_lock, flags);
1593 rv = -EMSGSIZE;
1594 goto out_err;
1595 }
1596
1597 lan_addr = (struct ipmi_lan_addr *) addr;
1598 if (lan_addr->lun > 3) {
1599 spin_lock_irqsave(&intf->counter_lock, flags);
1600 intf->sent_invalid_commands++;
1601 spin_unlock_irqrestore(&intf->counter_lock, flags);
1602 rv = -EINVAL;
1603 goto out_err;
1604 }
1605
1606 memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
1607
1608 if (recv_msg->msg.netfn & 0x1) {
1609 /* It's a response, so use the user's sequence
1610 from msgid. */
1611 spin_lock_irqsave(&intf->counter_lock, flags);
1612 intf->sent_lan_responses++;
1613 spin_unlock_irqrestore(&intf->counter_lock, flags);
1614 format_lan_msg(smi_msg, msg, lan_addr, msgid,
1615 msgid, source_lun);
1616
1617 /* Save the receive message so we can use it
1618 to deliver the response. */
1619 smi_msg->user_data = recv_msg;
1620 } else {
1621 /* It's a command, so get a sequence for it. */
1622
1623 spin_lock_irqsave(&(intf->seq_lock), flags);
1624
1625 spin_lock(&intf->counter_lock);
1626 intf->sent_lan_commands++;
1627 spin_unlock(&intf->counter_lock);
1628
1629 /* Create a sequence number with a 1 second
1630 timeout and 4 retries. */
1631 rv = intf_next_seq(intf,
1632 recv_msg,
1633 retry_time_ms,
1634 retries,
1635 0,
1636 &ipmb_seq,
1637 &seqid);
1638 if (rv) {
1639 /* We have used up all the sequence numbers,
1640 probably, so abort. */
1641 spin_unlock_irqrestore(&(intf->seq_lock),
1642 flags);
1643 goto out_err;
1644 }
1645
1646 /* Store the sequence number in the message,
1647 so that when the send message response
1648 comes back we can start the timer. */
1649 format_lan_msg(smi_msg, msg, lan_addr,
1650 STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
1651 ipmb_seq, source_lun);
1652
1653 /* Copy the message into the recv message data, so we
1654 can retransmit it later if necessary. */
1655 memcpy(recv_msg->msg_data, smi_msg->data,
1656 smi_msg->data_size);
1657 recv_msg->msg.data = recv_msg->msg_data;
1658 recv_msg->msg.data_len = smi_msg->data_size;
1659
1660 /* We don't unlock until here, because we need
1661 to copy the completed message into the
1662 recv_msg before we release the lock.
1663 Otherwise, race conditions may bite us. I
1664 know that's pretty paranoid, but I prefer
1665 to be correct. */
1666 spin_unlock_irqrestore(&(intf->seq_lock), flags);
1667 }
1668 } else {
1669 /* Unknown address type. */
1670 spin_lock_irqsave(&intf->counter_lock, flags);
1671 intf->sent_invalid_commands++;
1672 spin_unlock_irqrestore(&intf->counter_lock, flags);
1673 rv = -EINVAL;
1674 goto out_err;
1675 }
1676
1677#ifdef DEBUG_MSGING
1678 {
1679 int m;
Corey Minyarde8b33612005-09-06 15:18:45 -07001680 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 printk(" %2.2x", smi_msg->data[m]);
1682 printk("\n");
1683 }
1684#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08001685
1686 handlers->sender(intf->send_info, smi_msg, priority);
1687 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
1689 return 0;
1690
1691 out_err:
Corey Minyardb2c03942006-12-06 20:41:00 -08001692 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 ipmi_free_smi_msg(smi_msg);
1694 ipmi_free_recv_msg(recv_msg);
1695 return rv;
1696}
1697
Corey Minyardc14979b2005-09-06 15:18:38 -07001698static int check_addr(ipmi_smi_t intf,
1699 struct ipmi_addr *addr,
1700 unsigned char *saddr,
1701 unsigned char *lun)
1702{
1703 if (addr->channel >= IPMI_MAX_CHANNELS)
1704 return -EINVAL;
1705 *lun = intf->channels[addr->channel].lun;
1706 *saddr = intf->channels[addr->channel].address;
1707 return 0;
1708}
1709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710int ipmi_request_settime(ipmi_user_t user,
1711 struct ipmi_addr *addr,
1712 long msgid,
1713 struct kernel_ipmi_msg *msg,
1714 void *user_msg_data,
1715 int priority,
1716 int retries,
1717 unsigned int retry_time_ms)
1718{
Corey Minyardc14979b2005-09-06 15:18:38 -07001719 unsigned char saddr, lun;
1720 int rv;
1721
Corey Minyard8a3628d2006-03-31 02:30:40 -08001722 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001723 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001724 rv = check_addr(user->intf, addr, &saddr, &lun);
1725 if (rv)
1726 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 return i_ipmi_request(user,
1728 user->intf,
1729 addr,
1730 msgid,
1731 msg,
1732 user_msg_data,
1733 NULL, NULL,
1734 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001735 saddr,
1736 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 retries,
1738 retry_time_ms);
1739}
1740
1741int ipmi_request_supply_msgs(ipmi_user_t user,
1742 struct ipmi_addr *addr,
1743 long msgid,
1744 struct kernel_ipmi_msg *msg,
1745 void *user_msg_data,
1746 void *supplied_smi,
1747 struct ipmi_recv_msg *supplied_recv,
1748 int priority)
1749{
Corey Minyardc14979b2005-09-06 15:18:38 -07001750 unsigned char saddr, lun;
1751 int rv;
1752
Corey Minyard8a3628d2006-03-31 02:30:40 -08001753 if (!user)
Corey Minyard56a55ec2005-09-06 15:18:42 -07001754 return -EINVAL;
Corey Minyardc14979b2005-09-06 15:18:38 -07001755 rv = check_addr(user->intf, addr, &saddr, &lun);
1756 if (rv)
1757 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 return i_ipmi_request(user,
1759 user->intf,
1760 addr,
1761 msgid,
1762 msg,
1763 user_msg_data,
1764 supplied_smi,
1765 supplied_recv,
1766 priority,
Corey Minyardc14979b2005-09-06 15:18:38 -07001767 saddr,
1768 lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 -1, 0);
1770}
1771
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001772#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773static int ipmb_file_read_proc(char *page, char **start, off_t off,
1774 int count, int *eof, void *data)
1775{
1776 char *out = (char *) page;
1777 ipmi_smi_t intf = data;
Corey Minyardc14979b2005-09-06 15:18:38 -07001778 int i;
Corey Minyard8a3628d2006-03-31 02:30:40 -08001779 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
Corey Minyarde8b33612005-09-06 15:18:45 -07001781 for (i = 0; i < IPMI_MAX_CHANNELS; i++)
Corey Minyardc14979b2005-09-06 15:18:38 -07001782 rv += sprintf(out+rv, "%x ", intf->channels[i].address);
1783 out[rv-1] = '\n'; /* Replace the final space with a newline */
1784 out[rv] = '\0';
1785 rv++;
1786 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787}
1788
1789static int version_file_read_proc(char *page, char **start, off_t off,
1790 int count, int *eof, void *data)
1791{
1792 char *out = (char *) page;
1793 ipmi_smi_t intf = data;
1794
1795 return sprintf(out, "%d.%d\n",
Corey Minyard50c812b2006-03-26 01:37:21 -08001796 ipmi_version_major(&intf->bmc->id),
1797 ipmi_version_minor(&intf->bmc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798}
1799
1800static int stat_file_read_proc(char *page, char **start, off_t off,
1801 int count, int *eof, void *data)
1802{
1803 char *out = (char *) page;
1804 ipmi_smi_t intf = data;
1805
1806 out += sprintf(out, "sent_invalid_commands: %d\n",
1807 intf->sent_invalid_commands);
1808 out += sprintf(out, "sent_local_commands: %d\n",
1809 intf->sent_local_commands);
1810 out += sprintf(out, "handled_local_responses: %d\n",
1811 intf->handled_local_responses);
1812 out += sprintf(out, "unhandled_local_responses: %d\n",
1813 intf->unhandled_local_responses);
1814 out += sprintf(out, "sent_ipmb_commands: %d\n",
1815 intf->sent_ipmb_commands);
1816 out += sprintf(out, "sent_ipmb_command_errs: %d\n",
1817 intf->sent_ipmb_command_errs);
1818 out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
1819 intf->retransmitted_ipmb_commands);
1820 out += sprintf(out, "timed_out_ipmb_commands: %d\n",
1821 intf->timed_out_ipmb_commands);
1822 out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
1823 intf->timed_out_ipmb_broadcasts);
1824 out += sprintf(out, "sent_ipmb_responses: %d\n",
1825 intf->sent_ipmb_responses);
1826 out += sprintf(out, "handled_ipmb_responses: %d\n",
1827 intf->handled_ipmb_responses);
1828 out += sprintf(out, "invalid_ipmb_responses: %d\n",
1829 intf->invalid_ipmb_responses);
1830 out += sprintf(out, "unhandled_ipmb_responses: %d\n",
1831 intf->unhandled_ipmb_responses);
1832 out += sprintf(out, "sent_lan_commands: %d\n",
1833 intf->sent_lan_commands);
1834 out += sprintf(out, "sent_lan_command_errs: %d\n",
1835 intf->sent_lan_command_errs);
1836 out += sprintf(out, "retransmitted_lan_commands: %d\n",
1837 intf->retransmitted_lan_commands);
1838 out += sprintf(out, "timed_out_lan_commands: %d\n",
1839 intf->timed_out_lan_commands);
1840 out += sprintf(out, "sent_lan_responses: %d\n",
1841 intf->sent_lan_responses);
1842 out += sprintf(out, "handled_lan_responses: %d\n",
1843 intf->handled_lan_responses);
1844 out += sprintf(out, "invalid_lan_responses: %d\n",
1845 intf->invalid_lan_responses);
1846 out += sprintf(out, "unhandled_lan_responses: %d\n",
1847 intf->unhandled_lan_responses);
1848 out += sprintf(out, "handled_commands: %d\n",
1849 intf->handled_commands);
1850 out += sprintf(out, "invalid_commands: %d\n",
1851 intf->invalid_commands);
1852 out += sprintf(out, "unhandled_commands: %d\n",
1853 intf->unhandled_commands);
1854 out += sprintf(out, "invalid_events: %d\n",
1855 intf->invalid_events);
1856 out += sprintf(out, "events: %d\n",
1857 intf->events);
1858
1859 return (out - ((char *) page));
1860}
Randy Dunlap1aa16ee2006-12-06 20:41:20 -08001861#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
1863int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
1864 read_proc_t *read_proc, write_proc_t *write_proc,
1865 void *data, struct module *owner)
1866{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 int rv = 0;
Corey Minyard3b625942005-06-23 22:01:42 -07001868#ifdef CONFIG_PROC_FS
1869 struct proc_dir_entry *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 struct ipmi_proc_entry *entry;
1871
1872 /* Create a list element. */
1873 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1874 if (!entry)
1875 return -ENOMEM;
1876 entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
1877 if (!entry->name) {
1878 kfree(entry);
1879 return -ENOMEM;
1880 }
1881 strcpy(entry->name, name);
1882
1883 file = create_proc_entry(name, 0, smi->proc_dir);
1884 if (!file) {
1885 kfree(entry->name);
1886 kfree(entry);
1887 rv = -ENOMEM;
1888 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 file->data = data;
1890 file->read_proc = read_proc;
1891 file->write_proc = write_proc;
1892 file->owner = owner;
1893
Corey Minyard3b625942005-06-23 22:01:42 -07001894 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 /* Stick it on the list. */
1896 entry->next = smi->proc_entries;
1897 smi->proc_entries = entry;
Corey Minyard3b625942005-06-23 22:01:42 -07001898 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
Corey Minyard3b625942005-06-23 22:01:42 -07001900#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
1902 return rv;
1903}
1904
1905static int add_proc_entries(ipmi_smi_t smi, int num)
1906{
1907 int rv = 0;
1908
Corey Minyard3b625942005-06-23 22:01:42 -07001909#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 sprintf(smi->proc_dir_name, "%d", num);
1911 smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
1912 if (!smi->proc_dir)
1913 rv = -ENOMEM;
1914 else {
1915 smi->proc_dir->owner = THIS_MODULE;
1916 }
1917
1918 if (rv == 0)
1919 rv = ipmi_smi_add_proc_entry(smi, "stats",
1920 stat_file_read_proc, NULL,
1921 smi, THIS_MODULE);
1922
1923 if (rv == 0)
1924 rv = ipmi_smi_add_proc_entry(smi, "ipmb",
1925 ipmb_file_read_proc, NULL,
1926 smi, THIS_MODULE);
1927
1928 if (rv == 0)
1929 rv = ipmi_smi_add_proc_entry(smi, "version",
1930 version_file_read_proc, NULL,
1931 smi, THIS_MODULE);
Corey Minyard3b625942005-06-23 22:01:42 -07001932#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
1934 return rv;
1935}
1936
1937static void remove_proc_entries(ipmi_smi_t smi)
1938{
Corey Minyard3b625942005-06-23 22:01:42 -07001939#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 struct ipmi_proc_entry *entry;
1941
Corey Minyard3b625942005-06-23 22:01:42 -07001942 spin_lock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 while (smi->proc_entries) {
1944 entry = smi->proc_entries;
1945 smi->proc_entries = entry->next;
1946
1947 remove_proc_entry(entry->name, smi->proc_dir);
1948 kfree(entry->name);
1949 kfree(entry);
1950 }
Corey Minyard3b625942005-06-23 22:01:42 -07001951 spin_unlock(&smi->proc_entry_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
Corey Minyard3b625942005-06-23 22:01:42 -07001953#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954}
1955
Corey Minyard50c812b2006-03-26 01:37:21 -08001956static int __find_bmc_guid(struct device *dev, void *data)
1957{
1958 unsigned char *id = data;
1959 struct bmc_device *bmc = dev_get_drvdata(dev);
1960 return memcmp(bmc->guid, id, 16) == 0;
1961}
1962
1963static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
1964 unsigned char *guid)
1965{
1966 struct device *dev;
1967
1968 dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
1969 if (dev)
1970 return dev_get_drvdata(dev);
1971 else
1972 return NULL;
1973}
1974
1975struct prod_dev_id {
1976 unsigned int product_id;
1977 unsigned char device_id;
1978};
1979
1980static int __find_bmc_prod_dev_id(struct device *dev, void *data)
1981{
1982 struct prod_dev_id *id = data;
1983 struct bmc_device *bmc = dev_get_drvdata(dev);
1984
1985 return (bmc->id.product_id == id->product_id
Corey Minyard50c812b2006-03-26 01:37:21 -08001986 && bmc->id.device_id == id->device_id);
1987}
1988
1989static struct bmc_device *ipmi_find_bmc_prod_dev_id(
1990 struct device_driver *drv,
Corey Minyardf0b55da2006-12-06 20:40:54 -08001991 unsigned int product_id, unsigned char device_id)
Corey Minyard50c812b2006-03-26 01:37:21 -08001992{
1993 struct prod_dev_id id = {
1994 .product_id = product_id,
1995 .device_id = device_id,
1996 };
1997 struct device *dev;
1998
1999 dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
2000 if (dev)
2001 return dev_get_drvdata(dev);
2002 else
2003 return NULL;
2004}
2005
2006static ssize_t device_id_show(struct device *dev,
2007 struct device_attribute *attr,
2008 char *buf)
2009{
2010 struct bmc_device *bmc = dev_get_drvdata(dev);
2011
2012 return snprintf(buf, 10, "%u\n", bmc->id.device_id);
2013}
2014
2015static ssize_t provides_dev_sdrs_show(struct device *dev,
2016 struct device_attribute *attr,
2017 char *buf)
2018{
2019 struct bmc_device *bmc = dev_get_drvdata(dev);
2020
2021 return snprintf(buf, 10, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002022 (bmc->id.device_revision & 0x80) >> 7);
Corey Minyard50c812b2006-03-26 01:37:21 -08002023}
2024
2025static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
2026 char *buf)
2027{
2028 struct bmc_device *bmc = dev_get_drvdata(dev);
2029
2030 return snprintf(buf, 20, "%u\n",
Corey Minyard7947d2c2006-11-10 12:27:50 -08002031 bmc->id.device_revision & 0x0F);
Corey Minyard50c812b2006-03-26 01:37:21 -08002032}
2033
2034static ssize_t firmware_rev_show(struct device *dev,
2035 struct device_attribute *attr,
2036 char *buf)
2037{
2038 struct bmc_device *bmc = dev_get_drvdata(dev);
2039
2040 return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
2041 bmc->id.firmware_revision_2);
2042}
2043
2044static ssize_t ipmi_version_show(struct device *dev,
2045 struct device_attribute *attr,
2046 char *buf)
2047{
2048 struct bmc_device *bmc = dev_get_drvdata(dev);
2049
2050 return snprintf(buf, 20, "%u.%u\n",
2051 ipmi_version_major(&bmc->id),
2052 ipmi_version_minor(&bmc->id));
2053}
2054
2055static ssize_t add_dev_support_show(struct device *dev,
2056 struct device_attribute *attr,
2057 char *buf)
2058{
2059 struct bmc_device *bmc = dev_get_drvdata(dev);
2060
2061 return snprintf(buf, 10, "0x%02x\n",
2062 bmc->id.additional_device_support);
2063}
2064
2065static ssize_t manufacturer_id_show(struct device *dev,
2066 struct device_attribute *attr,
2067 char *buf)
2068{
2069 struct bmc_device *bmc = dev_get_drvdata(dev);
2070
2071 return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
2072}
2073
2074static ssize_t product_id_show(struct device *dev,
2075 struct device_attribute *attr,
2076 char *buf)
2077{
2078 struct bmc_device *bmc = dev_get_drvdata(dev);
2079
2080 return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
2081}
2082
2083static ssize_t aux_firmware_rev_show(struct device *dev,
2084 struct device_attribute *attr,
2085 char *buf)
2086{
2087 struct bmc_device *bmc = dev_get_drvdata(dev);
2088
2089 return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
2090 bmc->id.aux_firmware_revision[3],
2091 bmc->id.aux_firmware_revision[2],
2092 bmc->id.aux_firmware_revision[1],
2093 bmc->id.aux_firmware_revision[0]);
2094}
2095
2096static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
2097 char *buf)
2098{
2099 struct bmc_device *bmc = dev_get_drvdata(dev);
2100
2101 return snprintf(buf, 100, "%Lx%Lx\n",
2102 (long long) bmc->guid[0],
2103 (long long) bmc->guid[8]);
2104}
2105
Jeff Garzik5e593932006-10-11 01:22:21 -07002106static void remove_files(struct bmc_device *bmc)
Corey Minyard50c812b2006-03-26 01:37:21 -08002107{
Corey Minyardf0b55da2006-12-06 20:40:54 -08002108 if (!bmc->dev)
2109 return;
2110
Corey Minyard50c812b2006-03-26 01:37:21 -08002111 device_remove_file(&bmc->dev->dev,
2112 &bmc->device_id_attr);
2113 device_remove_file(&bmc->dev->dev,
2114 &bmc->provides_dev_sdrs_attr);
2115 device_remove_file(&bmc->dev->dev,
2116 &bmc->revision_attr);
2117 device_remove_file(&bmc->dev->dev,
2118 &bmc->firmware_rev_attr);
2119 device_remove_file(&bmc->dev->dev,
2120 &bmc->version_attr);
2121 device_remove_file(&bmc->dev->dev,
2122 &bmc->add_dev_support_attr);
2123 device_remove_file(&bmc->dev->dev,
2124 &bmc->manufacturer_id_attr);
2125 device_remove_file(&bmc->dev->dev,
2126 &bmc->product_id_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002127
Corey Minyard50c812b2006-03-26 01:37:21 -08002128 if (bmc->id.aux_firmware_revision_set)
2129 device_remove_file(&bmc->dev->dev,
2130 &bmc->aux_firmware_rev_attr);
2131 if (bmc->guid_set)
2132 device_remove_file(&bmc->dev->dev,
2133 &bmc->guid_attr);
Jeff Garzik5e593932006-10-11 01:22:21 -07002134}
2135
2136static void
2137cleanup_bmc_device(struct kref *ref)
2138{
2139 struct bmc_device *bmc;
2140
2141 bmc = container_of(ref, struct bmc_device, refcount);
2142
2143 remove_files(bmc);
Corey Minyard1d5636c2006-12-10 02:19:08 -08002144 platform_device_unregister(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002145 kfree(bmc);
2146}
2147
2148static void ipmi_bmc_unregister(ipmi_smi_t intf)
2149{
2150 struct bmc_device *bmc = intf->bmc;
2151
Corey Minyard759643b2006-12-06 20:40:59 -08002152 if (intf->sysfs_name) {
2153 sysfs_remove_link(&intf->si_dev->kobj, intf->sysfs_name);
2154 kfree(intf->sysfs_name);
2155 intf->sysfs_name = NULL;
2156 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002157 if (intf->my_dev_name) {
2158 sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name);
2159 kfree(intf->my_dev_name);
2160 intf->my_dev_name = NULL;
2161 }
2162
2163 mutex_lock(&ipmidriver_mutex);
2164 kref_put(&bmc->refcount, cleanup_bmc_device);
Corey Minyardf0b55da2006-12-06 20:40:54 -08002165 intf->bmc = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002166 mutex_unlock(&ipmidriver_mutex);
2167}
2168
Jeff Garzik5e593932006-10-11 01:22:21 -07002169static int create_files(struct bmc_device *bmc)
2170{
2171 int err;
2172
Corey Minyardf0b55da2006-12-06 20:40:54 -08002173 bmc->device_id_attr.attr.name = "device_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002174 bmc->device_id_attr.attr.mode = S_IRUGO;
2175 bmc->device_id_attr.show = device_id_show;
2176
2177 bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002178 bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
2179 bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
2180
2181 bmc->revision_attr.attr.name = "revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002182 bmc->revision_attr.attr.mode = S_IRUGO;
2183 bmc->revision_attr.show = revision_show;
2184
2185 bmc->firmware_rev_attr.attr.name = "firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002186 bmc->firmware_rev_attr.attr.mode = S_IRUGO;
2187 bmc->firmware_rev_attr.show = firmware_rev_show;
2188
2189 bmc->version_attr.attr.name = "ipmi_version";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002190 bmc->version_attr.attr.mode = S_IRUGO;
2191 bmc->version_attr.show = ipmi_version_show;
2192
2193 bmc->add_dev_support_attr.attr.name = "additional_device_support";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002194 bmc->add_dev_support_attr.attr.mode = S_IRUGO;
2195 bmc->add_dev_support_attr.show = add_dev_support_show;
2196
2197 bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002198 bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
2199 bmc->manufacturer_id_attr.show = manufacturer_id_show;
2200
2201 bmc->product_id_attr.attr.name = "product_id";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002202 bmc->product_id_attr.attr.mode = S_IRUGO;
2203 bmc->product_id_attr.show = product_id_show;
2204
2205 bmc->guid_attr.attr.name = "guid";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002206 bmc->guid_attr.attr.mode = S_IRUGO;
2207 bmc->guid_attr.show = guid_show;
2208
2209 bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
Corey Minyardf0b55da2006-12-06 20:40:54 -08002210 bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
2211 bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
2212
Jeff Garzik5e593932006-10-11 01:22:21 -07002213 err = device_create_file(&bmc->dev->dev,
2214 &bmc->device_id_attr);
2215 if (err) goto out;
2216 err = device_create_file(&bmc->dev->dev,
2217 &bmc->provides_dev_sdrs_attr);
2218 if (err) goto out_devid;
2219 err = device_create_file(&bmc->dev->dev,
2220 &bmc->revision_attr);
2221 if (err) goto out_sdrs;
2222 err = device_create_file(&bmc->dev->dev,
2223 &bmc->firmware_rev_attr);
2224 if (err) goto out_rev;
2225 err = device_create_file(&bmc->dev->dev,
2226 &bmc->version_attr);
2227 if (err) goto out_firm;
2228 err = device_create_file(&bmc->dev->dev,
2229 &bmc->add_dev_support_attr);
2230 if (err) goto out_version;
2231 err = device_create_file(&bmc->dev->dev,
2232 &bmc->manufacturer_id_attr);
2233 if (err) goto out_add_dev;
2234 err = device_create_file(&bmc->dev->dev,
2235 &bmc->product_id_attr);
2236 if (err) goto out_manu;
2237 if (bmc->id.aux_firmware_revision_set) {
2238 err = device_create_file(&bmc->dev->dev,
2239 &bmc->aux_firmware_rev_attr);
2240 if (err) goto out_prod_id;
2241 }
2242 if (bmc->guid_set) {
2243 err = device_create_file(&bmc->dev->dev,
2244 &bmc->guid_attr);
2245 if (err) goto out_aux_firm;
2246 }
2247
2248 return 0;
2249
2250out_aux_firm:
2251 if (bmc->id.aux_firmware_revision_set)
2252 device_remove_file(&bmc->dev->dev,
2253 &bmc->aux_firmware_rev_attr);
2254out_prod_id:
2255 device_remove_file(&bmc->dev->dev,
2256 &bmc->product_id_attr);
2257out_manu:
2258 device_remove_file(&bmc->dev->dev,
2259 &bmc->manufacturer_id_attr);
2260out_add_dev:
2261 device_remove_file(&bmc->dev->dev,
2262 &bmc->add_dev_support_attr);
2263out_version:
2264 device_remove_file(&bmc->dev->dev,
2265 &bmc->version_attr);
2266out_firm:
2267 device_remove_file(&bmc->dev->dev,
2268 &bmc->firmware_rev_attr);
2269out_rev:
2270 device_remove_file(&bmc->dev->dev,
2271 &bmc->revision_attr);
2272out_sdrs:
2273 device_remove_file(&bmc->dev->dev,
2274 &bmc->provides_dev_sdrs_attr);
2275out_devid:
2276 device_remove_file(&bmc->dev->dev,
2277 &bmc->device_id_attr);
2278out:
2279 return err;
2280}
2281
Corey Minyard759643b2006-12-06 20:40:59 -08002282static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
2283 const char *sysfs_name)
Corey Minyard50c812b2006-03-26 01:37:21 -08002284{
2285 int rv;
2286 struct bmc_device *bmc = intf->bmc;
2287 struct bmc_device *old_bmc;
2288 int size;
2289 char dummy[1];
2290
2291 mutex_lock(&ipmidriver_mutex);
2292
2293 /*
2294 * Try to find if there is an bmc_device struct
2295 * representing the interfaced BMC already
2296 */
2297 if (bmc->guid_set)
2298 old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid);
2299 else
2300 old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver,
2301 bmc->id.product_id,
2302 bmc->id.device_id);
2303
2304 /*
2305 * If there is already an bmc_device, free the new one,
2306 * otherwise register the new BMC device
2307 */
2308 if (old_bmc) {
2309 kfree(bmc);
2310 intf->bmc = old_bmc;
2311 bmc = old_bmc;
2312
2313 kref_get(&bmc->refcount);
2314 mutex_unlock(&ipmidriver_mutex);
2315
2316 printk(KERN_INFO
2317 "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
2318 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2319 bmc->id.manufacturer_id,
2320 bmc->id.product_id,
2321 bmc->id.device_id);
2322 } else {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002323 char name[14];
2324 unsigned char orig_dev_id = bmc->id.device_id;
2325 int warn_printed = 0;
2326
2327 snprintf(name, sizeof(name),
2328 "ipmi_bmc.%4.4x", bmc->id.product_id);
2329
2330 while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
2331 bmc->id.product_id,
Corey Minyard1d5636c2006-12-10 02:19:08 -08002332 bmc->id.device_id)) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002333 if (!warn_printed) {
2334 printk(KERN_WARNING PFX
2335 "This machine has two different BMCs"
2336 " with the same product id and device"
2337 " id. This is an error in the"
2338 " firmware, but incrementing the"
2339 " device id to work around the problem."
2340 " Prod ID = 0x%x, Dev ID = 0x%x\n",
2341 bmc->id.product_id, bmc->id.device_id);
2342 warn_printed = 1;
2343 }
2344 bmc->id.device_id++; /* Wraps at 255 */
2345 if (bmc->id.device_id == orig_dev_id) {
2346 printk(KERN_ERR PFX
2347 "Out of device ids!\n");
2348 break;
2349 }
2350 }
2351
2352 bmc->dev = platform_device_alloc(name, bmc->id.device_id);
Corey Minyard8a3628d2006-03-31 02:30:40 -08002353 if (!bmc->dev) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002354 mutex_unlock(&ipmidriver_mutex);
Corey Minyard50c812b2006-03-26 01:37:21 -08002355 printk(KERN_ERR
2356 "ipmi_msghandler:"
2357 " Unable to allocate platform device\n");
2358 return -ENOMEM;
2359 }
2360 bmc->dev->dev.driver = &ipmidriver;
2361 dev_set_drvdata(&bmc->dev->dev, bmc);
2362 kref_init(&bmc->refcount);
2363
Zhang, Yanminb48f5452006-11-16 01:19:08 -08002364 rv = platform_device_add(bmc->dev);
Corey Minyard50c812b2006-03-26 01:37:21 -08002365 mutex_unlock(&ipmidriver_mutex);
2366 if (rv) {
Corey Minyardf0b55da2006-12-06 20:40:54 -08002367 platform_device_put(bmc->dev);
2368 bmc->dev = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002369 printk(KERN_ERR
2370 "ipmi_msghandler:"
2371 " Unable to register bmc device: %d\n",
2372 rv);
2373 /* Don't go to out_err, you can only do that if
2374 the device is registered already. */
2375 return rv;
2376 }
2377
Jeff Garzik5e593932006-10-11 01:22:21 -07002378 rv = create_files(bmc);
2379 if (rv) {
2380 mutex_lock(&ipmidriver_mutex);
2381 platform_device_unregister(bmc->dev);
2382 mutex_unlock(&ipmidriver_mutex);
2383
2384 return rv;
2385 }
Corey Minyard50c812b2006-03-26 01:37:21 -08002386
2387 printk(KERN_INFO
2388 "ipmi: Found new BMC (man_id: 0x%6.6x, "
2389 " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
2390 bmc->id.manufacturer_id,
2391 bmc->id.product_id,
2392 bmc->id.device_id);
2393 }
2394
2395 /*
2396 * create symlink from system interface device to bmc device
2397 * and back.
2398 */
Corey Minyard759643b2006-12-06 20:40:59 -08002399 intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL);
2400 if (!intf->sysfs_name) {
2401 rv = -ENOMEM;
2402 printk(KERN_ERR
2403 "ipmi_msghandler: allocate link to BMC: %d\n",
2404 rv);
2405 goto out_err;
2406 }
2407
Corey Minyard50c812b2006-03-26 01:37:21 -08002408 rv = sysfs_create_link(&intf->si_dev->kobj,
Corey Minyard759643b2006-12-06 20:40:59 -08002409 &bmc->dev->dev.kobj, intf->sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002410 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002411 kfree(intf->sysfs_name);
2412 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002413 printk(KERN_ERR
2414 "ipmi_msghandler: Unable to create bmc symlink: %d\n",
2415 rv);
2416 goto out_err;
2417 }
2418
Corey Minyard759643b2006-12-06 20:40:59 -08002419 size = snprintf(dummy, 0, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002420 intf->my_dev_name = kmalloc(size+1, GFP_KERNEL);
2421 if (!intf->my_dev_name) {
Corey Minyard759643b2006-12-06 20:40:59 -08002422 kfree(intf->sysfs_name);
2423 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002424 rv = -ENOMEM;
2425 printk(KERN_ERR
2426 "ipmi_msghandler: allocate link from BMC: %d\n",
2427 rv);
2428 goto out_err;
2429 }
Corey Minyard759643b2006-12-06 20:40:59 -08002430 snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum);
Corey Minyard50c812b2006-03-26 01:37:21 -08002431
2432 rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj,
2433 intf->my_dev_name);
2434 if (rv) {
Corey Minyard759643b2006-12-06 20:40:59 -08002435 kfree(intf->sysfs_name);
2436 intf->sysfs_name = NULL;
Corey Minyard50c812b2006-03-26 01:37:21 -08002437 kfree(intf->my_dev_name);
2438 intf->my_dev_name = NULL;
2439 printk(KERN_ERR
2440 "ipmi_msghandler:"
2441 " Unable to create symlink to bmc: %d\n",
2442 rv);
2443 goto out_err;
2444 }
2445
2446 return 0;
2447
2448out_err:
2449 ipmi_bmc_unregister(intf);
2450 return rv;
2451}
2452
2453static int
2454send_guid_cmd(ipmi_smi_t intf, int chan)
2455{
2456 struct kernel_ipmi_msg msg;
2457 struct ipmi_system_interface_addr si;
2458
2459 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2460 si.channel = IPMI_BMC_CHANNEL;
2461 si.lun = 0;
2462
2463 msg.netfn = IPMI_NETFN_APP_REQUEST;
2464 msg.cmd = IPMI_GET_DEVICE_GUID_CMD;
2465 msg.data = NULL;
2466 msg.data_len = 0;
2467 return i_ipmi_request(NULL,
2468 intf,
2469 (struct ipmi_addr *) &si,
2470 0,
2471 &msg,
2472 intf,
2473 NULL,
2474 NULL,
2475 0,
2476 intf->channels[0].address,
2477 intf->channels[0].lun,
2478 -1, 0);
2479}
2480
2481static void
2482guid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2483{
2484 if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2485 || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
2486 || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD))
2487 /* Not for me */
2488 return;
2489
2490 if (msg->msg.data[0] != 0) {
2491 /* Error from getting the GUID, the BMC doesn't have one. */
2492 intf->bmc->guid_set = 0;
2493 goto out;
2494 }
2495
2496 if (msg->msg.data_len < 17) {
2497 intf->bmc->guid_set = 0;
2498 printk(KERN_WARNING PFX
2499 "guid_handler: The GUID response from the BMC was too"
2500 " short, it was %d but should have been 17. Assuming"
2501 " GUID is not available.\n",
2502 msg->msg.data_len);
2503 goto out;
2504 }
2505
2506 memcpy(intf->bmc->guid, msg->msg.data, 16);
2507 intf->bmc->guid_set = 1;
2508 out:
2509 wake_up(&intf->waitq);
2510}
2511
2512static void
2513get_guid(ipmi_smi_t intf)
2514{
2515 int rv;
2516
2517 intf->bmc->guid_set = 0x2;
2518 intf->null_user_handler = guid_handler;
2519 rv = send_guid_cmd(intf, 0);
2520 if (rv)
2521 /* Send failed, no GUID available. */
2522 intf->bmc->guid_set = 0;
2523 wait_event(intf->waitq, intf->bmc->guid_set != 2);
2524 intf->null_user_handler = NULL;
2525}
2526
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527static int
2528send_channel_info_cmd(ipmi_smi_t intf, int chan)
2529{
2530 struct kernel_ipmi_msg msg;
2531 unsigned char data[1];
2532 struct ipmi_system_interface_addr si;
2533
2534 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2535 si.channel = IPMI_BMC_CHANNEL;
2536 si.lun = 0;
2537
2538 msg.netfn = IPMI_NETFN_APP_REQUEST;
2539 msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
2540 msg.data = data;
2541 msg.data_len = 1;
2542 data[0] = chan;
2543 return i_ipmi_request(NULL,
2544 intf,
2545 (struct ipmi_addr *) &si,
2546 0,
2547 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07002548 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 NULL,
2550 NULL,
2551 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07002552 intf->channels[0].address,
2553 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 -1, 0);
2555}
2556
2557static void
Corey Minyard56a55ec2005-09-06 15:18:42 -07002558channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559{
2560 int rv = 0;
2561 int chan;
2562
Corey Minyard56a55ec2005-09-06 15:18:42 -07002563 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2564 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2565 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 {
2567 /* It's the one we want */
Corey Minyard56a55ec2005-09-06 15:18:42 -07002568 if (msg->msg.data[0] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 /* Got an error from the channel, just go on. */
2570
Corey Minyard56a55ec2005-09-06 15:18:42 -07002571 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 /* If the MC does not support this
2573 command, that is legal. We just
2574 assume it has one IPMB at channel
2575 zero. */
2576 intf->channels[0].medium
2577 = IPMI_CHANNEL_MEDIUM_IPMB;
2578 intf->channels[0].protocol
2579 = IPMI_CHANNEL_PROTOCOL_IPMB;
2580 rv = -ENOSYS;
2581
2582 intf->curr_channel = IPMI_MAX_CHANNELS;
2583 wake_up(&intf->waitq);
2584 goto out;
2585 }
2586 goto next_channel;
2587 }
Corey Minyard56a55ec2005-09-06 15:18:42 -07002588 if (msg->msg.data_len < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 /* Message not big enough, just go on. */
2590 goto next_channel;
2591 }
2592 chan = intf->curr_channel;
Corey Minyard56a55ec2005-09-06 15:18:42 -07002593 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
2594 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595
2596 next_channel:
2597 intf->curr_channel++;
2598 if (intf->curr_channel >= IPMI_MAX_CHANNELS)
2599 wake_up(&intf->waitq);
2600 else
2601 rv = send_channel_info_cmd(intf, intf->curr_channel);
2602
2603 if (rv) {
2604 /* Got an error somehow, just give up. */
2605 intf->curr_channel = IPMI_MAX_CHANNELS;
2606 wake_up(&intf->waitq);
2607
2608 printk(KERN_WARNING PFX
2609 "Error sending channel information: %d\n",
2610 rv);
2611 }
2612 }
2613 out:
2614 return;
2615}
2616
Corey Minyardfcfa4722007-10-18 03:07:09 -07002617void ipmi_poll_interface(ipmi_user_t user)
2618{
2619 ipmi_smi_t intf = user->intf;
2620
2621 if (intf->handlers->poll)
2622 intf->handlers->poll(intf->send_info);
2623}
2624
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2626 void *send_info,
Corey Minyard50c812b2006-03-26 01:37:21 -08002627 struct ipmi_device_id *device_id,
2628 struct device *si_dev,
Corey Minyard759643b2006-12-06 20:40:59 -08002629 const char *sysfs_name,
Corey Minyard453823b2006-03-31 02:30:39 -08002630 unsigned char slave_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631{
2632 int i, j;
2633 int rv;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002634 ipmi_smi_t intf;
Corey Minyardbca03242006-12-06 20:40:57 -08002635 ipmi_smi_t tintf;
Corey Minyardbca03242006-12-06 20:40:57 -08002636 struct list_head *link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 /* Make sure the driver is actually initialized, this handles
2639 problems with initialization order. */
2640 if (!initialized) {
2641 rv = ipmi_init_msghandler();
2642 if (rv)
2643 return rv;
2644 /* The init code doesn't return an error if it was turned
2645 off, but it won't initialize. Check that. */
2646 if (!initialized)
2647 return -ENODEV;
2648 }
2649
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07002650 intf = kzalloc(sizeof(*intf), GFP_KERNEL);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002651 if (!intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 return -ENOMEM;
Corey Minyardb2c03942006-12-06 20:41:00 -08002653
2654 intf->ipmi_version_major = ipmi_version_major(device_id);
2655 intf->ipmi_version_minor = ipmi_version_minor(device_id);
2656
Corey Minyard50c812b2006-03-26 01:37:21 -08002657 intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL);
2658 if (!intf->bmc) {
2659 kfree(intf);
2660 return -ENOMEM;
2661 }
Corey Minyardbca03242006-12-06 20:40:57 -08002662 intf->intf_num = -1; /* Mark it invalid for now. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002663 kref_init(&intf->refcount);
Corey Minyard50c812b2006-03-26 01:37:21 -08002664 intf->bmc->id = *device_id;
2665 intf->si_dev = si_dev;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002666 for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
2667 intf->channels[j].address = IPMI_BMC_SLAVE_ADDR;
2668 intf->channels[j].lun = 2;
2669 }
2670 if (slave_addr != 0)
2671 intf->channels[0].address = slave_addr;
2672 INIT_LIST_HEAD(&intf->users);
2673 intf->handlers = handlers;
2674 intf->send_info = send_info;
2675 spin_lock_init(&intf->seq_lock);
2676 for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
2677 intf->seq_table[j].inuse = 0;
2678 intf->seq_table[j].seqid = 0;
2679 }
2680 intf->curr_seq = 0;
2681#ifdef CONFIG_PROC_FS
2682 spin_lock_init(&intf->proc_entry_lock);
2683#endif
2684 spin_lock_init(&intf->waiting_msgs_lock);
2685 INIT_LIST_HEAD(&intf->waiting_msgs);
2686 spin_lock_init(&intf->events_lock);
2687 INIT_LIST_HEAD(&intf->waiting_events);
2688 intf->waiting_events_count = 0;
Corey Minyardd6dfd132006-03-31 02:30:41 -08002689 mutex_init(&intf->cmd_rcvrs_mutex);
Corey Minyardb9675132006-12-06 20:41:02 -08002690 spin_lock_init(&intf->maintenance_mode_lock);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002691 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2692 init_waitqueue_head(&intf->waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
Corey Minyard393d2cc2005-11-07 00:59:54 -08002694 spin_lock_init(&intf->counter_lock);
2695 intf->proc_dir = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
Corey Minyardb2c03942006-12-06 20:41:00 -08002697 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002698 mutex_lock(&ipmi_interfaces_mutex);
2699 /* Look for a hole in the numbers. */
2700 i = 0;
2701 link = &ipmi_interfaces;
2702 list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
2703 if (tintf->intf_num != i) {
2704 link = &tintf->link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 break;
2706 }
Corey Minyardbca03242006-12-06 20:40:57 -08002707 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 }
Corey Minyardbca03242006-12-06 20:40:57 -08002709 /* Add the new interface in numeric order. */
2710 if (i == 0)
2711 list_add_rcu(&intf->link, &ipmi_interfaces);
2712 else
2713 list_add_tail_rcu(&intf->link, link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
Corey Minyard453823b2006-03-31 02:30:39 -08002715 rv = handlers->start_processing(send_info, intf);
2716 if (rv)
2717 goto out;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002718
Corey Minyard50c812b2006-03-26 01:37:21 -08002719 get_guid(intf);
2720
Corey Minyardb2c03942006-12-06 20:41:00 -08002721 if ((intf->ipmi_version_major > 1)
2722 || ((intf->ipmi_version_major == 1)
2723 && (intf->ipmi_version_minor >= 5)))
Corey Minyard393d2cc2005-11-07 00:59:54 -08002724 {
2725 /* Start scanning the channels to see what is
2726 available. */
2727 intf->null_user_handler = channel_handler;
2728 intf->curr_channel = 0;
2729 rv = send_channel_info_cmd(intf, 0);
2730 if (rv)
2731 goto out;
2732
2733 /* Wait for the channel info to be read. */
2734 wait_event(intf->waitq,
2735 intf->curr_channel >= IPMI_MAX_CHANNELS);
Corey Minyard50c812b2006-03-26 01:37:21 -08002736 intf->null_user_handler = NULL;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002737 } else {
2738 /* Assume a single IPMB channel at zero. */
2739 intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
2740 intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
2741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
2743 if (rv == 0)
Corey Minyard393d2cc2005-11-07 00:59:54 -08002744 rv = add_proc_entries(intf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
Corey Minyard759643b2006-12-06 20:40:59 -08002746 rv = ipmi_bmc_register(intf, i, sysfs_name);
Corey Minyard50c812b2006-03-26 01:37:21 -08002747
Corey Minyard393d2cc2005-11-07 00:59:54 -08002748 out:
2749 if (rv) {
2750 if (intf->proc_dir)
2751 remove_proc_entries(intf);
Corey Minyardb2c03942006-12-06 20:41:00 -08002752 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002753 list_del_rcu(&intf->link);
2754 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002755 mutex_unlock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002756 synchronize_rcu();
Corey Minyard393d2cc2005-11-07 00:59:54 -08002757 kref_put(&intf->refcount, intf_free);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002758 } else {
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002759 /*
2760 * Keep memory order straight for RCU readers. Make
2761 * sure everything else is committed to memory before
2762 * setting intf_num to mark the interface valid.
2763 */
2764 smp_wmb();
Corey Minyardbca03242006-12-06 20:40:57 -08002765 intf->intf_num = i;
2766 mutex_unlock(&ipmi_interfaces_mutex);
Corey Minyard78ba2fa2007-02-10 01:45:45 -08002767 /* After this point the interface is legal to use. */
Corey Minyard50c812b2006-03-26 01:37:21 -08002768 call_smi_watchers(i, intf->si_dev);
Corey Minyardb2c03942006-12-06 20:41:00 -08002769 mutex_unlock(&smi_watchers_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 }
2771
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 return rv;
2773}
2774
Corey Minyardb2c03942006-12-06 20:41:00 -08002775static void cleanup_smi_msgs(ipmi_smi_t intf)
2776{
2777 int i;
2778 struct seq_table *ent;
2779
2780 /* No need for locks, the interface is down. */
2781 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
2782 ent = &(intf->seq_table[i]);
2783 if (!ent->inuse)
2784 continue;
2785 deliver_err_response(ent->recv_msg, IPMI_ERR_UNSPECIFIED);
2786 }
2787}
2788
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789int ipmi_unregister_smi(ipmi_smi_t intf)
2790{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 struct ipmi_smi_watcher *w;
Corey Minyardb2c03942006-12-06 20:41:00 -08002792 int intf_num = intf->intf_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793
Corey Minyard50c812b2006-03-26 01:37:21 -08002794 ipmi_bmc_unregister(intf);
2795
Corey Minyardb2c03942006-12-06 20:41:00 -08002796 mutex_lock(&smi_watchers_mutex);
Corey Minyardbca03242006-12-06 20:40:57 -08002797 mutex_lock(&ipmi_interfaces_mutex);
Corey Minyardb2c03942006-12-06 20:41:00 -08002798 intf->intf_num = -1;
2799 intf->handlers = NULL;
Corey Minyardbca03242006-12-06 20:40:57 -08002800 list_del_rcu(&intf->link);
2801 mutex_unlock(&ipmi_interfaces_mutex);
2802 synchronize_rcu();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803
Corey Minyardb2c03942006-12-06 20:41:00 -08002804 cleanup_smi_msgs(intf);
2805
Corey Minyard393d2cc2005-11-07 00:59:54 -08002806 remove_proc_entries(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
2808 /* Call all the watcher interfaces to tell them that
2809 an interface is gone. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08002810 list_for_each_entry(w, &smi_watchers, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08002811 w->smi_gone(intf_num);
2812 mutex_unlock(&smi_watchers_mutex);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002813
Corey Minyard393d2cc2005-11-07 00:59:54 -08002814 kref_put(&intf->refcount, intf_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 return 0;
2816}
2817
2818static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
2819 struct ipmi_smi_msg *msg)
2820{
2821 struct ipmi_ipmb_addr ipmb_addr;
2822 struct ipmi_recv_msg *recv_msg;
2823 unsigned long flags;
2824
2825
2826 /* This is 11, not 10, because the response must contain a
2827 * completion code. */
2828 if (msg->rsp_size < 11) {
2829 /* Message not big enough, just ignore it. */
2830 spin_lock_irqsave(&intf->counter_lock, flags);
2831 intf->invalid_ipmb_responses++;
2832 spin_unlock_irqrestore(&intf->counter_lock, flags);
2833 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. */
2858 spin_lock_irqsave(&intf->counter_lock, flags);
2859 intf->unhandled_ipmb_responses++;
2860 spin_unlock_irqrestore(&intf->counter_lock, flags);
2861 return 0;
2862 }
2863
2864 memcpy(recv_msg->msg_data,
2865 &(msg->rsp[9]),
2866 msg->rsp_size - 9);
2867 /* THe other fields matched, so no need to set them, except
2868 for netfn, which needs to be the response that was
2869 returned, not the request value. */
2870 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2871 recv_msg->msg.data = recv_msg->msg_data;
2872 recv_msg->msg.data_len = msg->rsp_size - 10;
2873 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
2874 spin_lock_irqsave(&intf->counter_lock, flags);
2875 intf->handled_ipmb_responses++;
2876 spin_unlock_irqrestore(&intf->counter_lock, flags);
2877 deliver_response(recv_msg);
2878
2879 return 0;
2880}
2881
2882static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2883 struct ipmi_smi_msg *msg)
2884{
Corey Minyard393d2cc2005-11-07 00:59:54 -08002885 struct cmd_rcvr *rcvr;
2886 int rv = 0;
2887 unsigned char netfn;
2888 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07002889 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002890 ipmi_user_t user = NULL;
2891 struct ipmi_ipmb_addr *ipmb_addr;
2892 struct ipmi_recv_msg *recv_msg;
2893 unsigned long flags;
Corey Minyardb2c03942006-12-06 20:41:00 -08002894 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895
2896 if (msg->rsp_size < 10) {
2897 /* Message not big enough, just ignore it. */
2898 spin_lock_irqsave(&intf->counter_lock, flags);
2899 intf->invalid_commands++;
2900 spin_unlock_irqrestore(&intf->counter_lock, flags);
2901 return 0;
2902 }
2903
2904 if (msg->rsp[2] != 0) {
2905 /* An error getting the response, just ignore it. */
2906 return 0;
2907 }
2908
2909 netfn = msg->rsp[4] >> 2;
2910 cmd = msg->rsp[8];
Corey Minyardc69c3122006-09-30 23:27:56 -07002911 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002913 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07002914 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08002915 if (rcvr) {
2916 user = rcvr->user;
2917 kref_get(&user->refcount);
2918 } else
2919 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08002920 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921
2922 if (user == NULL) {
2923 /* We didn't find a user, deliver an error response. */
2924 spin_lock_irqsave(&intf->counter_lock, flags);
2925 intf->unhandled_commands++;
2926 spin_unlock_irqrestore(&intf->counter_lock, flags);
2927
2928 msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
2929 msg->data[1] = IPMI_SEND_MSG_CMD;
2930 msg->data[2] = msg->rsp[3];
2931 msg->data[3] = msg->rsp[6];
2932 msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
2933 msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
Corey Minyardc14979b2005-09-06 15:18:38 -07002934 msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 /* rqseq/lun */
2936 msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
2937 msg->data[8] = msg->rsp[8]; /* cmd */
2938 msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
2939 msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
2940 msg->data_size = 11;
2941
2942#ifdef DEBUG_MSGING
2943 {
2944 int m;
2945 printk("Invalid command:");
Corey Minyarde8b33612005-09-06 15:18:45 -07002946 for (m = 0; m < msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 printk(" %2.2x", msg->data[m]);
2948 printk("\n");
2949 }
2950#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08002951 rcu_read_lock();
2952 handlers = intf->handlers;
2953 if (handlers) {
2954 handlers->sender(intf->send_info, msg, 0);
2955 /* We used the message, so return the value
2956 that causes it to not be freed or
2957 queued. */
2958 rv = -1;
2959 }
2960 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 } else {
2962 /* Deliver the message to the user. */
2963 spin_lock_irqsave(&intf->counter_lock, flags);
2964 intf->handled_commands++;
2965 spin_unlock_irqrestore(&intf->counter_lock, flags);
2966
2967 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08002968 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 /* We couldn't allocate memory for the
2970 message, so requeue it for handling
2971 later. */
2972 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08002973 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 } else {
2975 /* Extract the source address from the data. */
2976 ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
2977 ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
2978 ipmb_addr->slave_addr = msg->rsp[6];
2979 ipmb_addr->lun = msg->rsp[7] & 3;
2980 ipmb_addr->channel = msg->rsp[3] & 0xf;
2981
2982 /* Extract the rest of the message information
2983 from the IPMB header.*/
2984 recv_msg->user = user;
2985 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
2986 recv_msg->msgid = msg->rsp[7] >> 2;
2987 recv_msg->msg.netfn = msg->rsp[4] >> 2;
2988 recv_msg->msg.cmd = msg->rsp[8];
2989 recv_msg->msg.data = recv_msg->msg_data;
2990
2991 /* We chop off 10, not 9 bytes because the checksum
2992 at the end also needs to be removed. */
2993 recv_msg->msg.data_len = msg->rsp_size - 10;
2994 memcpy(recv_msg->msg_data,
2995 &(msg->rsp[9]),
2996 msg->rsp_size - 10);
2997 deliver_response(recv_msg);
2998 }
2999 }
3000
3001 return rv;
3002}
3003
3004static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
3005 struct ipmi_smi_msg *msg)
3006{
3007 struct ipmi_lan_addr lan_addr;
3008 struct ipmi_recv_msg *recv_msg;
3009 unsigned long flags;
3010
3011
3012 /* This is 13, not 12, because the response must contain a
3013 * completion code. */
3014 if (msg->rsp_size < 13) {
3015 /* Message not big enough, just ignore it. */
3016 spin_lock_irqsave(&intf->counter_lock, flags);
3017 intf->invalid_lan_responses++;
3018 spin_unlock_irqrestore(&intf->counter_lock, flags);
3019 return 0;
3020 }
3021
3022 if (msg->rsp[2] != 0) {
3023 /* An error getting the response, just ignore it. */
3024 return 0;
3025 }
3026
3027 lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
3028 lan_addr.session_handle = msg->rsp[4];
3029 lan_addr.remote_SWID = msg->rsp[8];
3030 lan_addr.local_SWID = msg->rsp[5];
3031 lan_addr.channel = msg->rsp[3] & 0x0f;
3032 lan_addr.privilege = msg->rsp[3] >> 4;
3033 lan_addr.lun = msg->rsp[9] & 3;
3034
3035 /* It's a response from a remote entity. Look up the sequence
3036 number and handle the response. */
3037 if (intf_find_seq(intf,
3038 msg->rsp[9] >> 2,
3039 msg->rsp[3] & 0x0f,
3040 msg->rsp[10],
3041 (msg->rsp[6] >> 2) & (~1),
3042 (struct ipmi_addr *) &(lan_addr),
3043 &recv_msg))
3044 {
3045 /* We were unable to find the sequence number,
3046 so just nuke the message. */
3047 spin_lock_irqsave(&intf->counter_lock, flags);
3048 intf->unhandled_lan_responses++;
3049 spin_unlock_irqrestore(&intf->counter_lock, flags);
3050 return 0;
3051 }
3052
3053 memcpy(recv_msg->msg_data,
3054 &(msg->rsp[11]),
3055 msg->rsp_size - 11);
3056 /* The other fields matched, so no need to set them, except
3057 for netfn, which needs to be the response that was
3058 returned, not the request value. */
3059 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3060 recv_msg->msg.data = recv_msg->msg_data;
3061 recv_msg->msg.data_len = msg->rsp_size - 12;
3062 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3063 spin_lock_irqsave(&intf->counter_lock, flags);
3064 intf->handled_lan_responses++;
3065 spin_unlock_irqrestore(&intf->counter_lock, flags);
3066 deliver_response(recv_msg);
3067
3068 return 0;
3069}
3070
3071static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
3072 struct ipmi_smi_msg *msg)
3073{
Corey Minyard393d2cc2005-11-07 00:59:54 -08003074 struct cmd_rcvr *rcvr;
3075 int rv = 0;
3076 unsigned char netfn;
3077 unsigned char cmd;
Corey Minyardc69c3122006-09-30 23:27:56 -07003078 unsigned char chan;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003079 ipmi_user_t user = NULL;
3080 struct ipmi_lan_addr *lan_addr;
3081 struct ipmi_recv_msg *recv_msg;
3082 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
3084 if (msg->rsp_size < 12) {
3085 /* Message not big enough, just ignore it. */
3086 spin_lock_irqsave(&intf->counter_lock, flags);
3087 intf->invalid_commands++;
3088 spin_unlock_irqrestore(&intf->counter_lock, flags);
3089 return 0;
3090 }
3091
3092 if (msg->rsp[2] != 0) {
3093 /* An error getting the response, just ignore it. */
3094 return 0;
3095 }
3096
3097 netfn = msg->rsp[6] >> 2;
3098 cmd = msg->rsp[10];
Corey Minyardc69c3122006-09-30 23:27:56 -07003099 chan = msg->rsp[3] & 0xf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003101 rcu_read_lock();
Corey Minyardc69c3122006-09-30 23:27:56 -07003102 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003103 if (rcvr) {
3104 user = rcvr->user;
3105 kref_get(&user->refcount);
3106 } else
3107 user = NULL;
Corey Minyarde61fb5b2005-11-07 01:00:05 -08003108 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110 if (user == NULL) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003111 /* We didn't find a user, just give up. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 spin_lock_irqsave(&intf->counter_lock, flags);
3113 intf->unhandled_commands++;
3114 spin_unlock_irqrestore(&intf->counter_lock, flags);
3115
3116 rv = 0; /* Don't do anything with these messages, just
3117 allow them to be freed. */
3118 } else {
3119 /* Deliver the message to the user. */
3120 spin_lock_irqsave(&intf->counter_lock, flags);
3121 intf->handled_commands++;
3122 spin_unlock_irqrestore(&intf->counter_lock, flags);
3123
3124 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003125 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 /* We couldn't allocate memory for the
3127 message, so requeue it for handling
3128 later. */
3129 rv = 1;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003130 kref_put(&user->refcount, free_user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 } else {
3132 /* Extract the source address from the data. */
3133 lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
3134 lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
3135 lan_addr->session_handle = msg->rsp[4];
3136 lan_addr->remote_SWID = msg->rsp[8];
3137 lan_addr->local_SWID = msg->rsp[5];
3138 lan_addr->lun = msg->rsp[9] & 3;
3139 lan_addr->channel = msg->rsp[3] & 0xf;
3140 lan_addr->privilege = msg->rsp[3] >> 4;
3141
3142 /* Extract the rest of the message information
3143 from the IPMB header.*/
3144 recv_msg->user = user;
3145 recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
3146 recv_msg->msgid = msg->rsp[9] >> 2;
3147 recv_msg->msg.netfn = msg->rsp[6] >> 2;
3148 recv_msg->msg.cmd = msg->rsp[10];
3149 recv_msg->msg.data = recv_msg->msg_data;
3150
3151 /* We chop off 12, not 11 bytes because the checksum
3152 at the end also needs to be removed. */
3153 recv_msg->msg.data_len = msg->rsp_size - 12;
3154 memcpy(recv_msg->msg_data,
3155 &(msg->rsp[11]),
3156 msg->rsp_size - 12);
3157 deliver_response(recv_msg);
3158 }
3159 }
3160
3161 return rv;
3162}
3163
3164static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
3165 struct ipmi_smi_msg *msg)
3166{
3167 struct ipmi_system_interface_addr *smi_addr;
3168
3169 recv_msg->msgid = 0;
3170 smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
3171 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3172 smi_addr->channel = IPMI_BMC_CHANNEL;
3173 smi_addr->lun = msg->rsp[0] & 3;
3174 recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
3175 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3176 recv_msg->msg.cmd = msg->rsp[1];
3177 memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
3178 recv_msg->msg.data = recv_msg->msg_data;
3179 recv_msg->msg.data_len = msg->rsp_size - 3;
3180}
3181
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182static int handle_read_event_rsp(ipmi_smi_t intf,
3183 struct ipmi_smi_msg *msg)
3184{
3185 struct ipmi_recv_msg *recv_msg, *recv_msg2;
3186 struct list_head msgs;
3187 ipmi_user_t user;
3188 int rv = 0;
3189 int deliver_count = 0;
3190 unsigned long flags;
3191
3192 if (msg->rsp_size < 19) {
3193 /* Message is too small to be an IPMB event. */
3194 spin_lock_irqsave(&intf->counter_lock, flags);
3195 intf->invalid_events++;
3196 spin_unlock_irqrestore(&intf->counter_lock, flags);
3197 return 0;
3198 }
3199
3200 if (msg->rsp[2] != 0) {
3201 /* An error getting the event, just ignore it. */
3202 return 0;
3203 }
3204
3205 INIT_LIST_HEAD(&msgs);
3206
Corey Minyard393d2cc2005-11-07 00:59:54 -08003207 spin_lock_irqsave(&intf->events_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208
3209 spin_lock(&intf->counter_lock);
3210 intf->events++;
3211 spin_unlock(&intf->counter_lock);
3212
3213 /* Allocate and fill in one message for every user that is getting
3214 events. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003215 rcu_read_lock();
3216 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003217 if (!user->gets_events)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 continue;
3219
3220 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003221 if (!recv_msg) {
Corey Minyard393d2cc2005-11-07 00:59:54 -08003222 rcu_read_unlock();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003223 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
3224 link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 list_del(&recv_msg->link);
3226 ipmi_free_recv_msg(recv_msg);
3227 }
3228 /* We couldn't allocate memory for the
3229 message, so requeue it for handling
3230 later. */
3231 rv = 1;
3232 goto out;
3233 }
3234
3235 deliver_count++;
3236
3237 copy_event_into_recv_msg(recv_msg, msg);
3238 recv_msg->user = user;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003239 kref_get(&user->refcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 list_add_tail(&(recv_msg->link), &msgs);
3241 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003242 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243
3244 if (deliver_count) {
3245 /* Now deliver all the messages. */
3246 list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
3247 list_del(&recv_msg->link);
3248 deliver_response(recv_msg);
3249 }
3250 } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
3251 /* No one to receive the message, put it in queue if there's
3252 not already too many things in the queue. */
3253 recv_msg = ipmi_alloc_recv_msg();
Corey Minyard8a3628d2006-03-31 02:30:40 -08003254 if (!recv_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 /* We couldn't allocate memory for the
3256 message, so requeue it for handling
3257 later. */
3258 rv = 1;
3259 goto out;
3260 }
3261
3262 copy_event_into_recv_msg(recv_msg, msg);
3263 list_add_tail(&(recv_msg->link), &(intf->waiting_events));
Corey Minyard4791c032006-04-10 22:54:31 -07003264 intf->waiting_events_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 } else {
3266 /* There's too many things in the queue, discard this
3267 message. */
3268 printk(KERN_WARNING PFX "Event queue full, discarding an"
3269 " incoming event\n");
3270 }
3271
3272 out:
3273 spin_unlock_irqrestore(&(intf->events_lock), flags);
3274
3275 return rv;
3276}
3277
3278static int handle_bmc_rsp(ipmi_smi_t intf,
3279 struct ipmi_smi_msg *msg)
3280{
3281 struct ipmi_recv_msg *recv_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 unsigned long flags;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003283 struct ipmi_user *user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284
3285 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
Corey Minyard56a55ec2005-09-06 15:18:42 -07003286 if (recv_msg == NULL)
3287 {
3288 printk(KERN_WARNING"IPMI message received with no owner. This\n"
3289 "could be because of a malformed message, or\n"
3290 "because of a hardware error. Contact your\n"
3291 "hardware vender for assistance\n");
3292 return 0;
3293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294
Corey Minyard393d2cc2005-11-07 00:59:54 -08003295 user = recv_msg->user;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 /* Make sure the user still exists. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003297 if (user && !user->valid) {
Corey Minyard56a55ec2005-09-06 15:18:42 -07003298 /* The user for the message went away, so give up. */
3299 spin_lock_irqsave(&intf->counter_lock, flags);
3300 intf->unhandled_local_responses++;
3301 spin_unlock_irqrestore(&intf->counter_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 ipmi_free_recv_msg(recv_msg);
3303 } else {
3304 struct ipmi_system_interface_addr *smi_addr;
3305
3306 spin_lock_irqsave(&intf->counter_lock, flags);
3307 intf->handled_local_responses++;
3308 spin_unlock_irqrestore(&intf->counter_lock, flags);
3309 recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
3310 recv_msg->msgid = msg->msgid;
3311 smi_addr = ((struct ipmi_system_interface_addr *)
3312 &(recv_msg->addr));
3313 smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3314 smi_addr->channel = IPMI_BMC_CHANNEL;
3315 smi_addr->lun = msg->rsp[0] & 3;
3316 recv_msg->msg.netfn = msg->rsp[0] >> 2;
3317 recv_msg->msg.cmd = msg->rsp[1];
3318 memcpy(recv_msg->msg_data,
3319 &(msg->rsp[2]),
3320 msg->rsp_size - 2);
3321 recv_msg->msg.data = recv_msg->msg_data;
3322 recv_msg->msg.data_len = msg->rsp_size - 2;
3323 deliver_response(recv_msg);
3324 }
3325
3326 return 0;
3327}
3328
3329/* Handle a new message. Return 1 if the message should be requeued,
3330 0 if the message should be freed, or -1 if the message should not
3331 be freed or requeued. */
3332static int handle_new_recv_msg(ipmi_smi_t intf,
3333 struct ipmi_smi_msg *msg)
3334{
3335 int requeue;
3336 int chan;
3337
3338#ifdef DEBUG_MSGING
3339 int m;
3340 printk("Recv:");
Corey Minyarde8b33612005-09-06 15:18:45 -07003341 for (m = 0; m < msg->rsp_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 printk(" %2.2x", msg->rsp[m]);
3343 printk("\n");
3344#endif
3345 if (msg->rsp_size < 2) {
3346 /* Message is too small to be correct. */
3347 printk(KERN_WARNING PFX "BMC returned to small a message"
3348 " for netfn %x cmd %x, got %d bytes\n",
3349 (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
3350
3351 /* Generate an error response for the message. */
3352 msg->rsp[0] = msg->data[0] | (1 << 2);
3353 msg->rsp[1] = msg->data[1];
3354 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3355 msg->rsp_size = 3;
3356 } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
3357 || (msg->rsp[1] != msg->data[1])) /* Command */
3358 {
3359 /* The response is not even marginally correct. */
3360 printk(KERN_WARNING PFX "BMC returned incorrect response,"
3361 " expected netfn %x cmd %x, got netfn %x cmd %x\n",
3362 (msg->data[0] >> 2) | 1, msg->data[1],
3363 msg->rsp[0] >> 2, msg->rsp[1]);
3364
3365 /* Generate an error response for the message. */
3366 msg->rsp[0] = msg->data[0] | (1 << 2);
3367 msg->rsp[1] = msg->data[1];
3368 msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
3369 msg->rsp_size = 3;
3370 }
3371
3372 if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3373 && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
3374 && (msg->user_data != NULL))
3375 {
3376 /* It's a response to a response we sent. For this we
3377 deliver a send message response to the user. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003378 struct ipmi_recv_msg *recv_msg = msg->user_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379
3380 requeue = 0;
3381 if (msg->rsp_size < 2)
3382 /* Message is too small to be correct. */
3383 goto out;
3384
3385 chan = msg->data[2] & 0x0f;
3386 if (chan >= IPMI_MAX_CHANNELS)
3387 /* Invalid channel number */
3388 goto out;
3389
Corey Minyard393d2cc2005-11-07 00:59:54 -08003390 if (!recv_msg)
3391 goto out;
3392
3393 /* Make sure the user still exists. */
3394 if (!recv_msg->user || !recv_msg->user->valid)
3395 goto out;
3396
3397 recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
3398 recv_msg->msg.data = recv_msg->msg_data;
3399 recv_msg->msg.data_len = 1;
3400 recv_msg->msg_data[0] = msg->rsp[2];
3401 deliver_response(recv_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3403 && (msg->rsp[1] == IPMI_GET_MSG_CMD))
3404 {
3405 /* It's from the receive queue. */
3406 chan = msg->rsp[3] & 0xf;
3407 if (chan >= IPMI_MAX_CHANNELS) {
3408 /* Invalid channel number */
3409 requeue = 0;
3410 goto out;
3411 }
3412
3413 switch (intf->channels[chan].medium) {
3414 case IPMI_CHANNEL_MEDIUM_IPMB:
3415 if (msg->rsp[4] & 0x04) {
3416 /* It's a response, so find the
3417 requesting message and send it up. */
3418 requeue = handle_ipmb_get_msg_rsp(intf, msg);
3419 } else {
3420 /* It's a command to the SMS from some other
3421 entity. Handle that. */
3422 requeue = handle_ipmb_get_msg_cmd(intf, msg);
3423 }
3424 break;
3425
3426 case IPMI_CHANNEL_MEDIUM_8023LAN:
3427 case IPMI_CHANNEL_MEDIUM_ASYNC:
3428 if (msg->rsp[6] & 0x04) {
3429 /* It's a response, so find the
3430 requesting message and send it up. */
3431 requeue = handle_lan_get_msg_rsp(intf, msg);
3432 } else {
3433 /* It's a command to the SMS from some other
3434 entity. Handle that. */
3435 requeue = handle_lan_get_msg_cmd(intf, msg);
3436 }
3437 break;
3438
3439 default:
3440 /* We don't handle the channel type, so just
3441 * free the message. */
3442 requeue = 0;
3443 }
3444
3445 } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
3446 && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
3447 {
3448 /* It's an asyncronous event. */
3449 requeue = handle_read_event_rsp(intf, msg);
3450 } else {
3451 /* It's a response from the local BMC. */
3452 requeue = handle_bmc_rsp(intf, msg);
3453 }
3454
3455 out:
3456 return requeue;
3457}
3458
3459/* Handle a new message from the lower layer. */
3460void ipmi_smi_msg_received(ipmi_smi_t intf,
3461 struct ipmi_smi_msg *msg)
3462{
3463 unsigned long flags;
3464 int rv;
3465
3466
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 if ((msg->data_size >= 2)
3468 && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
3469 && (msg->data[1] == IPMI_SEND_MSG_CMD)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003470 && (msg->user_data == NULL))
3471 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 /* This is the local response to a command send, start
3473 the timer for these. The user_data will not be
3474 NULL if this is a response send, and we will let
3475 response sends just go through. */
3476
3477 /* Check for errors, if we get certain errors (ones
3478 that mean basically we can try again later), we
3479 ignore them and start the timer. Otherwise we
3480 report the error immediately. */
3481 if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
3482 && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
Corey Minyard46d52b02006-11-08 17:44:55 -08003483 && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
3484 && (msg->rsp[2] != IPMI_BUS_ERR)
3485 && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 {
3487 int chan = msg->rsp[3] & 0xf;
3488
3489 /* Got an error sending the message, handle it. */
3490 spin_lock_irqsave(&intf->counter_lock, flags);
3491 if (chan >= IPMI_MAX_CHANNELS)
3492 ; /* This shouldn't happen */
3493 else if ((intf->channels[chan].medium
3494 == IPMI_CHANNEL_MEDIUM_8023LAN)
3495 || (intf->channels[chan].medium
3496 == IPMI_CHANNEL_MEDIUM_ASYNC))
3497 intf->sent_lan_command_errs++;
3498 else
3499 intf->sent_ipmb_command_errs++;
3500 spin_unlock_irqrestore(&intf->counter_lock, flags);
3501 intf_err_seq(intf, msg->msgid, msg->rsp[2]);
3502 } else {
3503 /* The message was sent, start the timer. */
3504 intf_start_seq_timer(intf, msg->msgid);
3505 }
3506
3507 ipmi_free_smi_msg(msg);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003508 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 }
3510
3511 /* To preserve message order, if the list is not empty, we
3512 tack this message onto the end of the list. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003513 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
3514 if (!list_empty(&intf->waiting_msgs)) {
3515 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003516 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003517 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003519 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520
3521 rv = handle_new_recv_msg(intf, msg);
3522 if (rv > 0) {
3523 /* Could not handle the message now, just add it to a
3524 list to handle later. */
Hironobu Ishii177294d2005-11-11 08:12:21 -06003525 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003526 list_add_tail(&msg->link, &intf->waiting_msgs);
Hironobu Ishii177294d2005-11-11 08:12:21 -06003527 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 } else if (rv == 0) {
3529 ipmi_free_smi_msg(msg);
3530 }
3531
Corey Minyard393d2cc2005-11-07 00:59:54 -08003532 out:
3533 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534}
3535
3536void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
3537{
3538 ipmi_user_t user;
3539
Corey Minyard393d2cc2005-11-07 00:59:54 -08003540 rcu_read_lock();
3541 list_for_each_entry_rcu(user, &intf->users, link) {
Corey Minyard8a3628d2006-03-31 02:30:40 -08003542 if (!user->handler->ipmi_watchdog_pretimeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 continue;
3544
3545 user->handler->ipmi_watchdog_pretimeout(user->handler_data);
3546 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003547 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548}
3549
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
Corey Minyard882fe012005-05-01 08:59:12 -07003551static struct ipmi_smi_msg *
3552smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
3553 unsigned char seq, long seqid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554{
Corey Minyard882fe012005-05-01 08:59:12 -07003555 struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 if (!smi_msg)
3557 /* If we can't allocate the message, then just return, we
3558 get 4 retries, so this should be ok. */
Corey Minyard882fe012005-05-01 08:59:12 -07003559 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560
3561 memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
3562 smi_msg->data_size = recv_msg->msg.data_len;
3563 smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
3564
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565#ifdef DEBUG_MSGING
3566 {
3567 int m;
3568 printk("Resend: ");
Corey Minyarde8b33612005-09-06 15:18:45 -07003569 for (m = 0; m < smi_msg->data_size; m++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 printk(" %2.2x", smi_msg->data[m]);
3571 printk("\n");
3572 }
3573#endif
Corey Minyard882fe012005-05-01 08:59:12 -07003574 return smi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575}
3576
Corey Minyard393d2cc2005-11-07 00:59:54 -08003577static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
3578 struct list_head *timeouts, long timeout_period,
3579 int slot, unsigned long *flags)
3580{
Corey Minyardb2c03942006-12-06 20:41:00 -08003581 struct ipmi_recv_msg *msg;
3582 struct ipmi_smi_handlers *handlers;
3583
3584 if (intf->intf_num == -1)
3585 return;
Corey Minyard393d2cc2005-11-07 00:59:54 -08003586
3587 if (!ent->inuse)
3588 return;
3589
3590 ent->timeout -= timeout_period;
3591 if (ent->timeout > 0)
3592 return;
3593
3594 if (ent->retries_left == 0) {
3595 /* The message has used all its retries. */
3596 ent->inuse = 0;
3597 msg = ent->recv_msg;
3598 list_add_tail(&msg->link, timeouts);
3599 spin_lock(&intf->counter_lock);
3600 if (ent->broadcast)
3601 intf->timed_out_ipmb_broadcasts++;
3602 else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3603 intf->timed_out_lan_commands++;
3604 else
3605 intf->timed_out_ipmb_commands++;
3606 spin_unlock(&intf->counter_lock);
3607 } else {
3608 struct ipmi_smi_msg *smi_msg;
3609 /* More retries, send again. */
3610
3611 /* Start with the max timer, set to normal
3612 timer after the message is sent. */
3613 ent->timeout = MAX_MSG_TIMEOUT;
3614 ent->retries_left--;
3615 spin_lock(&intf->counter_lock);
3616 if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
3617 intf->retransmitted_lan_commands++;
3618 else
3619 intf->retransmitted_ipmb_commands++;
3620 spin_unlock(&intf->counter_lock);
3621
3622 smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
3623 ent->seqid);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003624 if (!smi_msg)
Corey Minyard393d2cc2005-11-07 00:59:54 -08003625 return;
3626
3627 spin_unlock_irqrestore(&intf->seq_lock, *flags);
Corey Minyardb2c03942006-12-06 20:41:00 -08003628
Corey Minyard393d2cc2005-11-07 00:59:54 -08003629 /* Send the new message. We send with a zero
3630 * priority. It timed out, I doubt time is
3631 * that critical now, and high priority
3632 * messages are really only for messages to the
3633 * local MC, which don't get resent. */
Corey Minyardb2c03942006-12-06 20:41:00 -08003634 handlers = intf->handlers;
3635 if (handlers)
3636 intf->handlers->sender(intf->send_info,
3637 smi_msg, 0);
3638 else
3639 ipmi_free_smi_msg(smi_msg);
3640
Corey Minyard393d2cc2005-11-07 00:59:54 -08003641 spin_lock_irqsave(&intf->seq_lock, *flags);
3642 }
3643}
3644
3645static void ipmi_timeout_handler(long timeout_period)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646{
3647 ipmi_smi_t intf;
3648 struct list_head timeouts;
3649 struct ipmi_recv_msg *msg, *msg2;
3650 struct ipmi_smi_msg *smi_msg, *smi_msg2;
3651 unsigned long flags;
Corey Minyardbca03242006-12-06 20:40:57 -08003652 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653
Corey Minyardbca03242006-12-06 20:40:57 -08003654 rcu_read_lock();
3655 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 /* See if any waiting messages need to be processed. */
Corey Minyard393d2cc2005-11-07 00:59:54 -08003657 spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
Corey Minyard8a3628d2006-03-31 02:30:40 -08003658 list_for_each_entry_safe(smi_msg, smi_msg2,
3659 &intf->waiting_msgs, link) {
3660 if (!handle_new_recv_msg(intf, smi_msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 list_del(&smi_msg->link);
3662 ipmi_free_smi_msg(smi_msg);
3663 } else {
3664 /* To preserve message order, quit if we
3665 can't handle a message. */
3666 break;
3667 }
3668 }
Corey Minyard393d2cc2005-11-07 00:59:54 -08003669 spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670
3671 /* Go through the seq table and find any messages that
3672 have timed out, putting them in the timeouts
3673 list. */
David Barksdale41c57a82007-01-30 14:36:25 -08003674 INIT_LIST_HEAD(&timeouts);
Corey Minyard393d2cc2005-11-07 00:59:54 -08003675 spin_lock_irqsave(&intf->seq_lock, flags);
Corey Minyardbca03242006-12-06 20:40:57 -08003676 for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
3677 check_msg_timeout(intf, &(intf->seq_table[i]),
3678 &timeouts, timeout_period, i,
Corey Minyard393d2cc2005-11-07 00:59:54 -08003679 &flags);
3680 spin_unlock_irqrestore(&intf->seq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
Corey Minyard393d2cc2005-11-07 00:59:54 -08003682 list_for_each_entry_safe(msg, msg2, &timeouts, link)
Corey Minyardb2c03942006-12-06 20:41:00 -08003683 deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
Corey Minyardb9675132006-12-06 20:41:02 -08003684
3685 /*
3686 * Maintenance mode handling. Check the timeout
3687 * optimistically before we claim the lock. It may
3688 * mean a timeout gets missed occasionally, but that
3689 * only means the timeout gets extended by one period
3690 * in that case. No big deal, and it avoids the lock
3691 * most of the time.
3692 */
3693 if (intf->auto_maintenance_timeout > 0) {
3694 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
3695 if (intf->auto_maintenance_timeout > 0) {
3696 intf->auto_maintenance_timeout
3697 -= timeout_period;
3698 if (!intf->maintenance_mode
3699 && (intf->auto_maintenance_timeout <= 0))
3700 {
3701 intf->maintenance_mode_enable = 0;
3702 maintenance_mode_update(intf);
3703 }
3704 }
3705 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
3706 flags);
3707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 }
Corey Minyardbca03242006-12-06 20:40:57 -08003709 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710}
3711
3712static void ipmi_request_event(void)
3713{
Corey Minyardb2c03942006-12-06 20:41:00 -08003714 ipmi_smi_t intf;
3715 struct ipmi_smi_handlers *handlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716
Corey Minyardbca03242006-12-06 20:40:57 -08003717 rcu_read_lock();
Corey Minyardb2c03942006-12-06 20:41:00 -08003718 /* Called from the timer, no need to check if handlers is
3719 * valid. */
3720 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb9675132006-12-06 20:41:02 -08003721 /* No event requests when in maintenance mode. */
3722 if (intf->maintenance_mode_enable)
3723 continue;
3724
Corey Minyardb2c03942006-12-06 20:41:00 -08003725 handlers = intf->handlers;
3726 if (handlers)
3727 handlers->request_events(intf->send_info);
3728 }
Corey Minyardbca03242006-12-06 20:40:57 -08003729 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730}
3731
3732static struct timer_list ipmi_timer;
3733
3734/* Call every ~100 ms. */
3735#define IPMI_TIMEOUT_TIME 100
3736
3737/* How many jiffies does it take to get to the timeout time. */
3738#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
3739
3740/* Request events from the queue every second (this is the number of
3741 IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
3742 future, IPMI will add a way to know immediately if an event is in
3743 the queue and this silliness can go away. */
3744#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
3745
Corey Minyard8f43f842005-06-23 22:01:40 -07003746static atomic_t stop_operation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3748
3749static void ipmi_timeout(unsigned long data)
3750{
Corey Minyard8f43f842005-06-23 22:01:40 -07003751 if (atomic_read(&stop_operation))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753
3754 ticks_to_req_ev--;
3755 if (ticks_to_req_ev == 0) {
3756 ipmi_request_event();
3757 ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
3758 }
3759
3760 ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
3761
Corey Minyard8f43f842005-06-23 22:01:40 -07003762 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763}
3764
3765
3766static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
3767static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
3768
3769/* FIXME - convert these to slabs. */
3770static void free_smi_msg(struct ipmi_smi_msg *msg)
3771{
3772 atomic_dec(&smi_msg_inuse_count);
3773 kfree(msg);
3774}
3775
3776struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
3777{
3778 struct ipmi_smi_msg *rv;
3779 rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
3780 if (rv) {
3781 rv->done = free_smi_msg;
3782 rv->user_data = NULL;
3783 atomic_inc(&smi_msg_inuse_count);
3784 }
3785 return rv;
3786}
3787
3788static void free_recv_msg(struct ipmi_recv_msg *msg)
3789{
3790 atomic_dec(&recv_msg_inuse_count);
3791 kfree(msg);
3792}
3793
3794struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
3795{
3796 struct ipmi_recv_msg *rv;
3797
3798 rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
3799 if (rv) {
Corey Minyarda9eec552006-08-31 21:27:45 -07003800 rv->user = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 rv->done = free_recv_msg;
3802 atomic_inc(&recv_msg_inuse_count);
3803 }
3804 return rv;
3805}
3806
Corey Minyard393d2cc2005-11-07 00:59:54 -08003807void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
3808{
3809 if (msg->user)
3810 kref_put(&msg->user->refcount, free_user);
3811 msg->done(msg);
3812}
3813
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814#ifdef CONFIG_IPMI_PANIC_EVENT
3815
3816static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
3817{
3818}
3819
3820static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
3821{
3822}
3823
3824#ifdef CONFIG_IPMI_PANIC_STRING
Corey Minyard56a55ec2005-09-06 15:18:42 -07003825static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003827 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3828 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
3829 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
3830 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 {
3832 /* A get event receiver command, save it. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003833 intf->event_receiver = msg->msg.data[1];
3834 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 }
3836}
3837
Corey Minyard56a55ec2005-09-06 15:18:42 -07003838static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839{
Corey Minyard56a55ec2005-09-06 15:18:42 -07003840 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
3841 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
3842 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
3843 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 {
3845 /* A get device id command, save if we are an event
3846 receiver or generator. */
Corey Minyard56a55ec2005-09-06 15:18:42 -07003847 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
3848 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 }
3850}
3851#endif
3852
3853static void send_panic_events(char *str)
3854{
3855 struct kernel_ipmi_msg msg;
3856 ipmi_smi_t intf;
3857 unsigned char data[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 struct ipmi_system_interface_addr *si;
3859 struct ipmi_addr addr;
3860 struct ipmi_smi_msg smi_msg;
3861 struct ipmi_recv_msg recv_msg;
3862
3863 si = (struct ipmi_system_interface_addr *) &addr;
3864 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3865 si->channel = IPMI_BMC_CHANNEL;
3866 si->lun = 0;
3867
3868 /* Fill in an event telling that we have failed. */
3869 msg.netfn = 0x04; /* Sensor or Event. */
3870 msg.cmd = 2; /* Platform event command. */
3871 msg.data = data;
3872 msg.data_len = 8;
Matt Domschcda315a2005-12-12 00:37:32 -08003873 data[0] = 0x41; /* Kernel generator ID, IPMI table 5-4 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 data[1] = 0x03; /* This is for IPMI 1.0. */
3875 data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
3876 data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
3877 data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
3878
3879 /* Put a few breadcrumbs in. Hopefully later we can add more things
3880 to make the panic events more useful. */
3881 if (str) {
3882 data[3] = str[0];
3883 data[6] = str[1];
3884 data[7] = str[2];
3885 }
3886
3887 smi_msg.done = dummy_smi_done_handler;
3888 recv_msg.done = dummy_recv_done_handler;
3889
3890 /* For every registered interface, send the event. */
Corey Minyardbca03242006-12-06 20:40:57 -08003891 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08003892 if (!intf->handlers)
3893 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 continue;
3895
3896 /* Send the event announcing the panic. */
3897 intf->handlers->set_run_to_completion(intf->send_info, 1);
3898 i_ipmi_request(NULL,
3899 intf,
3900 &addr,
3901 0,
3902 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003903 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 &smi_msg,
3905 &recv_msg,
3906 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003907 intf->channels[0].address,
3908 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 0, 1); /* Don't retry, and don't wait. */
3910 }
3911
3912#ifdef CONFIG_IPMI_PANIC_STRING
3913 /* On every interface, dump a bunch of OEM event holding the
3914 string. */
3915 if (!str)
3916 return;
3917
Corey Minyardbca03242006-12-06 20:40:57 -08003918 /* For every registered interface, send the event. */
3919 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 char *p = str;
3921 struct ipmi_ipmb_addr *ipmb;
3922 int j;
3923
Corey Minyardbca03242006-12-06 20:40:57 -08003924 if (intf->intf_num == -1)
3925 /* Interface was not ready yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 continue;
3927
Corey Minyard78ba2fa2007-02-10 01:45:45 -08003928 /*
3929 * intf_num is used as an marker to tell if the
3930 * interface is valid. Thus we need a read barrier to
3931 * make sure data fetched before checking intf_num
3932 * won't be used.
3933 */
3934 smp_rmb();
3935
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 /* First job here is to figure out where to send the
3937 OEM events. There's no way in IPMI to send OEM
3938 events using an event send command, so we have to
3939 find the SEL to put them in and stick them in
3940 there. */
3941
3942 /* Get capabilities from the get device id. */
3943 intf->local_sel_device = 0;
3944 intf->local_event_generator = 0;
3945 intf->event_receiver = 0;
3946
3947 /* Request the device info from the local MC. */
3948 msg.netfn = IPMI_NETFN_APP_REQUEST;
3949 msg.cmd = IPMI_GET_DEVICE_ID_CMD;
3950 msg.data = NULL;
3951 msg.data_len = 0;
3952 intf->null_user_handler = device_id_fetcher;
3953 i_ipmi_request(NULL,
3954 intf,
3955 &addr,
3956 0,
3957 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003958 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 &smi_msg,
3960 &recv_msg,
3961 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003962 intf->channels[0].address,
3963 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 0, 1); /* Don't retry, and don't wait. */
3965
3966 if (intf->local_event_generator) {
3967 /* Request the event receiver from the local MC. */
3968 msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
3969 msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
3970 msg.data = NULL;
3971 msg.data_len = 0;
3972 intf->null_user_handler = event_receiver_fetcher;
3973 i_ipmi_request(NULL,
3974 intf,
3975 &addr,
3976 0,
3977 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07003978 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 &smi_msg,
3980 &recv_msg,
3981 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07003982 intf->channels[0].address,
3983 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 0, 1); /* no retry, and no wait. */
3985 }
3986 intf->null_user_handler = NULL;
3987
3988 /* Validate the event receiver. The low bit must not
3989 be 1 (it must be a valid IPMB address), it cannot
3990 be zero, and it must not be my address. */
3991 if (((intf->event_receiver & 1) == 0)
3992 && (intf->event_receiver != 0)
Corey Minyardc14979b2005-09-06 15:18:38 -07003993 && (intf->event_receiver != intf->channels[0].address))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 {
3995 /* The event receiver is valid, send an IPMB
3996 message. */
3997 ipmb = (struct ipmi_ipmb_addr *) &addr;
3998 ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
3999 ipmb->channel = 0; /* FIXME - is this right? */
4000 ipmb->lun = intf->event_receiver_lun;
4001 ipmb->slave_addr = intf->event_receiver;
4002 } else if (intf->local_sel_device) {
4003 /* The event receiver was not valid (or was
4004 me), but I am an SEL device, just dump it
4005 in my SEL. */
4006 si = (struct ipmi_system_interface_addr *) &addr;
4007 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
4008 si->channel = IPMI_BMC_CHANNEL;
4009 si->lun = 0;
4010 } else
4011 continue; /* No where to send the event. */
4012
4013
4014 msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
4015 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
4016 msg.data = data;
4017 msg.data_len = 16;
4018
4019 j = 0;
4020 while (*p) {
4021 int size = strlen(p);
4022
4023 if (size > 11)
4024 size = 11;
4025 data[0] = 0;
4026 data[1] = 0;
4027 data[2] = 0xf0; /* OEM event without timestamp. */
Corey Minyardc14979b2005-09-06 15:18:38 -07004028 data[3] = intf->channels[0].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 data[4] = j++; /* sequence # */
4030 /* Always give 11 bytes, so strncpy will fill
4031 it with zeroes for me. */
4032 strncpy(data+5, p, 11);
4033 p += size;
4034
4035 i_ipmi_request(NULL,
4036 intf,
4037 &addr,
4038 0,
4039 &msg,
Corey Minyard56a55ec2005-09-06 15:18:42 -07004040 intf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 &smi_msg,
4042 &recv_msg,
4043 0,
Corey Minyardc14979b2005-09-06 15:18:38 -07004044 intf->channels[0].address,
4045 intf->channels[0].lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 0, 1); /* no retry, and no wait. */
4047 }
4048 }
4049#endif /* CONFIG_IPMI_PANIC_STRING */
4050}
4051#endif /* CONFIG_IPMI_PANIC_EVENT */
4052
Randy Dunlap0c8204b2006-12-10 02:19:06 -08004053static int has_panicked;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054
4055static int panic_event(struct notifier_block *this,
4056 unsigned long event,
4057 void *ptr)
4058{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 ipmi_smi_t intf;
4060
Lee Revellf18190b2006-06-26 18:30:00 +02004061 if (has_panicked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 return NOTIFY_DONE;
Lee Revellf18190b2006-06-26 18:30:00 +02004063 has_panicked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064
4065 /* For every registered interface, set it to run to completion. */
Corey Minyardbca03242006-12-06 20:40:57 -08004066 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
Corey Minyardb2c03942006-12-06 20:41:00 -08004067 if (!intf->handlers)
4068 /* Interface is not ready. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 continue;
4070
4071 intf->handlers->set_run_to_completion(intf->send_info, 1);
4072 }
4073
4074#ifdef CONFIG_IPMI_PANIC_EVENT
4075 send_panic_events(ptr);
4076#endif
4077
4078 return NOTIFY_DONE;
4079}
4080
4081static struct notifier_block panic_block = {
4082 .notifier_call = panic_event,
4083 .next = NULL,
4084 .priority = 200 /* priority: INT_MAX >= x >= 0 */
4085};
4086
4087static int ipmi_init_msghandler(void)
4088{
Corey Minyard50c812b2006-03-26 01:37:21 -08004089 int rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090
4091 if (initialized)
4092 return 0;
4093
Corey Minyard50c812b2006-03-26 01:37:21 -08004094 rv = driver_register(&ipmidriver);
4095 if (rv) {
4096 printk(KERN_ERR PFX "Could not register IPMI driver\n");
4097 return rv;
4098 }
4099
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 printk(KERN_INFO "ipmi message handler version "
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004101 IPMI_DRIVER_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102
Corey Minyard3b625942005-06-23 22:01:42 -07004103#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 proc_ipmi_root = proc_mkdir("ipmi", NULL);
4105 if (!proc_ipmi_root) {
4106 printk(KERN_ERR PFX "Unable to create IPMI proc dir");
4107 return -ENOMEM;
4108 }
4109
4110 proc_ipmi_root->owner = THIS_MODULE;
Corey Minyard3b625942005-06-23 22:01:42 -07004111#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112
Corey Minyard409035e2006-06-28 04:26:53 -07004113 setup_timer(&ipmi_timer, ipmi_timeout, 0);
4114 mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115
Alan Sterne041c682006-03-27 01:16:30 -08004116 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117
4118 initialized = 1;
4119
4120 return 0;
4121}
4122
4123static __init int ipmi_init_msghandler_mod(void)
4124{
4125 ipmi_init_msghandler();
4126 return 0;
4127}
4128
4129static __exit void cleanup_ipmi(void)
4130{
4131 int count;
4132
4133 if (!initialized)
4134 return;
4135
Alan Sterne041c682006-03-27 01:16:30 -08004136 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
4138 /* This can't be called if any interfaces exist, so no worry about
4139 shutting down the interfaces. */
4140
4141 /* Tell the timer to stop, then wait for it to stop. This avoids
4142 problems with race conditions removing the timer here. */
Corey Minyard8f43f842005-06-23 22:01:40 -07004143 atomic_inc(&stop_operation);
4144 del_timer_sync(&ipmi_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145
Corey Minyard3b625942005-06-23 22:01:42 -07004146#ifdef CONFIG_PROC_FS
Alexey Dobriyan3542ae42007-10-16 23:26:50 -07004147 remove_proc_entry(proc_ipmi_root->name, NULL);
Corey Minyard3b625942005-06-23 22:01:42 -07004148#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149
Corey Minyard50c812b2006-03-26 01:37:21 -08004150 driver_unregister(&ipmidriver);
4151
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 initialized = 0;
4153
4154 /* Check for buffer leaks. */
4155 count = atomic_read(&smi_msg_inuse_count);
4156 if (count != 0)
4157 printk(KERN_WARNING PFX "SMI message count %d at exit\n",
4158 count);
4159 count = atomic_read(&recv_msg_inuse_count);
4160 if (count != 0)
4161 printk(KERN_WARNING PFX "recv message count %d at exit\n",
4162 count);
4163}
4164module_exit(cleanup_ipmi);
4165
4166module_init(ipmi_init_msghandler_mod);
4167MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07004168MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
4169MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
4170MODULE_VERSION(IPMI_DRIVER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171
4172EXPORT_SYMBOL(ipmi_create_user);
4173EXPORT_SYMBOL(ipmi_destroy_user);
4174EXPORT_SYMBOL(ipmi_get_version);
4175EXPORT_SYMBOL(ipmi_request_settime);
4176EXPORT_SYMBOL(ipmi_request_supply_msgs);
Corey Minyardfcfa4722007-10-18 03:07:09 -07004177EXPORT_SYMBOL(ipmi_poll_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178EXPORT_SYMBOL(ipmi_register_smi);
4179EXPORT_SYMBOL(ipmi_unregister_smi);
4180EXPORT_SYMBOL(ipmi_register_for_cmd);
4181EXPORT_SYMBOL(ipmi_unregister_for_cmd);
4182EXPORT_SYMBOL(ipmi_smi_msg_received);
4183EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
4184EXPORT_SYMBOL(ipmi_alloc_smi_msg);
4185EXPORT_SYMBOL(ipmi_addr_length);
4186EXPORT_SYMBOL(ipmi_validate_addr);
4187EXPORT_SYMBOL(ipmi_set_gets_events);
4188EXPORT_SYMBOL(ipmi_smi_watcher_register);
4189EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
4190EXPORT_SYMBOL(ipmi_set_my_address);
4191EXPORT_SYMBOL(ipmi_get_my_address);
4192EXPORT_SYMBOL(ipmi_set_my_LUN);
4193EXPORT_SYMBOL(ipmi_get_my_LUN);
4194EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
Corey Minyard393d2cc2005-11-07 00:59:54 -08004196EXPORT_SYMBOL(ipmi_free_recv_msg);